pry-moves 1.0.1 → 1.0.2

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
2
  SHA256:
3
- metadata.gz: 47c7a7529bee28ca664536458891b00f6a1bee574869106686cd2abef9b57adb
4
- data.tar.gz: 13d671c5f8ed4005304da6d4201908c0857d19e8ee3fe85631d18cea5c109580
3
+ metadata.gz: a9dc991b1aed888cf23fd1e9a76b29d274ce56989119f802982e9fbdc46cc034
4
+ data.tar.gz: 25e331897d83de799b696e84d1de474166095d4e80853a7f9cde99ba64290432
5
5
  SHA512:
6
- metadata.gz: addaf61aa995184e49f3b655f1d4fa863fa0554d1fb00f022fce7a9e1d8671595c03056e37754fd394bf9a204e32c91b3005a00fac3287f2803bafb66273e2d6
7
- data.tar.gz: 9ba407049732e75c27e8cc87936e25967a30798212098fce844e948e7986912874137088fc87ffc8d9ef48ca09a3c2445da545132109a58ed47d5c4577775db4
6
+ metadata.gz: fbaa701da70c665fe7795de825db1540e5a1ab2d4f2021c41d4294c14bce3429b34b7e64d21949f51fd08dbbc24b6ffc047776bb7207b8c73834893e0e03ced7
7
+ data.tar.gz: 169ee4d3b3e40f8f63c7969c2b709c82dfc23881c994a335b25635fbf90b798ea21616bc33c08dd0bd44418a2c996f0b5eb6079732d769ff5c061757af35f5e7
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pry-moves (1.0.1)
4
+ pry-moves (1.0.2)
5
5
  binding_of_caller (~> 0.7)
6
6
  colorize (~> 0.8)
7
+ diffy (~> 3.4.0)
7
8
  pry (>= 0.10.4, < 0.13)
8
9
 
9
10
  GEM
@@ -15,6 +16,7 @@ GEM
15
16
  colorize (0.8.1)
16
17
  debug_inspector (1.1.0)
17
18
  diff-lcs (1.3)
19
+ diffy (3.4.0)
18
20
  method_source (0.9.0)
19
21
  pry (0.11.3)
20
22
  coderay (~> 1.1.0)
