pry-moves 0.1.13 → 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 +1 -1
- data/Gemfile.lock +9 -5
- data/README.md +25 -9
- data/lib/commands/debug.rb +21 -0
- data/lib/commands/finish.rb +26 -0
- data/lib/commands/goto.rb +19 -0
- data/lib/commands/iterate.rb +22 -0
- data/lib/commands/next.rb +37 -0
- data/lib/commands/next_breakpoint.rb +22 -0
- data/lib/commands/step.rb +83 -0
- data/lib/commands/trace_command.rb +87 -0
- data/lib/commands/trace_helpers.rb +49 -0
- data/lib/commands/traced_method.rb +71 -0
- data/lib/debug_sugar.rb +73 -0
- data/lib/pry-moves/add_suffix.rb +87 -0
- data/lib/pry-moves/backtrace.rb +99 -50
- data/lib/pry-moves/bindings_stack.rb +106 -0
- data/lib/pry-moves/commands.rb +42 -3
- data/lib/pry-moves/error_with_data.rb +10 -0
- data/lib/pry-moves/formatter.rb +79 -0
- data/lib/pry-moves/painter.rb +3 -2
- data/lib/pry-moves/pry_ext.rb +66 -18
- data/lib/pry-moves/pry_wrapper.rb +30 -17
- data/lib/pry-moves/recursion_tracker.rb +94 -0
- data/lib/pry-moves/restartable.rb +39 -0
- data/lib/pry-moves/version.rb +1 -1
- data/lib/pry-moves/watch.rb +3 -0
- data/lib/pry-moves.rb +77 -6
- data/lib/pry-stack_explorer/frame_helpers.rb +114 -0
- data/lib/pry-stack_explorer/frame_manager.rb +6 -9
- data/lib/pry-stack_explorer/pry-stack_explorer.rb +2 -17
- data/lib/pry-stack_explorer/{commands.rb → stack_commands.rb} +6 -109
- data/lib/pry-stack_explorer/when_started_hook.rb +10 -65
- data/playground/Gemfile.lock +9 -5
- data/playground/README.md +1 -0
- data/playground/playground.rb +94 -9
- data/playground/sand.rb +12 -10
- data/playground/test.rb +5 -1
- data/playground/test.sh +1 -0
- data/pry-moves.gemspec +4 -2
- data/publish.sh +2 -1
- data/spec/backtrace_spec.rb +11 -13
- data/spec/blocks_spec.rb +41 -8
- data/spec/commands_spec.rb +26 -25
- data/spec/pry_debugger.rb +5 -1
- data/spec/redirection_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -4
- data/spec/step_spec.rb +51 -0
- metadata +60 -13
- data/lib/pry-moves/helpers.rb +0 -56
- data/lib/pry-moves/trace_commands.rb +0 -109
- data/lib/pry-moves/traced_method.rb +0 -61
- data/lib/pry-moves/tracer.rb +0 -140
- data/lib/pry-moves/traversing.rb +0 -69
data/lib/pry-moves/pry_ext.rb
CHANGED
@@ -1,32 +1,32 @@
|
|
1
1
|
class << Pry
|
2
|
-
|
3
|
-
|
4
|
-
def start_with_pry_nav(target = TOPLEVEL_BINDING, options = {})
|
5
|
-
old_options = options.reject { |k, _| k == :pry_remote }
|
2
|
+
alias pry_moves_origin_start start
|
6
3
|
|
4
|
+
def start(target = TOPLEVEL_BINDING, options = {})
|
7
5
|
if target.is_a?(Binding) && PryMoves.check_file_context(target)
|
8
6
|
# Wrap the tracer around the usual Pry.start
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
original_verbosity = $VERBOSE
|
8
|
+
$VERBOSE = nil # Disable warnings for pry-moves
|
9
|
+
PryMoves::PryWrapper.new(target, options, self).run
|
10
|
+
$VERBOSE = original_verbosity
|
12
11
|
else
|
13
12
|
# No need for the tracer unless we have a file context to step through
|
14
|
-
|
13
|
+
pry_moves_origin_start(target, options)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
alias_method :start, :start_with_pry_nav
|
19
17
|
end
|
20
18
|
|
21
19
|
Binding.class_eval do
|
22
20
|
|
21
|
+
attr_accessor :index, :hidden
|
22
|
+
|
23
23
|
alias pry_forced pry
|
24
24
|
|
25
|
-
def pry
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
pry_forced
|
25
|
+
def pry options = nil
|
26
|
+
if !Pry.config.disable_breakpoints and
|
27
|
+
# Don't start binding.pry when semaphore locked by current thread
|
28
|
+
PryMoves.synchronize_threads
|
29
|
+
pry_forced options
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -34,6 +34,32 @@ end
|
|
34
34
|
|
35
35
|
Pry.config.pager = false
|
36
36
|
|
37
|
+
Pry::Command.class_eval do
|
38
|
+
class << self
|
39
|
+
attr_accessor :original_user_input
|
40
|
+
end
|
41
|
+
|
42
|
+
alias run_origin_for_pry_moves run
|
43
|
+
def run(command_string, *args)
|
44
|
+
Pry.config.original_user_input = self.class.original_user_input
|
45
|
+
result = run_origin_for_pry_moves command_string, *args
|
46
|
+
Pry.config.original_user_input = nil
|
47
|
+
result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Pry::CommandSet.class_eval do
|
52
|
+
|
53
|
+
alias alias_command_origin_for_pry_moves alias_command
|
54
|
+
|
55
|
+
def alias_command(match, action, options = {})
|
56
|
+
cmd = alias_command_origin_for_pry_moves match, action, options
|
57
|
+
cmd.original_user_input = match
|
58
|
+
cmd
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
37
63
|
Pry::Command::Whereami.class_eval do
|
38
64
|
# Negligent function from Pry - evidently poor output format
|
39
65
|
# would be wanted to be changed often by developers,
|
@@ -56,11 +82,19 @@ Pry::Command::Whereami.class_eval do
|
|
56
82
|
end
|
57
83
|
|
58
84
|
def build_output
|
59
|
-
lines = []
|
60
|
-
|
61
|
-
|
85
|
+
lines = ['']
|
86
|
+
|
87
|
+
formatter = PryMoves::Formatter.new
|
88
|
+
prefix = Thread.current[:pry_moves_debug] ? "👾 " : ""
|
89
|
+
lines << "#{prefix}#{formatter.shorten_path location}"
|
90
|
+
lines << " ." + formatter.method_signature(target)
|
62
91
|
lines << ''
|
63
92
|
lines << "#{code.with_line_numbers(use_line_numbers?).with_marker(marker).highlighted}"
|
93
|
+
|
94
|
+
lines << PryMoves::Watch.instance.output(target) unless PryMoves::Watch.instance.empty?
|
95
|
+
lines.concat PryMoves.messages
|
96
|
+
PryMoves.messages.clear
|
97
|
+
|
64
98
|
lines << ''
|
65
99
|
lines.join "\n"
|
66
100
|
end
|
@@ -82,4 +116,18 @@ Pry::Code::LOC.class_eval do
|
|
82
116
|
tuple[0] = " #{marker} #{ line }"
|
83
117
|
end
|
84
118
|
|
85
|
-
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Pry::Output.class_eval do
|
122
|
+
|
123
|
+
alias pry_moves_origin_for_puts puts
|
124
|
+
|
125
|
+
def puts *args
|
126
|
+
first = args[0]
|
127
|
+
if first.is_a? String and first.start_with? "(pry) output error"
|
128
|
+
first.slice! 400..-1
|
129
|
+
end
|
130
|
+
pry_moves_origin_for_puts *args
|
131
|
+
end
|
132
|
+
|
133
|
+
end if defined? Pry::Output
|
@@ -2,24 +2,24 @@ require 'pry' unless defined? Pry
|
|
2
2
|
|
3
3
|
module PryMoves
|
4
4
|
class PryWrapper
|
5
|
-
def initialize(binding_, pry_start_options
|
5
|
+
def initialize(binding_, pry_start_options, pry)
|
6
6
|
@init_binding = binding_
|
7
7
|
@pry_start_options = pry_start_options # Options to use for Pry.start
|
8
|
+
@pry = pry
|
8
9
|
end
|
9
10
|
|
10
|
-
def run
|
11
|
+
def run
|
11
12
|
PryMoves.lock
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
initial_frame = PryMoves::BindingsStack.new(@pry_start_options).initial_frame
|
15
|
+
if not @pry_start_options[:pry_moves_loop] and
|
16
|
+
initial_frame.local_variable_defined? :debug_redirect
|
17
|
+
debug_redirect = initial_frame.local_variable_get(:debug_redirect)
|
18
|
+
PryMoves.messages << "⏩ redirected to #{debug_redirect}"
|
19
|
+
@command = {action: :step, binding: initial_frame}
|
20
|
+
else
|
21
|
+
start_pry
|
20
22
|
end
|
21
|
-
PryMoves.is_open = false
|
22
|
-
Pry.config.marker = "=>"
|
23
23
|
|
24
24
|
if @command
|
25
25
|
trace_command
|
@@ -30,11 +30,24 @@ class PryWrapper
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
return_value
|
33
|
+
@return_value
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
+
def start_pry
|
39
|
+
Pry.config.marker = "⛔️" if @pry_start_options[:exit_from_method]
|
40
|
+
PryMoves.is_open = true
|
41
|
+
|
42
|
+
@command = catch(:breakout_nav) do # Coordinates with PryMoves::Commands
|
43
|
+
@return_value = @pry.pry_moves_origin_start(@init_binding, @pry_start_options)
|
44
|
+
nil # Nothing thrown == no navigational command
|
45
|
+
end
|
46
|
+
|
47
|
+
PryMoves.is_open = false
|
48
|
+
Pry.config.marker = "=>"
|
49
|
+
end
|
50
|
+
|
38
51
|
def trace_command
|
39
52
|
if @command[:action] == :debug
|
40
53
|
wrap_debug
|
@@ -61,9 +74,9 @@ class PryWrapper
|
|
61
74
|
tracer = start_tracing
|
62
75
|
begin
|
63
76
|
@command[:binding].eval @command[:param]
|
64
|
-
rescue => e
|
77
|
+
rescue StandardError, SyntaxError => e
|
65
78
|
Thread.current.set_trace_func nil
|
66
|
-
puts e
|
79
|
+
puts "❌️ Error during #{"debug".yellow} execution: #{e}"
|
67
80
|
end
|
68
81
|
tracer.stop_tracing
|
69
82
|
end.join
|
@@ -73,9 +86,9 @@ class PryWrapper
|
|
73
86
|
|
74
87
|
def start_tracing
|
75
88
|
@last_runtime_binding = @command[:binding]
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
PryMoves::TraceCommand.trace @command, @pry_start_options do |binding|
|
90
|
+
Pry.start(binding, @pry_start_options)
|
91
|
+
end
|
79
92
|
end
|
80
93
|
|
81
94
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module PryMoves::Recursion
|
2
|
+
|
3
|
+
class Tracker
|
4
|
+
|
5
|
+
attr_reader :loops
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@history = []
|
9
|
+
@loops = 0
|
10
|
+
@missing = 0
|
11
|
+
@currently_missing = []
|
12
|
+
@missing_lines = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def track file, line_num, bt_index, binding_index
|
16
|
+
line = "#{file}:#{line_num}"
|
17
|
+
if @last_index
|
18
|
+
check_recursion line, bt_index, binding_index
|
19
|
+
elsif (prev_index = @history.rindex line)
|
20
|
+
@loops += 1
|
21
|
+
@last_index = prev_index
|
22
|
+
@recursion_size = 1
|
23
|
+
else
|
24
|
+
@history << line
|
25
|
+
@last_index = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
@repetitions_start ||= bt_index if @loops == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_recursion line, bt_index, binding_index
|
32
|
+
prev_index = @history.rindex line
|
33
|
+
if prev_index == @last_index
|
34
|
+
@loops += 1
|
35
|
+
@missing = 0
|
36
|
+
@recursion_size = 0
|
37
|
+
@missing_lines.concat @currently_missing
|
38
|
+
@repetitions_end = bt_index
|
39
|
+
elsif prev_index && prev_index > @last_index
|
40
|
+
@last_index = prev_index + 1
|
41
|
+
@recursion_size += 1
|
42
|
+
# todo: finish tracking and debug multi-line recursions
|
43
|
+
elsif @missing <= @recursion_size
|
44
|
+
@missing += 1
|
45
|
+
@currently_missing << binding_index
|
46
|
+
false
|
47
|
+
else
|
48
|
+
# @missing_lines = nil
|
49
|
+
# @last_index = nil
|
50
|
+
@is_finished = true
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def finished?
|
56
|
+
@is_finished
|
57
|
+
end
|
58
|
+
|
59
|
+
def good?
|
60
|
+
@repetitions_start and @repetitions_end
|
61
|
+
end
|
62
|
+
|
63
|
+
def apply result
|
64
|
+
label = "♻️ recursion with #{@loops} loops"
|
65
|
+
label += " Ⓜ️ #{@missing} missing lines #{@missing_lines}" if @missing_lines.present?
|
66
|
+
label = "...(#{label})..."
|
67
|
+
# puts "#{@repetitions_start}..#{@repetitions_end}"
|
68
|
+
result[@repetitions_start..@repetitions_end] = [label]
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
class Holder < Array
|
74
|
+
|
75
|
+
def initialize(*args)
|
76
|
+
super
|
77
|
+
new_tracker
|
78
|
+
end
|
79
|
+
|
80
|
+
def new_tracker
|
81
|
+
@tracker = Tracker.new
|
82
|
+
end
|
83
|
+
|
84
|
+
def track *args
|
85
|
+
@tracker.track *args
|
86
|
+
if @tracker.finished?
|
87
|
+
self << @tracker if @tracker.good?
|
88
|
+
new_tracker
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module PryMoves::Restartable
|
2
|
+
|
3
|
+
attr_accessor :restart_requested, :reload_requested,
|
4
|
+
:reload_rake_tasks
|
5
|
+
|
6
|
+
def restartable context
|
7
|
+
trigger :each_new_run, context
|
8
|
+
yield
|
9
|
+
re_execution
|
10
|
+
rescue PryMoves::Restart
|
11
|
+
puts "🔄️ Restarting execution"
|
12
|
+
self.restart_requested = false
|
13
|
+
PryMoves.reset
|
14
|
+
trigger :restart, context
|
15
|
+
retry
|
16
|
+
rescue PryMoves::Reload
|
17
|
+
puts "🔮 try to use @ with reload"
|
18
|
+
exit 3
|
19
|
+
end
|
20
|
+
|
21
|
+
def re_execution
|
22
|
+
raise PryMoves::Restart if restart_requested
|
23
|
+
raise PryMoves::Reload if reload_requested
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
class PryMoves::Restart < RuntimeError
|
30
|
+
end
|
31
|
+
class PryMoves::Reload < RuntimeError
|
32
|
+
end
|
33
|
+
RSpec::Support::AllExceptionsExceptOnesWeMustNotRescue::AVOID_RESCUING.concat [PryMoves::Restart, PryMoves::Reload] if defined? RSpec
|
34
|
+
|
35
|
+
Pry.config.hooks.add_hook(:after_eval, :exit_on_re_execution) do |_, _, _pry_|
|
36
|
+
if PryMoves.restart_requested or PryMoves.reload_requested
|
37
|
+
Pry.run_command 'exit-all'
|
38
|
+
end
|
39
|
+
end
|
data/lib/pry-moves/version.rb
CHANGED
data/lib/pry-moves/watch.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'singleton'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
class PryMoves::Watch
|
4
5
|
|
@@ -44,6 +45,8 @@ class PryMoves::Watch
|
|
44
45
|
"\033[1m#{cmd}\033[0m: #{format binding_.eval(cmd)}"
|
45
46
|
rescue NameError
|
46
47
|
"\033[1m#{cmd}\033[0m: <undefined>"
|
48
|
+
rescue => e
|
49
|
+
"\033[1m#{cmd}\033[0m: <#{e}>"
|
47
50
|
end
|
48
51
|
|
49
52
|
def format(text)
|
data/lib/pry-moves.rb
CHANGED
@@ -1,19 +1,34 @@
|
|
1
1
|
require 'pry' unless defined? Pry
|
2
|
+
require 'colorize'
|
3
|
+
require 'diffy'
|
2
4
|
|
3
5
|
require 'pry-moves/version'
|
4
|
-
require 'pry-moves/trace_commands'
|
5
|
-
require 'pry-moves/traced_method'
|
6
|
-
require 'pry-moves/tracer'
|
7
6
|
require 'pry-moves/pry_ext'
|
8
7
|
require 'pry-moves/commands'
|
9
|
-
require 'pry-moves/
|
8
|
+
require 'pry-moves/add_suffix'
|
10
9
|
require 'pry-moves/pry_wrapper'
|
10
|
+
require 'pry-moves/bindings_stack'
|
11
|
+
require 'pry-moves/formatter'
|
11
12
|
require 'pry-moves/backtrace'
|
12
13
|
require 'pry-moves/watch'
|
13
|
-
require 'pry-moves/helpers'
|
14
14
|
require 'pry-moves/painter'
|
15
|
+
require 'pry-moves/restartable'
|
16
|
+
require 'pry-moves/recursion_tracker'
|
17
|
+
require 'pry-moves/error_with_data'
|
18
|
+
|
19
|
+
require 'commands/traced_method'
|
20
|
+
require 'commands/trace_helpers'
|
21
|
+
require 'commands/trace_command'
|
22
|
+
require 'commands/debug'
|
23
|
+
require 'commands/finish'
|
24
|
+
require 'commands/goto'
|
25
|
+
require 'commands/iterate'
|
26
|
+
require 'commands/next'
|
27
|
+
require 'commands/next_breakpoint'
|
28
|
+
require 'commands/step'
|
15
29
|
|
16
30
|
require 'pry-stack_explorer/pry-stack_explorer'
|
31
|
+
require 'debug_sugar'
|
17
32
|
|
18
33
|
# Optionally load pry-remote monkey patches
|
19
34
|
require 'pry-moves/pry_remote_ext' if defined? PryRemote
|
@@ -22,8 +37,36 @@ module PryMoves
|
|
22
37
|
TRACE_IGNORE_FILES = Dir[File.join(File.dirname(__FILE__), '**', '*.rb')].map { |f| File.expand_path(f) }
|
23
38
|
|
24
39
|
extend self
|
40
|
+
extend PryMoves::Restartable
|
41
|
+
|
42
|
+
attr_accessor :is_open, :trace, :stack_tips,
|
43
|
+
:stop_on_breakpoints, :launched_specs_examples, :debug_called_times
|
25
44
|
|
26
|
-
|
45
|
+
def reset
|
46
|
+
self.launched_specs_examples = 0
|
47
|
+
self.stop_on_breakpoints = true
|
48
|
+
self.debug_called_times = 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def debug(message = nil, at: nil, options: nil)
|
52
|
+
pry_moves_stack_end = true
|
53
|
+
PryMoves.re_execution
|
54
|
+
if PryMoves.stop_on_breakpoints
|
55
|
+
self.debug_called_times += 1
|
56
|
+
if at
|
57
|
+
return unless self.debug_called_times == at
|
58
|
+
end
|
59
|
+
if message
|
60
|
+
PryMoves.messages << (message.is_a?(String) ? message : message.ai)
|
61
|
+
end
|
62
|
+
binding.pry options
|
63
|
+
PryMoves.re_execution
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def error(message)
|
68
|
+
debug message, options: {is_error: true}
|
69
|
+
end
|
27
70
|
|
28
71
|
# Checks that a binding is in a local file context. Extracted from
|
29
72
|
# https://github.com/pry/pry/blob/master/lib/pry/default_commands/context.rb
|
@@ -36,9 +79,18 @@ module PryMoves
|
|
36
79
|
@semaphore ||= Mutex.new
|
37
80
|
end
|
38
81
|
|
82
|
+
def messages
|
83
|
+
@messages ||= []
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_command(command, &block)
|
87
|
+
Pry.commands.block_command command, "", &block
|
88
|
+
end
|
89
|
+
|
39
90
|
def locked?
|
40
91
|
semaphore.locked?
|
41
92
|
end
|
93
|
+
alias tracing? locked?
|
42
94
|
|
43
95
|
def lock
|
44
96
|
semaphore.lock unless semaphore.locked?
|
@@ -59,6 +111,25 @@ module PryMoves
|
|
59
111
|
true
|
60
112
|
end
|
61
113
|
|
114
|
+
def trigger(event, context)
|
115
|
+
triggers[event].each {|t| t.call context}
|
116
|
+
end
|
117
|
+
|
118
|
+
def triggers
|
119
|
+
@triggers ||= Hash.new do |hash, key|
|
120
|
+
hash[key] = []
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
TRIGGERS = [:each_new_run, :restart]
|
125
|
+
def on(trigger, &block)
|
126
|
+
error "Invalid trigger, possible triggers: #{TRIGGERS}", trigger unless trigger.in? TRIGGERS
|
127
|
+
triggers[trigger] << block
|
128
|
+
end
|
129
|
+
|
62
130
|
# Reference to currently running pry-remote server. Used by the tracer.
|
63
131
|
attr_accessor :current_remote_server
|
64
132
|
end
|
133
|
+
|
134
|
+
PryMoves.reset
|
135
|
+
PryMoves.trace = true if ENV['TRACE_MOVES']
|
@@ -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
|
@@ -33,13 +33,6 @@ module PryStackExplorer
|
|
33
33
|
@prior_backtrace = _pry_.backtrace
|
34
34
|
end
|
35
35
|
|
36
|
-
def filter_bindings(vapid_frames: false)
|
37
|
-
bindings.reject do |binding|
|
38
|
-
!vapid_frames and
|
39
|
-
binding.local_variable_defined?(:vapid_frame)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
36
|
# Iterate over all frames
|
44
37
|
def each(&block)
|
45
38
|
bindings.each(&block)
|
@@ -61,14 +54,18 @@ module PryStackExplorer
|
|
61
54
|
# @param [Fixnum] index The index.
|
62
55
|
def set_binding_index_safely(index)
|
63
56
|
if index > bindings.size - 1
|
64
|
-
raise Pry::CommandError, "At top of stack, cannot go further"
|
57
|
+
raise Pry::CommandError, "Shouldn't happen: At top of stack, cannot go further"
|
65
58
|
elsif index < 0
|
66
|
-
raise Pry::CommandError, "At bottom of stack, cannot go further"
|
59
|
+
raise Pry::CommandError, "Shouldn't happen: At bottom of stack, cannot go further"
|
67
60
|
else
|
68
61
|
self.binding_index = index
|
69
62
|
end
|
70
63
|
end
|
71
64
|
|
65
|
+
def goto_index index
|
66
|
+
change_frame_to bindings.index {|b| b.index == index }
|
67
|
+
end
|
68
|
+
|
72
69
|
# Change active frame to the one indexed by `index`.
|
73
70
|
# Note that indexing base is `0`
|
74
71
|
# @param [Fixnum] index The index of the frame.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# pry-stack_explorer.rb
|
2
2
|
# (C) John Mair (banisterfiend); MIT license
|
3
3
|
|
4
|
-
require "pry-stack_explorer/
|
4
|
+
require "pry-stack_explorer/stack_commands"
|
5
5
|
require "pry-stack_explorer/frame_manager"
|
6
6
|
require "pry-stack_explorer/when_started_hook"
|
7
7
|
require "binding_of_caller"
|
@@ -121,20 +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
|
|
126
|
-
# monkey-patch the whereami command to show some frame information,
|
127
|
-
# useful for navigating stack.
|
128
|
-
Pry.config.hooks.add_hook(:before_whereami, :stack_explorer) do
|
129
|
-
if PryStackExplorer.frame_manager(_pry_) && !internal_binding?(target)
|
130
|
-
bindings = PryStackExplorer.frame_manager(_pry_).bindings
|
131
|
-
binding_index = PryStackExplorer.frame_manager(_pry_).binding_index
|
132
|
-
|
133
|
-
info = "#{Pry::Helpers::Text.bold('Frame:')} "+
|
134
|
-
"#{binding_index}/#{bindings.size - 1} "+
|
135
|
-
"#{bindings[binding_index].frame_type}"
|
136
|
-
|
137
|
-
output.puts "\n"
|
138
|
-
output.puts info
|
139
|
-
end
|
140
|
-
end
|