Module: PryStack
- Defined in:
- lib/pry-stack.rb,
lib/pry-stack/commands.rb,
lib/pry-stack/frame_manager.rb,
lib/pry-stack/when_started_hook.rb
Defined Under Namespace
Modules: FrameHelpers Classes: FrameManager, WhenStartedHook
Constant Summary collapse
- Commands =
Pry::CommandSet.new do create_command "up", "Go up to the caller's context." do include FrameHelpers " Usage: up [OPTIONS]\n Go up to the caller's context. Accepts optional numeric parameter for how many frames to move up.\n Also accepts a string (regex) instead of numeric; for jumping to nearest parent method frame which matches the regex.\n e.g: up #=> Move up 1 stack frame.\n e.g: up 3 #=> Move up 2 stack frames.\n e.g: up meth #=> Jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`.\n BANNER\n\n def process\n inc = args.first.nil? ? \"1\" : args.first\n\n if !frame_manager\n raise Pry::CommandError, \"Nowhere to go!\"\n else\n if inc =~ /\\d+/\n frame_manager.change_frame_to frame_manager.binding_index + inc.to_i\n elsif match = /^([A-Z]+[^#.]*)(#|\\.)(.+)$/.match(inc)\n new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :up)\n frame_manager.change_frame_to new_frame_index\n elsif inc =~ /^[^-].*$/\n new_frame_index = find_frame_by_regex(Regexp.new(inc), :up)\n frame_manager.change_frame_to new_frame_index\n end\n end\n end\n end\n\n create_command \"down\", \"Go down to the callee's context.\" do\n include FrameHelpers\n\n banner <<-BANNER\n Usage: down [OPTIONS]\n Go down to the callee's context. Accepts optional numeric parameter for how many frames to move down.\n Also accepts a string (regex) instead of numeric; for jumping to nearest child method frame which matches the regex.\n e.g: down #=> Move down 1 stack frame.\n e.g: down 3 #=> Move down 2 stack frames.\n e.g: down meth #=> Jump to nearest child stack frame whose method matches /meth/ regex, i.e `my_method`.\n BANNER\n\n def process\n inc = args.first.nil? ? \"1\" : args.first\n\n if !frame_manager\n raise Pry::CommandError, \"Nowhere to go!\"\n else\n if inc =~ /\\d+/\n if frame_manager.binding_index - inc.to_i < 0\n raise Pry::CommandError, \"At bottom of stack, cannot go further!\"\n else\n frame_manager.change_frame_to frame_manager.binding_index - inc.to_i\n end\n elsif match = /^([A-Z]+[^#.]*)(#|\\.)(.+)$/.match(inc)\n new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :down)\n frame_manager.change_frame_to new_frame_index\n elsif inc =~ /^[^-].*$/\n new_frame_index = find_frame_by_regex(Regexp.new(inc), :down)\n frame_manager.change_frame_to new_frame_index\n end\n end\n end\n end\n\n create_command \"frame\", \"Switch to a particular frame.\" do\n include FrameHelpers\n\n banner <<-BANNER\n Usage: frame [OPTIONS]\n Switch to a particular frame. Accepts numeric parameter (or regex for method name) for the target frame to switch to (use with show-stack).\n Negative frame numbers allowed. When given no parameter show information about the current frame.\n\n e.g: frame 4 #=> jump to the 4th frame\n e.g: frame meth #=> jump to nearest parent stack frame whose method matches /meth/ regex, i.e `my_method`\n e.g: frame -2 #=> jump to the second-to-last frame\n e.g: frame #=> show information info about current frame\n BANNER\n\n def process\n if !frame_manager\n raise Pry::CommandError, \"nowhere to go!\"\n else\n\n if args[0] =~ /\\d+/\n frame_manager.change_frame_to args[0].to_i\n elsif match = /^([A-Z]+[^#.]*)(#|\\.)(.+)$/.match(args[0])\n new_frame_index = find_frame_by_object_regex(Regexp.new(match[1]), Regexp.new(match[3]), :up)\n frame_manager.change_frame_to new_frame_index\n elsif args[0] =~ /^[^-].*$/\n new_frame_index = find_frame_by_regex(Regexp.new(args[0]), :up)\n frame_manager.change_frame_to new_frame_index\n else\n output.puts \"#\#{frame_manager.binding_index} \#{frame_info(target, true)}\"\n end\n end\n end\n end\n\n create_command \"stack\", \"Show all frames\" do\n include FrameHelpers\n\n banner <<-BANNER\n Usage: stack [OPTIONS]\n Show all accessible stack frames.\n e.g: show-stack -v\n BANNER\n\n def options(opt)\n opt.on :v, :verbose, \"Include extra information.\"\n opt.on :H, :head, \"Display the first N stack frames (defaults to 10).\", :optional_argument => true, :as => Integer, :default => 10\n opt.on :T, :tail, \"Display the last N stack frames (defaults to 10).\", :optional_argument => true, :as => Integer, :default => 10\n opt.on :c, :current, \"Display N frames either side of current frame (default to 5).\", :optional_argument => true, :as => Integer, :default => 5\n end\n\n def memoized_info(index, b, verbose)\n frame_manager.user[:frame_info] ||= Hash.new { |h, k| h[k] = [] }\n\n if verbose\n frame_manager.user[:frame_info][:v][index] ||= frame_info(b, verbose)\n else\n frame_manager.user[:frame_info][:normal][index] ||= frame_info(b, verbose)\n end\n end\n\n private :memoized_info\n\n # @return [Array<Fixnum, Array<Binding>>] Return tuple of\n # base_frame_index and the array of frames.\n def selected_stack_frames\n if opts.present?(:head)\n [0, frame_manager.bindings[0..(opts[:head] - 1)]]\n\n elsif opts.present?(:tail)\n tail = opts[:tail]\n if tail > frame_manager.bindings.size\n tail = frame_manager.bindings.size\n end\n\n base_frame_index = frame_manager.bindings.size - tail\n [base_frame_index, frame_manager.bindings[base_frame_index..-1]]\n\n elsif opts.present?(:current)\n first_frame_index = frame_manager.binding_index - (opts[:current])\n first_frame_index = 0 if first_frame_index < 0\n last_frame_index = frame_manager.binding_index + (opts[:current])\n [first_frame_index, frame_manager.bindings[first_frame_index..last_frame_index]]\n\n else\n [0, frame_manager.bindings]\n end\n end\n\n private :selected_stack_frames\n\n def process\n if !frame_manager\n output.puts \"No caller stack available!\"\n else\n content = \"\"\n content << \"\\n\#{text.bold(\"Showing all accessible frames in stack (\#{frame_manager.bindings.size} in total):\")}\\n--\\n\"\n\n base_frame_index, frames = selected_stack_frames\n frames.each_with_index.to_a.reverse.each do |b, index|\n i = index + base_frame_index\n if i == frame_manager.binding_index\n content << \"=> #\#{i} \#{memoized_info(i, b, opts[:v])}\\n\"\n else\n content << \" #\#{i} \#{memoized_info(i, b, opts[:v])}\\n\"\n end\n end\n\n stagger_output content\n end\n end\n\n end\n\n alias_command \"show-stack\", \"stack\"\n\nend\n"
Class Method Summary collapse
-
.bindings_equal?(b1, b2) ⇒ Boolean
Simple test to check whether two
Bindingobjects are equal. -
.clear_frame_managers(_pry_) ⇒ Object
(also: delete_frame_managers)
Clear the stack of frame managers for the Pry instance.
-
.create_and_push_frame_manager(bindings, _pry_, options = {}) ⇒ Object
Create a
Pry::FrameManagerobject and push it onto the frame manager stack for the relevant_pry_instance. -
.frame_hash ⇒ Hash
The hash storing all frames for all Pry instances for the current thread.
-
.frame_manager(_pry_) ⇒ PryStack::FrameManager
The currently active frame manager.
-
.frame_managers(_pry_) ⇒ Array
Return the complete frame manager stack for the Pry instance.
-
.pop_frame_manager(_pry_) ⇒ Pry::FrameManager
Delete the currently active frame manager.
-
.pop_helper(popped_fm, _pry_) ⇒ Object
Restore the Pry instance to operate on the previous binding.
-
.push_helper(fm, options = {}) ⇒ Object
Update the Pry instance to operate on the specified frame for the current frame manager.
Class Method Details
.bindings_equal?(b1, b2) ⇒ Boolean
Simple test to check whether two Binding objects are equal.
104 105 106 107 108 109 |
# File 'lib/pry-stack.rb', line 104 def bindings_equal?(b1, b2) (b1.eval('self').equal?(b2.eval('self'))) && (b1.eval('__method__') == b2.eval('__method__')) && (b1.eval('local_variables').map { |v| b1.eval("#{v}") }.equal?( b2.eval('local_variables').map { |v| b2.eval("#{v}") })) end |
.clear_frame_managers(_pry_) ⇒ Object Also known as: delete_frame_managers
Clear the stack of frame managers for the Pry instance
88 89 90 91 |
# File 'lib/pry-stack.rb', line 88 def clear_frame_managers(_pry_) pop_frame_manager(_pry_) until frame_managers(_pry_).empty? frame_hash.delete(_pry_) # this line should be unnecessary! end |
.create_and_push_frame_manager(bindings, _pry_, options = {}) ⇒ Object
Create a Pry::FrameManager object and push it onto the frame
manager stack for the relevant _pry_ instance.
30 31 32 33 34 35 |
# File 'lib/pry-stack.rb', line 30 def create_and_push_frame_manager(bindings, _pry_, ={}) fm = FrameManager.new(bindings, _pry_) frame_hash[_pry_].push fm push_helper(fm, ) fm end |
.frame_hash ⇒ Hash
Returns The hash storing all frames for all Pry instances for the current thread.
14 15 16 |
# File 'lib/pry-stack.rb', line 14 def frame_hash Thread.current[:__pry_frame_managers__] ||= Hash.new { |h, k| h[k] = [] } end |
.frame_manager(_pry_) ⇒ PryStack::FrameManager
Returns The currently active frame manager.
96 97 98 |
# File 'lib/pry-stack.rb', line 96 def frame_manager(_pry_) frame_hash[_pry_].last end |
.frame_managers(_pry_) ⇒ Array
Return the complete frame manager stack for the Pry instance
22 23 24 |
# File 'lib/pry-stack.rb', line 22 def frame_managers(_pry_) frame_hash[_pry_] end |
.pop_frame_manager(_pry_) ⇒ Pry::FrameManager
Delete the currently active frame manager
55 56 57 58 59 60 61 |
# File 'lib/pry-stack.rb', line 55 def pop_frame_manager(_pry_) return if frame_managers(_pry_).empty? popped_fm = frame_managers(_pry_).pop pop_helper(popped_fm, _pry_) popped_fm end |
.pop_helper(popped_fm, _pry_) ⇒ Object
Restore the Pry instance to operate on the previous binding. Also responsible for restoring Pry instance's backtrace.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/pry-stack.rb', line 67 def pop_helper(popped_fm, _pry_) if frame_managers(_pry_).empty? if _pry_.binding_stack.empty? _pry_.binding_stack.push popped_fm.prior_binding else _pry_.binding_stack[-1] = popped_fm.prior_binding end frame_hash.delete(_pry_) else frame_manager(_pry_).refresh_frame(false) end # restore backtrace _pry_.backtrace = popped_fm.prior_backtrace end |
.push_helper(fm, options = {}) ⇒ Object
Update the Pry instance to operate on the specified frame for the current frame manager.
41 42 43 44 45 46 47 |
# File 'lib/pry-stack.rb', line 41 def push_helper(fm, ={}) = { :initial_frame => 0 }.merge!() fm.change_frame_to([:initial_frame], false) end |