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.
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