pry-moves 0.1.13 → 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 +15 -7
- 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 +67 -43
- data/lib/pry-moves/bindings_stack.rb +97 -0
- data/lib/pry-moves/commands.rb +42 -3
- data/lib/pry-moves/formatter.rb +74 -0
- data/lib/pry-moves/painter.rb +3 -2
- 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 -6
- data/lib/pry-stack_explorer/frame_manager.rb +6 -9
- data/lib/pry-stack_explorer/pry-stack_explorer.rb +1 -16
- data/lib/pry-stack_explorer/{commands.rb → stack_commands.rb} +10 -6
- data/lib/pry-stack_explorer/when_started_hook.rb +10 -65
- data/playground/Gemfile.lock +6 -4
- data/playground/README.md +1 -0
- data/playground/playground.rb +94 -9
- data/playground/test.rb +5 -1
- data/playground/test.sh +1 -0
- data/pry-moves.gemspec +3 -2
- data/publish.sh +2 -1
- 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 -13
- data/lib/pry-moves/helpers.rb +0 -56
- data/lib/pry-moves/trace_commands.rb +0 -109
- data/lib/pry-moves/traced_method.rb +0 -61
- data/lib/pry-moves/tracer.rb +0 -140
- data/lib/pry-moves/traversing.rb +0 -69
@@ -1,109 +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
|
-
def trace_goto(event, file, line, method, binding_)
|
106
|
-
event == 'line' && @goto_line == line and @method[:file] == file
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
module PryMoves::TracedMethod
|
2
|
-
|
3
|
-
private
|
4
|
-
|
5
|
-
def set_traced_method(binding)
|
6
|
-
@recursion_level = 0
|
7
|
-
@c_stack_level = 0
|
8
|
-
@stay_at_frame = nil # reset tracked digest
|
9
|
-
|
10
|
-
method = find_method_definition binding
|
11
|
-
if method
|
12
|
-
source = method.source_location
|
13
|
-
set_method({
|
14
|
-
file: source[0],
|
15
|
-
start: source[1],
|
16
|
-
name: method.name,
|
17
|
-
end: (source[1] + method.source.count("\n") - 1)
|
18
|
-
})
|
19
|
-
else
|
20
|
-
set_method({file: binding.eval('__FILE__')})
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def find_method_definition(binding)
|
25
|
-
method_name, obj, line, file =
|
26
|
-
binding.eval '[__method__, self, __LINE__, __FILE__]'
|
27
|
-
return unless method_name
|
28
|
-
|
29
|
-
method = obj.method(method_name)
|
30
|
-
return method if method.source_location[0] == file
|
31
|
-
|
32
|
-
# If found file was different - search definition at superclasses:
|
33
|
-
obj.class.ancestors.each do |cls|
|
34
|
-
if cls.instance_methods(false).include? method_name
|
35
|
-
method = cls.instance_method method_name
|
36
|
-
return method if method.source_location[0] == file
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
pry_puts "⚠️ Unable to find definition for method #{method_name} in #{obj}"
|
41
|
-
|
42
|
-
nil
|
43
|
-
end
|
44
|
-
|
45
|
-
def set_method(method)
|
46
|
-
#puts "set_traced_method #{method}"
|
47
|
-
@method = method
|
48
|
-
end
|
49
|
-
|
50
|
-
def within_current_method?(file, line)
|
51
|
-
@method[:file] == file and (
|
52
|
-
@method[:start].nil? or
|
53
|
-
line.between?(@method[:start], @method[:end])
|
54
|
-
)
|
55
|
-
end
|
56
|
-
|
57
|
-
def before_end?(line)
|
58
|
-
@method[:end] and line < @method[:end]
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
data/lib/pry-moves/tracer.rb
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
require 'digest'
|
2
|
-
|
3
|
-
require 'pry' unless defined? Pry
|
4
|
-
|
5
|
-
module PryMoves
|
6
|
-
class Tracer
|
7
|
-
|
8
|
-
include PryMoves::TraceCommands
|
9
|
-
include PryMoves::TracedMethod
|
10
|
-
|
11
|
-
def initialize(command, pry_start_options)
|
12
|
-
@command = command
|
13
|
-
@pry_start_options = pry_start_options
|
14
|
-
end
|
15
|
-
|
16
|
-
def trace
|
17
|
-
@action = @command[:action]
|
18
|
-
#puts "COMMAND: #{@action}"
|
19
|
-
binding_ = @command[:binding]
|
20
|
-
set_traced_method binding_
|
21
|
-
|
22
|
-
@recursion_level -= 1 if @pry_start_options.delete :exit_from_method
|
23
|
-
|
24
|
-
case @action
|
25
|
-
when :step
|
26
|
-
@step_into_funcs = nil
|
27
|
-
func = @command[:param]
|
28
|
-
if func == '+'
|
29
|
-
@step_in_everywhere = true
|
30
|
-
elsif func
|
31
|
-
@step_into_funcs = [func]
|
32
|
-
@step_into_funcs << '=initialize' if func == 'new' or func == '=new'
|
33
|
-
@caller_digest = frame_digest(binding_)
|
34
|
-
end
|
35
|
-
when :finish
|
36
|
-
@method_to_finish = @method
|
37
|
-
@block_to_finish =
|
38
|
-
(binding_.frame_type == :block) &&
|
39
|
-
frame_digest(binding_)
|
40
|
-
when :next
|
41
|
-
if @command[:param] == 'blockless'
|
42
|
-
@stay_at_frame = frame_digest(binding_)
|
43
|
-
end
|
44
|
-
when :iterate
|
45
|
-
@iteration_start_line = binding_.eval('__LINE__')
|
46
|
-
@caller_digest = frame_digest(binding_)
|
47
|
-
when :goto
|
48
|
-
@goto_line = @command[:param].to_i
|
49
|
-
end
|
50
|
-
|
51
|
-
start_tracing
|
52
|
-
end
|
53
|
-
|
54
|
-
def stop_tracing
|
55
|
-
trace_obj.set_trace_func nil
|
56
|
-
Pry.config.disable_breakpoints = false
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def start_tracing
|
62
|
-
#puts "##trace_obj #{trace_obj}"
|
63
|
-
Pry.config.disable_breakpoints = true
|
64
|
-
trace_obj.set_trace_func method(:tracing_func).to_proc
|
65
|
-
end
|
66
|
-
|
67
|
-
# You can't call set_trace_func or Thread.current.set_trace_func recursively
|
68
|
-
# even in different threads 😪
|
69
|
-
# But! 💡
|
70
|
-
# The hack is - you can call Thread.current.set_trace_func
|
71
|
-
# from inside of set_trace_func! 🤗
|
72
|
-
def trace_obj
|
73
|
-
Thread.current[:pry_moves_debug] ?
|
74
|
-
Thread.current : Kernel
|
75
|
-
end
|
76
|
-
|
77
|
-
def frame_digest(binding_)
|
78
|
-
#puts "frame_digest for: #{binding_.eval '__callee__'}"
|
79
|
-
Digest::MD5.hexdigest binding_.instance_variable_get('@iseq').disasm
|
80
|
-
end
|
81
|
-
|
82
|
-
def tracing_func(event, file, line, id, binding_, klass)
|
83
|
-
# printf ": %8s %s:%-2d %10s %8s rec:#{@recursion_level} st:#{@c_stack_level}\n", event, file, line, id, klass
|
84
|
-
|
85
|
-
# Ignore traces inside pry-moves code
|
86
|
-
return if file && TRACE_IGNORE_FILES.include?(File.expand_path(file))
|
87
|
-
|
88
|
-
catch (:skip) do
|
89
|
-
if send "trace_#{@action}", event, file, line, id, binding_
|
90
|
-
stop_tracing
|
91
|
-
Pry.start(binding_, @pry_start_options)
|
92
|
-
|
93
|
-
# for cases when currently traced method called more times recursively
|
94
|
-
elsif %w(call return).include?(event) and within_current_method?(file, line) and
|
95
|
-
@method[:name] == id # fix for bug in traced_method: return for dynamic methods has line number inside of caller
|
96
|
-
delta = event == 'call' ? 1 : -1
|
97
|
-
#puts "recursion #{event}: #{delta}; changed: #{@recursion_level} => #{@recursion_level + delta}"
|
98
|
-
@recursion_level += delta
|
99
|
-
elsif %w(c-call c-return).include?(event)
|
100
|
-
delta = event == 'c-call' ? 1 : -1
|
101
|
-
@c_stack_level += delta
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def method_matches?(method)
|
107
|
-
@step_into_funcs.any? do |pattern|
|
108
|
-
if pattern.start_with? '='
|
109
|
-
"=#{method}" == pattern
|
110
|
-
else
|
111
|
-
method.include? pattern
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def redirect_step_into?(binding_)
|
117
|
-
return false unless binding_.local_variable_defined? :debug_redirect
|
118
|
-
|
119
|
-
debug_redirect = binding_.local_variable_get(:debug_redirect)
|
120
|
-
@step_into_funcs = [debug_redirect.to_s] if debug_redirect
|
121
|
-
true
|
122
|
-
end
|
123
|
-
|
124
|
-
def debug_info(file, line, id)
|
125
|
-
puts "📽 Action:#{@action}; recur:#{@recursion_level}; #{@method[:file]}:#{file}"
|
126
|
-
puts "#{id} #{@method[:start]} > #{line} > #{@method[:end]}"
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
def pry_puts(text)
|
131
|
-
@command[:pry].output.puts text
|
132
|
-
end
|
133
|
-
|
134
|
-
def exit_from_method
|
135
|
-
@pry_start_options[:exit_from_method] = true
|
136
|
-
true
|
137
|
-
end
|
138
|
-
|
139
|
-
end
|
140
|
-
end
|
data/lib/pry-moves/traversing.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module PryMoves
|
2
|
-
|
3
|
-
class Traversing < Pry::ClassCommand
|
4
|
-
|
5
|
-
group 'Input and Output'
|
6
|
-
description "Continue traversing of last object in history."
|
7
|
-
|
8
|
-
banner <<-'BANNER'
|
9
|
-
Usage: .method | 123 | :hash_key
|
10
|
-
|
11
|
-
Continue traversing of last object in history
|
12
|
-
|
13
|
-
E.g. `orders` will list array, then `3` will enter `orders[3]`, then `.price` will enter `orders[3].price`
|
14
|
-
BANNER
|
15
|
-
|
16
|
-
def process(cmd)
|
17
|
-
last_cmd = Pry.history.to_a[-1]
|
18
|
-
cmd = "#{last_cmd}#{wrap_command(cmd)}"
|
19
|
-
_pry_.pager.page " > #{cmd}\n"
|
20
|
-
_pry_.eval cmd
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
class Method < Traversing
|
29
|
-
match(/^\.(.+)$/)
|
30
|
-
|
31
|
-
def wrap_command(cmd)
|
32
|
-
".#{cmd}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class ArrayIndex < Traversing
|
37
|
-
match(/^(\d+)$/)
|
38
|
-
|
39
|
-
def wrap_command(cmd)
|
40
|
-
"[#{cmd}]"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class HashKey < Traversing
|
45
|
-
match(/^(:\w+)$/)
|
46
|
-
|
47
|
-
def wrap_command(cmd)
|
48
|
-
"[#{cmd}]"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
Pry::Commands.add_command(PryMoves::Method)
|
53
|
-
Pry::Commands.add_command(PryMoves::ArrayIndex)
|
54
|
-
Pry::Commands.add_command(PryMoves::HashKey)
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
Pry::History.class_eval do
|
59
|
-
|
60
|
-
EXCLUDE = [PryMoves::Method, PryMoves::ArrayIndex, PryMoves::HashKey]
|
61
|
-
|
62
|
-
def <<(line)
|
63
|
-
return if EXCLUDE.any? do |cls|
|
64
|
-
line.match(cls.match)
|
65
|
-
end
|
66
|
-
push line
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|