data/README.md CHANGED
@@ -25,10 +25,14 @@ Documentation for latest version. For [v0.1.12 see documentation here](https://g
25
25
  * `bt +` `bt hidden` - show backtrace including hidden frames
26
26
  * `bt a` `bt all` - full backtrace with system and hidden frames
27
27
  * `bt 10` - go to backtrace line 10
28
+ * `bt save` - save backtrace to memory
29
+ * `bt diff` - diff with saved backtrace
28
30
  * `bt > foo` - write backtrace to file `log/backtrace_foo.log`
29
- * `up`/`down`/`top`/`bottom` - move over call stack
31
+ * `up`/`down`/`top`/`bottom` (`bm`) - move over call stack
30
32
  * `up +` - move up, including vapid frames (block callers, hidden frames)
31
33
  * `up pattern` - move up till first frame which method name or file position in format `folder/script.rb:12` matches regexp pattern
34
+ * `%` - print current frame of call stack (alias to `whereami`)
35
+ * `$` - fully print current function without line numbers
32
36
  * `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
37
  * `.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`
34
38
  * `watch variable` - display variable's value on each step
@@ -58,7 +62,7 @@ _Demo class source [here](https://github.com/garmoshka-mo/pry-moves/issues/1)_
58
62
 
59
63
  ## Backtrace and call stack
60
64
 
61
- You can explicitly hide frames from backtrace and call stack by defining `hide_from_stack` variable:
65
+ You can explicitly hide frames from call stack by defining variables like this:
62
66
 
63
67
  ```ruby
64
68
  def insignificant_method
@@ -68,6 +72,10 @@ def insignificant_method
68
72
  end
69
73
  ```
70
74
 
75
+ * `hide_from_stack` - hide this function from stack
76
+ * `pry_moves_stack_tip` - stop on first frame above this function
77
+ * `pry_moves_stack_end` - limits stack from bottom, not possible to step below this frame
78
+
71
79
  ## Configuration
72
80
 
73
81
  Here is default configuration, you can reassign it:
@@ -5,8 +5,12 @@ class PryMoves::Debug < PryMoves::TraceCommand
5
5
  end
6
6
 
7
7
  def trace(event, file, line, method, binding_)
8
- return unless event == 'line'
8
+ return if event != 'line' or @cancel_debug
9
9
  if @first_line_skipped
10
+ if binding_.local_variable_defined?(:pry_cancel_debug)
11
+ @cancel_debug = true
12
+ return
13
+ end
10
14
  true
11
15
  else
12
16
  @first_line_skipped = true
data/lib/debug_sugar.rb CHANGED
@@ -1,36 +1,37 @@
1
1
  def debug *args
2
- pry_moves_stack_root = true
2
+ pry_moves_stack_end = true
3
3
  PryMoves.debug *args
4
4
  end
5
5
 
6
- def error(msg, debug_object = nil)
7
- pry_moves_stack_root = true
6
+ def error(msg = "Error", debug_object = nil)
7
+ pry_moves_stack_end = true
8
8
  err = "😱 #{msg}"
9
9
  unless PryMoves.open?
10
10
  if PryMoves.stop_on_breakpoints
11
11
  lines = [err.red]
12
12
  lines.prepend debug_object.ai if debug_object
13
- PryMoves.debug lines.join("\n")
13
+ PryMoves.error lines.join("\n")
14
14
  else
15
15
  STDERR.puts debug_object.ai if debug_object
16
16
  STDERR.puts err.ljust(80, ' ').red
17
17
  end
18
18
  end
19
- raise msg
19
+ raise PryMoves::ErrorWithData.new(msg, debug_object)
20
20
  end
21
21
 
22
22
  def shit!(err = 'Oh, shit!', debug_object = nil)
23
- pry_moves_stack_root = true
23
+ return if ENV['NO_SHIT']
24
+ pry_moves_stack_end = true
24
25
  message = "💩 #{err.is_a?(String) ? err : err.message}"
25
26
  raise err unless PryMoves.stop_on_breakpoints
26
27
  lines = [message.red]
27
28
  lines.prepend debug_object.ai if debug_object
28
- PryMoves.debug lines.join("\n")
29
+ PryMoves.error lines.join("\n")
29
30
  nil
30
31
  end
31
32
 
32
33
  def required(var)
33
- pry_moves_stack_root = true
34
+ pry_moves_stack_end = true
34
35
  error("required parameter is missing") if var.nil?
35
36
  var
36
37
  end
@@ -44,7 +45,7 @@ RSpec.configure do |config|
44
45
  end
45
46
 
46
47
  config.around(:each) do |example|
47
- PryMoves.restartable do
48
+ PryMoves.restartable(rspec_example: example) do
48
49
  example.run
49
50
  end
50
51
  end
@@ -57,7 +58,7 @@ Rake::Task.class_eval do
57
58
 
58
59
  def execute(args=nil)
59
60
  args ||= EMPTY_TASK_ARGS
60
- PryMoves.restartable do
61
+ PryMoves.restartable(rake_args: args) do
61
62
  reload_actions if PryMoves.reload_rake_tasks
62
63
  execute_origin_for_pry_moves args
63
64
  end
@@ -29,10 +29,17 @@ class PryMoves::Backtrace
29
29
  end
30
30
 
31
31
  def run_command(param, param2)
32
- if param.is_a?(String) and (match = param.match /^>(.*)/)
32
+ if param == 'save'
33
+ @filter = 'hidden'
34
+ @@backtrace = build_backtrace
35
+ @pry.output.puts "💾 Backtrace saved (#{@@backtrace.count} lines)"
36
+ elsif param == 'diff'
37
+ @filter = 'hidden'
38
+ diff
39
+ elsif param.is_a?(String) and (match = param.match /^>(.*)/)
33
40
  suffix = match[1].size > 0 ? match[1] : param2
34
41
  @formatter.colorize = false
35
- write_to_file build, suffix
42
+ write_to_file build_backtrace, suffix
36
43
  elsif param and param.match /\d+/
37
44
  index = param.to_i
38
45
  frame_manager.goto_index index
@@ -47,10 +54,10 @@ class PryMoves::Backtrace
47
54
  @colorize = true
48
55
  @lines_numbers = true
49
56
  @filter = filter if filter.is_a? String
50
- @pry.output.puts build
57
+ @pry.output.puts build_backtrace
51
58
  end
52
59
 
53
- def build
60
+ def build_backtrace
54
61
  show_all = %w(a all).include?(@filter)
55
62
  show_vapid = %w(+ hidden vapid).include?(@filter) || show_all
56
63
  result = []
@@ -58,10 +65,10 @@ class PryMoves::Backtrace
58
65
 
59
66
  recursion = PryMoves::Recursion::Holder.new
60
67
 
61
- frame_manager.bindings.each_with_details do |binding, vapid|
68
+ frame_manager.bindings.reverse.each do |binding|
62
69
  next if !show_all and binding.eval('__FILE__').match self.class::filter
63
70
 
64
- if !show_vapid and vapid
71
+ if !show_vapid and binding.hidden
65
72
  vapid_count += 1
66
73
  next
67
74
  end
@@ -83,7 +90,7 @@ class PryMoves::Backtrace
83
90
  result << build_line(binding, file, line)
84
91
  end
85
92
 
86
- recursion.each { |t| t.apply result }
93
+ # recursion.each { |t| t.apply result }
87
94
 
88
95
  result << "👽 frames hidden: #{vapid_count}" if vapid_count > 0
89
96
 
@@ -125,23 +132,34 @@ class PryMoves::Backtrace
125
132
  "#{root}/backtrace_#{file_suffix}.log"
126
133
  end
127
134
 
135
+ def diff
136
+ return STDERR.puts "No backtrace saved. Use `bt save` first".yellow unless defined? @@backtrace
137
+
138
+ diff = Diffy::Diff.new(@@backtrace.join("\n"), build_backtrace.join("\n")).to_s "color"
139
+ diff = 'Backtraces are equal' if diff.strip.empty?
140
+ @pry.output.puts diff
141
+ end
142
+
128
143
  end
129
144
 
130
145
  Pry.config.exception_handler = proc do |output, exception, _|
146
+
147
+ def print_error message, exception, output
148
+ output.puts message.red
149
+ exception.backtrace.reject! {|l| l.match /sugar\.rb/}
150
+ exception.backtrace.first(3).each { output.puts _1.white }
151
+ end
152
+
131
153
  if Pry::UserError === exception && SyntaxError === exception
132
154
  output.puts "SyntaxError: #{exception.message.sub(/.*syntax error, */m, '')}"
133
155
  else
134
156
 
135
- output.puts "#{exception.class}: #{exception.message}"
136
- exception.backtrace.reject! {|l| l.match /sugar\.rb/}
137
- output.puts "from #{exception.backtrace.first}"
157
+ print_error "#{exception.class}: #{exception.message}", exception, output
138
158
 
139
159
  if exception.respond_to? :cause
140
160
  cause = exception.cause
141
161
  while cause
142
- output.puts "Caused by #{cause.class}: #{cause}\n"
143
- cause.backtrace.reject! {|l| l.match /sugar\.rb/}
144
- output.puts "from #{cause.backtrace.first}"
162
+ print_error "Caused by #{cause.class}: #{cause}\n", exception, output
145
163
  cause = cause.cause
146
164
  end
147
165
  end
@@ -1,7 +1,7 @@
1
1
  class PryMoves::BindingsStack < Array
2
2
 
3
- def initialize
4
- @vapid_bindings = []
3
+ def initialize options
4
+ @options = options
5
5
  bindings = binding.callers # binding_of_caller has bug and always returns callers of current binding,
6
6
  # no matter at which binding method is called. So no need to pass here binding
7
7
  pre_callers = Thread.current[:pre_callers]
@@ -14,20 +14,16 @@ class PryMoves::BindingsStack < Array
14
14
  def suggest_initial_frame_index
15
15
  m = PryMoves::TracedMethod.last
16
16
  return 0 if m and m.binding_inside?(first)
17
- index{|b| not vapid? b} || 0
17
+ index {|b| for_for_initial_frame b} || 0
18
18
  end
19
19
  def initial_frame
20
- find{|b| not vapid? b}
20
+ find {|b| for_for_initial_frame b}
21
21
  end
22
22
 
23
- def each_with_details
24
- self.reverse.each do |binding|
25
- yield binding, vapid?(binding)
26
- end
27
- end
28
-
29
- def vapid?(binding)
30
- @vapid_bindings.include? binding
23
+ def for_for_initial_frame b
24
+ not b.hidden and (
25
+ @options[:is_error] or b.eval("__method__") != :initialize
26
+ )
31
27
  end
32
28
 
33
29
  private
@@ -47,25 +43,35 @@ class PryMoves::BindingsStack < Array
47
43
  file, method, obj = binding.eval("[__FILE__, __method__, self]")
48
44
 
49
45
  if file.match PryMoves::Backtrace::filter
50
- @vapid_bindings << binding
46
+ binding.hidden = true
51
47
  elsif stepped_out
52
48
  if actual_file == file and actual_method == method or
53
49
  binding.local_variable_defined? :pry_moves_deferred_call
54
50
  stepped_out = false
55
51
  else
56
- @vapid_bindings << binding
52
+ binding.hidden = true
57
53
  end
58
54
  elsif binding.frame_type == :block
59
55
  stepped_out = true
60
56
  actual_file = file
61
57
  actual_method = method
62
58
  elsif obj and method and obj.method(method).source.strip.match /^delegate\s/
63
- @vapid_bindings << binding
59
+ binding.hidden = true
64
60
  end
65
61
 
66
62
  if binding.local_variable_defined? :hide_from_stack
67
- @vapid_bindings << binding
63
+ binding.hidden = true
64
+ end
65
+ end
66
+
67
+ stack_tip_met = false
68
+ stack_tips = PryMoves.stack_tips || []
69
+ reverse.each do |binding|
70
+ if binding.local_variable_defined?(:pry_moves_stack_tip) ||
71
+ stack_tips.include?(binding.eval("__method__"))
72
+ stack_tip_met = true
68
73
  end
74
+ binding.hidden = true if stack_tip_met
69
75
  end
70
76
  end
71
77
 
@@ -82,14 +88,17 @@ class PryMoves::BindingsStack < Array
82
88
  end
83
89
 
84
90
  def top_internal_frame_index(bindings)
91
+ pry_moves_debug = Thread.current[:pry_moves_debug]
85
92
  bindings.rindex do |b|
86
- if b.frame_type == :method
87
- method, self_ = b.eval("[__method__, self]")
93
+ if not pry_moves_debug and b.frame_type == :eval
94
+ true
95
+ elsif b.frame_type == :method
96
+ method, self_ = b.eval("[__method__, self, __FILE__]")
88
97
 
89
98
  self_.equal?(Pry) && method == :start ||
90
99
  self_.class == Binding && method == :pry ||
91
100
  self_.is_a?(PryMoves::TraceCommand) && method == :tracing_func ||
92
- b.local_variable_defined?(:pry_moves_stack_root)
101
+ b.local_variable_defined?(:pry_moves_stack_end)
93
102
  end
94
103
  end
95
104
  end
@@ -0,0 +1,10 @@
1
+ class PryMoves::ErrorWithData < StandardError
2
+
3
+ attr_reader :metadata
4
+
5
+ def initialize(msg, metadata)
6
+ super msg
7
+ @metadata = metadata
8
+ end
9
+
10
+ end
@@ -6,6 +6,7 @@ class PryMoves::Formatter
6
6
  @colorize = colorize
7
7
  end
8
8
 
9
+ MAX_PARAMS = 5
9
10
  def method_signature(binding)
10
11
  meth = binding.eval('__method__')
11
12
  meth_obj = meth ? Pry::Method.from_binding(binding) : nil
@@ -31,6 +32,9 @@ class PryMoves::Formatter
31
32
  end
32
33
  show_value ? "#{name} #{value}" : name
33
34
  end
35
+ if args.count > MAX_PARAMS
36
+ args = args.first(MAX_PARAMS) + ["(#{args.count - MAX_PARAMS} more params)…"]
37
+ end
34
38
  "#{meth_obj.name}(#{args.join(', ')})"
35
39
  end
36
40
  end
@@ -18,15 +18,15 @@ end
18
18
 
19
19
  Binding.class_eval do
20
20
 
21
- attr_accessor :index
21
+ attr_accessor :index, :hidden
22
22
 
23
23
  alias pry_forced pry
24
24
 
25
- def pry
25
+ def pry options = nil
26
26
  if !Pry.config.disable_breakpoints and
27
27
  # Don't start binding.pry when semaphore locked by current thread
28
28
  PryMoves.synchronize_threads
29
- pry_forced
29
+ pry_forced options
30
30
  end
31
31
  end
32
32
 
@@ -11,7 +11,7 @@ class PryWrapper
11
11
  def run
12
12
  PryMoves.lock
13
13
 
14
- initial_frame = PryMoves::BindingsStack.new.initial_frame
14
+ initial_frame = PryMoves::BindingsStack.new(@pry_start_options).initial_frame
15
15
  if not @pry_start_options[:pry_moves_loop] and
16
16
  initial_frame.local_variable_defined? :debug_redirect
17
17
  debug_redirect = initial_frame.local_variable_get(:debug_redirect)
@@ -76,7 +76,7 @@ class PryWrapper
76
76
  @command[:binding].eval @command[:param]
77
77
  rescue StandardError, SyntaxError => e
78
78
  Thread.current.set_trace_func nil
79
- puts "❌️ #{e}"
79
+ puts "❌️ Error during #{"debug".yellow} execution: #{e}"
80
80
  end
81
81
  tracer.stop_tracing
82
82
  end.join
@@ -3,14 +3,15 @@ module PryMoves::Restartable
3
3
  attr_accessor :restart_requested, :reload_requested,
4
4
  :reload_rake_tasks
5
5
 
6
- def restartable
7
- trigger :new_run
6
+ def restartable context
7
+ trigger :each_new_run, context
8
8
  yield
9
9
  re_execution
10
10
  rescue PryMoves::Restart
11
+ puts "🔄️ Restarting execution"
11
12
  self.restart_requested = false
12
13
  PryMoves.reset
13
- trigger :restart
14
+ trigger :restart, context
14
15
  retry
15
16
  rescue PryMoves::Reload
16
17
  puts "🔮 try to use @ with reload"
@@ -1,3 +1,3 @@
1
1
  module PryMoves
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
data/lib/pry-moves.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'pry' unless defined? Pry
2
+ require 'colorize'
3
+ require 'diffy'
2
4
 
3
5
  require 'pry-moves/version'
4
6
  require 'pry-moves/pry_ext'
@@ -12,6 +14,7 @@ require 'pry-moves/watch'
12
14
  require 'pry-moves/painter'
13
15
  require 'pry-moves/restartable'
14
16
  require 'pry-moves/recursion_tracker'
17
+ require 'pry-moves/error_with_data'
15
18
 
16
19
  require 'commands/traced_method'
17
20
  require 'commands/trace_helpers'
@@ -36,7 +39,7 @@ module PryMoves
36
39
  extend self
37
40
  extend PryMoves::Restartable
38
41
 
39
- attr_accessor :is_open, :trace,
42
+ attr_accessor :is_open, :trace, :stack_tips,
40
43
  :stop_on_breakpoints, :launched_specs_examples, :debug_called_times
41
44
 
42
45
  def reset
@@ -45,20 +48,26 @@ module PryMoves
45
48
  self.debug_called_times = 0
46
49
  end
47
50
 
48
- def debug(message = nil, at: nil)
49
- pry_moves_stack_root = true
51
+ def debug(message = nil, at: nil, options: nil)
52
+ pry_moves_stack_end = true
50
53
  PryMoves.re_execution
51
54
  if PryMoves.stop_on_breakpoints
52
55
  self.debug_called_times += 1
53
56
  if at
54
57
  return unless self.debug_called_times == at
55
58
  end
56
- PryMoves.messages << message if message
57
- binding.pry
59
+ if message
60
+ PryMoves.messages << (message.is_a?(String) ? message : message.ai)
61
+ end
62
+ binding.pry options
58
63
  PryMoves.re_execution
59
64
  end
60
65
  end
61
66
 
67
+ def error(message)
68
+ debug message, options: {is_error: true}
69
+ end
70
+
62
71
  # Checks that a binding is in a local file context. Extracted from
63
72
  # https://github.com/pry/pry/blob/master/lib/pry/default_commands/context.rb
64
73
  def check_file_context(target)
@@ -102,8 +111,8 @@ module PryMoves
102
111
  true
103
112
  end
104
113
 
105
- def trigger(event)
106
- triggers[event].each &:call
114
+ def trigger(event, context)
115
+ triggers[event].each {|t| t.call context}
107
116
  end
108
117
 
109
118
  def triggers
@@ -112,7 +121,9 @@ module PryMoves
112
121
  end
113
122
  end
114
123
 
124
+ TRIGGERS = [:each_new_run, :restart]
115
125
  def on(trigger, &block)
126
+ error "Invalid trigger, possible triggers: #{TRIGGERS}", trigger unless trigger.in? TRIGGERS
116
127
  triggers[trigger] << block
117
128
  end
118
129
 
@@ -0,0 +1,114 @@
1
+ module PryStackExplorer; end
2
+ module PryStackExplorer::FrameHelpers
3
+ private
4
+
5
+ # @return [PryStackExplorer::FrameManager] The active frame manager for
6
+ # the current `Pry` instance.
7
+ def frame_manager
8
+ PryStackExplorer.frame_manager(_pry_)
9
+ end
10
+
11
+ # @return [Array<PryStackExplorer::FrameManager>] All the frame
12
+ # managers for the current `Pry` instance.
13
+ def frame_managers
14
+ PryStackExplorer.frame_managers(_pry_)
15
+ end
16
+
17
+ # @return [Boolean] Whether there is a context to return to once
18
+ # the current `frame_manager` is popped.
19
+ def prior_context_exists?
20
+ frame_managers.count > 1 || frame_manager.prior_binding
21
+ end
22
+
23
+ # Return a description of the frame (binding).
24
+ # This is only useful for regular old bindings that have not been
25
+ # enhanced by `#of_caller`.
26
+ # @param [Binding] b The binding.
27
+ # @return [String] A description of the frame (binding).
28
+ def frame_description(b)
29
+ b_self = b.eval('self')
30
+ b_method = b.eval('__method__')
31
+
32
+ if b_method && b_method != :__binding__ && b_method != :__binding_impl__
33
+ b_method.to_s
34
+ elsif b_self.instance_of?(Module)
35
+ "<module:#{b_self}>"
36
+ elsif b_self.instance_of?(Class)
37
+ "<class:#{b_self}>"
38
+ else
39
+ "<main>"
40
+ end
41
+ end
42
+
43
+ # Return a description of the passed binding object. Accepts an
44
+ # optional `verbose` parameter.
45
+ # @param [Binding] b The binding.
46
+ # @param [Boolean] verbose Whether to generate a verbose description.
47
+ # @return [String] The description of the binding.
48
+ def frame_info(b, verbose = false)
49
+ b_self = b.eval('self')
50
+ type = b.frame_type ? "[#{b.frame_type}]".ljust(9) : ""
51
+ desc = b.frame_description ? "#{b.frame_description}" : "#{frame_description(b)}"
52
+ sig = PryMoves::Formatter.new.method_signature b
53
+
54
+ self_clipped = "#{Pry.view_clip(b_self)}"
55
+ path = "@ #{b.eval('__FILE__')}:#{b.eval('__LINE__')}"
56
+
57
+ if !verbose
58
+ "#{type} #{desc} #{sig}"
59
+ else
60
+ "#{type} #{desc} #{sig}\n in #{self_clipped} #{path}"
61
+ end
62
+ end
63
+
64
+ def find_frame_by_regex(regex, up_or_down)
65
+ frame_index = find_frame_by_block(up_or_down) do |b|
66
+ (b.eval('"#{__FILE__}:#{__LINE__}"') =~ regex) or
67
+ (b.eval("__method__").to_s =~ regex)
68
+ end
69
+
70
+ frame_index || raise(Pry::CommandError, "No frame that matches #{regex.source} found")
71
+ end
72
+
73
+ def find_frame_by_block(up_or_down)
74
+ start_index = frame_manager.binding_index
75
+
76
+ if up_or_down == :down
77
+ enum = start_index == 0 ? [].each :
78
+ frame_manager.bindings[0..start_index - 1].reverse_each
79
+ else
80
+ enum = frame_manager.bindings[start_index + 1..-1]
81
+ end
82
+
83
+ new_frame = enum.find do |b|
84
+ yield(b)
85
+ end
86
+
87
+ frame_manager.bindings.index(new_frame)
88
+ end
89
+
90
+ def find_frame_by_direction(dir, step_into_vapid: false)
91
+ frame_index = find_frame_by_block(dir) do |b|
92
+ step_into_vapid or not b.hidden
93
+ end
94
+
95
+ if !frame_index and !step_into_vapid
96
+ frame_index = find_frame_by_block(dir) {true}
97
+ end
98
+
99
+ frame_index ||
100
+ raise(Pry::CommandError, "At #{dir == :up ? 'top' : 'bottom'} of stack, cannot go further")
101
+ end
102
+
103
+ def move(direction, param)
104
+ raise Pry::CommandError, "Nowhere to go" unless frame_manager
105
+
106
+ if param == '+' or param.nil?
107
+ index = find_frame_by_direction direction, step_into_vapid: param == '+'
108
+ frame_manager.change_frame_to index
109
+ else
110
+ index = find_frame_by_regex(Regexp.new(param), direction)
111
+ frame_manager.change_frame_to index
112
+ end
113
+ end
114
+ end
@@ -121,5 +121,5 @@ end
121
121
  Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, PryStackExplorer::WhenStartedHook.new)
