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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +6 -4
  4. data/README.md +28 -8
  5. data/lib/commands/debug.rb +17 -0
  6. data/lib/commands/finish.rb +26 -0
  7. data/lib/commands/goto.rb +19 -0
  8. data/lib/commands/iterate.rb +22 -0
  9. data/lib/commands/next.rb +37 -0
  10. data/lib/commands/next_breakpoint.rb +22 -0
  11. data/lib/commands/step.rb +83 -0
  12. data/lib/commands/trace_command.rb +87 -0
  13. data/lib/commands/trace_helpers.rb +49 -0
  14. data/lib/commands/traced_method.rb +71 -0
  15. data/lib/debug_sugar.rb +72 -0
  16. data/lib/pry-moves/add_suffix.rb +88 -0
  17. data/lib/pry-moves/backtrace.rb +70 -46
  18. data/lib/pry-moves/bindings_stack.rb +97 -0
  19. data/lib/pry-moves/commands.rb +50 -7
  20. data/lib/pry-moves/formatter.rb +74 -0
  21. data/lib/pry-moves/painter.rb +5 -0
  22. data/lib/pry-moves/pry_ext.rb +64 -16
  23. data/lib/pry-moves/pry_wrapper.rb +30 -17
  24. data/lib/pry-moves/restartable.rb +38 -0
  25. data/lib/pry-moves/version.rb +1 -1
  26. data/lib/pry-moves/watch.rb +3 -0
  27. data/lib/pry-moves.rb +65 -4
  28. data/lib/pry-stack_explorer/VERSION +2 -0
  29. data/lib/pry-stack_explorer/frame_manager.rb +6 -9
  30. data/lib/pry-stack_explorer/pry-stack_explorer.rb +3 -17
  31. data/lib/pry-stack_explorer/{commands.rb → stack_commands.rb} +10 -6
  32. data/lib/pry-stack_explorer/when_started_hook.rb +17 -63
  33. data/playground/Gemfile.lock +9 -9
  34. data/playground/README.md +1 -0
  35. data/playground/playground.rb +94 -9
  36. data/playground/sand.rb +46 -12
  37. data/playground/test.rb +5 -1
  38. data/playground/test.sh +1 -0
  39. data/pry-moves.gemspec +3 -2
  40. data/publish.sh +3 -0
  41. data/spec/backtrace_spec.rb +11 -13
  42. data/spec/blocks_spec.rb +41 -8
  43. data/spec/commands_spec.rb +26 -25
  44. data/spec/pry_debugger.rb +5 -1
  45. data/spec/redirection_spec.rb +7 -0
  46. data/spec/spec_helper.rb +9 -4
  47. data/spec/step_spec.rb +51 -0
  48. metadata +43 -10
  49. data/lib/pry-moves/helpers.rb +0 -50
  50. data/lib/pry-moves/trace_commands.rb +0 -105
  51. data/lib/pry-moves/tracer.rb +0 -169
@@ -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
@@ -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