pry-moves 0.1.13 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|