122
122
 
123
123
  # Import the StackExplorer commands
124
- Pry.config.commands.import PryStackExplorer::Commands
124
+ Pry.config.commands.import PryStackExplorer::COMMANDS
125
125
 
@@ -1,121 +1,13 @@
1
- module PryStackExplorer
2
- module FrameHelpers
3
- private
4
-
5
- # @return [PryStackExplorer::FrameManager] The active frame manager for
6
- # the current `Pry` instance.
7
- def frame_manager
8
- PryStackExplorer.frame_manager(_pry_)
9
- end
10
-
11
- # @return [Array<PryStackExplorer::FrameManager>] All the frame
12
- # managers for the current `Pry` instance.
13
- def frame_managers
14
- PryStackExplorer.frame_managers(_pry_)
15
- end
16
-
17
- # @return [Boolean] Whether there is a context to return to once
18
- # the current `frame_manager` is popped.
19
- def prior_context_exists?
20
- frame_managers.count > 1 || frame_manager.prior_binding
21
- end
22
-
23
- # Return a description of the frame (binding).
24
- # This is only useful for regular old bindings that have not been
25
- # enhanced by `#of_caller`.
26
- # @param [Binding] b The binding.
27
- # @return [String] A description of the frame (binding).
28
- def frame_description(b)
29
- b_self = b.eval('self')
30
- b_method = b.eval('__method__')
31
-
32
- if b_method && b_method != :__binding__ && b_method != :__binding_impl__
33
- b_method.to_s
34
- elsif b_self.instance_of?(Module)
35
- "<module:#{b_self}>"
36
- elsif b_self.instance_of?(Class)
37
- "<class:#{b_self}>"
38
- else
39
- "<main>"
40
- end
41
- end
42
-
43
- # Return a description of the passed binding object. Accepts an
44
- # optional `verbose` parameter.
45
- # @param [Binding] b The binding.
46
- # @param [Boolean] verbose Whether to generate a verbose description.
47
- # @return [String] The description of the binding.
48
- def frame_info(b, verbose = false)
49
- b_self = b.eval('self')
50
- type = b.frame_type ? "[#{b.frame_type}]".ljust(9) : ""
51
- desc = b.frame_description ? "#{b.frame_description}" : "#{frame_description(b)}"
52
- sig = PryMoves::Formatter.new.method_signature b
53
-
54
- self_clipped = "#{Pry.view_clip(b_self)}"
55
- path = "@ #{b.eval('__FILE__')}:#{b.eval('__LINE__')}"
56
-
57
- if !verbose
58
- "#{type} #{desc} #{sig}"
59
- else
60
- "#{type} #{desc} #{sig}\n in #{self_clipped} #{path}"
61
- end
62
- end
63
-
64
- def find_frame_by_regex(regex, up_or_down)
65
- frame_index = find_frame_by_block(up_or_down) do |b|
66
- (b.eval('"#{__FILE__}:#{__LINE__}"') =~ regex) or
67
- (b.eval("__method__").to_s =~ regex)
68
- end
69
-
70
- frame_index || raise(Pry::CommandError, "No frame that matches #{regex.source} found")
71
- end
1
+ require_relative 'frame_helpers.rb'
72
2
 
