pry-moves 0.1.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +6 -4
- data/README.md +28 -8
- data/lib/commands/debug.rb +17 -0
- data/lib/commands/finish.rb +26 -0
- data/lib/commands/goto.rb +19 -0
- data/lib/commands/iterate.rb +22 -0
- data/lib/commands/next.rb +37 -0
- data/lib/commands/next_breakpoint.rb +22 -0
- data/lib/commands/step.rb +83 -0
- data/lib/commands/trace_command.rb +87 -0
- data/lib/commands/trace_helpers.rb +49 -0
- data/lib/commands/traced_method.rb +71 -0
- data/lib/debug_sugar.rb +72 -0
- data/lib/pry-moves/add_suffix.rb +88 -0
- data/lib/pry-moves/backtrace.rb +70 -46
- data/lib/pry-moves/bindings_stack.rb +97 -0
- data/lib/pry-moves/commands.rb +50 -7
- data/lib/pry-moves/formatter.rb +74 -0
- data/lib/pry-moves/painter.rb +5 -0
- data/lib/pry-moves/pry_ext.rb +64 -16
- data/lib/pry-moves/pry_wrapper.rb +30 -17
- data/lib/pry-moves/restartable.rb +38 -0
- data/lib/pry-moves/version.rb +1 -1
- data/lib/pry-moves/watch.rb +3 -0
- data/lib/pry-moves.rb +65 -4
- data/lib/pry-stack_explorer/VERSION +2 -0
- data/lib/pry-stack_explorer/frame_manager.rb +6 -9
- data/lib/pry-stack_explorer/pry-stack_explorer.rb +3 -17
- data/lib/pry-stack_explorer/{commands.rb → stack_commands.rb} +10 -6
- data/lib/pry-stack_explorer/when_started_hook.rb +17 -63
- data/playground/Gemfile.lock +9 -9
- data/playground/README.md +1 -0
- data/playground/playground.rb +94 -9
- data/playground/sand.rb +46 -12
- data/playground/test.rb +5 -1
- data/playground/test.sh +1 -0
- data/pry-moves.gemspec +3 -2
- data/publish.sh +3 -0
- data/spec/backtrace_spec.rb +11 -13
- data/spec/blocks_spec.rb +41 -8
- data/spec/commands_spec.rb +26 -25
- data/spec/pry_debugger.rb +5 -1
- data/spec/redirection_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -4
- data/spec/step_spec.rb +51 -0
- metadata +43 -10
- data/lib/pry-moves/helpers.rb +0 -50
- data/lib/pry-moves/trace_commands.rb +0 -105
- data/lib/pry-moves/tracer.rb +0 -169
data/lib/pry-moves/helpers.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module PryMoves::Helpers
|
2
|
-
|
3
|
-
extend self
|
4
|
-
|
5
|
-
# @return [String] Signature for the method object in Class#method format.
|
6
|
-
def method_signature_with_owner(binding)
|
7
|
-
meth = binding.eval('__method__')
|
8
|
-
meth_obj = meth ? Pry::Method.from_binding(binding) : nil
|
9
|
-
if !meth_obj
|
10
|
-
""
|
11
|
-
elsif meth_obj.undefined?
|
12
|
-
"#{meth_obj.name_with_owner}(UNKNOWN) (undefined method)"
|
13
|
-
else
|
14
|
-
args = meth_obj.parameters.inject([]) do |arr, (type, name)|
|
15
|
-
name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
|
16
|
-
arr << case type
|
17
|
-
when :req then name.to_s
|
18
|
-
when :opt then "#{name}=?"
|
19
|
-
when :rest then "*#{name}"
|
20
|
-
when :block then "&#{name}"
|
21
|
-
else '?'
|
22
|
-
end
|
23
|
-
end
|
24
|
-
"#{meth_obj.name_with_owner}(#{args.join(', ')})"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def method_signature(binding)
|
29
|
-
meth = binding.eval('__method__')
|
30
|
-
meth_obj = meth ? Pry::Method.from_binding(binding) : nil
|
31
|
-
if !meth_obj
|
32
|
-
""
|
33
|
-
elsif meth_obj.undefined?
|
34
|
-
"#{meth_obj.name}(UNKNOWN) (undefined method)"
|
35
|
-
else
|
36
|
-
args = meth_obj.parameters.inject([]) do |arr, (type, name)|
|
37
|
-
name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
|
38
|
-
arr << case type
|
39
|
-
when :req then name.to_s
|
40
|
-
when :opt then "#{name}=?"
|
41
|
-
when :rest then "*#{name}"
|
42
|
-
when :block then "&#{name}"
|
43
|
-
else '?'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
"#{meth_obj.name}(#{args.join(', ')})"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
module PryMoves::TraceCommands
|
2
|
-
|
3
|
-
private
|
4
|
-
|
5
|
-
def trace_step(event, file, line, method, binding_)
|
6
|
-
return unless event == 'line'
|
7
|
-
|
8
|
-
if @step_in_everywhere
|
9
|
-
true
|
10
|
-
elsif @step_into_funcs
|
11
|
-
|
12
|
-
if @recursion_level < 0
|
13
|
-
pry_puts "⚠️ Unable to find function with name #{@step_into_funcs.join(',')}"
|
14
|
-
return true
|
15
|
-
end
|
16
|
-
|
17
|
-
method = binding_.eval('__callee__').to_s
|
18
|
-
return false unless method_matches?(method)
|
19
|
-
|
20
|
-
func_reached = (not @caller_digest or
|
21
|
-
# if we want to step-in only into straight descendant
|
22
|
-
@caller_digest == frame_digest(binding_.of_caller(3 + 1)))
|
23
|
-
|
24
|
-
if func_reached
|
25
|
-
@caller_digest = nil
|
26
|
-
not redirect_step_into? binding_
|
27
|
-
end
|
28
|
-
|
29
|
-
elsif redirect_step_into? binding_
|
30
|
-
false
|
31
|
-
else
|
32
|
-
not binding_.local_variable_defined? :hide_from_stack
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def trace_next(event, file, line, method, binding_)
|
37
|
-
traced_method_exit = (@recursion_level < 0 and %w(line call).include? event)
|
38
|
-
if traced_method_exit
|
39
|
-
# Set new traced method, because we left previous one
|
40
|
-
set_traced_method binding_
|
41
|
-
throw :skip if event == 'call'
|
42
|
-
end
|
43
|
-
|
44
|
-
if @recursion_level == 0 and
|
45
|
-
within_current_method?(file, line)
|
46
|
-
|
47
|
-
if event == 'line'
|
48
|
-
if @stay_at_frame
|
49
|
-
return (
|
50
|
-
@stay_at_frame == frame_digest(binding_.of_caller(3)) or
|
51
|
-
@c_stack_level < 0
|
52
|
-
)
|
53
|
-
else
|
54
|
-
return true
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
exit_from_method if event == 'return' and
|
59
|
-
method != :to_s and before_end?(line)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def trace_finish(event, file, line, method, binding_)
|
64
|
-
return unless event == 'line'
|
65
|
-
if @recursion_level < 0 or @method_to_finish != @method
|
66
|
-
if redirect_step_into?(binding_)
|
67
|
-
@action = :step
|
68
|
-
return false
|
69
|
-
end
|
70
|
-
return true
|
71
|
-
end
|
72
|
-
|
73
|
-
# for finishing blocks inside current method
|
74
|
-
if @block_to_finish
|
75
|
-
@recursion_level == 0 and
|
76
|
-
within_current_method?(file, line) and
|
77
|
-
@block_to_finish != frame_digest(binding_.of_caller(3))
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def trace_debug(event, file, line, method, binding_)
|
82
|
-
return unless event == 'line'
|
83
|
-
if @first_line_skipped
|
84
|
-
true
|
85
|
-
else
|
86
|
-
@first_line_skipped = true
|
87
|
-
false
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def trace_iterate(event, file, line, method, binding_)
|
92
|
-
return exit_from_method if event == 'return' and
|
93
|
-
within_current_method?(file, line)
|
94
|
-
|
95
|
-
# промотка итерации -
|
96
|
-
# попасть на ту же или предыдущую строку или выйти из дайджеста
|
97
|
-
# будучи в том же методе
|
98
|
-
event == 'line' and @recursion_level == 0 and
|
99
|
-
within_current_method?(file, line) and
|
100
|
-
(line <= @iteration_start_line or
|
101
|
-
@caller_digest != frame_digest(binding_.of_caller(3))
|
102
|
-
)
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|
data/lib/pry-moves/tracer.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
require 'pry' unless defined? Pry
|
2
|
-
|
3
|
-
module PryMoves
|
4
|
-
class Tracer
|
5
|
-
|
6
|
-
include PryMoves::TraceCommands
|
7
|
-
|
8
|
-
def initialize(command, pry_start_options)
|
9
|
-
@command = command
|
10
|
-
@pry_start_options = pry_start_options
|
11
|
-
end
|
12
|
-
|
13
|
-
def trace
|
14
|
-
@action = @command[:action]
|
15
|
-
#puts "COMMAND: #{@action}"
|
16
|
-
binding_ = @command[:binding]
|
17
|
-
set_traced_method binding_
|
18
|
-
|
19
|
-
@recursion_level -= 1 if @pry_start_options.delete :exit_from_method
|
20
|
-
|
21
|
-
case @action
|
22
|
-
when :step
|
23
|
-
@step_into_funcs = nil
|
24
|
-
func = @command[:param]
|
25
|
-
if func == '+'
|
26
|
-
@step_in_everywhere = true
|
27
|
-
elsif func
|
28
|
-
@step_into_funcs = [func]
|
29
|
-
@step_into_funcs << '=initialize' if func == 'new' or func == '=new'
|
30
|
-
@caller_digest = frame_digest(binding_)
|
31
|
-
end
|
32
|
-
when :finish
|
33
|
-
@method_to_finish = @method
|
34
|
-
@block_to_finish =
|
35
|
-
(binding_.frame_type == :block) &&
|
36
|
-
frame_digest(binding_)
|
37
|
-
when :next
|
38
|
-
if @command[:param] == 'blockless'
|
39
|
-
@stay_at_frame = frame_digest(binding_)
|
40
|
-
end
|
41
|
-
when :iterate
|
42
|
-
@iteration_start_line = binding_.eval('__LINE__')
|
43
|
-
@caller_digest = frame_digest(binding_)
|
44
|
-
end
|
45
|
-
|
46
|
-
start_tracing
|
47
|
-
end
|
48
|
-
|
49
|
-
def stop_tracing
|
50
|
-
trace_obj.set_trace_func nil
|
51
|
-
Pry.config.disable_breakpoints = false
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def start_tracing
|
57
|
-
#puts "##trace_obj #{trace_obj}"
|
58
|
-
Pry.config.disable_breakpoints = true
|
59
|
-
trace_obj.set_trace_func method(:tracing_func).to_proc
|
60
|
-
end
|
61
|
-
|
62
|
-
# You can't call set_trace_func or Thread.current.set_trace_func recursively
|
63
|
-
# even in different threads 😪
|
64
|
-
# But! 💡
|
65
|
-
# The hack is - you can call Thread.current.set_trace_func
|
66
|
-
# from inside of set_trace_func! 🤗
|
67
|
-
def trace_obj
|
68
|
-
Thread.current[:pry_moves_debug] ?
|
69
|
-
Thread.current : Kernel
|
70
|
-
end
|
71
|
-
|
72
|
-
def set_traced_method(binding)
|
73
|
-
@recursion_level = 0
|
74
|
-
@c_stack_level = 0
|
75
|
-
@stay_at_frame = nil # reset tracked digest
|
76
|
-
|
77
|
-
method = binding.eval 'method(__method__) if __method__'
|
78
|
-
if method
|
79
|
-
source = method.source_location
|
80
|
-
set_method({
|
81
|
-
file: source[0],
|
82
|
-
start: source[1],
|
83
|
-
name: method.name,
|
84
|
-
end: (source[1] + method.source.count("\n") - 1)
|
85
|
-
})
|
86
|
-
else
|
87
|
-
set_method({file: binding.eval('__FILE__')})
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def set_method(method)
|
92
|
-
#puts "set_traced_method #{method}"
|
93
|
-
@method = method
|
94
|
-
end
|
95
|
-
|
96
|
-
def frame_digest(binding_)
|
97
|
-
#puts "frame_digest for: #{binding_.eval '__callee__'}"
|
98
|
-
Digest::MD5.hexdigest binding_.instance_variable_get('@iseq').disasm
|
99
|
-
end
|
100
|
-
|
101
|
-
def tracing_func(event, file, line, id, binding_, klass)
|
102
|
-
#printf ": %8s %s:%-2d %10s %8s rec:#{@recursion_level} st:#{@c_stack_level}\n", event, file, line, id, klass
|
103
|
-
|
104
|
-
# Ignore traces inside pry-moves code
|
105
|
-
return if file && TRACE_IGNORE_FILES.include?(File.expand_path(file))
|
106
|
-
|
107
|
-
catch (:skip) do
|
108
|
-
if send "trace_#{@action}", event, file, line, id, binding_
|
109
|
-
stop_tracing
|
110
|
-
Pry.start(binding_, @pry_start_options)
|
111
|
-
|
112
|
-
# for cases when currently traced method called more times recursively
|
113
|
-
elsif %w(call return).include?(event) and within_current_method?(file, line) and
|
114
|
-
@method[:name] == id # fix for bug in traced_method: return for dynamic methods has line number inside of caller
|
115
|
-
delta = event == 'call' ? 1 : -1
|
116
|
-
#puts "recursion #{event}: #{delta}; changed: #{@recursion_level} => #{@recursion_level + delta}"
|
117
|
-
@recursion_level += delta
|
118
|
-
elsif %w(c-call c-return).include?(event)
|
119
|
-
delta = event == 'c-call' ? 1 : -1
|
120
|
-
@c_stack_level += delta
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def method_matches?(method)
|
126
|
-
@step_into_funcs.any? do |pattern|
|
127
|
-
if pattern.start_with? '='
|
128
|
-
"=#{method}" == pattern
|
129
|
-
else
|
130
|
-
method.include? pattern
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def redirect_step_into?(binding_)
|
136
|
-
return false unless binding_.local_variable_defined? :debug_redirect
|
137
|
-
|
138
|
-
debug_redirect = binding_.local_variable_get(:debug_redirect)
|
139
|
-
@step_into_funcs = [debug_redirect.to_s] if debug_redirect
|
140
|
-
true
|
141
|
-
end
|
142
|
-
|
143
|
-
def debug_info(file, line, id)
|
144
|
-
puts "📽 Action:#{@action}; recur:#{@recursion_level}; #{@method[:file]}:#{file}"
|
145
|
-
puts "#{id} #{@method[:start]} > #{line} > #{@method[:end]}"
|
146
|
-
end
|
147
|
-
|
148
|
-
def within_current_method?(file, line)
|
149
|
-
@method[:file] == file and (
|
150
|
-
@method[:start].nil? or
|
151
|
-
line.between?(@method[:start], @method[:end])
|
152
|
-
)
|
153
|
-
end
|
154
|
-
|
155
|
-
def before_end?(line)
|
156
|
-
@method[:end] and line < @method[:end]
|
157
|
-
end
|
158
|
-
|
159
|
-
def pry_puts(text)
|
160
|
-
@command[:pry].output.puts text
|
161
|
-
end
|
162
|
-
|
163
|
-
def exit_from_method
|
164
|
-
@pry_start_options[:exit_from_method] = true
|
165
|
-
true
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
end
|