pry-moves 0.1.7 → 0.1.13

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d6153285cad4b74e4f713aa6a39220ffccdba822
4
- data.tar.gz: a71792935b64874e19544c929d550ee720df99ef
2
+ SHA256:
3
+ metadata.gz: 8826581b1684b35099d08f56064e2f3b38ccf3e0d24e3bf40779de9da58151f1
4
+ data.tar.gz: d73a5a0b30ac023416e901a3a965d95b4d232bdef5c0f44ab49ec4dfc7708585
5
5
  SHA512:
6
- metadata.gz: 25310e06f4523f1b50a610e4ab896521d8747ce5fc775d80d38b9937c9c91665300cb82e671bc38f0da5aadd22acb3539037a07e72919d686eeb37a3890ab208
7
- data.tar.gz: a00fc3b9880df6f65524cc804a677e2a209d0f0d5f9a207e1b06c0b1735bb731d68ffb3da5b706f43ae629d4bfe95352bd47de82d9b09d95a86ce16df80d0dda
6
+ metadata.gz: 2ade46c2440bcd4e14a296b9f3785ce0fff501abe953670ce19c9851d0b52488795113179717dffab6b57221c81839317236417bd1ce76380ceed96c3ed4a596
7
+ data.tar.gz: b5b959011051e252cb8a65c1b049f0cdfd8dcd6056b47b7cc7ba87052bb84ec5e1fd767d641385ab2ac1c162f0230d6a7bc760f77ac2699bc5fdbd5d6e812a05
@@ -1,39 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pry-moves (0.1.6)
4
+ pry-moves (0.1.13)
5
5
  binding_of_caller (~> 0.7)
6
- pry (>= 0.9.10, < 0.11.0)
6
+ pry (>= 0.10.4, < 0.12.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- binding_of_caller (0.7.2)
11
+ binding_of_caller (0.8.0)
12
12
  debug_inspector (>= 0.0.1)
13
- coderay (1.1.1)
13
+ coderay (1.1.2)
14
14
  debug_inspector (0.0.3)
15
15
  diff-lcs (1.3)
16
- method_source (0.8.2)
17
- pry (0.10.4)
16
+ method_source (0.9.0)
17
+ pry (0.11.3)
18
18
  coderay (~> 1.1.0)
19
- method_source (~> 0.8.1)
20
- slop (~> 3.4)
19
+ method_source (~> 0.9.0)
21
20
  pry-remote (0.1.8)
22
21
  pry (~> 0.9)
23
22
  slop (~> 3.0)
24
- rspec (3.6.0)
25
- rspec-core (~> 3.6.0)
26
- rspec-expectations (~> 3.6.0)
27
- rspec-mocks (~> 3.6.0)
28
- rspec-core (3.6.0)
29
- rspec-support (~> 3.6.0)
30
- rspec-expectations (3.6.0)
23
+ rspec (3.8.0)
24
+ rspec-core (~> 3.8.0)
25
+ rspec-expectations (~> 3.8.0)
26
+ rspec-mocks (~> 3.8.0)
27
+ rspec-core (3.8.0)
28
+ rspec-support (~> 3.8.0)
29
+ rspec-expectations (3.8.1)
31
30
  diff-lcs (>= 1.2.0, < 2.0)
32
- rspec-support (~> 3.6.0)
33
- rspec-mocks (3.6.0)
31
+ rspec-support (~> 3.8.0)
32
+ rspec-mocks (3.8.0)
34
33
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.6.0)
36
- rspec-support (3.6.0)
34
+ rspec-support (~> 3.8.0)
35
+ rspec-support (3.8.0)
37
36
  slop (3.6.0)
38
37
 
39
38
  PLATFORMS
@@ -46,4 +45,4 @@ DEPENDENCIES
46
45
  rspec
47
46
 
48
47
  BUNDLED WITH
49
- 1.14.5
48
+ 2.1.1
data/README.md CHANGED
@@ -15,15 +15,19 @@ _An execution control add-on for [Pry][pry]._
15
15
  * `s method_name` - step into method `method_name` (For example from `User.new.method_name`). Partial name match supported.
16
16
  * `s +` - step into function, including hidden frames