73
- def find_frame_by_block(up_or_down)
74
- start_index = frame_manager.binding_index
75
-
76
- if up_or_down == :down
77
- enum = start_index == 0 ? [].each :
78
- frame_manager.bindings[0..start_index - 1].reverse_each
79
- else
80
- enum = frame_manager.bindings[start_index + 1..-1]
81
- end
82
-
83
- new_frame = enum.find do |b|
84
- yield(b)
85
- end
86
-
87
- frame_manager.bindings.index(new_frame)
88
- end
89
-
90
- def find_frame_by_direction(dir, step_into_vapid: false)
91
- frame_index = find_frame_by_block(dir) do |b|
92
- step_into_vapid or
93
- not frame_manager.bindings.vapid?(b)
94
- end
95
-
96
- if !frame_index and !step_into_vapid
97
- frame_index = find_frame_by_block(dir) {true}
98
- end
99
-
100
- frame_index ||
101
- raise(Pry::CommandError, "At #{dir == :up ? 'top' : 'bottom'} of stack, cannot go further")
102
- end
3
+ module PryStackExplorer
103
4
 
104
- def move(direction, param)
105
- raise Pry::CommandError, "Nowhere to go" unless frame_manager
5
+ COMMANDS = Pry::CommandSet.new do
106
6
 
