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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c8495d3cd82bfbcb6772aa7c5ba21c06aa5528a5fe9bc064589b5291ddaf2e1
4
- data.tar.gz: afe2e3ff6c378e2ea61c7bb21ea6814f68f64b31216f576868808ad6c41a6da2
3
+ metadata.gz: 2c08b34502f7649fecea8dbf09d8bbc04e917341a260c92bc1e1b50e70ad7fe3
4
+ data.tar.gz: 27be890e5b41dafdbdf58279c85618682ef8a3f24fa2a89094053ec8d5af9455
5
5
  SHA512:
6
- metadata.gz: d7ecf92cbc18b7c6e8c1c245d10b9112c264b44a4c7617aa928bcc9a8b2f36f8b61728806b9483e65c2aa8fc5f9d1f13374c4614d92a360a9cec52102ab80166
7
- data.tar.gz: 7da0796248828d36db8fcd305e95a28f7d3e1a517178d2e587785b9998fb42d33058f62a1e7d5fa890da965deaaab6a1c21af92366fbb673809100c28f4985c2
6
+ metadata.gz: b3d5d0a64ab6d910529b3e228154d609b638892913e66ea66c0403e152aea5aa9dceb8e66a46e8515978142af942bb7f59801ec233e1abcb2be44c2338279bc2
7
+ data.tar.gz: f288273d0b30e3bde39ec975e3bd5cb360a7d1a2f747cf8ab95d17e9190ac4f38797c9b21a90a3398383fd5b384dbd4df675a250ad23723360e60ccaed8ebf75
data/Gemfile CHANGED
@@ -4,6 +4,6 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development, :test do
7
- gem 'pry'
7
+ gem 'pry', '0.11.3'
8
8
  gem 'rspec'
9
9
  end
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pry-moves (0.1.8)
4
+ pry-moves (1.0.0)
5
5
  binding_of_caller (~> 0.7)
6
- pry (>= 0.9.10, < 0.12.0)
6
+ colorize (~> 0.8)
7
+ pry (>= 0.10.4, < 0.13)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
@@ -11,6 +12,7 @@ GEM
11
12
  binding_of_caller (0.8.0)
12
13
  debug_inspector (>= 0.0.1)
13
14
  coderay (1.1.2)
15
+ colorize (0.8.1)
14
16
  debug_inspector (0.0.3)
15
17
  diff-lcs (1.3)
16
18
  method_source (0.9.0)
@@ -39,10 +41,10 @@ PLATFORMS
39
41
  ruby
40
42
 
41
43
  DEPENDENCIES
42
- pry
44
+ pry (= 0.11.3)
43
45
  pry-moves!
44
46
  pry-remote (~> 0.1.6)
45
47
  rspec
46
48
 
47
49
  BUNDLED WITH
48
- 1.16.6
50
+ 1.17.3
data/README.md CHANGED
@@ -9,26 +9,35 @@ _An execution control add-on for [Pry][pry]._
9
9
 
10
10
  ## Commands:
11
11
 
