pry-moves 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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