Added support for complex syntax to the `cd` command, e.g: cd ../@x/y../z. Updated tests.
cd @x/@y/@z will push @x and @y and @z onto the stack in that order cd ../../ will pop @z and @y off the stack
This commit is contained in:
parent
545d6f6921
commit
253add814b
|
@ -6,28 +6,44 @@ class Pry
|
|||
Context = Pry::CommandSet.new do
|
||||
import Ls
|
||||
|
||||
command "cd", "Start a Pry session on VAR (use `cd ..` to go back and `cd /` to return to Pry top-level)", :keep_retval => true do |obj|
|
||||
case obj
|
||||
when ".."
|
||||
command "cd", "Move into a new context (use `cd ..` to go back and `cd /` to return to Pry top-level). Complex syntax (e.g cd ../@x/y) also supported." do |obj|
|
||||
path = arg_string.split(/\//)
|
||||
stack = _pry_.binding_stack.dup
|
||||
|
||||
if _pry_.binding_stack.one?
|
||||
# when breaking out of top-level then behave like `quit` command
|
||||
_pry_.binding_stack.clear
|
||||
throw(:breakout)
|
||||
else
|
||||
# otherwise just pop a binding
|
||||
_pry_.binding_stack.pop.eval('self')
|
||||
# special case when we only get a single "/", return to root
|
||||
stack = [stack.first] if path.empty?
|
||||
|
||||
resolve_failure = false
|
||||
path.each do |context|
|
||||
begin
|
||||
case context.chomp
|
||||
when ""
|
||||
stack = [stack.first]
|
||||
when "::"
|
||||
stack.push(TOPLEVEL_BINDING)
|
||||
when "."
|
||||
next
|
||||
when ".."
|
||||
if stack.one?
|
||||
_pry_.binding_stack.clear
|
||||
throw(:breakout)
|
||||
else
|
||||
stack.pop
|
||||
end
|
||||
else
|
||||
stack.push(Pry.binding_for(stack.last.eval(context)))
|
||||
end
|
||||
|
||||
rescue RescuableException => e
|
||||
puts "exception was: #{e.inspect}"
|
||||
output.puts "Bad object path: #{arg_string}. Failed trying to resolve: #{context}"
|
||||
resolve_failure = true
|
||||
end
|
||||
when nil, "/"
|
||||
_pry_.binding_stack = [_pry_.binding_stack.first]
|
||||
nil
|
||||
when "::"
|
||||
_pry_.binding_stack.push TOPLEVEL_BINDING
|
||||
void
|
||||
else
|
||||
_pry_.binding_stack.push Pry.binding_for(target.eval(arg_string))
|
||||
void
|
||||
end
|
||||
|
||||
next if resolve_failure
|
||||
|
||||
_pry_.binding_stack = stack
|
||||
end
|
||||
|
||||
command "switch-to", "Start a new sub-session on a binding in the current stack (numbered by nesting)." do |selection|
|
||||
|
|
|
@ -299,6 +299,8 @@ class Pry
|
|||
# @param [Binding] target The target of the Pry session.
|
||||
def process_line(val, eval_string, target)
|
||||
result = @command_processor.process_commands(val, eval_string, target)
|
||||
|
||||
# set a temporary (just so we can inject the value we want into eval_string)
|
||||
Thread.current[:__pry_cmd_result__] = result
|
||||
|
||||
# note that `result` wraps the result of command processing; if a
|
||||
|
|
|
@ -127,12 +127,7 @@ describe "Pry::DefaultCommands::Context" do
|
|||
end
|
||||
|
||||
it 'should break out of the repl loop of Pry instance when binding_stack has only one binding with cd ..' do
|
||||
# redirect_pry_io(InputTester.new("ls"), StringIO.new) do
|
||||
# o = Pry.new.tap { |v| v.repl(0) }
|
||||
# end
|
||||
|
||||
Pry.start(0, :input => StringIO.new("cd ..")).should == 0
|
||||
|
||||
end
|
||||
|
||||
it 'should break out to outer-most session with cd /' do
|
||||
|
@ -159,9 +154,79 @@ describe "Pry::DefaultCommands::Context" do
|
|||
$outer.should == :outer
|
||||
end
|
||||
|
||||
it 'should start a session on TOPLEVEL_BINDING with cd ::' do
|
||||
b = Pry.binding_for(:outer)
|
||||
it 'should cd into an object and its ivar using cd obj/@ivar syntax' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj/@x", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 3
|
||||
$result[1].eval('self').should == $obj
|
||||
$result[2].eval('self').should == 66
|
||||
end
|
||||
|
||||
it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj/@x/", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 3
|
||||
$result[1].eval('self').should == $obj
|
||||
$result[2].eval('self').should == 66
|
||||
end
|
||||
|
||||
it 'should cd into previous object and its local using cd ../local syntax' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj", "local = :local", "cd @x", "cd ../local", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 3
|
||||
$result[1].eval('self').should == $obj
|
||||
$result[2].eval('self').should == :local
|
||||
end
|
||||
|
||||
it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj/@x/..", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 2
|
||||
$result[1].eval('self').should == $obj
|
||||
end
|
||||
|
||||
it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
$obj.instance_variable_set(:@y, 79)
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj/@x/../@y", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 3
|
||||
$result[1].eval('self').should == $obj
|
||||
$result[2].eval('self').should == 79
|
||||
end
|
||||
|
||||
it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do
|
||||
$obj = Object.new
|
||||
$obj.instance_variable_set(:@x, 66)
|
||||
TOPLEVEL_BINDING.eval('@z = 20')
|
||||
|
||||
redirect_pry_io(InputTester.new("cd $obj/@x/", "cd /@z", "$result = _pry_.binding_stack.dup", "exit-all"), StringIO.new) do
|
||||
Pry.start
|
||||
end
|
||||
$result.size.should == 2
|
||||
$result[1].eval('self').should == 20
|
||||
end
|
||||
|
||||
it 'should start a session on TOPLEVEL_BINDING with cd ::' do
|
||||
redirect_pry_io(InputTester.new("cd ::", "$obj = self", "exit-all"), StringIO.new) do
|
||||
5.pry
|
||||
end
|
||||
|
|
|
@ -689,15 +689,13 @@ describe Pry do
|
|||
end
|
||||
|
||||
it 'should create a command in a nested context and that command should be accessible from the parent' do
|
||||
redirect_pry_io(StringIO.new, StringIO.new) do
|
||||
str_input = StringIO.new("@x=nil\ncd 7\n_pry_.commands.instance_eval {\ncommand('bing') { |arg| run arg }\n}\ncd ..\nbing ls\nexit-all")
|
||||
str_output = StringIO.new
|
||||
Pry.input = str_input
|
||||
obj = Object.new
|
||||
Pry.new(:output => str_output).repl(obj)
|
||||
Pry.input = Readline
|
||||
str_output.string.should =~ /@x/
|
||||
str_output = StringIO.new
|
||||
x = "@x=nil\ncd 7\n_pry_.commands.instance_eval {\ncommand('bing') { |arg| run arg }\n}\ncd ..\nbing ls\nexit-all"
|
||||
redirect_pry_io(StringIO.new("@x=nil\ncd 7\n_pry_.commands.instance_eval {\ncommand('bing') { |arg| run arg }\n}\ncd ..\nbing ls\nexit-all"), str_output) do
|
||||
Pry.new.repl(0)
|
||||
end
|
||||
|
||||
str_output.string.should =~ /@x/
|
||||
end
|
||||
|
||||
it 'should define a command that keeps its return value' do
|
||||
|
|
Loading…
Reference in New Issue