12
+ Documentation for latest version. For [v0.1.12 see documentation here](https://github.com/garmoshka-mo/pry-moves/tree/v0.1.12#commands)
13
+
12
14
  * `n` - **next** line in current frame, including block lines (moving to next line goes as naturally expected)
13
15
  * `nn` - **next** line in current frame, skipping block lines
14
16
  * `s` - **step** into function execution
15
17
  * `s method_name` - step into method `method_name` (For example from `User.new.method_name`). Partial name match supported.
16
18
  * `s +` - step into function, including hidden frames
17
19
  * `f` - **finish** execution of current frame (block or method) and stop at next line on higher level
18
- * `iterate` - go to next iteration of current block
19
20
  * `c` - **continue**
20
- * `bt` - show latest 5 lines from backtrace
21
- * `bt 10` - latest 10 lines
22
- * `bt full` - full backtrace
23
- * `bt +` - full backtrace with hidden frames. Aliases: `bt hidden` `bt vapid` `bt all`
21
+ * `b` - go to next breakpoint (breakpoints currently are methods which contain "debug" in their name)
22
+ * `iterate` - go to next iteration of current block
23
+ * `g 10` - **goto** line 10
24
+ * `bt` - show backtrace, excluding hidden frames
25
+ * `bt +` `bt hidden` - show backtrace including hidden frames
26
+ * `bt a` `bt all` - full backtrace with system and hidden frames
27
+ * `bt 10` - go to backtrace line 10
24
28
  * `bt > foo` - write backtrace to file `log/backtrace_foo.log`
25
29
  * `up`/`down`/`top`/`bottom` - move over call stack
26
30
  * `up +` - move up, including vapid frames (block callers, hidden frames)
27
31
  * `up pattern` - move up till first frame which method name or file position in format `folder/script.rb:12` matches regexp pattern
28
32
  * `debug some_method(some_param)` - call `some_method(some_param)` and interactively step into it. This way you can virtually "step back" by executing previous pieces of code from current method
33
+ * `.method` or `123` or `:hash_key` - Continue traversing of last object in history. E.g. `orders` will list array, then `3` will enter `orders[3]`, then `.price` will enter `orders[3].price`
29
34
  * `watch variable` - display variable's value on each step
35
+ * `@` - restart. Set config `PryMoves.reload_rake_tasks = true` to automatically reload rake tasks
36
+ * `#` - exit with code 3, can be wrapped in bash script to fully reload ruby scripts
30
37
  * `!` - exit
31
38
 
39
+ Variable & methods names takes precedence over commands.
40
+ So if you have variable named `step`, to execute command `step` type `cmd step` or command's alias, e.g. `s`
32
41
 
33
42
  ## Examples
34
43
 
@@ -61,16 +70,25 @@ end
61
70
 
62
71
  ## Configuration
63
72
 
64
- Here is default configuration, you can override it:
73
+ Here is default configuration, you can reassign it:
65
74
 
66
75
  ```ruby
67
- PryMoves::Backtrace::lines_count = 5
68
76
  PryMoves::Backtrace::filter =
69
77
  /(\/gems\/|\/rubygems\/|\/bin\/|\/lib\/ruby\/|\/pry-moves\/)/
70
78
  ```
71
79
 
72
80
  ## Threads, helpers
73
81
 
82
+ To allow traveling to parent thread, use:
83
+
84
+ ```ruby
85
+ pre_callers = binding.callers
86
+ Thread.new do
87
+ Thread.current[:pre_callers] = pre_callers
88
+ #...
89
+ end
90
+ ```
91
+
74
92
  `pry-moves` can't stop other threads on `binding.pry`, so they will continue to run.
75
93
  This makes `pry-moves` not always suitable for debugging of multi-thread projects.
76
94
 
@@ -110,6 +128,8 @@ Please note that debugging functionality is implemented through
110
128
 
111
129
  ```
112
130
  bundle exec rspec
131
+
132
+ DEBUG=true bundle exec rspec -e 'backtrace should backtrace'
113
133
  ```
114
134
 
115
135
  ## ToDo
@@ -126,7 +146,7 @@ bundle exec rspec
126
146
  * Ivo Anjo ([@ivoanjo](https://github.com/ivoanjo))
127
147
 
128
148
  Patches and bug reports are welcome. Just send a [pull request][pullrequests] or
129
- file an [issue][issues]. [Project changelog][changelog].
149
+ file an [issue][issues].
130
150
 
131
151
  ## Acknowledgments
132
152
 
@@ -0,0 +1,17 @@
1
+ class PryMoves::Debug < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ #
5
+ end
6
+
7
+ def trace(event, file, line, method, binding_)
8
+ return unless event == 'line'
9
+ if @first_line_skipped
10
+ true
11
+ else
12
+ @first_line_skipped = true
13
+ false
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,26 @@
1
+ class PryMoves::Finish < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @block_to_finish = frame_digest(binding_) if binding_.frame_type == :block
5
+ end
6
+
7
+ def trace(event, file, line, method, binding_)
8
+ return true if @on_exit_from_method
9
+ return if @call_depth > 0 or event == 'c-return'
10
+
11
+ return true if @call_depth < 0
12
+
13
+ # early return:
14
+ return true if event == 'return' and
15
+ @call_depth == 0 and @method.within?(file, line) and
16
+ method == @method[:name] and @method.before_end?(line)
17
+
18
+ # for finishing blocks inside current method
19
+ if @block_to_finish
20
+ ((@call_depth == 0) ^ (event == 'return')) and
21
+ @method.within?(file, line) and
22
+ @block_to_finish != current_frame_digest
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,19 @@
1
+ class PryMoves::Goto < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @goto_line = @command[:param].to_i
5
+ end
6
+
7
+ def trace(event, file, line, method, binding_)
8
+ if @call_depth < 0 or
9
+ @call_depth == 0 and event == 'return' and @method.within?(file, line)
10
+ PryMoves.messages << "⚠️ Unable to reach line #{@goto_line} in current frame"
11
+ return true
12
+ end
13
+
14
+ event == 'line' && @goto_line == line and
15
+ @method[:file] == file and
16
+ @call_depth == 0
17
+ end
18
+
19
+ end
@@ -0,0 +1,22 @@
1
+ class PryMoves::Iterate < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @iteration_start_line = binding_.eval('__LINE__')
5
+ @caller_digest = frame_digest(binding_)
6
+ end
7
+
8
+ def trace(event, file, line, method, binding_)
9
+ return true if event == 'return' and
10
+ @method.within?(file, line)
11
+
12
+ # промотка итерации -
13
+ # попасть на ту же или предыдущую строку или выйти из дайджеста
14
+ # будучи в том же методе
15
+ event == 'line' and @call_depth == 0 and
16
+ @method.within?(file, line) and
17
+ (line <= @iteration_start_line or
18
+ @caller_digest != current_frame_digest
19
+ )
20
+ end
21
+
22
+ end
@@ -0,0 +1,37 @@
1
+ class PryMoves::Next < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @start_line = binding_.eval('__LINE__')
5
+ @start_digest = frame_digest(binding_)
6
+ if @command[:param] == 'blockless'
7
+ @stay_at_frame = @start_digest
8
+ end
9
+ @events_traced = 0
10
+ end
11
+
12
+ def trace(event, file, line, method, binding_)
13
+ @events_traced += 1
14
+
15
+ return true if @call_depth < 0
16
+
17
+ return unless @call_depth == 0 and @method.within?(file, line)
18
+
19
+ if event == 'line'
20
+ if @stay_at_frame
21
+ return (
22
+ @stay_at_frame == current_frame_digest or
23
+ @c_stack_level < 0
24
+ )
25
+ elsif @start_line != line or (
26
+ @events_traced > 1 and # чтобы не застревало на while (vx = shift)
27
+ @start_digest == current_frame_digest # for correct iterating over one_line_in_block
28
+ )
29
+ return true
30
+ end
31
+ end
32
+
33
+ true if event == 'return' and
34
+ method == @method[:name] and @method.before_end?(line)
35
+ end
36
+
37
+ end
@@ -0,0 +1,22 @@
1
+ class PryMoves::NextBreakpoint < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @reach_digest = frame_digest(binding_)
5
+ end
6
+
7
+ def trace(event, file, line, method, binding_)
8
+ if @reach_digest
9
+ if @reach_digest == current_frame_digest
10
+ @reach_digest = nil
11
+ else
12
+ return
13
+ end
14
+ end
15
+
16
+ if method.to_s.include? "debug"
17
+ @pry_start_options[:initial_frame] = 1
18
+ true
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,83 @@
1
+ class PryMoves::Step < PryMoves::TraceCommand
2
+
3
+ def init(binding_)
4
+ @step_into_funcs = nil
5
+ @start_line = binding_.eval('__LINE__')
6
+ @caller_digest = frame_digest(binding_)
7
+ func = @command[:param]
8
+ redirect_step? binding_ # set @step_into_funcs from initial binding
9
+ if func == '+'
10
+ @step_in_everywhere = true
11
+ elsif func
12
+ @find_straight_descendant = true
13
+ @step_into_funcs = [func]
14
+ @step_into_funcs << '=initialize' if ['new', '=new'].include? func
15
+ end
16
+ end
17
+
18
+ def trace(event, file, line, method, binding_)
19
+ if binding_.local_variable_defined? :pry_moves_skip
20
+ finish_cmd = {binding: binding_}
21
+ PryMoves::Finish.new finish_cmd, @pry_start_options do |binding|
22
+ start_tracing
23
+ end
24
+ return
25
+ end
26
+
27
+ @const_missing_level ||= 0
28
+ if method == :const_missing
29
+ if event == 'call'
30
+ @const_missing_level += 1
31
+ elsif event == 'return'
32
+ @const_missing_level -= 1
33
+ end
34
+ end
35
+ return if @const_missing_level > 0
36
+
37
+ return unless event == 'line'
38
+
39
+ if @step_in_everywhere
40
+ return true
41
+ elsif @step_into_funcs
42
+ if @call_depth < 0
43
+ PryMoves.messages << "⚠️ Unable to find function with name #{@step_into_funcs.join(',')}"
44
+ return true
45
+ end
46
+
47
+ return false if keep_search_method? binding_
48
+ elsif redirect_step? binding_
49
+ return false
50
+ elsif binding_.local_variable_defined? :hide_from_stack and
51
+ not @method.within?(file, line, method)
52
+ return false
53
+ end
54
+
55
+ true
56
+ end
57
+
58
+ def keep_search_method? binding_
59
+ return true unless method_matches? binding_.eval('__callee__')
60
+
61
+ return true if @find_straight_descendant &&
62
+ # if we want to step-in only into straight descendant
63
+ @caller_digest != current_frame_digest(upward: 1 + 1) # 1 for getting parent and 1 for 'def keep_search_method?'
64
+ @find_straight_descendant = false
65
+
66
+ return true if redirect_step? binding_
67
+ end
68
+
69
+ def method_matches?(method)
70
+ @step_into_funcs.any? do |pattern|
71
+ if pattern.is_a? Symbol
72
+ method == pattern
73
+ elsif pattern.is_a? Regexp
74
+ method.to_s.match pattern
75
+ elsif pattern.start_with? '='
76
+ "=#{method}" == pattern
77
+ else
78
+ method.to_s.include? pattern
79
+ end
80
+ end
81
+ end
82
+
83
+ end
@@ -0,0 +1,87 @@
1
+ require 'digest'
2
+ require 'pry' unless defined? Pry
3
+
4
+ module PryMoves
5
+ class TraceCommand
6
+
7
+ include PryMoves::TraceHelpers
8
+
9
+ def self.trace(command, pry_start_options, &callback)
10
+ cls = command[:action].to_s.split('_').collect(&:capitalize).join
11
+ cls = Object.const_get "PryMoves::#{cls}"
12
+ cls.new command, pry_start_options, &callback
13
+ end
14
+
15
+ def initialize(command, pry_start_options, &callback)
16
+ @command = command
17
+ @pry_start_options = pry_start_options
18
+ @pry_start_options[:pry_moves_loop] = true
19
+ @callback = callback
20
+ @call_depth = 0
21
+ @c_stack_level = 0
22
+
23
+ binding_ = @command[:binding] # =Command.target - more rich, contains required @iseq
24
+ unless binding_.instance_variable_get('@iseq')
25
+ binding_ = PryMoves::BindingsStack.new.initial_frame
26
+ end
27
+ @method = PryMoves::TracedMethod.new binding_
28
+
29
+ if @pry_start_options.delete :exit_from_method
30
+ @on_exit_from_method = true
31
+ @call_depth -= 1
32
+ end
33
+ @pry_start_options.delete :initial_frame
34
+
35
+ init binding_
36
+ start_tracing
37
+ end
38
+
39
+ def start_tracing
40
+ #puts "##trace_obj #{trace_obj}"
41
+ Pry.config.disable_breakpoints = true
42
+ trace_obj.set_trace_func method(:tracing_func).to_proc
43
+ end
44
+
45
+ def stop_tracing
46
+ trace_obj.set_trace_func nil
47
+ Pry.config.disable_breakpoints = false
48
+ end
49
+
50
+ # You can't call set_trace_func or Thread.current.set_trace_func recursively
51
+ # even in different threads 😪
52
+ # But! 💡
53
+ # The hack is - you can call Thread.current.set_trace_func
54
+ # from inside of set_trace_func! 🤗
55
+ def trace_obj
56
+ Thread.current[:pry_moves_debug] ?
57
+ Thread.current : Kernel
58
+ end
59
+
60
+ def tracing_func(event, file, line, id, binding_, klass)
61
+
62
+ # Ignore traces inside pry-moves code
63
+ return if file && TRACE_IGNORE_FILES.include?(File.expand_path(file))
64
+ return unless binding_ # ignore strange cases
65
+
66
+ # for cases when currently traced method called more times recursively
67
+ if event == "call" and @method.within?(file, line, id)
68
+ @call_depth += 1
69
+ elsif %w(c-call c-return).include?(event)
70
+ # todo: может быть, c-return тоже правильнее делать после trace
71
+ delta = event == 'c-call' ? 1 : -1
72
+ @c_stack_level += delta
73
+ end
74
+
75
+ printf "👟 %8s %s:%-2d %10s %8s dep:#{@call_depth} c_st:#{@c_stack_level}\n", event, file, line, id, klass if PryMoves.trace # TRACE_MOVES=1
76
+
77
+ if trace event, file, line, id, binding_
78
+ @pry_start_options[:exit_from_method] = true if event == 'return'
79
+ stop_tracing
80
+ @callback.call binding_
81
+ elsif event == "return" and @method.within?(file, line, id)
82
+ @call_depth -= 1
83
+ end
84
+ end
85
+
86
+ end
87
+ end