mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Extract object path resolution into a class
This commit is contained in:
parent
249dbabe59
commit
2467871169
5 changed files with 93 additions and 69 deletions
|
@ -169,3 +169,4 @@ require "pry/indent"
|
|||
require "pry/last_exception"
|
||||
require "pry/prompt"
|
||||
require "pry/inspector"
|
||||
require 'pry/object_path'
|
||||
|
|
|
@ -21,7 +21,8 @@ class Pry
|
|||
|
||||
def process
|
||||
state.old_stack ||= []
|
||||
stack, state.old_stack = context_from_object_path(arg_string, _pry_, state.old_stack)
|
||||
stack, state.old_stack =
|
||||
ObjectPath.new(arg_string, _pry_.binding_stack, state.old_stack).resolve
|
||||
_pry_.binding_stack = stack if stack
|
||||
end
|
||||
end
|
||||
|
|
|
@ -119,73 +119,6 @@ class Pry
|
|||
|
||||
Pry::Pager.page(text, out)
|
||||
end
|
||||
|
||||
# @param [String] arg_string The object path expressed as a string.
|
||||
# @param [Pry] _pry_ The relevant Pry instance.
|
||||
# @param [Array<Binding>] old_stack The state of the old binding stack
|
||||
# @return [Array<Array<Binding>, Array<Binding>>] An array
|
||||
# containing two elements: The new `binding_stack` and the old `binding_stack`.
|
||||
def context_from_object_path(arg_string, _pry_=nil, old_stack=[])
|
||||
|
||||
# Extract command arguments. Delete blank arguments like " ", but
|
||||
# don't delete empty strings like "".
|
||||
path = arg_string.split(/\//).delete_if { |a| a =~ /\A\s+\z/ }
|
||||
stack = _pry_.binding_stack.dup
|
||||
state_old_stack = old_stack
|
||||
|
||||
# Special case when we only get a single "/", return to root.
|
||||
if path.empty?
|
||||
state_old_stack = stack.dup unless old_stack.empty?
|
||||
stack = [stack.first]
|
||||
end
|
||||
|
||||
path.each_with_index do |context, i|
|
||||
begin
|
||||
case context.chomp
|
||||
when ""
|
||||
state_old_stack = stack.dup
|
||||
stack = [stack.first]
|
||||
when "::"
|
||||
state_old_stack = stack.dup
|
||||
stack.push(TOPLEVEL_BINDING)
|
||||
when "."
|
||||
next
|
||||
when ".."
|
||||
unless stack.size == 1
|
||||
# Don't rewrite old_stack if we're in complex expression
|
||||
# (e.g.: `cd 1/2/3/../4).
|
||||
state_old_stack = stack.dup if path.first == ".."
|
||||
stack.pop
|
||||
end
|
||||
when "-"
|
||||
unless old_stack.empty?
|
||||
# Interchange current stack and old stack with each other.
|
||||
stack, state_old_stack = state_old_stack, stack
|
||||
end
|
||||
else
|
||||
state_old_stack = stack.dup if i == 0
|
||||
stack.push(Pry.binding_for(stack.last.eval(context)))
|
||||
end
|
||||
|
||||
rescue RescuableException => e
|
||||
# Restore old stack to its initial values.
|
||||
state_old_stack = old_stack
|
||||
|
||||
msg = [
|
||||
"Bad object path: #{arg_string}.",
|
||||
"Failed trying to resolve: #{context}.",
|
||||
e.inspect
|
||||
].join(' ')
|
||||
|
||||
CommandError.new(msg).tap do |err|
|
||||
err.set_backtrace e.backtrace
|
||||
raise err
|
||||
end
|
||||
end
|
||||
end
|
||||
return stack, state_old_stack
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class Pry::InputCompleter
|
|||
if path.call.empty?
|
||||
target = options[:target]
|
||||
else
|
||||
target, _ = Pry::Helpers::BaseHelpers.context_from_object_path(path.call, @pry)
|
||||
target, _ = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve
|
||||
target = target.last
|
||||
end
|
||||
|
||||
|
|
89
lib/pry/object_path.rb
Normal file
89
lib/pry/object_path.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
class Pry
|
||||
# `ObjectPath` implements the resolution of "object paths", which are strings
|
||||
# that are similar to filesystem paths but meant for traversing Ruby objects.
|
||||
# Examples of valid object paths include:
|
||||
#
|
||||
# x
|
||||
# @foo/@bar
|
||||
# "string"/upcase
|
||||
# Pry/Method
|
||||
#
|
||||
# Object paths are mostly relevant in the context of the `cd` command.
|
||||
# @see https://github.com/pry/pry/wiki/State-navigation
|
||||
class ObjectPath
|
||||
# @param [String] path_string The object path expressed as a string.
|
||||
# @param [Array<Binding>] current_stack The current state of the binding
|
||||
# stack.
|
||||
# @param [Array<Binding>] old_stack The previous state of the binding
|
||||
# stack, if applicable.
|
||||
def initialize(path_string, current_stack, old_stack=[])
|
||||
@path_string = path_string
|
||||
@current_stack = current_stack
|
||||
@old_stack = old_stack
|
||||
end
|
||||
|
||||
# @return [Array(Array<Binding>, Array<Binding>)] an array
|
||||
# containing two elements, the new binding stack and the old binding
|
||||
# stack.
|
||||
def resolve
|
||||
# Extract command arguments. Delete blank arguments like " ", but
|
||||
# don't delete empty strings like "".
|
||||
path = @path_string.split(/\//).delete_if { |a| a =~ /\A\s+\z/ }
|
||||
stack = @current_stack.dup
|
||||
state_old_stack = @old_stack
|
||||
|
||||
# Special case when we only get a single "/", return to root.
|
||||
if path.empty?
|
||||
state_old_stack = stack.dup unless @old_stack.empty?
|
||||
stack = [stack.first]
|
||||
end
|
||||
|
||||
path.each_with_index do |context, i|
|
||||
begin
|
||||
case context.chomp
|
||||
when ""
|
||||
state_old_stack = stack.dup
|
||||
stack = [stack.first]
|
||||
when "::"
|
||||
state_old_stack = stack.dup
|
||||
stack.push(TOPLEVEL_BINDING)
|
||||
when "."
|
||||
next
|
||||
when ".."
|
||||
unless stack.size == 1
|
||||
# Don't rewrite old_stack if we're in complex expression
|
||||
# (e.g.: `cd 1/2/3/../4).
|
||||
state_old_stack = stack.dup if path.first == ".."
|
||||
stack.pop
|
||||
end
|
||||
when "-"
|
||||
unless @old_stack.empty?
|
||||
# Interchange current stack and old stack with each other.
|
||||
stack, state_old_stack = state_old_stack, stack
|
||||
end
|
||||
else
|
||||
state_old_stack = stack.dup if i == 0
|
||||
stack.push(Pry.binding_for(stack.last.eval(context)))
|
||||
end
|
||||
|
||||
rescue RescuableException => e
|
||||
# Restore old stack to its initial values.
|
||||
state_old_stack = @old_stack
|
||||
|
||||
msg = [
|
||||
"Bad object path: #{@path_string}.",
|
||||
"Failed trying to resolve: #{context}.",
|
||||
e.inspect
|
||||
].join(' ')
|
||||
|
||||
CommandError.new(msg).tap do |err|
|
||||
err.set_backtrace e.backtrace
|
||||
raise err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
[stack, state_old_stack]
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue