pryx 0.12.0 → 0.12.1

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: 32be9dee5f11b22b7cc96644943a86adf5ae51a1e634e4c16a5cdd01b8245b3a
4
- data.tar.gz: 5b2d22c7c2177ccd9ef3ac0813ec67bc354e457cb5d0880ef2f20966e2062dfd
3
+ metadata.gz: c0a4fd9f677ce53582ab29d0aa651a8f882430ad9f38b3e09a4f0241b45258b3
4
+ data.tar.gz: 3ea2ef13871304a19da84298d3c69f8a8a7ff3988611927ae5827e2117dc3f8a
5
5
  SHA512:
6
- metadata.gz: 6d77e2d271fe47d4b5028a7af1ea51cd1dd443220d12ce21e9c720fe356ea126607d65b3af260f902fe80efffeacf7998873dcdb5dac00ec0d2ea320dbb8d590
7
- data.tar.gz: 1708bfeafb9e2c95e71887e7e64b7cadac8816b6797ec582dd40739629ecce302cb10340d1f5d78add4cace5151ae1a5c1f68cefc84ca6988084153bfee090bc
6
+ metadata.gz: b85934aaac5f9df4959d02f68d744e076f2a5d5bbd23bc0ec139727623899779500b214620608c57362348f70c274e241b45bcdb6acd9a0ff622dccb8d6e279e
7
+ data.tar.gz: a350c9b58d4b744611534709cf3aa0c63132cf3e68547801223a8c5baa70056440f89394ea8fa51c837fda44c18d3c7fefa3a507269d18474accc4c859eae022
@@ -0,0 +1,365 @@
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_instance)
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_instance)
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
+ meth = b.eval('__method__')
50
+ b_self = b.eval('self')
51
+ meth_obj = Pry::Method.from_binding(b) if meth
52
+
53
+ type = b.frame_type ? "[#{b.frame_type}]".ljust(9) : ""
54
+ desc = b.frame_description ? "#{b.frame_description}" : "#{frame_description(b)}"
55
+ sig = meth_obj ? "<#{signature_with_owner(meth_obj)}>" : ""
56
+
57
+ self_clipped = "#{Pry.view_clip(b_self)}"
58
+ path = '@ ' + b.source_location.join(':')
59
+
60
+ if !verbose
61
+ "#{type} #{desc} #{sig}"
62
+ else
63
+ "#{type} #{desc} #{sig}\n in #{self_clipped} #{path}"
64
+ end
65
+ end
66
+
67
+ # @param [Pry::Method] meth_obj The method object.
68
+ # @return [String] Signature for the method object in Class#method format.
69
+ def signature_with_owner(meth_obj)
70
+ if !meth_obj.undefined?
71
+ args = meth_obj.parameters.inject([]) do |arr, (type, name)|
72
+ name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
73
+ arr << case type
74
+ when :req then name.to_s
75
+ when :opt then "#{name}=?"
76
+ when :rest then "*#{name}"
77
+ when :block then "&#{name}"
78
+ else '?'
79
+ end
80
+ end
81
+ "#{meth_obj.name_with_owner}(#{args.join(', ')})"
82
+ else
83
+ "#{meth_obj.name_with_owner}(UNKNOWN) (undefined method)"
84
+ end
85
+ end
86
+
87
+ # Regexp.new(args[0])
88
+ def find_frame_by_regex(regex, up_or_down)
89
+ frame_index = find_frame_by_block(up_or_down) do |b|
90
+ b.eval("__method__").to_s =~ regex
91
+ end
92
+
93
+ if frame_index
94
+ frame_index
95
+ else
96
+ raise Pry::CommandError, "No frame that matches #{regex.source} found!"
97
+ end
98
+ end
99
+
100
+ def find_frame_by_object_regex(class_regex, method_regex, up_or_down)
101
+ frame_index = find_frame_by_block(up_or_down) do |b|
102
+ class_match = b.eval("self.class").to_s =~ class_regex
103
+ meth_match = b.eval("__method__").to_s =~ method_regex
104
+
105
+ class_match && meth_match
106
+ end
107
+
108
+ if frame_index
109
+ frame_index
110
+ else
111
+ raise Pry::CommandError, "No frame that matches #{class_regex.source}" + '#' + "#{method_regex.source} found!"
112
+ end
113
+ end
114
+
115
+ def find_frame_by_block(up_or_down)
116
+ start_index = frame_manager.binding_index
117
+
118
+ if up_or_down == :down
119
+ enum = frame_manager.bindings[0..start_index - 1].reverse_each
120
+ else
121
+ enum = frame_manager.bindings[start_index + 1..-1]
122
+ end
123
+
124
+ new_frame = enum.find do |b|
125
+ yield(b)
126
+ end
127
+
128
+ frame_manager.bindings.index(new_frame)
129
+ end
130
+ end
131
+
132
+
133
+ Commands = Pry::CommandSet.new do
134
+ create_command "up", "Go up to the caller's context." do
135
+ include FrameHelpers
136
+
137
+ banner <<-BANNER
138
+ Usage: up [OPTIONS]
139
+ Go up to the caller's context. Accepts optional numeric parameter for how many frames to move up.
140
+ Also accepts a string (regex) instead of numeric; for jumping to nearest parent method frame which matches the regex.
141
+ e.g: up #=> Move up 1 stack frame.
142
+ e.g: up 3 #=> Move up 2 stack frames.
143
+ e.g: up meth #=> Jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`.
144
+ BANNER
145
+
146
+ def process
147
+ inc = args.first.nil? ? "1" : args.first
148
+
149
+ if !frame_manager
150
+ raise Pry::CommandError, "Nowhere to go!"
151
+ else
152
+ if inc =~ /\d+/
153
+ frame_manager.change_frame_to frame_manager.binding_index + inc.to_i
154
+ elsif match = /^([A-Z]+[^#.]*)(#|\.)(.+)$/.match(inc)
155
+ new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :up)
156
+ frame_manager.change_frame_to new_frame_index
157
+ elsif inc =~ /^[^-].*$/
158
+ new_frame_index = find_frame_by_regex(Regexp.new(inc), :up)
159
+ frame_manager.change_frame_to new_frame_index
160
+ end
161
+ end
162
+ end
163
+ end
164
+
165
+ create_command "down", "Go down to the callee's context." do
166
+ include FrameHelpers
167
+
168
+ banner <<-BANNER
169
+ Usage: down [OPTIONS]
170
+ Go down to the callee's context. Accepts optional numeric parameter for how many frames to move down.
171
+ Also accepts a string (regex) instead of numeric; for jumping to nearest child method frame which matches the regex.
172
+ e.g: down #=> Move down 1 stack frame.
173
+ e.g: down 3 #=> Move down 2 stack frames.
174
+ e.g: down meth #=> Jump to nearest child stack frame whose method matches /meth/ regex, i.e `my_method`.
175
+ BANNER
176
+
177
+ def process
178
+ inc = args.first.nil? ? "1" : args.first
179
+
180
+ if !frame_manager
181
+ raise Pry::CommandError, "Nowhere to go!"
182
+ else
183
+ if inc =~ /\d+/
184
+ if frame_manager.binding_index - inc.to_i < 0
185
+ raise Pry::CommandError, "At bottom of stack, cannot go further!"
186
+ else
187
+ frame_manager.change_frame_to frame_manager.binding_index - inc.to_i
188
+ end
189
+ elsif match = /^([A-Z]+[^#.]*)(#|\.)(.+)$/.match(inc)
190
+ new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :down)
191
+ frame_manager.change_frame_to new_frame_index
192
+ elsif inc =~ /^[^-].*$/
193
+ new_frame_index = find_frame_by_regex(Regexp.new(inc), :down)
194
+ frame_manager.change_frame_to new_frame_index
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ create_command "frame", "Switch to a particular frame." do
201
+ include FrameHelpers
202
+
203
+ banner <<-BANNER
204
+ Usage: frame [OPTIONS]
205
+ Switch to a particular frame. Accepts numeric parameter (or regex for method name) for the target frame to switch to (use with show-stack).
206
+ Negative frame numbers allowed. When given no parameter show information about the current frame.
207
+
208
+ e.g: frame 4 #=> jump to the 4th frame
209
+ e.g: frame meth #=> jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`
210
+ e.g: frame -2 #=> jump to the second-to-last frame
211
+ e.g: frame #=> show information info about current frame
212
+ BANNER
213
+
214
+ def process
215
+ if !frame_manager
216
+ raise Pry::CommandError, "nowhere to go!"
217
+ else
218
+
219
+ if args[0] =~ /\d+/
220
+ frame_manager.change_frame_to args[0].to_i
221
+ elsif match = /^([A-Z]+[^#.]*)(#|\.)(.+)$/.match(args[0])
222
+ new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :up)
223
+ frame_manager.change_frame_to new_frame_index
224
+ elsif args[0] =~ /^[^-].*$/
225
+ new_frame_index = find_frame_by_regex(Regexp.new(args[0]), :up)
226
+ frame_manager.change_frame_to new_frame_index
227
+ else
228
+ output.puts "##{frame_manager.binding_index} #{frame_info(target, true)}"
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ create_command "stack", "Show all frames" do
235
+ include FrameHelpers
236
+
237
+ banner <<-BANNER
238
+ Usage: stack [OPTIONS]
239
+ Show all accessible stack frames.
240
+ e.g: stack -v
241
+
242
+ alias: show-stack
243
+ BANNER
244
+
245
+ def options(opt)
246
+ opt.on :v, :verbose, "Include extra information."
247
+ opt.on :H, :head, "Display the first N stack frames (defaults to 10).", :optional_argument => true, :as => Integer, :default => 10
248
+ opt.on :T, :tail, "Display the last N stack frames (defaults to 10).", :optional_argument => true, :as => Integer, :default => 10
249
+ opt.on :c, :current, "Display N frames either side of current frame (default to 5).", :optional_argument => true, :as => Integer, :default => 5
250
+ opt.on :a, :app, "Display application frames only", optional_argument: true
251
+ end
252
+
253
+ def memoized_info(index, b, verbose)
254
+ frame_manager.user[:frame_info] ||= Hash.new { |h, k| h[k] = [] }
255
+
256
+ if verbose
257
+ frame_manager.user[:frame_info][:v][index] ||= frame_info(b, verbose)
258
+ else
259
+ frame_manager.user[:frame_info][:normal][index] ||= frame_info(b, verbose)
260
+ end
261
+ end
262
+
263
+ private :memoized_info
264
+
265
+ # @return [Array<Fixnum, Array<Binding>>] Return tuple of
266
+ # base_frame_index and the array of frames.
267
+ def selected_stack_frames
268
+ if opts.present?(:head)
269
+ [0, frame_manager.bindings[0..(opts[:head] - 1)]]
270
+
271
+ elsif opts.present?(:tail)
272
+ tail = opts[:tail]
273
+ if tail > frame_manager.bindings.size
274
+ tail = frame_manager.bindings.size
275
+ end
276
+
277
+ base_frame_index = frame_manager.bindings.size - tail
278
+ [base_frame_index, frame_manager.bindings[base_frame_index..-1]]
279
+
280
+ elsif opts.present?(:current)
281
+ first_frame_index = frame_manager.binding_index - (opts[:current])
282
+ first_frame_index = 0 if first_frame_index < 0
283
+ last_frame_index = frame_manager.binding_index + (opts[:current])
284
+ [first_frame_index, frame_manager.bindings[first_frame_index..last_frame_index]]
285
+
286
+ else
287
+ [0, frame_manager.bindings]
288
+ end
289
+ end
290
+
291
+ private :selected_stack_frames
292
+
293
+ def process
294
+ return no_stack_available! unless frame_manager
295
+
296
+ title = "Showing all accessible frames in stack (#{frame_manager.bindings.size} in total):"
297
+
298
+ content = [
299
+ bold(title),
300
+ "---",
301
+ make_stack_lines
302
+ ].join("\n")
303
+
304
+ stagger_output content
305
+ end
306
+
307
+ private
308
+
309
+ def make_stack_lines
310
+ frames_with_indices.map do |b, i|
311
+ make_stack_line(b, i, (i == frame_manager.binding_index))
312
+ end.join("\n")
313
+ end
314
+
315
+ def frames_with_indices
316
+ if opts.present?(:app) && defined?(ActiveSupport::BacktraceCleaner)
317
+ app_frames
318
+ else
319
+ offset_frames
320
+ end
321
+ end
322
+
323
+ # "=> #0 method_name <Class#method(...)>"
324
+ def make_stack_line(b, i, active)
325
+ arw = active ? "=>" : " "
326
+
327
+ "#{arw} ##{i} #{memoized_info(i, b, opts[:v])}"
328
+ end
329
+
330
+ def offset_frames
331
+ base_frame_index, frames = selected_stack_frames
332
+
333
+ frames.each_with_index.map do |frame, index|
334
+ [frame, index + base_frame_index]
335
+ end
336
+ end
337
+
338
+ def no_stack_available!
339
+ output.puts "No caller stack available!"
340
+ end
341
+
342
+ LOCATION_LAMBDA = ->(_binding){ _binding.source_location[0] }
343
+
344
+ def app_frames
345
+ locations = frame_manager.bindings.map(&LOCATION_LAMBDA)
346
+ filtered = backtrace_cleaner.clean(locations)
347
+
348
+ frame_manager.bindings
349
+ .each_with_index
350
+ .map
351
+ .select do |_binding, _index|
352
+ LOCATION_LAMBDA.call(_binding).in?(filtered)
353
+ end
354
+ end
355
+
356
+ # also see Rails::BacktraceCleaner
357
+ def backtrace_cleaner
358
+ @backtrace_cleaner ||= ActiveSupport::BacktraceCleaner.new
359
+ end
360
+ end
361
+
362
+ alias_command "show-stack", "stack"
363
+
364
+ end
365
+ end
@@ -0,0 +1,85 @@
1
+ module PryStackExplorer
2
+
3
+ # This class represents a call-stack. It stores the
4
+ # frames that make up the stack and is responsible for updating the
5
+ # associated Pry instance to reflect the active frame. It is fully Enumerable.
6
+ class FrameManager
7
+ include Enumerable
8
+
9
+ # @return [Array<Binding>] The array of bindings that constitute
10
+ # the call-stack.
11
+ attr_accessor :bindings
12
+
13
+ # @return [Fixnum] The index of the active frame (binding) in the call-stack.
14
+ attr_accessor :binding_index
15
+
16
+ # @return [Hash] A hash for user defined data
17
+ attr_reader :user
18
+
19
+ # @return [Binding] The binding of the Pry instance before the
20
+ # FrameManager took over.
21
+ attr_reader :prior_binding
22
+
23
+ # @return [Array] The backtrace of the Pry instance before the
24
+ # FrameManager took over.
25
+ attr_reader :prior_backtrace
26
+
27
+ def initialize(bindings, _pry_)
28
+ self.bindings = bindings
29
+ self.binding_index = 0
30
+ @pry = _pry_
31
+ @user = {}
32
+ @prior_binding = _pry_.binding_stack.last
33
+ @prior_backtrace = _pry_.backtrace
34
+ end
35
+
36
+ # Iterate over all frames
37
+ def each(&block)
38
+ bindings.each(&block)
39
+ end
40
+
41
+ # Ensure the Pry instance's active binding is the frame manager's
42
+ # active binding.
43
+ def refresh_frame(run_whereami=true)
44
+ change_frame_to binding_index, run_whereami
45
+ end
46
+
47
+ # @return [Binding] The currently active frame
48
+ def current_frame
49
+ bindings[binding_index]
50
+ end
51
+
52
+ # Set the binding index (aka frame index), but raising an Exception when invalid
53
+ # index received. Also converts negative indices to their positive counterparts.
54
+ # @param [Fixnum] index The index.
55
+ def set_binding_index_safely(index)
56
+ if index > bindings.size - 1
57
+ raise Pry::CommandError, "At top of stack, cannot go further!"
58
+ elsif index < -bindings.size
59
+ raise Pry::CommandError, "At bottom of stack, cannot go further!"
60
+ else
61
+ # wrap around negative indices
62
+ index = (bindings.size - 1) + index + 1 if index < 0
63
+
64
+ self.binding_index = index
65
+ end
66
+ end
67
+
68
+ # Change active frame to the one indexed by `index`.
69
+ # Note that indexing base is `0`
70
+ # @param [Fixnum] index The index of the frame.
71
+ def change_frame_to(index, run_whereami=true)
72
+
73
+ set_binding_index_safely(index)
74
+
75
+ if @pry.binding_stack.empty?
76
+ @pry.binding_stack.replace [bindings[binding_index]]
77
+ else
78
+ @pry.binding_stack[-1] = bindings[binding_index]
79
+ end
80
+
81
+ @pry.run_command "whereami" if run_whereami
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module PryStackExplorer
2
+ VERSION = '0.6.1'
3
+ end
@@ -0,0 +1,96 @@
1
+ module PryStackExplorer
2
+ class WhenStartedHook
3
+ include Pry::Helpers::BaseHelpers
4
+
5
+ def caller_bindings(target)
6
+ bindings = binding.callers
7
+
8
+ bindings = remove_internal_frames(bindings)
9
+ bindings = remove_debugger_frames(bindings)
10
+ bindings = bindings.drop(1) if pry_method_frame?(bindings.first)
11
+
12
+ # Use the binding returned by #of_caller if possible (as we get
13
+ # access to frame_type).
14
+ # Otherwise stick to the given binding (target).
15
+ if !PryStackExplorer.bindings_equal?(target, bindings.first)
16
+ bindings.shift
17
+ bindings.unshift(target)
18
+ end
19
+
20
+ bindings
21
+ end
22
+
23
+ def call(target, options, _pry_)
24
+ target ||= _pry_.binding_stack.first if _pry_
25
+ options = {
26
+ :call_stack => true,
27
+ :initial_frame => 0
28
+ }.merge!(options)
29
+
30
+ return if !options[:call_stack]
31
+
32
+ if options[:call_stack].is_a?(Array)
33
+ bindings = options[:call_stack]
34
+
35
+ if !valid_call_stack?(bindings)
36
+ raise ArgumentError, ":call_stack must be an array of bindings"
37
+ end
38
+ else
39
+ bindings = caller_bindings(target)
40
+ end
41
+
42
+ PryStackExplorer.create_and_push_frame_manager bindings, _pry_, :initial_frame => options[:initial_frame]
43
+ end
44
+
45
+ private
46
+
47
+ # remove internal frames related to setting up the session
48
+ def remove_internal_frames(bindings)
49
+ start_frames = internal_frames_with_indices(bindings)
50
+ return bindings if start_frames.empty?
51
+
52
+ start_frame_index = start_frames.first.last
53
+
54
+ if start_frames.size >= 2
55
+ # god knows what's going on in here
56
+ idx1, idx2 = start_frames.take(2).map(&:last)
57
+ start_frame_index = idx2 if !nested_session?(bindings[idx1..idx2])
58
+ end
59
+
60
+ bindings.drop(start_frame_index + 1)
61
+ end
62
+
63
+ # remove pry-nav / pry-debugger / pry-byebug frames
64
+ def remove_debugger_frames(bindings)
65
+ bindings.drop_while { |b| b.source_location[0] =~ /pry-(?:nav|debugger|byebug)/ }
66
+ end
67
+
68
+ # binding.pry frame
69
+ # @return [Boolean]
70
+ def pry_method_frame?(binding)
71
+ safe_send(binding.eval("__method__"), :==, :pry)
72
+ end
73
+
74
+ # When a pry session is started within a pry session
75
+ # @return [Boolean]
76
+ def nested_session?(bindings)
77
+ bindings.detect do |b|
78
+ safe_send(b.eval("__method__"), :==, :re) &&
79
+ safe_send(b.eval("self.class"), :equal?, Pry)
80
+ end
81
+ end
82
+
83
+ # @return [Array<Array<Binding, Fixnum>>]
84
+ def internal_frames_with_indices(bindings)
85
+ bindings.each_with_index.select do |b, i|
86
+ b.frame_type == :method &&
87
+ safe_send(b.eval("self"), :equal?, Pry) &&
88
+ safe_send(b.eval("__method__"), :==, :start)
89
+ end
90
+ end
91
+
92
+ def valid_call_stack?(bindings)
93
+ bindings.any? && bindings.all? { |v| v.is_a?(Binding) }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,138 @@
1
+ # pry-stack_explorer.rb
2
+ # (C) John Mair (banisterfiend); MIT license
3
+
4
+ require "pry" unless defined?(::Pry)
5
+ require "pry-stack_explorer/version"
6
+ require "pry-stack_explorer/commands"
7
+ require "pry-stack_explorer/frame_manager"
8
+ require "pry-stack_explorer/when_started_hook"
9
+ require "binding_of_caller"
10
+
11
+ module PryStackExplorer
12
+
13
+ # short-hand for `PryStackExplorer`
14
+ ::SE = self
15
+
16
+ class << self
17
+ # @return [Hash] The hash storing all frames for all Pry instances for
18
+ # the current thread.
19
+ def frame_hash
20
+ Thread.current[:__pry_frame_managers__] ||= Hash.new { |h, k| h[k] = [] }
21
+ end
22
+
23
+ # Return the complete frame manager stack for the Pry instance
24
+ # @param [Pry] _pry_ The Pry instance associated with the frame
25
+ # managers
26
+ # @return [Array] The stack of Pry::FrameManager objections
27
+ def frame_managers(_pry_)
28
+ frame_hash[_pry_]
29
+ end
30
+
31
+ # Create a `Pry::FrameManager` object and push it onto the frame
32
+ # manager stack for the relevant `_pry_` instance.
33
+ # @param [Array] bindings The array of bindings (frames)
34
+ # @param [Pry] _pry_ The Pry instance associated with the frame manager
35
+ def create_and_push_frame_manager(bindings, _pry_, options={})
36
+ fm = FrameManager.new(bindings, _pry_)
37
+ frame_hash[_pry_].push fm
38
+ push_helper(fm, options)
39
+ fm
40
+ end
41
+
42
+ # Update the Pry instance to operate on the specified frame for the
43
+ # current frame manager.
44
+ # @param [PryStackExplorer::FrameManager] fm The active frame manager.
45
+ # @param [Hash] options The options hash.
46
+ def push_helper(fm, options={})
47
+ options = {
48
+ :initial_frame => 0
49
+ }.merge!(options)
50
+
51
+ fm.change_frame_to(options[:initial_frame], false)
52
+ end
53
+
54
+ private :push_helper
55
+
56
+ # Delete the currently active frame manager
57
+ # @param [Pry] _pry_ The Pry instance associated with the frame
58
+ # managers.
59
+ # @return [Pry::FrameManager] The popped frame manager.
60
+ def pop_frame_manager(_pry_)
61
+ return if frame_managers(_pry_).empty?
62
+
63
+ popped_fm = frame_managers(_pry_).pop
64
+ pop_helper(popped_fm, _pry_)
65
+ popped_fm
66
+ end
67
+
68
+ # Restore the Pry instance to operate on the previous
69
+ # binding. Also responsible for restoring Pry instance's backtrace.
70
+ # @param [Pry::FrameManager] popped_fm The recently popped frame manager.
71
+ # @param [Pry] _pry_ The Pry instance associated with the frame managers.
72
+ def pop_helper(popped_fm, _pry_)
73
+ if frame_managers(_pry_).empty?
74
+ if _pry_.binding_stack.empty?
75
+ _pry_.binding_stack.push popped_fm.prior_binding
76
+ else
77
+ _pry_.binding_stack[-1] = popped_fm.prior_binding
78
+ end
79
+
80
+ frame_hash.delete(_pry_)
81
+ else
82
+ frame_manager(_pry_).refresh_frame(false)
83
+ end
84
+
85
+ # restore backtrace
86
+ _pry_.backtrace = popped_fm.prior_backtrace
87
+ end
88
+
89
+ private :pop_helper
90
+
91
+ # Clear the stack of frame managers for the Pry instance
92
+ # @param [Pry] _pry_ The Pry instance associated with the frame managers
93
+ def clear_frame_managers(_pry_)
94
+ pop_frame_manager(_pry_) until frame_managers(_pry_).empty?
95
+ frame_hash.delete(_pry_) # this line should be unnecessary!
96
+ end
97
+
98
+ alias_method :delete_frame_managers, :clear_frame_managers
99
+
100
+ # @return [PryStackExplorer::FrameManager] The currently active frame manager
101
+ def frame_manager(_pry_)
102
+ frame_hash[_pry_].last
103
+ end
104
+
105
+ # Simple test to check whether two `Binding` objects are equal.
106
+ # @param [Binding] b1 First binding.
107
+ # @param [Binding] b2 Second binding.
108
+ # @return [Boolean] Whether the `Binding`s are equal.
109
+ def bindings_equal?(b1, b2)
110
+ (b1.eval('self').equal?(b2.eval('self'))) &&
111
+ (b1.eval('__method__') == b2.eval('__method__')) &&
112
+ (b1.eval('local_variables').map { |v| b1.eval("#{v}") }.equal?(
113
+ b2.eval('local_variables').map { |v| b2.eval("#{v}") }))
114
+ end
115
+ end
116
+ end
117
+
118
+ Pry.config.hooks.add_hook(:after_session, :delete_frame_manager) do |_, _, _pry_|
119
+ PryStackExplorer.clear_frame_managers(_pry_)
120
+ end
121
+
122
+ Pry.config.hooks.add_hook(:when_started, :save_caller_bindings, PryStackExplorer::WhenStartedHook.new)
123
+
124
+ # Import the StackExplorer commands
125
+ Pry.config.commands.import PryStackExplorer::Commands
126
+
127
+ # monkey-patch the whereami command to show some frame information,
128
+ # useful for navigating stack.
129
+ Pry.config.hooks.add_hook(:before_whereami, :stack_explorer) do
130
+ if PryStackExplorer.frame_manager(pry_instance) && !internal_binding?(target)
131
+ bindings = PryStackExplorer.frame_manager(pry_instance).bindings
132
+ binding_index = PryStackExplorer.frame_manager(pry_instance).binding_index
133
+
134
+ output.puts "\n"
135
+ output.puts "#{Pry::Helpers::Text.bold('Frame number:')} #{binding_index}/#{bindings.size - 1}"
136
+ output.puts "#{Pry::Helpers::Text.bold('Frame type:')} #{bindings[binding_index].frame_type}" if bindings[binding_index].frame_type
137
+ end
138
+ end
data/lib/pryx/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pryx
4
- VERSION = [0, 12, 0]
4
+ VERSION = [0, 12, 1]
5
5
 
6
6
  class << VERSION
7
7
  include Comparable
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pryx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Billy.Zheng(zw963)
@@ -136,19 +136,19 @@ dependencies:
136
136
  - !ruby/object:Gem::Version
137
137
  version: '1.6'
138
138
  - !ruby/object:Gem::Dependency
139
- name: pry-stack_explorer
139
+ name: binding_of_caller
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '0.6'
144
+ version: '2.0'
145
145
  type: :runtime
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '0.6'
151
+ version: '2.0'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: m
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +222,11 @@ files:
222
222
  - lib/pry-nav/tracer.rb
223
223
  - lib/pry-nav/version.rb
224
224
  - lib/pry-remote.rb
225
+ - lib/pry-stack_explorer.rb
226
+ - lib/pry-stack_explorer/commands.rb
227
+ - lib/pry-stack_explorer/frame_manager.rb
228
+ - lib/pry-stack_explorer/version.rb
229
+ - lib/pry-stack_explorer/when_started_hook.rb
225
230
  - lib/pry-state.rb
226
231
  - lib/pry-state/hook_action.rb
227
232
  - lib/pry-state/printer.rb