107
- if param == '+' or param.nil?
108
- index = find_frame_by_direction direction, step_into_vapid: param == '+'
109
- frame_manager.change_frame_to index
110
- else
111
- index = find_frame_by_regex(Regexp.new(param), direction)
112
- frame_manager.change_frame_to index
113
- end
7
+ block_command '%', 'Print current stack frame' do
8
+ run 'whereami'
114
9
  end
115
- end
116
-
117
10
 
118
- Commands = Pry::CommandSet.new do
119
11
  create_command "up", "Go up to the caller's context." do
120
12
  include FrameHelpers
121
13
 
@@ -163,6 +55,7 @@ module PryStackExplorer
163
55
  frame_manager.change_frame_to 0
164
56
  end
165
57
  end
58
+ alias_command 'bm', 'bottom'
166
59
 
167
60
  create_command "frame", "Switch to a particular frame." do
168
61
  include FrameHelpers
@@ -22,7 +22,7 @@ module PryStackExplorer
22
22
  raise ArgumentError, ":call_stack must be an array of bindings"
23
23
  end
24
24
  else
25
- bindings = PryMoves::BindingsStack.new
25
+ bindings = PryMoves::BindingsStack.new options
26
26
  initial_frame ||= bindings.suggest_initial_frame_index
27
27
  # if Thread.current[:pry_moves_debug] and initial_frame > 0