17
17
  * `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
18
19
  * `c` - **continue**
20
+ * `g 10` - **goto** line 10
19
21
  * `bt` - show latest 5 lines from backtrace
20
22
  * `bt 10` - latest 10 lines
21
- * `bt all` - full backtrace
23
+ * `bt full` - full backtrace
24
+ * `bt +` - full backtrace with hidden frames. Aliases: `bt hidden` `bt vapid` `bt all`
22
25
  * `bt > foo` - write backtrace to file `log/backtrace_foo.log`
23
26
  * `up`/`down`/`top`/`bottom` - move over call stack
24
27
  * `up +` - move up, including vapid frames (block callers, hidden frames)
25
28
  * `up pattern` - move up till first frame which method name or file position in format `folder/script.rb:12` matches regexp pattern
26
29
  * `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
30
+ * `.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`
27
31
  * `watch variable` - display variable's value on each step
28
32
  * `!` - exit
29
33
 
@@ -69,6 +73,16 @@ PryMoves::Backtrace::filter =
69
73
 
70
74
  ## Threads, helpers
71
75
 
76
+ To allow traveling to parent thread, use:
77
+
78
+ ```ruby
79
+ pre_callers = binding.callers
80
+ Thread.new do
81
+ Thread.current[:pre_callers] = pre_callers
82
+ #...
83
+ end
84
+ ```
85
+
72
86
  `pry-moves` can't stop other threads on `binding.pry`, so they will continue to run.
73
87
  This makes `pry-moves` not always suitable for debugging of multi-thread projects.
74
88
 
@@ -110,6 +124,10 @@ Please note that debugging functionality is implemented through
110
124
  bundle exec rspec
