mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
e6ac84e99c
This is a preparational step for #1824 (Enabling `# frozen_string_literal: true` in `~/.pryc` crashes most operations) Alternative to https://github.com/pry/pry/pull/2030 (config: delete the `control_d_handler` option) We had to jump a few hoops to change how the handler works. The problem is that mutation is the default expected behaviour. Therefore, we had to change its API. There's no need to pass `eval_string` because `pry_instance` already has it as an attribute. `config.control_d_handler` is a proxy proc, to preserve backwards compatibility with users of old signature (one known user is Pry Byebug). The handler will emit a warning if the old signature is used.
257 lines
7.2 KiB
Ruby
257 lines
7.2 KiB
Ruby
describe 'cd' do
|
|
before do
|
|
@o = Object.new
|
|
@obj = Object.new
|
|
@obj.instance_variable_set(:@x, 66)
|
|
@obj.instance_variable_set(:@y, 79)
|
|
@o.instance_variable_set(:@obj, @obj)
|
|
|
|
@t = pry_tester(@o) do
|
|
def mapped_binding_stack
|
|
binding_stack.map { |b| b.eval('self') }
|
|
end
|
|
|
|
def binding_stack
|
|
pry.binding_stack.dup
|
|
end
|
|
|
|
def command_state
|
|
pry.commands['cd'].state
|
|
end
|
|
|
|
def old_stack
|
|
pry.commands['cd'].state.old_stack.dup
|
|
end
|
|
end
|
|
end
|
|
|
|
after { Pry::CommandState.default.reset('cd') }
|
|
|
|
describe 'old stack toggling with `cd -`' do
|
|
describe 'in fresh pry instance' do
|
|
it 'should not toggle when there is no old stack' do
|
|
2.times do
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'when an error was raised' do
|
|
it 'should not toggle and should keep correct stacks' do
|
|
expect { @t.eval 'cd %' }.to raise_error Pry::CommandError
|
|
|
|
expect(@t.old_stack).to eq []
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.old_stack).to eq []
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
end
|
|
end
|
|
|
|
describe 'when using simple cd syntax' do
|
|
it 'should toggle' do
|
|
@t.eval 'cd :mon_dogg', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :mon_dogg]
|
|
end
|
|
end
|
|
|
|
describe "when using complex cd syntax" do
|
|
it 'should toggle with a complex path (simple case)' do
|
|
@t.eval 'cd 1/2/3', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 1, 2, 3]
|
|
end
|
|
|
|
it 'should toggle with a complex path (more complex case)' do
|
|
@t.eval 'cd 1/2/3', 'cd ../4', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 1, 2, 3]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 1, 2, 4]
|
|
end
|
|
end
|
|
|
|
describe 'series of cd calls' do
|
|
it 'should toggle with fuzzy `cd -` calls' do
|
|
@t.eval 'cd :mon_dogg', 'cd -', 'cd 42', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 42]
|
|
end
|
|
end
|
|
|
|
describe 'when using cd ..' do
|
|
it 'should toggle with a simple path' do
|
|
@t.eval 'cd :john_dogg', 'cd ..'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :john_dogg]
|
|
end
|
|
|
|
it 'should toggle with a complex path' do
|
|
@t.eval 'cd 1/2/3/../4', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 1, 2, 4]
|
|
end
|
|
end
|
|
|
|
describe 'when using cd ::' do
|
|
it 'should toggle' do
|
|
@t.eval 'cd ::', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, TOPLEVEL_BINDING.eval('self')]
|
|
end
|
|
end
|
|
|
|
describe 'when using cd /' do
|
|
it 'should toggle' do
|
|
@t.eval 'cd /', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
|
|
@t.eval 'cd :john_dogg', 'cd /', 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :john_dogg]
|
|
end
|
|
end
|
|
|
|
describe 'when using ^D (Control-D) key press' do
|
|
it 'should keep correct old binding' do
|
|
@t.eval 'cd :john_dogg', 'cd :mon_dogg', 'cd :kyr_dogg',
|
|
'Pry.config.control_d_handler.call(pry_instance)'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :john_dogg, :mon_dogg]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :john_dogg, :mon_dogg, :kyr_dogg]
|
|
|
|
@t.eval 'cd -'
|
|
expect(@t.mapped_binding_stack).to eq [@o, :john_dogg, :mon_dogg]
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'should cd into simple input' do
|
|
@t.eval 'cd :mon_ouie'
|
|
expect(@t.eval('self')).to eq :mon_ouie
|
|
end
|
|
|
|
it 'should break out of session with cd ..' do
|
|
@t.eval 'cd :outer', 'cd :inner'
|
|
expect(@t.eval('self')).to eq :inner
|
|
|
|
@t.eval 'cd ..'
|
|
expect(@t.eval('self')).to eq :outer
|
|
end
|
|
|
|
it "should not leave the REPL session when given 'cd ..'" do
|
|
@t.eval 'cd ..'
|
|
expect(@t.eval('self')).to eq @o
|
|
end
|
|
|
|
it 'should break out to outer-most session with cd /' do
|
|
@t.eval 'cd :inner'
|
|
expect(@t.eval('self')).to eq :inner
|
|
|
|
@t.eval 'cd 5'
|
|
expect(@t.eval('self')).to eq 5
|
|
|
|
@t.eval 'cd /'
|
|
expect(@t.eval('self')).to eq @o
|
|
end
|
|
|
|
it 'should break out to outer-most session with just cd (no args)' do
|
|
@t.eval 'cd :inner'
|
|
expect(@t.eval('self')).to eq :inner
|
|
|
|
@t.eval 'cd 5'
|
|
expect(@t.eval('self')).to eq 5
|
|
|
|
@t.eval 'cd'
|
|
expect(@t.eval('self')).to eq @o
|
|
end
|
|
|
|
it 'should cd into an object and its ivar using cd obj/@ivar syntax' do
|
|
@t.eval 'cd @obj/@x'
|
|
expect(@t.mapped_binding_stack).to eq [@o, @obj, 66]
|
|
end
|
|
|
|
it 'cds into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do
|
|
@t.eval 'cd @obj/@x/'
|
|
expect(@t.mapped_binding_stack).to eq [@o, @obj, 66]
|
|
end
|
|
|
|
it 'should cd into previous object and its local using cd ../local syntax' do
|
|
@t.eval 'cd @obj', 'local = :local', 'cd @x', 'cd ../local'
|
|
expect(@t.mapped_binding_stack).to eq [@o, @obj, :local]
|
|
end
|
|
|
|
it 'cds into an object and its ivar and back again using cd obj/@ivar/.. syntax' do
|
|
@t.eval 'cd @obj/@x/..'
|
|
expect(@t.mapped_binding_stack).to eq [@o, @obj]
|
|
end
|
|
|
|
it(
|
|
'cds into an object and its ivar and back and then into another ivar ' \
|
|
'using cd obj/@ivar/../@y syntax'
|
|
) do
|
|
@t.eval 'cd @obj/@x/../@y'
|
|
expect(@t.mapped_binding_stack).to eq [@o, @obj, 79]
|
|
end
|
|
|
|
it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do
|
|
@t.eval '@z = 20', 'cd @obj/@x/', 'cd /@z'
|
|
expect(@t.mapped_binding_stack).to eq [@o, 20]
|
|
end
|
|
|
|
it 'should start a session on TOPLEVEL_BINDING with cd ::' do
|
|
@t.eval 'cd ::'
|
|
expect(@t.eval('self')).to eq TOPLEVEL_BINDING.eval('self')
|
|
end
|
|
|
|
it 'should cd into complex input (with spaces)' do
|
|
def @o.hello(_x, _y, _z) # rubocop:disable Naming/UncommunicativeMethodParamName
|
|
:mon_ouie
|
|
end
|
|
|
|
@t.eval 'cd hello 1, 2, 3'
|
|
expect(@t.eval('self')).to eq :mon_ouie
|
|
end
|
|
|
|
it 'should not cd into complex input when it encounters an exception' do
|
|
expect { @t.eval 'cd 1/2/swoop_a_doop/3' }.to raise_error Pry::CommandError
|
|
|
|
expect(@t.mapped_binding_stack).to eq [@o]
|
|
end
|
|
|
|
it 'can cd into an expression containing a string with slashes in it' do
|
|
@t.eval 'cd ["http://google.com"]'
|
|
expect(@t.eval('self')).to eq ["http://google.com"]
|
|
end
|
|
|
|
it 'can cd into an expression with division in it' do
|
|
@t.eval 'cd (10/2)/even?'
|
|
expect(@t.eval('self')).to eq false
|
|
end
|
|
|
|
# Regression test for ticket #516.
|
|
it 'should be able to cd into the Object BasicObject' do
|
|
expect { @t.eval 'cd BasicObject.new' }.to_not raise_error
|
|
end
|
|
|
|
# https://github.com/pry/pry/issues/1596
|
|
it "can cd into objects that redefine #respond_to? to return true" do
|
|
expect { @t.eval('cd Class.new { def respond_to?(m) true end }.new') }
|
|
.to_not raise_error
|
|
end
|
|
end
|