28
28
  if initial_frame > 0
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- pry-moves (1.0.0)
4
+ pry-moves (1.0.1)
5
5
  binding_of_caller (~> 0.7)
6
6
  colorize (~> 0.8)
7
+ diffy
7
8
  pry (>= 0.10.4, < 0.13)
8
9
 
9
10
  GEM
@@ -13,7 +14,8 @@ GEM
13
14
  debug_inspector (>= 0.0.1)
14
15
  coderay (1.1.3)
15
16
  colorize (0.8.1)
16
- debug_inspector (0.0.3)
17
+ debug_inspector (1.1.0)
18
+ diffy (3.4.0)
17
19
  method_source (0.9.2)
18
20
  pry (0.12.2)
19
21
  coderay (~> 1.1.0)
data/playground/sand.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # cd playground
2
+ # be ruby sand.rb
3
+
1
4
  require 'pry-moves'
2
5
  require './tracer.rb'
3
6
 
@@ -7,42 +10,41 @@ def fi(param)
7
10
  puts param
8
11
  end
9
12
 
10
- class A
13
+ class Sand
11
14
 
12
15
  def initialize
13
16
  puts :xuilo
14
17
  end
15
18
 
16
- def aa
19
+ def some_logic
17
20
  puts 'aa: step 1'
