Fix ^D press in nested REPLs
The interesting moment is that `cd -` is still a bit dorky. [1] pry(main)> _pry_.repl :a [2] pry(:a):1> _pry_.repl :b [3] pry(:b):2> cd - [4] pry(:b):2> cd - [5] pry(:b):2> The problem is that `_pry_.repl` pushes a new binding onto `binding_stack`, however, it knows nothing about `old_stack`. Well, there is a workaround for this. [1] pry(main)> _pry_.repl :a [2] pry(:a):1> ^D [3] pry(main)> cd - [4] pry(:a):1> cd - [5] pry(main)> Fix "undefined method `old_stack=' for nil:NilClass" error in this commit, when you press ^D in a nested REPL. Add a test case for this. Rewrite some comments and old Control-D units tests (so they use newer test API). Signed-off-by: Kyrylo Silin <kyrylosilin@gmail.com>
This commit is contained in:
parent
0b5e55ca4e
commit
c7b28efc24
21
lib/pry.rb
21
lib/pry.rb
|
@ -104,23 +104,22 @@ class Pry
|
|||
end,
|
||||
]
|
||||
|
||||
# Deal with the ^D key being pressed, different behaviour in
|
||||
# different cases:
|
||||
# 1) In an expression - behave like `!` command (clear input buffer)
|
||||
# 2) At top-level session - behave like `exit command (break out of repl loop)
|
||||
# 3) In a nested session - behave like `cd ..` (pop a binding)
|
||||
# Deal with the ^D key being pressed. Different behaviour in different cases:
|
||||
# 1. In an expression behave like `!` command.
|
||||
# 2. At top-level session behave like `exit` command.
|
||||
# 3. In a nested session behave like `cd ..`.
|
||||
DEFAULT_CONTROL_D_HANDLER = proc do |eval_string, _pry_|
|
||||
if !eval_string.empty?
|
||||
# Clear input buffer.
|
||||
eval_string.replace("")
|
||||
eval_string.replace('') # Clear input buffer.
|
||||
elsif _pry_.binding_stack.one?
|
||||
# ^D at top-level breaks out of a REPL loop.
|
||||
_pry_.binding_stack.clear
|
||||
throw(:breakout)
|
||||
else
|
||||
# Otherwise, saves current binding stack as old stack and pops last
|
||||
# binding out of binding stack (the old stack still has that binding).
|
||||
_pry_.command_state["cd"].old_stack = _pry_.binding_stack.dup
|
||||
# Store the entire binding stack before popping. Useful for `cd -`.
|
||||
if _pry_.command_state['cd'].nil?
|
||||
_pry_.command_state['cd'] = OpenStruct.new
|
||||
end
|
||||
_pry_.command_state['cd'].old_stack = _pry_.binding_stack.dup
|
||||
_pry_.binding_stack.pop
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,45 +1,58 @@
|
|||
require 'helper'
|
||||
|
||||
describe Pry::DEFAULT_CONTROL_D_HANDLER do
|
||||
describe 'control-d press' do
|
||||
|
||||
describe "control-d press" do
|
||||
|
||||
before do
|
||||
# Simulates a ^D press.
|
||||
@control_d = "Pry::DEFAULT_CONTROL_D_HANDLER.call('', _pry_)"
|
||||
@binding_stack = "self.binding_stack = _pry_.binding_stack.dup"
|
||||
end
|
||||
|
||||
describe 'in an expression' do
|
||||
it 'should clear out passed string' do
|
||||
str = "hello world"
|
||||
describe "in an expression" do
|
||||
it "should clear out passed string" do
|
||||
str = 'hello world'
|
||||
Pry::DEFAULT_CONTROL_D_HANDLER.call(str, nil)
|
||||
str.should == ""
|
||||
str.should == ''
|
||||
end
|
||||
end
|
||||
|
||||
describe 'at top-level session' do
|
||||
it 'should break out of a REPL loop' do
|
||||
instance = nil
|
||||
redirect_pry_io(InputTester.new(@control_d)) do
|
||||
instance = Pry.new
|
||||
instance.repl
|
||||
|
||||
describe "at top-level session" do
|
||||
it "breaks out of a REPL" do
|
||||
pry_tester(0).simulate_repl do |t|
|
||||
t.eval @control_d
|
||||
end.should == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "in a nested session" do
|
||||
it "pops last binding from the binding stack" do
|
||||
pry_tester(0).simulate_repl { |t|
|
||||
t.eval 'cd :foo'
|
||||
t.eval('_pry_.binding_stack.size').should == 2
|
||||
t.eval(@control_d)
|
||||
t.eval('_pry_.binding_stack.size').should == 1
|
||||
t.eval 'exit-all'
|
||||
}
|
||||
end
|
||||
|
||||
it "breaks out of the parent session" do
|
||||
pry_tester(:outer).simulate_repl do |o|
|
||||
o.context = :inner
|
||||
o.simulate_repl { |i|
|
||||
i.eval('_pry_.current_context.eval("self")').should == :inner
|
||||
i.eval('_pry_.binding_stack.size').should == 2
|
||||
i.eval @control_d
|
||||
i.eval('_pry_.binding_stack.size').should == 1
|
||||
i.eval('_pry_.current_context.eval("self")').should == :outer
|
||||
i.eval 'throw :breakout'
|
||||
}
|
||||
o.eval 'exit-all'
|
||||
end
|
||||
|
||||
instance.binding_stack.should.be.empty
|
||||
end
|
||||
end
|
||||
|
||||
describe 'in a nested session' do
|
||||
it 'should pop last binding from the binding stack' do
|
||||
base = OpenStruct.new
|
||||
base.obj = OpenStruct.new
|
||||
|
||||
redirect_pry_io(InputTester.new("cd obj", "self.stack_size = _pry_.binding_stack.size",
|
||||
@control_d, "self.stack_size = _pry_.binding_stack.size", "exit-all")) do
|
||||
Pry.start(base)
|
||||
end
|
||||
|
||||
base.obj.stack_size.should == 2
|
||||
base.stack_size.should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue