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.
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 +15 -7
  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 +67 -43
  18. data/lib/pry-moves/bindings_stack.rb +97 -0
  19. data/lib/pry-moves/commands.rb +42 -3
  20. data/lib/pry-moves/formatter.rb +74 -0
  21. data/lib/pry-moves/painter.rb +3 -2
  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 -6
  28. data/lib/pry-stack_explorer/frame_manager.rb +6 -9
  29. data/lib/pry-stack_explorer/pry-stack_explorer.rb +1 -16
  30. data/lib/pry-stack_explorer/{commands.rb → stack_commands.rb} +10 -6
  31. data/lib/pry-stack_explorer/when_started_hook.rb +10 -65
  32. data/playground/Gemfile.lock +6 -4
  33. data/playground/README.md +1 -0
  34. data/playground/playground.rb +94 -9
  35. data/playground/test.rb +5 -1
  36. data/playground/test.sh +1 -0
  37. data/pry-moves.gemspec +3 -2
  38. data/publish.sh +2 -1
  39. data/spec/backtrace_spec.rb +11 -13
  40. data/spec/blocks_spec.rb +41 -8
  41. data/spec/commands_spec.rb +26 -25
  42. data/spec/pry_debugger.rb +5 -1
  43. data/spec/redirection_spec.rb +7 -0
  44. data/spec/spec_helper.rb +9 -4
  45. data/spec/step_spec.rb +51 -0
  46. metadata +43 -13
  47. data/lib/pry-moves/helpers.rb +0 -56
  48. data/lib/pry-moves/trace_commands.rb +0 -109
  49. data/lib/pry-moves/traced_method.rb +0 -61
  50. data/lib/pry-moves/tracer.rb +0 -140
  51. 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
@@ -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
@@ -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