18
21
  puts 'aa: step 2'
19
22
  end
20
23
 
21
- def bb
24
+ def method_with_hidden_stack
22
25
  debug_redirect = :aa
23
26
  hide_from_stack = true
24
27
  puts 'bb: step 1'
25
28
  puts 'bb: step 2'
26
- aa
29
+ some_logic
27
30
  end
28
31
 
29
- def cc
32
+ def debugged_method
30
33
  koko = :love
31
- binding.pry
32
- bb
34
+ debug
35
+ method_with_hidden_stack
33
36
  (2..4).each do |i|
34
37
  puts i
35
38
  end
36
39
  puts :two
37
40
  end
38
- alias cc_al cc
41
+ alias debugged_method_alias debugged_method
39
42
 
40
43
  end
41
44
 
42
45
  puts :prepare
43
46
 
44
- A.new.cc_al
45
- A.new.cc_al
47
+ Sand.new.method_with_hidden_stack
46
48
 
47
49
 
48
50
  bb = 1
data/pry-moves.gemspec CHANGED
@@ -22,5 +22,6 @@ Gem::Specification.new do |gem|
22
22
  gem.add_runtime_dependency 'pry', '>= 0.10.4', '< 0.13'
23
23
  gem.add_runtime_dependency 'binding_of_caller', '~> 0.7'
