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:
John Mair 2011-09-06 04:12:53 +12:00
parent 545d6f6921
commit 253add814b
4 changed files with 115 additions and 34 deletions

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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