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 +4 -4
- data/Gemfile.lock +3 -1
- data/README.md +10 -2
- data/lib/commands/debug.rb +5 -1
- data/lib/debug_sugar.rb +11 -10
- data/lib/pry-moves/backtrace.rb +31 -13
- data/lib/pry-moves/bindings_stack.rb +28 -19
- data/lib/pry-moves/error_with_data.rb +10 -0
- data/lib/pry-moves/formatter.rb +4 -0
- data/lib/pry-moves/pry_ext.rb +3 -3
- data/lib/pry-moves/pry_wrapper.rb +2 -2
- data/lib/pry-moves/restartable.rb +4 -3
- data/lib/pry-moves/version.rb +1 -1
- data/lib/pry-moves.rb +18 -7
- data/lib/pry-stack_explorer/frame_helpers.rb +114 -0
- data/lib/pry-stack_explorer/pry-stack_explorer.rb +1 -1
- data/lib/pry-stack_explorer/stack_commands.rb +6 -113
- data/lib/pry-stack_explorer/when_started_hook.rb +1 -1
- data/playground/Gemfile.lock +4 -2
- data/playground/sand.rb +12 -10
- data/pry-moves.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9dc991b1aed888cf23fd1e9a76b29d274ce56989119f802982e9fbdc46cc034
|
4
|
+
data.tar.gz: 25e331897d83de799b696e84d1de474166095d4e80853a7f9cde99ba64290432
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
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:
|
data/lib/commands/debug.rb
CHANGED
@@ -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
|
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
|
-
|
2
|
+
pry_moves_stack_end = true
|
3
3
|
PryMoves.debug *args
|
4
4
|
end
|
5
5
|
|
6
|
-
def error(msg, debug_object = nil)
|
7
|
-
|
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.
|
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
|
-
|
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.
|
29
|
+
PryMoves.error lines.join("\n")
|
29
30
|
nil
|
30
31
|
end
|
31
32
|
|
32
33
|
def required(var)
|
33
|
-
|
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
|
data/lib/pry-moves/backtrace.rb
CHANGED
@@ -29,10 +29,17 @@ class PryMoves::Backtrace
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def run_command(param, param2)
|
32
|
-
if param
|
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
|
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
|
57
|
+
@pry.output.puts build_backtrace
|
51
58
|
end
|
52
59
|
|
53
|
-
def
|
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.
|
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
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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|
|
17
|
+
index {|b| for_for_initial_frame b} || 0
|
18
18
|
end
|
19
19
|
def initial_frame
|
20
|
-
find{|b|
|
20
|
+
find {|b| for_for_initial_frame b}
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
59
|
+
binding.hidden = true
|
64
60
|
end
|
65
61
|
|
66
62
|
if binding.local_variable_defined? :hide_from_stack
|
67
|
-
|
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 == :
|
87
|
-
|
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?(:
|
101
|
+
b.local_variable_defined?(:pry_moves_stack_end)
|
93
102
|
end
|
94
103
|
end
|
95
104
|
end
|
data/lib/pry-moves/formatter.rb
CHANGED
@@ -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
|
data/lib/pry-moves/pry_ext.rb
CHANGED
@@ -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 :
|
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"
|
data/lib/pry-moves/version.rb
CHANGED
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
|
-
|
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
|
-
|
57
|
-
|
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
|
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::
|
124
|
+
Pry.config.commands.import PryStackExplorer::COMMANDS
|
125
125
|
|
@@ -1,121 +1,13 @@
|
|
1
|
-
|
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
|
-
|
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
|
-
|
105
|
-
raise Pry::CommandError, "Nowhere to go" unless frame_manager
|
5
|
+
COMMANDS = Pry::CommandSet.new do
|
106
6
|
|
107
|
-
|
108
|
-
|
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
|
data/playground/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ..
|
3
3
|
specs:
|
4
|
-
pry-moves (1.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 (
|
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
|
13
|
+
class Sand
|
11
14
|
|
12
15
|
def initialize
|
13
16
|
puts :xuilo
|
14
17
|
end
|
15
18
|
|
16
|
-
def
|
19
|
+
def some_logic
|
17
20
|
puts 'aa: step 1'
|
18
21
|
puts 'aa: step 2'
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
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
|
-
|
29
|
+
some_logic
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
32
|
+
def debugged_method
|
30
33
|
koko = :love
|
31
|
-
|
32
|
-
|
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
|
41
|
+
alias debugged_method_alias debugged_method
|
39
42
|
|
40
43
|
end
|
41
44
|
|
42
45
|
puts :prepare
|
43
46
|
|
44
|
-
|
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.
|
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:
|
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
|