24
24
  gem.add_runtime_dependency 'colorize', '~> 0.8'
25
+ gem.add_runtime_dependency 'diffy', '~> 3.4.0'
25
26
  gem.add_development_dependency 'pry-remote', '~> 0.1.6'
26
27
  end
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: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - garmoshka-mo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-01 00:00:00.000000000 Z
11
+ date: 2022-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -58,6 +58,20 @@ dependencies:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0.8'
61
+ - !ruby/object:Gem::Dependency
62
+ name: diffy
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 3.4.0
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 3.4.0
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: pry-remote
63
77
  requirement: !ruby/object:Gem::Requirement
@@ -103,6 +117,7 @@ files:
103
117
  - lib/pry-moves/bindings_stack.rb
104
118
  - lib/pry-moves/cli.rb
105
119
  - lib/pry-moves/commands.rb
120
+ - lib/pry-moves/error_with_data.rb
106
121
  - lib/pry-moves/formatter.rb
107
122
  - lib/pry-moves/painter.rb
108
123
  - lib/pry-moves/pry_ext.rb
@@ -113,6 +128,7 @@ files:
113
128
  - lib/pry-moves/version.rb
114
129
  - lib/pry-moves/watch.rb
115
130
  - lib/pry-stack_explorer/VERSION
131
+ - lib/pry-stack_explorer/frame_helpers.rb
116
132
  - lib/pry-stack_explorer/frame_manager.rb
117
133
  - lib/pry-stack_explorer/pry-stack_explorer.rb
118
134
  - lib/pry-stack_explorer/stack_commands.rb