1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
# frozen_string_literal: true
class Pry
module Byebug
#
# Wrapper for Byebug.breakpoints that respects our Processor and has better
# failure behavior. Acts as an Enumerable.
#
module Breakpoints
extend Enumerable
extend self
#
# Breakpoint in a file:line location
#
class FileBreakpoint < SimpleDelegator
def source_code
Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
end
def to_s
"#{source} @ #{pos}"
end
end
#
# Breakpoint in a Class#method location
#
class MethodBreakpoint < SimpleDelegator
def initialize(byebug_bp, method)
__setobj__ byebug_bp
@method = method
end
def source_code
Pry::Code.from_method(Pry::Method.from_str(@method))
end
def to_s
@method
end
end
def breakpoints
@breakpoints ||= []
end
#
# Adds a method breakpoint.
#
def add_method(method, expression = nil)
validate_expression expression
owner, name = method.split(/[\.#]/)
byebug_bp = ::Byebug::Breakpoint.add(owner, name.to_sym, expression)
bp = MethodBreakpoint.new byebug_bp, method
breakpoints << bp
bp
end
#
# Adds a file breakpoint.
#
def add_file(file, line, expression = nil)
real_file = (file != Pry.eval_path)
raise(ArgumentError, "Invalid file!") if real_file && !File.exist?(file)
validate_expression expression
path = (real_file ? File.expand_path(file) : file)
bp = FileBreakpoint.new ::Byebug::Breakpoint.add(path, line, expression)
breakpoints << bp
bp
end
#
# Changes the conditional expression for a breakpoint.
#
def change(id, expression = nil)
validate_expression expression
breakpoint = find_by_id(id)
breakpoint.expr = expression
breakpoint
end
#
# Deletes an existing breakpoint with the given ID.
#
def delete(id)
deleted =
::Byebug::Breakpoint.remove(id) &&
breakpoints.delete(find_by_id(id))
raise(ArgumentError, "No breakpoint ##{id}") unless deleted
end
#
# Deletes all breakpoints.
#
def delete_all
@breakpoints = []
::Byebug.breakpoints.clear
end
#
# Enables a disabled breakpoint with the given ID.
#
def enable(id)
change_status id, true
end
#
# Disables a breakpoint with the given ID.
#
def disable(id)
change_status id, false
end
#
# Disables all breakpoints.
#
def disable_all
each do |breakpoint|
breakpoint.enabled = false
end
end
def to_a
breakpoints
end
def size
to_a.size
end
def each(&block)
to_a.each(&block)
end
def last
to_a.last
end
def find_by_id(id)
breakpoint = find { |b| b.id == id }
raise(ArgumentError, "No breakpoint ##{id}!") unless breakpoint
breakpoint
end
private
def change_status(id, enabled = true)
breakpoint = find_by_id(id)
breakpoint.enabled = enabled
breakpoint
end
def validate_expression(exp)
valid = exp && (exp.empty? || !Pry::Code.complete_expression?(exp))
return unless valid
raise("Invalid breakpoint conditional: #{expression}")
end
end
end
end
|