111
125
  ```
112
126
 
127
+ ## ToDo
128
+
129
+ * `iterate` - steps in into child sub-block - should skip
130
+
113
131
  ## Contributors
114
132
 
115
133
  * Gopal Patel ([@nixme](https://github.com/nixme))
@@ -120,7 +138,7 @@ bundle exec rspec
120
138
  * Ivo Anjo ([@ivoanjo](https://github.com/ivoanjo))
121
139
 
122
140
  Patches and bug reports are welcome. Just send a [pull request][pullrequests] or
123
- file an [issue][issues]. [Project changelog][changelog].
141
+ file an [issue][issues].
124
142
 
125
143
  ## Acknowledgments
126
144
 
@@ -2,9 +2,11 @@ require 'pry' unless defined? Pry
2
2
 
3
3
  require 'pry-moves/version'
4
4
  require 'pry-moves/trace_commands'
5
+ require 'pry-moves/traced_method'
5
6
  require 'pry-moves/tracer'
6
7
  require 'pry-moves/pry_ext'
7
8
  require 'pry-moves/commands'
9
+ require 'pry-moves/traversing'
8
10
  require 'pry-moves/pry_wrapper'
9
11
  require 'pry-moves/backtrace'
10
12
  require 'pry-moves/watch'
@@ -34,6 +36,10 @@ module PryMoves
34
36
  @semaphore ||= Mutex.new
35
37
  end
36
38
 
39
+ def locked?
40
+ semaphore.locked?
41
+ end
42
+
37
43
  def lock
38
44
  semaphore.lock unless semaphore.locked?
39
45
  end
@@ -47,13 +53,10 @@ module PryMoves
47
53
  end
48
54
 
49
55
  def synchronize_threads
50
- return if Thread.current[:pry_moves_debug]
56
+ return true if Thread.current[:pry_moves_debug]
51
57
 
52
- semaphore.synchronize {}
53
- rescue ThreadError => e
54
- puts e.backtrace.reverse
55
- puts e
56
- raise e
58
+ semaphore.synchronize {} rescue return
59
+ true
57
60
  end
58
61
 
59
62
  # Reference to currently running pry-remote server. Used by the tracer.
@@ -44,7 +44,7 @@ class PryMoves::Backtrace
44
44
 
45
45
  def build
46
46
  result = []
47
- show_vapid = @lines_count == 'all'
47
+ show_vapid = %w(+ all hidden vapid).include? @lines_count
48
48
  stack = stack_bindings(show_vapid)
49
49
  .reverse.reject do |binding|
50
50
  binding.eval('__FILE__').match self.class::filter
@@ -61,9 +61,10 @@ class PryMoves::Backtrace
61
61
  def build_result(stack, result)
62
62
  current_object = nil
63
63
  stack.each do |binding|
64
- obj = binding.eval 'self'
65
- if current_object != obj
66
- result << "#{format_obj(obj)}:"
64
+ obj, debug_snapshot = binding.eval '[self, (debug_snapshot rescue nil)]'
65
+ # Comparison of objects directly may raise exception
66
+ if current_object.object_id != obj.object_id
67
+ result << "#{debug_snapshot || format_obj(obj)}:"
67
68
  current_object = obj
68
69
  end
69
70
 
@@ -81,8 +82,7 @@ class PryMoves::Backtrace
81
82
  end
82
83
 
83
84
  def build_line(binding)
84
- file = "#{binding.eval('__FILE__')}"
85
- file.gsub!( /^#{Rails.root.to_s}/, '') if defined? Rails
85
+ file = PryMoves::Helpers.shorten_path "#{binding.eval('__FILE__')}"
86
86
 
87
87
  signature = PryMoves::Helpers.method_signature binding
88
88
  signature = ":#{binding.frame_type}" if !signature or signature.length < 1
@@ -5,32 +5,36 @@ module PryMoves
5
5
  block_command 'step', 'Step execution into the next line or method.' do |param|
6
6
  breakout_navigation :step, param
7
7
  end
8
+ alias_command 's', 'step'
8
9
 
9
- block_command 'finish', 'Finish - xule tut neponyatnogo.' do |param|
10
+ block_command 'finish', 'Finish - xule tut neponyatnogo' do |param|
10
11
  breakout_navigation :finish, param
11
12
  end
13
+ alias_command 'f', 'finish'
12
14
 
13
15
  block_command 'next', 'Execute the next line stepping into blocks' do |param|
14
16
  breakout_navigation :next, param
15
17
  end
18
+ alias_command 'n', 'next'
16
19
 
17
- block_command 'nn', 'Execute the next line skipping blocks.' do |param|
20
+ block_command 'nn', 'Execute the next line skipping blocks' do |param|
18
21
  breakout_navigation :next, 'blockless'
19
22
  end
20
23
 
21
- block_command 'iterate', 'Stop on next iteration of this method.' do |param|
24
+ block_command 'iterate', 'Go to next iteration of current block' do |param|
22
25
  breakout_navigation :iterate, param
23
26
  end
24
27
 
25
- block_command 'continue', 'Continue program execution and end the Pry session.' do
28
+ block_command 'goto', 'goto line' do |param|
29
+ breakout_navigation :goto, param
30
+ end
31
+ alias_command 'g', 'goto'
32
+
33
+ block_command 'continue', 'Continue program execution and end the Pry session' do
26
34
  check_file_context
27
35
  run 'exit-all'
28
36
  end
29
-
30
37
  alias_command 'c', 'continue'
31
- alias_command 's', 'step'
32
- alias_command 'n', 'next'
33
- alias_command 'f', 'finish'
34
38
 
35
39
  block_command 'watch', 'Display value of expression on every move' do |param|
36
40
  PryMoves::Watch.instance.process_cmd param, target
@@ -46,6 +50,7 @@ module PryMoves
46
50
  end
47
51
 
48
52
  block_command '!', 'exit' do
53
+ PryMoves.unlock
49
54
  Pry.config.exit_requested = true
50
55
  run '!!!'
51
56
  end
@@ -47,4 +47,10 @@ module PryMoves::Helpers
47
47
  end
48
48
  end
49
49
 
50
+ PATH_TRASH = defined?(Rails) ? Rails.root.to_s : Dir.pwd
51
+
52
+ def shorten_path(path)
53
+ path.gsub( /^#{PATH_TRASH}\//, '')
54
+ end
55
+
50
56
  end
@@ -14,10 +14,14 @@ module PryMoves::Painter
14
14
 
15
15
  def self.colorize(obj)
16
16
  colored_str = Canvas.new
17
+ obj = obj.class if obj.inspect.start_with? "#<"
17
18
  catch (:cut) do
18
19
  Pry::ColorPrinter.pp obj, colored_str
19
20
  end
20
21
  colored_str.chomp
22
+ rescue => e
23
+ "Inspect error: #{e}\n" +
24
+ "#{e.backtrace.first(3).join("\n")}"
21
25
  end
22
26
 
23
27
  end
@@ -24,7 +24,8 @@ Binding.class_eval do
24
24
 
25
25
  def pry
26
26
  unless Pry.config.disable_breakpoints
27
- PryMoves.synchronize_threads
27
+ PryMoves.synchronize_threads ||
28
+ return # Don't start binding.pry when semaphore locked by current thread
28
29
  pry_forced
29
30
  end
30
31
  end
@@ -56,7 +57,7 @@ Pry::Command::Whereami.class_eval do
56
57
 
57
58
  def build_output
58
59
  lines = []
59
- lines << "#{text.bold('From:')} #{location}"
60
+ lines << "#{text.bold('From:')} #{PryMoves::Helpers.shorten_path location}"
60
61
  lines << PryMoves::Watch.instance.output(target) unless PryMoves::Watch.instance.empty?
61
62
  lines << ''
62
63
  lines << "#{code.with_line_numbers(use_line_numbers?).with_marker(marker).highlighted}"
@@ -10,7 +10,7 @@ class PryWrapper
10
10
  def run(&block)
11
11
  PryMoves.lock
12
12
 
13
- Pry.config.marker = "⛔️ " if @pry_start_options[:exit_from_method]
13
+ Pry.config.marker = "⛔️" if @pry_start_options[:exit_from_method]
14
14
 
15
15
  return_value = nil
16
16
  PryMoves.is_open = true
@@ -58,7 +58,6 @@ class PryWrapper
58
58
  end
59
59
 
60
60
  Thread.current[:pry_moves_debug] = true
61
- #@command[:binding].eval 'puts "###########"'
62
61
  tracer = start_tracing
63
62
  begin
64
63
  @command[:binding].eval @command[:param]
@@ -2,7 +2,7 @@ module PryMoves::TraceCommands
2
2
 
3
3
  private
4
4
 
5
- def trace_step(event, file, line, binding_)
5
+ def trace_step(event, file, line, method, binding_)
6
6
  return unless event == 'line'
7
7
 
8
8
  if @step_in_everywhere
@@ -33,7 +33,7 @@ module PryMoves::TraceCommands
33
33
  end
34
34
  end
35
35
 
36
- def trace_next(event, file, line, binding_)
36
+ def trace_next(event, file, line, method, binding_)
37
37
  traced_method_exit = (@recursion_level < 0 and %w(line call).include? event)
38
38
  if traced_method_exit
39
39
  # Set new traced method, because we left previous one
@@ -45,20 +45,22 @@ module PryMoves::TraceCommands
45
45
  within_current_method?(file, line)
46
46
 
47
47
  if event == 'line'
48
- return (
49
- not @stay_at_frame or
50
- @stay_at_frame == frame_digest(binding_.of_caller(3))
51
- )
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
52
56
  end
53
57
 
54
- if event == 'return' and before_end?(line)
55
- @pry_start_options[:exit_from_method] = true
56
- true
57
- end
58
+ exit_from_method if event == 'return' and
59
+ method != :to_s and before_end?(line)
58
60
  end
59
61
  end
60
62
 
61
- def trace_finish(event, file, line, binding_)
63
+ def trace_finish(event, file, line, method, binding_)
62
64
  return unless event == 'line'
63
65
  if @recursion_level < 0 or @method_to_finish != @method
64
66
  if redirect_step_into?(binding_)
@@ -76,7 +78,7 @@ module PryMoves::TraceCommands
76
78
  end
77
79
  end
78
80
 
79
- def trace_debug(event, file, line, binding_)
81
+ def trace_debug(event, file, line, method, binding_)
80
82
  return unless event == 'line'
81
83
  if @first_line_skipped
82
84
  true
@@ -86,11 +88,22 @@ module PryMoves::TraceCommands
86
88
  end
87
89
  end
88
90
 
89
- def trace_iteration(event, file, line, binding_)
90
- raise 'not implemented'
91
- # implementation:
92
- # 1) ставить метки там, где происходит сама итерация?
93
- # 2) можно догадываться по имени методов в стеке вверху: each / each_with_index
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
94
107
  end
95
108
 
96
109
  end
@@ -0,0 +1,61 @@
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,9 +1,12 @@
1
+ require 'digest'
2
+
1
3
  require 'pry' unless defined? Pry
2
4
 
3
5
  module PryMoves
4
6
  class Tracer
5
7
 
6
8
  include PryMoves::TraceCommands
9
+ include PryMoves::TracedMethod
7
10
 
8
11
  def initialize(command, pry_start_options)
9
12
  @command = command
@@ -38,6 +41,11 @@ class Tracer
38
41
  if @command[:param] == 'blockless'
39
42
  @stay_at_frame = frame_digest(binding_)
40
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
41
49
  end
42
50
 
43
51
  start_tracing
@@ -66,41 +74,19 @@ class Tracer
66
74
  Thread.current : Kernel
67
75
  end
68
76
 
69
- def set_traced_method(binding)
70
- @recursion_level = 0
71
-
72
- method = binding.eval 'method(__method__) if __method__'
73
- if method
74
- source = method.source_location
75
- set_method({
76
- file: source[0],
77
- start: source[1],
78
- name: method.name,
79
- end: (source[1] + method.source.count("\n") - 1)
80
- })
81
- else
82
- set_method({file: binding.eval('__FILE__')})
83
- end
84
- end
85
-
86
- def set_method(method)
87
- #puts "set_traced_method #{method}"
88
- @method = method
89
- end
90
-
91
77
  def frame_digest(binding_)
92
78
  #puts "frame_digest for: #{binding_.eval '__callee__'}"
93
79
  Digest::MD5.hexdigest binding_.instance_variable_get('@iseq').disasm
94
80
  end
95
81
 
96
82
  def tracing_func(event, file, line, id, binding_, klass)
97
- #printf "#{trace_obj}: %8s %s:%-2d %10s %8s rec:#{@recursion_level}\n", event, file, line, id, klass
83
+ # printf ": %8s %s:%-2d %10s %8s rec:#{@recursion_level} st:#{@c_stack_level}\n", event, file, line, id, klass
98
84
 
99
85
  # Ignore traces inside pry-moves code
100
86
  return if file && TRACE_IGNORE_FILES.include?(File.expand_path(file))
101
87
 
102
88
  catch (:skip) do
103
- if send "trace_#{@action}", event, file, line, binding_
89
+ if send "trace_#{@action}", event, file, line, id, binding_
104
90
  stop_tracing
105
91
  Pry.start(binding_, @pry_start_options)
106
92
 
@@ -110,6 +96,9 @@ class Tracer
110
96
  delta = event == 'call' ? 1 : -1
111
97
  #puts "recursion #{event}: #{delta}; changed: #{@recursion_level} => #{@recursion_level + delta}"
112
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
113
102
  end
114
103
  end
115
104
  end
@@ -137,20 +126,15 @@ class Tracer
137
126
  puts "#{id} #{@method[:start]} > #{line} > #{@method[:end]}"
138
127
  end
139
128
 
140
- def within_current_method?(file, line)
141
- @method[:file] == file and (
142
- @method[:start].nil? or
143
- line.between?(@method[:start], @method[:end])
144
- )
145
- end
146
-
147
- def before_end?(line)
148
- @method[:end] and line < @method[:end]
149
- end
150
129
 
151
130
  def pry_puts(text)
152
131
  @command[:pry].output.puts text
153
132
  end
154
133
 
134
+ def exit_from_method
135
+ @pry_start_options[:exit_from_method] = true
136
+ true
137
+ end
138
+
139
+ end
155
140
  end
156
- end
@@ -0,0 +1,69 @@
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
@@ -1,3 +1,3 @@
1
1
  module PryMoves
2
- VERSION = '0.1.7'
2
+ VERSION = '0.1.13'
3
3
  end
@@ -0,0 +1,2 @@
1
+ Forked and modified copy of pry-stack_explorer v0.4.9.
2
+ Latest upstream merged: v0.4.9.3
@@ -108,7 +108,7 @@ module PryStackExplorer
108
108
  (b1.eval('self').equal?(b2.eval('self'))) &&
109
109
  (b1.eval('__method__') == b2.eval('__method__')) &&
110
110
  (b1.eval('local_variables').map { |v| b1.eval("#{v}") }.equal?(
111
- b2.eval('local_variables').map { |v| b2.eval("#{v}") }))
111
+ b2.eval('local_variables').map { |v| b2.eval("#{v}") }))
112
112
  end
113
113
  end
114
114
  end
@@ -117,6 +117,7 @@ Pry.config.hooks.add_hook(:after_session, :delete_frame_manager) do |_, _, _pry_
117
117
  PryStackExplorer.clear_frame_managers(_pry_)
118
118
  end
119
119
 
120
+ # Can be moved to start_with_pry_nav to isolate from other use cases of Pry
120
121
  Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, PryStackExplorer::WhenStartedHook.new)
121
122
 
122
123
  # Import the StackExplorer commands
@@ -124,14 +125,14 @@ Pry.config.commands.import PryStackExplorer::Commands
124
125
 
125
126
  # monkey-patch the whereami command to show some frame information,
126
127
  # useful for navigating stack.
127
- Pry.config.commands.before_command("whereami") do |num|
128
+ Pry.config.hooks.add_hook(:before_whereami, :stack_explorer) do
128
129
  if PryStackExplorer.frame_manager(_pry_) && !internal_binding?(target)
129
130
  bindings = PryStackExplorer.frame_manager(_pry_).bindings
130
131
  binding_index = PryStackExplorer.frame_manager(_pry_).binding_index
131
132
 
132
133
  info = "#{Pry::Helpers::Text.bold('Frame:')} "+
133
- "#{binding_index}/#{bindings.size - 1} "+
134
- "#{bindings[binding_index].frame_type}"
134
+ "#{binding_index}/#{bindings.size - 1} "+
135
+ "#{bindings[binding_index].frame_type}"
135
136
 
136
137
  output.puts "\n"
137
138
  output.puts info
@@ -12,6 +12,11 @@ module PryStackExplorer
12
12
  end
13
13
 
14
14
  def call(target, options, _pry_)
15
+ start_from_console = target.eval('__callee__').nil? &&
16
+ target.eval('__FILE__') == '<main>' &&
17
+ target.eval('__LINE__') == 0
18
+ return if start_from_console
19
+
15
20
  target ||= _pry_.binding_stack.first if _pry_
16
21
  options = {
17
22
  :call_stack => true,
@@ -23,14 +28,18 @@ module PryStackExplorer
23
28
  if options[:call_stack].is_a?(Array)
24
29
  bindings = options[:call_stack]
25
30
 
26
- if !valid_call_stack?(bindings)
31
+ unless valid_call_stack?(bindings)
27
32
  raise ArgumentError, ":call_stack must be an array of bindings"
28
33
  end
29
34
  else
30
35
  bindings = caller_bindings(target)
36
+ initial_frame = bindings.find do |b|
37
+ not b.local_variable_defined?(:vapid_frame)
38
+ end
39
+ options[:initial_frame] = bindings.index initial_frame
31
40
  end
32
41
 
33
- PryStackExplorer.create_and_push_frame_manager bindings, _pry_, :initial_frame => options[:initial_frame]
42
+ PryStackExplorer.create_and_push_frame_manager bindings, _pry_, initial_frame: options[:initial_frame]
34
43
  end
35
44
 
36
45
  private
@@ -1,23 +1,21 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- pry-moves (0.1.6)
4
+ pry-moves (0.1.11)
5
5
  binding_of_caller (~> 0.7)
6
- pry (>= 0.9.10, < 0.11.0)
6
+ pry (>= 0.10.4, < 1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- binding_of_caller (0.7.2)
11
+ binding_of_caller (0.8.0)
12
12
  debug_inspector (>= 0.0.1)
13
- coderay (1.1.1)
13
+ coderay (1.1.2)
14
14
  debug_inspector (0.0.3)
15
- method_source (0.8.2)
16
- pry (0.10.4)
15
+ method_source (0.9.2)
16
+ pry (0.12.2)
17
17
  coderay (~> 1.1.0)
18
- method_source (~> 0.8.1)
19
- slop (~> 3.4)
20
- slop (3.6.0)
18
+ method_source (~> 0.9.0)
21
19
 
22
20
  PLATFORMS
23
21
  ruby
@@ -26,4 +24,4 @@ DEPENDENCIES
26
24
  pry-moves!
27
25
 
28
26
  BUNDLED WITH
29
- 1.14.5
27
+ 1.17.0
@@ -54,11 +54,20 @@ class Playground
54
54
  self
55
55
  end
56
56
 
57
- def with_simple_block
58
- binding.pry # stop in with_simple_block
59
- iterator do |i|
57
+ def nested_block(early_return: false)
58
+ binding.pry # stop in nested_block
59
+ iterator do |i| # iterator line
60
+ dummy = 1 # inside block
61
+ return if early_return
62
+ end
63
+ :after_block # after block
64
+ end
65
+
66
+ def native_block(early_return: false)
67
+ binding.pry # stop in native_block
68
+ 2.times do |i| # iterator line
60
69
  dummy = 1 # inside block
61
- dummy = 2
70
+ return if early_return
62
71
  end
63
72
  :after_block # after block
64
73
  end
@@ -10,33 +10,25 @@ end
10
10
  class A
11
11
 
12
12
  def initialize
13
- hide_from_stack = true
14
13
  puts :xuilo
15
14
  end
16
15
 
17
- def kozi
18
- puts 'aa2 1'
19
- puts 'aa2 2'
20
- end
21
-
22
16
  def aa
23
- debug_redirect = :kozi
24
17
  puts 'aa: step 1'
25
18
  puts 'aa: step 2'
26
- kozi
27
19
  end
28
20
 
29
21
  def bb
30
- #debug_redirect = :aa
22
+ debug_redirect = :aa
23
+ hide_from_stack = true
31
24
  puts 'bb: step 1'
32
25
  puts 'bb: step 2'
33
26
  aa
34
27
  end
35
28
 
36
29
  def cc
37
- #debug_redirect = :bb
38
- hide_from_stack = true
39
30
  koko = :love
31
+ binding.pry
40
32
  bb
41
33
  (2..4).each do |i|
42
34
  puts i
@@ -47,12 +39,8 @@ class A
47
39
 
48
40
  end
49
41
 
50
- require './playground.rb'
51
- Playground.new.basic_next
52
-
53
42
  puts :prepare
54
43
 
55
- binding.pry
56
44
  A.new.cc_al
57
45
  A.new.cc_al
58
46
 
@@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  # Dependencies
21
21
  gem.required_ruby_version = '>= 1.8.7'
22
- gem.add_runtime_dependency 'pry', '>= 0.9.10', '< 0.11.0'
22
+ gem.add_runtime_dependency 'pry', '>= 0.10.4', '< 0.12.0'
23
23
  gem.add_runtime_dependency 'binding_of_caller', '~> 0.7'
24
24
  gem.add_development_dependency 'pry-remote', '~> 0.1.6'
25
25
  end
@@ -0,0 +1,2 @@
1
+ gem build pry-moves.gemspec
2
+ gem push pry-moves-`ruby -e 'require "./lib/pry-moves/version.rb"; puts PryMoves::VERSION'`.gem
@@ -28,12 +28,12 @@ describe 'blocks' do
28
28
 
29
29
  it 'should finish simple block' do
30
30
  breakpoints [
31
- [nil, 'stop in with_simple_block'],
32
- ['n', ''],
31
+ [nil, 'stop in nested_block'],
32
+ ['n', 'iterator line'],
33
33
  ['', 'inside block'],
34
34
  ['f', 'after block']
35
35
  ]
36
- Playground.new.with_simple_block
36
+ Playground.new.nested_block
37
37
  end
38
38
 
39
39
  it 'should finish block with sub-calls' do
@@ -47,5 +47,54 @@ describe 'blocks' do
47
47
  Playground.new.zaloop
48
48
  end
49
49
 
50
+ it 'should iterate over native block' do
51
+ breakpoints [
52
+ [nil, 'stop in native_block'],
53
+ ['n', 'iterator line'],
54
+ ['n', 'inside block'],
55
+ ['i', {output: '=> 0'}],
56
+ ['iterate', 'inside block'],
57
+ ['i', {output: '=> 1'}],
58
+ ['iterate', 'after block'],
59
+ ]
60
+ Playground.new.native_block
61
+ end
62
+
63
+ it 'should iterate over nested block' do
64
+ breakpoints [
65
+ [nil, 'stop in nested_block'],
66
+ ['n', 'iterator line'],
67
+ ['n', 'inside block'],
68
+ ['i', {output: '=> 0'}],
69
+ ['iterate', 'inside block'],
70
+ ['i', {output: '=> 1'}],
71
+ ['iterate', 'after block'],
72
+ ]
73
+ Playground.new.nested_block
74
+ end
50
75
 
76
+ it 'should return during iterating native block' do
77
+ breakpoints [
78
+ [nil, 'stop in native_block'],
79
+ ['n', 'iterator line'],
80
+ ['n', 'inside block'],
81
+ ['iterate', 'iterator line'],
82
+ ['n', 'exit'],
83
+ ]
84
+ Playground.new.native_block early_return: true
85
+ :exit # exit
86
+ end
87
+
88
+ it 'should return during iterating nested block' do
89
+ breakpoints [
90
+ [nil, 'stop in nested_block'],
91
+ ['n', 'iterator line'],
92
+ ['n', 'inside block'],
93
+ ['iterate', 'iterator line'],
94
+ ['n', 'exit'],
95
+ ]
96
+ Playground.new.nested_block early_return: true
97
+ :exit # exit
98
+ end
99
+
51
100
  end
@@ -2,31 +2,41 @@ module PryDebugger
2
2
 
3
3
  module Breakpoints
4
4
  def breakpoints(breakpoints)
5
+ steps = []
5
6
  breakpoints.each_with_index do |b, index|
6
7
  next_b = breakpoints[index+1]
7
- b[0] = next_b ? next_b[0] : nil
8
+ steps << {
9
+ cmd: b[0],
10
+ expected: b[1],
11
+ next_cmd: next_b ? next_b[0] : nil,
12
+ index: index
13
+ }
8
14
  end
9
15
 
10
16
  PryDebugger.breakpoints =
11
- breakpoints.map do |b|
17
+ steps.map do |step|
12
18
  Proc.new do |label, binding_, output|
13
- compare(b[1], label, binding_, output)
14
- b[0]
19
+ compare(step, label, binding_, output)
20
+ step[:next_cmd]
15
21
  end
16
22
  end
17
23
  end
18
24
 
19
- def compare(subj, label, binding_, output)
20
- if subj.is_a? Proc
21
- subj.call binding_, output
22
- elsif subj.is_a? Hash
23
- if subj[:output_includes]
24
- expect(output).to include subj[:output_includes]
25
+ def compare(step, label, binding_, output)
26
+ exp = step[:expected]
27
+ if exp.is_a? Proc
28
+ exp.call binding_, output
29
+ elsif exp.is_a? Hash
30
+ if exp[:output_includes]
31
+ expect(output).to include exp[:output_includes]
25
32
  else
26
- expect(output).to eq subj[:output]
33
+ expect(output).to eq exp[:output]
27
34
  end
28
- elsif not subj.nil?
29
- expect(label).to eq subj
35
+ elsif not exp.nil?
36
+ err = <<-TEXT
37
+ [#{step[:index]}] #{step[:cmd]} => '#{exp}', got '#{label}'
38
+ TEXT
39
+ expect(label).to eq(exp), err
30
40
  end
31
41
  end
32
42
  end
@@ -81,8 +91,8 @@ module PryDebugger
81
91
  raise 'Next breakpoint handler missing' if @breakpoints_procs.size == 0
82
92
  #puts (@breakpoint_call += 1)
83
93
  output = @output.take_away
84
- output.match(/^ => .*#(.*)/)
85
- label = ($1 || '').strip
94
+ output.match(/^ (=>|⛔️) .*#(.*)/)
95
+ label = ($2 || '').strip
86
96
  @breakpoints_procs.shift.call label, binding_, output.strip
87
97
  end
88
98
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-moves
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - garmoshka-mo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-09 00:00:00.000000000 Z
11
+ date: 2020-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.9.10
19
+ version: 0.10.4
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 0.11.0
22
+ version: 0.12.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.9.10
29
+ version: 0.10.4
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.11.0
32
+ version: 0.12.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: binding_of_caller
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -82,9 +82,12 @@ files:
82
82
  - lib/pry-moves/pry_remote_ext.rb
83
83
  - lib/pry-moves/pry_wrapper.rb
84
84
  - lib/pry-moves/trace_commands.rb
85
+ - lib/pry-moves/traced_method.rb
85
86
  - lib/pry-moves/tracer.rb
87
+ - lib/pry-moves/traversing.rb
86
88
  - lib/pry-moves/version.rb
87
89
  - lib/pry-moves/watch.rb
90
+ - lib/pry-stack_explorer/VERSION
88
91
  - lib/pry-stack_explorer/commands.rb
89
92
  - lib/pry-stack_explorer/frame_manager.rb
90
93
  - lib/pry-stack_explorer/pry-stack_explorer.rb
@@ -100,6 +103,7 @@ files:
100
103
  - playground/threads.rb
101
104
  - playground/tracer.rb
102
105
  - pry-moves.gemspec
106
+ - publish.sh
103
107
  - spec/backtrace_spec.rb
104
108
  - spec/blocks_spec.rb
105
109
  - spec/commands_spec.rb
@@ -110,7 +114,7 @@ homepage: https://github.com/garmoshka-mo/pry-moves
110
114
  licenses:
111
115
  - MIT
112
116
  metadata: {}
113
- post_install_message:
117
+ post_install_message:
114
118
  rdoc_options: []
115
119
  require_paths:
116
120
  - lib
@@ -125,9 +129,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
129
  - !ruby/object:Gem::Version
126
130
  version: '0'
127
131
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.6.8
130
- signing_key:
132
+ rubygems_version: 3.1.2
133
+ signing_key:
131
134
  specification_version: 4
132
135
  summary: Debugger for ruby
133
136
  test_files: