1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00
pry--pry/test/test_pry.rb
John Mair 4e3853ea33 now using 'retry' (in read loop) to switch input objects in input_stack
This is so we can make the switch to the new input object seemless on encountering EOFError in previous input object.
We also detect whether we are going to go into an infinite EOFError state (i.e if Pry.config.input generates EOFError) and so we break out of the REPL with an error message
and a throw(:breakout)
2011-09-16 03:27:19 +12:00

1276 lines
45 KiB
Ruby

require 'helper'
describe Pry do
if RUBY_PLATFORM !~ /mingw/ && RUBY_PLATFORM !~ /mswin/ && RUBY_PLATFORM != 'java'
describe 'warning emissions' do
it 'should emit no warnings' do
Open4.popen4 'ruby -I lib -rubygems -r"pry" -W -e "exit"' do |pid, stdin, stdout, stderr|
stderr.read.empty?.should == true
end
end
end
end
if RUBY_VERSION =~ /1.9/
describe "Exotic object support" do
# regression test for exotic object support
it "Should not error when return value is a BasicObject instance" do
lambda do
redirect_pry_io(InputTester.new("BasicObject.new", "exit-all"), StringIO.new) do
Pry.start
end
end.should.not.raise NoMethodError
end
end
end
describe "Pry.binding_for" do
# regression test for burg's bug (see git history)
it "Should not error when object doesn't have a valid == method" do
o = Object.new
def o.==(other)
raise
end
lambda { Pry.binding_for(o) }.should.not.raise Exception
end
end
describe "open a Pry session on an object" do
describe "rep" do
before do
class Hello
end
end
after do
Object.send(:remove_const, :Hello)
end
# bug fix for https://github.com/banister/pry/issues/93
it 'should not leak pry constants into Object namespace' do
input_string = "CommandContext"
str_output = StringIO.new
o = Object.new
pry_tester = Pry.new(:input => StringIO.new(input_string),
:output => str_output,
:exception_handler => proc { |_, exception, _pry_| @excep = exception },
:print => proc {}
).rep(o)
@excep.is_a?(NameError).should == true
end
if defined?(BasicObject)
it 'should be able to operate inside the BasicObject class' do
$obj = nil
redirect_pry_io(InputTester.new(":foo", "$obj = _", "exit-all"), StringIO.new) do
BasicObject.pry
end
$obj.should == :foo
$obj = nil
end
end
it 'should set an ivar on an object' do
input_string = "@x = 10"
input = InputTester.new(input_string)
o = Object.new
pry_tester = Pry.new(:input => input, :output => Pry::NullOutput)
pry_tester.rep(o)
o.instance_variable_get(:@x).should == 10
end
it 'should display error and throw(:breakout) if Pry instance runs out of input' do
str_output = StringIO.new
catch(:breakout) do
redirect_pry_io(StringIO.new(":nothing\n"), str_output) do
Pry.new.repl
end
end
str_output.string.should =~ /Error: Pry ran out of things to read/
end
it 'should make self evaluate to the receiver of the rep session' do
o = :john
str_output = StringIO.new
pry_tester = Pry.new(:input => InputTester.new("self"), :output => str_output)
pry_tester.rep(o)
str_output.string.should =~ /:john/
end
it 'should work with multi-line input' do
o = Object.new
str_output = StringIO.new
pry_tester = Pry.new(:input => InputTester.new("x = ", "1 + 4"), :output => str_output)
pry_tester.rep(o)
str_output.string.should =~ /5/
end
it 'should define a nested class under Hello and not on top-level or Pry' do
pry_tester = Pry.new(:input => InputTester.new("class Nested", "end"), :output => Pry::NullOutput)
pry_tester.rep(Hello)
Hello.const_defined?(:Nested).should == true
end
it 'should suppress output if input ends in a ";" and is an Exception object (single line)' do
o = Object.new
str_output = StringIO.new
pry_tester = Pry.new(:input => InputTester.new("Exception.new;"), :output => str_output)
pry_tester.rep(o)
str_output.string.should == ""
end
it 'should suppress output if input ends in a ";" (single line)' do
o = Object.new
str_output = StringIO.new
pry_tester = Pry.new(:input => InputTester.new("x = 5;"), :output => str_output)
pry_tester.rep(o)
str_output.string.should == ""
end
it 'should suppress output if input ends in a ";" (multi-line)' do
o = Object.new
str_output = StringIO.new
pry_tester = Pry.new(:input => InputTester.new("def self.blah", ":test", "end;"), :output => str_output)
pry_tester.rep(o)
str_output.string.should == ""
end
it 'should be able to evaluate exceptions normally' do
o = Exception.new
str_output = StringIO.new
was_called = false
pry_tester = Pry.new(:input => InputTester.new("self"),
:output => str_output,
:exception_handler => proc { was_called = true })
pry_tester.rep(o)
was_called.should == false
end
it 'should notice when exceptions are raised' do
o = Exception.new
str_output = StringIO.new
was_called = false
pry_tester = Pry.new(:input => InputTester.new("raise self"),
:output => str_output,
:exception_handler => proc { was_called = true })
pry_tester.rep(o)
was_called.should == true
end
it 'should not try to catch intended exceptions' do
lambda { mock_pry("raise SystemExit") }.should.raise SystemExit
# SIGTERM
lambda { mock_pry("raise SignalException.new(15)") }.should.raise SignalException
end
end
describe "Pry#run_command" do
it 'should run a command in a specified context' do
b = Pry.binding_for(7)
p = Pry.new(:output => StringIO.new)
p.run_command("ls -m", b)
p.output.string.should =~ /divmod/
end
it 'should run a command in the context of a session' do
mock_pry("@session_ivar = 10", "_pry_.run_command('ls')").should =~ /@session_ivar/
end
end
describe "repl" do
describe "basic functionality" do
it 'should set an ivar on an object and exit the repl' do
input_strings = ["@x = 10", "exit-all"]
input = InputTester.new(*input_strings)
o = Object.new
pry_tester = Pry.start(o, :input => input, :output => Pry::NullOutput)
o.instance_variable_get(:@x).should == 10
end
end
describe "history arrays" do
it 'sets _ to the last result' do
res = []
input = InputTester.new *[":foo", "self << _", "42", "self << _"]
pry = Pry.new(:input => input, :output => Pry::NullOutput)
pry.repl(res)
res.should == [:foo, 42]
end
it 'sets out to an array with the result' do
res = {}
input = InputTester.new *[":foo", "42", "self[:res] = _out_"]
pry = Pry.new(:input => input, :output => Pry::NullOutput)
pry.repl(res)
res[:res].should.be.kind_of Pry::HistoryArray
res[:res][1..2].should == [:foo, 42]
end
it 'sets _in_ to an array with the entered lines' do
res = {}
input = InputTester.new *[":foo", "42", "self[:res] = _in_"]
pry = Pry.new(:input => input, :output => Pry::NullOutput)
pry.repl(res)
res[:res].should.be.kind_of Pry::HistoryArray
res[:res][1..2].should == [":foo\n", "42\n"]
end
it 'uses 100 as the size of _in_ and _out_' do
res = []
input = InputTester.new *["self << _out_.max_size << _in_.max_size"]
pry = Pry.new(:input => input, :output => Pry::NullOutput)
pry.repl(res)
res.should == [100, 100]
end
it 'can change the size of the history arrays' do
res = []
input = InputTester.new *["self << _out_.max_size << _in_.max_size"]
pry = Pry.new(:input => input, :output => Pry::NullOutput,
:memory_size => 1000)
pry.repl(res)
res.should == [1000, 1000]
end
it 'store exceptions' do
res = []
input = InputTester.new *["foo!","self << _in_[-1] << _out_[-1]"]
pry = Pry.new(:input => input, :output => Pry::NullOutput,
:memory_size => 1000)
pry.repl(res)
res.first.should == "foo!\n"
res.last.should.be.kind_of NoMethodError
end
end
describe "test loading rc files" do
before do
Pry.instance_variable_set(:@initial_session, true)
end
after do
Pry::RC_FILES.clear
Pry.config.should_load_rc = false
end
it "should run the rc file only once" do
Pry.config.should_load_rc = true
Pry::RC_FILES << File.expand_path("../testrc", __FILE__)
Pry.start(self, :input => StringIO.new("exit-all\n"), :output => Pry::NullOutput)
TEST_RC.should == [0]
Pry.start(self, :input => StringIO.new("exit-all\n"), :output => Pry::NullOutput)
TEST_RC.should == [0]
Object.remove_const(:TEST_RC)
end
it "should not run the rc file at all if Pry.config.should_load_rc is false" do
Pry.config.should_load_rc = false
Pry.start(self, :input => StringIO.new("exit-all\n"), :output => Pry::NullOutput)
Object.const_defined?(:TEST_RC).should == false
end
it "should not load the rc file if #repl method invoked" do
Pry.config.should_load_rc = true
Pry.new(:input => StringIO.new("exit-all\n"), :output => Pry::NullOutput).repl(self)
Object.const_defined?(:TEST_RC).should == false
Pry.config.should_load_rc = false
end
end
describe "nesting" do
after do
Pry.reset_defaults
Pry.color = false
end
it 'should nest properly' do
Pry.input = InputTester.new("cd 1", "cd 2", "cd 3", "\"nest:\#\{(_pry_.binding_stack.size - 1)\}\"", "exit-all")
str_output = StringIO.new
Pry.output = str_output
o = Object.new
pry_tester = o.pry
str_output.string.should =~ /nest:3/
end
end
describe "defining methods" do
it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do
[Object.new, {}, []].each do |val|
str_input = StringIO.new("def hello;end")
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
val.methods(false).map(&:to_sym).include?(:hello).should == true
end
end
it 'should define an instance method on the module when performing "def meth;end" inside the module' do
str_input = StringIO.new("def hello;end")
hello = Module.new
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
end
it 'should define an instance method on the class when performing "def meth;end" inside the class' do
str_input = StringIO.new("def hello;end")
hello = Class.new
Pry.new(:input => str_input, :output => StringIO.new).rep(hello)
hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true
end
it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do
# should include float in here, but test fails for some reason
# on 1.8.7, no idea why!
[:test, 0, true, false, nil].each do |val|
str_input = StringIO.new("def hello;end")
Pry.new(:input => str_input, :output => StringIO.new).rep(val)
val.class.instance_methods(false).map(&:to_sym).include?(:hello).should == true
end
end
end
describe "commands" do
it 'should run a command with no parameter' do
pry_tester = Pry.new
pry_tester.commands = CommandTester
pry_tester.input = InputTester.new("command1", "exit-all")
pry_tester.commands = CommandTester
str_output = StringIO.new
pry_tester.output = str_output
pry_tester.rep
str_output.string.should =~ /command1/
end
it 'should run a command with one parameter' do
pry_tester = Pry.new
pry_tester.commands = CommandTester
pry_tester.input = InputTester.new("command2 horsey", "exit-all")
pry_tester.commands = CommandTester
str_output = StringIO.new
pry_tester.output = str_output
pry_tester.rep
str_output.string.should =~ /horsey/
end
end
describe "Object#pry" do
after do
Pry.reset_defaults
Pry.color = false
end
it "should start a pry session on the receiver (first form)" do
Pry.input = InputTester.new("self", "exit-all")
str_output = StringIO.new
Pry.output = str_output
20.pry
str_output.string.should =~ /20/
end
it "should start a pry session on the receiver (second form)" do
Pry.input = InputTester.new("self", "exit-all")
str_output = StringIO.new
Pry.output = str_output
pry 20
str_output.string.should =~ /20/
end
it "should error if more than one argument is passed to Object#pry" do
lambda { pry(20, :input => Readline) }.should.raise ArgumentError
end
end
describe "Pry.binding_for" do
it 'should return TOPLEVEL_BINDING if parameter self is main' do
_main_ = lambda { TOPLEVEL_BINDING.eval('self') }
Pry.binding_for(_main_.call).is_a?(Binding).should == true
Pry.binding_for(_main_.call).should == TOPLEVEL_BINDING
Pry.binding_for(_main_.call).should == Pry.binding_for(_main_.call)
end
end
describe "test Pry defaults" do
after do
Pry.reset_defaults
Pry.color = false
end
describe "input" do
after do
Pry.reset_defaults
Pry.color = false
end
it 'should set the input default, and the default should be overridable' do
Pry.input = InputTester.new("5")
str_output = StringIO.new
Pry.output = str_output
Pry.new.rep
str_output.string.should =~ /5/
Pry.new(:input => InputTester.new("6")).rep
str_output.string.should =~ /6/
end
it 'should pass in the prompt if readline arity is 1' do
Pry.prompt = proc { "A" }
arity_one_input = Class.new do
attr_accessor :prompt
def readline(prompt)
@prompt = prompt
"exit-all"
end
end.new
Pry.start(self, :input => arity_one_input, :output => Pry::NullOutput)
arity_one_input.prompt.should == Pry.prompt.call
end
it 'should not pass in the prompt if the arity is 0' do
Pry.prompt = proc { "A" }
arity_zero_input = Class.new do
def readline
"exit-all"
end
end.new
lambda { Pry.start(self, :input => arity_zero_input, :output => Pry::NullOutput) }.should.not.raise Exception
end
it 'should not pass in the prompt if the arity is -1' do
Pry.prompt = proc { "A" }
arity_multi_input = Class.new do
attr_accessor :prompt
def readline(*args)
@prompt = args.first
"exit-all"
end
end.new
Pry.start(self, :input => arity_multi_input, :output => Pry::NullOutput)
arity_multi_input.prompt.should == nil
end
end
it 'should set the output default, and the default should be overridable' do
Pry.input = InputTester.new("5", "6", "7")
str_output = StringIO.new
Pry.output = str_output
Pry.new.rep
str_output.string.should =~ /5/
Pry.new.rep
str_output.string.should =~ /5\n.*6/
str_output2 = StringIO.new
Pry.new(:output => str_output2).rep
str_output2.string.should.not =~ /5\n.*6/
str_output2.string.should =~ /7/
end
describe "commands" do
it 'should interpolate ruby code into commands' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do |arg|
arg
end
end
$test_interpolation = "bing"
str_output = StringIO.new
Pry.new(:input => StringIO.new('hello #{$test_interpolation}'), :output => str_output, :commands => klass).rep
str_output.string.should =~ /bing/
$test_interpolation = nil
end
# bug fix for https://github.com/pry/pry/issues/170
it 'should not choke on complex string interpolation when checking if ruby code is a command' do
redirect_pry_io(InputTester.new('/#{Regexp.escape(File.expand_path("."))}/'), str_output = StringIO.new) do
pry
end
str_output.string.should.not =~ /SyntaxError/
end
it 'should NOT interpolate ruby code into commands if :interpolate => false' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true, :interpolate => false do |arg|
arg
end
end
$test_interpolation = "bing"
str_output = StringIO.new
Pry.new(:input => StringIO.new('hello #{$test_interpolation}'), :output => str_output, :commands => klass).rep
str_output.string.should =~ /test_interpolation/
$test_interpolation = nil
end
it 'should NOT try to interpolate pure ruby code (no commands) ' do
str_output = StringIO.new
Pry.new(:input => StringIO.new('format \'#{aggy}\''), :output => str_output).rep
str_output.string.should.not =~ /NameError/
Pry.new(:input => StringIO.new('format #{aggy}'), :output => str_output).rep
str_output.string.should.not =~ /NameError/
$test_interpolation = "blah"
Pry.new(:input => StringIO.new('format \'#{$test_interpolation}\''), :output => str_output).rep
str_output.string.should.not =~ /blah/
$test_interpolation = nil
end
it 'should create a command with a space in its name' do
set = Pry::CommandSet.new do
command "hello baby", "" do
output.puts "hello baby command"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("hello baby", "exit-all"), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello baby command/
end
it 'should create a command with a space in its name and pass an argument' do
set = Pry::CommandSet.new do
command "hello baby", "" do |arg|
output.puts "hello baby command #{arg}"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("hello baby john"), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello baby command john/
end
it 'should create a regex command and be able to invoke it' do
set = Pry::CommandSet.new do
command /hello(.)/, "" do
c = captures.first
output.puts "hello#{c}"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("hello1"), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello1/
end
it 'should create a regex command and pass captures into the args list before regular arguments' do
set = Pry::CommandSet.new do
command /hello(.)/, "" do |c1, a1|
output.puts "hello #{c1} #{a1}"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("hello1 baby"), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello 1 baby/
end
it 'should create a regex command and interpolate the captures' do
set = Pry::CommandSet.new do
command /hello (.*)/, "" do |c1|
output.puts "hello #{c1}"
end
end
str_output = StringIO.new
$obj = "bing"
redirect_pry_io(InputTester.new('hello #{$obj}'), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello bing/
$obj = nil
end
it 'should create a regex command and arg_string should be interpolated' do
set = Pry::CommandSet.new do
command /hello(\w+)/, "" do |c1, a1, a2, a3|
output.puts "hello #{c1} #{a1} #{a2} #{a3}"
end
end
str_output = StringIO.new
$a1 = "bing"
$a2 = "bong"
$a3 = "bang"
redirect_pry_io(InputTester.new('hellojohn #{$a1} #{$a2} #{$a3}'), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello john bing bong bang/
$a1 = nil
$a2 = nil
$a3 = nil
end
it 'if a regex capture is missing it should be nil' do
set = Pry::CommandSet.new do
command /hello(.)?/, "" do |c1, a1|
output.puts "hello #{c1.inspect} #{a1}"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("hello baby"), str_output) do
Pry.new(:commands => set).rep
end
str_output.string.should =~ /hello nil baby/
end
it 'should create a command in a nested context and that command should be accessible from the parent' do
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
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do
:kept_hello
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /:kept_hello/
str_output.string.should =~ /=>/
end
it 'should define a command that does NOT keep its return value' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => false do
:kept_hello
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
(str_output.string =~ /:kept_hello/).should == nil
str_output.string !~ /=>/
end
it 'should define a command that keeps its return value even when nil' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do
nil
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /nil/
str_output.string.should =~ /=>/
end
it 'should define a command that keeps its return value but does not return when value is void' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do
void
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("hello\n"), :output => str_output, :commands => klass).rep
str_output.string.empty?.should == true
end
it 'a command (with :keep_retval => false) that replaces eval_string with a valid expression should not have the expression value suppressed' do
klass = Pry::CommandSet.new do
command "hello", "" do
eval_string.replace("6")
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /6/
end
it 'a command (with :keep_retval => true) that replaces eval_string with a valid expression should overwrite the eval_string with the return value' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do
eval_string.replace("6")
7
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /7/
str_output.string.should.not =~ /6/
end
it 'a command that return a value in a multi-line expression should clear the expression and return the value' do
klass = Pry::CommandSet.new do
command "hello", "", :keep_retval => true do
5
end
end
str_output = StringIO.new
Pry.new(:input => StringIO.new("def yo\nhello\n"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /5/
end
it 'should set the commands default, and the default should be overridable' do
klass = Pry::CommandSet.new do
command "hello" do
output.puts "hello world"
end
end
Pry.commands = klass
str_output = StringIO.new
Pry.new(:input => InputTester.new("hello"), :output => str_output).rep
str_output.string.should =~ /hello world/
other_klass = Pry::CommandSet.new do
command "goodbye", "" do
output.puts "goodbye world"
end
end
str_output = StringIO.new
Pry.new(:input => InputTester.new("goodbye"), :output => str_output, :commands => other_klass).rep
str_output.string.should =~ /goodbye world/
end
it 'should inherit "help" command from Pry::CommandBase' do
klass = Pry::CommandSet.new do
command "h", "h command" do
end
end
klass.commands.keys.size.should == 3
klass.commands.keys.include?("help").should == true
klass.commands.keys.include?("install-command").should == true
klass.commands.keys.include?("h").should == true
end
it 'should inherit commands from Pry::Commands' do
klass = Pry::CommandSet.new Pry::Commands do
command "v" do
end
end
klass.commands.include?("nesting").should == true
klass.commands.include?("jump-to").should == true
klass.commands.include?("cd").should == true
klass.commands.include?("v").should == true
end
it 'should alias a command with another command' do
klass = Pry::CommandSet.new do
alias_command "help2", "help"
end
klass.commands["help2"].block.should == klass.commands["help"].block
end
it 'should change description of a command using desc' do
klass = Pry::CommandSet.new do; end
orig = klass.commands["help"].description
klass.instance_eval do
desc "help", "blah"
end
klass.commands["help"].description.should.not == orig
klass.commands["help"].description.should == "blah"
end
it 'should run a command from within a command' do
klass = Pry::CommandSet.new do
command "v" do
output.puts "v command"
end
command "run_v" do
run "v"
end
end
str_output = StringIO.new
Pry.new(:input => InputTester.new("run_v"), :output => str_output, :commands => klass).rep
str_output.string.should =~ /v command/
end
it 'should run a regex command from within a command' do
klass = Pry::CommandSet.new do
command /v(.*)?/ do |arg|
output.puts "v #{arg}"
end
command "run_v" do
run "vbaby"
end
end
str_output = StringIO.new
redirect_pry_io(InputTester.new("run_v"), str_output) do
Pry.new(:commands => klass).rep
end
str_output.string.should =~ /v baby/
end
it 'should run a command from within a command with arguments' do
klass = Pry::CommandSet.new do
command /v(\w+)/ do |arg1, arg2|
output.puts "v #{arg1} #{arg2}"
end
command "run_v_explicit_parameter" do
run "vbaby", "param"
end
command "run_v_embedded_parameter" do
run "vbaby param"
end
end
["run_v_explicit_parameter", "run_v_embedded_parameter"].each do |cmd|
str_output = StringIO.new
redirect_pry_io(InputTester.new(cmd), str_output) do
Pry.new(:commands => klass).rep
end
str_output.string.should =~ /v baby param/
end
end
it 'should enable an inherited method to access opts and output and target, due to instance_exec' do
klass = Pry::CommandSet.new do
command "v" do
output.puts "#{target.eval('self')}"
end
end
child_klass = Pry::CommandSet.new klass do
end
str_output = StringIO.new
Pry.new(:print => proc {}, :input => InputTester.new("v"),
:output => str_output, :commands => child_klass).rep("john")
str_output.string.rstrip.should == "john"
end
it 'should import commands from another command object' do
klass = Pry::CommandSet.new do
import_from Pry::Commands, "ls", "jump-to"
end
klass.commands.include?("ls").should == true
klass.commands.include?("jump-to").should == true
end
it 'should delete some inherited commands when using delete method' do
klass = Pry::CommandSet.new Pry::Commands do
command "v" do
end
delete "show-doc", "show-method"
delete "ls"
end
klass.commands.include?("nesting").should == true
klass.commands.include?("jump-to").should == true
klass.commands.include?("cd").should == true
klass.commands.include?("v").should == true
klass.commands.include?("show-doc").should == false
klass.commands.include?("show-method").should == false
klass.commands.include?("ls").should == false
end
it 'should override some inherited commands' do
klass = Pry::CommandSet.new Pry::Commands do
command "jump-to" do
output.puts "jump-to the music"
end
command "help" do
output.puts "help to the music"
end
end
# suppress evaluation output
Pry.print = proc {}
str_output = StringIO.new
Pry.new(:input => InputTester.new("jump-to"), :output => str_output, :commands => klass).rep
str_output.string.rstrip.should == "jump-to the music"
str_output = StringIO.new
Pry.new(:input => InputTester.new("help"), :output => str_output, :commands => klass).rep
str_output.string.rstrip.should == "help to the music"
Pry.reset_defaults
Pry.color = false
end
end
it "should set the print default, and the default should be overridable" do
new_print = proc { |out, value| out.puts value }
Pry.print = new_print
Pry.new.print.should == Pry.print
str_output = StringIO.new
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
str_output.string.should == "test\n"
str_output = StringIO.new
Pry.new(:input => InputTester.new("\"test\""), :output => str_output,
:print => proc { |out, value| out.puts value.reverse }).rep
str_output.string.should == "tset\n"
Pry.new.print.should == Pry.print
str_output = StringIO.new
Pry.new(:input => InputTester.new("\"test\""), :output => str_output).rep
str_output.string.should == "test\n"
end
describe "pry return values" do
it 'should return the target object' do
Pry.start(self, :input => StringIO.new("exit-all"), :output => Pry::NullOutput).should == self
end
it 'should return the parameter given to exit-all' do
Pry.start(self, :input => StringIO.new("exit-all 10"), :output => Pry::NullOutput).should == 10
end
it 'should return the parameter (multi word string) given to exit-all' do
Pry.start(self, :input => StringIO.new("exit-all \"john mair\""), :output => Pry::NullOutput).should == "john mair"
end
it 'should return the parameter (function call) given to exit-all' do
Pry.start(self, :input => StringIO.new("exit-all 'abc'.reverse"), :output => Pry::NullOutput).should == 'cba'
end
it 'should return the parameter (self) given to exit-all' do
Pry.start("carl", :input => StringIO.new("exit-all self"), :output => Pry::NullOutput).should == "carl"
end
end
describe "prompts" do
it 'should set the prompt default, and the default should be overridable (single prompt)' do
new_prompt = proc { "test prompt> " }
Pry.prompt = new_prompt
Pry.new.prompt.should == Pry.prompt
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt> "
new_prompt = proc { "A" }
pry_tester = Pry.new(:prompt => new_prompt)
pry_tester.prompt.should == new_prompt
pry_tester.select_prompt(true, 0).should == "A"
pry_tester.select_prompt(false, 0).should == "A"
Pry.new.prompt.should == Pry.prompt
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt> "
end
it 'should set the prompt default, and the default should be overridable (multi prompt)' do
new_prompt = [proc { "test prompt> " }, proc { "test prompt* " }]
Pry.prompt = new_prompt
Pry.new.prompt.should == Pry.prompt
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt* "
new_prompt = [proc { "A" }, proc { "B" }]
pry_tester = Pry.new(:prompt => new_prompt)
pry_tester.prompt.should == new_prompt
pry_tester.select_prompt(true, 0).should == "A"
pry_tester.select_prompt(false, 0).should == "B"
Pry.new.prompt.should == Pry.prompt
Pry.new.select_prompt(true, 0).should == "test prompt> "
Pry.new.select_prompt(false, 0).should == "test prompt* "
end
describe 'storing and restoring the prompt' do
before do
make = lambda do |name,i|
prompt = [ proc { "#{i}>" } , proc { "#{i+1}>" } ]
(class << prompt; self; end).send(:define_method, :inspect) { "<Prompt-#{name}>" }
prompt
end
@a , @b , @c = make[:a,0] , make[:b,1] , make[:c,2]
@pry = Pry.new :prompt => @a
end
it 'should have a prompt stack' do
@pry.push_prompt @b
@pry.push_prompt @c
@pry.prompt.should == @c
@pry.pop_prompt
@pry.prompt.should == @b
@pry.pop_prompt
@pry.prompt.should == @a
end
it 'should restore overridden prompts when returning from file-mode' do
pry = Pry.new :input => InputTester.new('shell-mode', 'shell-mode'),
:prompt => [ proc { 'P>' } ] * 2
pry.select_prompt(true, 0).should == "P>"
pry.re
pry.select_prompt(true, 0).should =~ /\Apry .* \$ \z/
pry.re
pry.select_prompt(true, 0).should == "P>"
end
it '#pop_prompt should return the popped prompt' do
@pry.push_prompt @b
@pry.push_prompt @c
@pry.pop_prompt.should == @c
@pry.pop_prompt.should == @b
end
it 'should not pop the last prompt' do
@pry.push_prompt @b
@pry.pop_prompt.should == @b
@pry.pop_prompt.should == @a
@pry.pop_prompt.should == @a
@pry.prompt.should == @a
end
describe '#prompt= should replace the current prompt with the new prompt' do
it 'when only one prompt on the stack' do
@pry.prompt = @b
@pry.prompt.should == @b
@pry.pop_prompt.should == @b
@pry.pop_prompt.should == @b
end
it 'when several prompts on the stack' do
@pry.push_prompt @b
@pry.prompt = @c
@pry.pop_prompt.should == @c
@pry.pop_prompt.should == @a
end
end
end
end
describe "view_clip used for displaying an object in a truncated format" do
VC_MAX_LENGTH = 60
describe "given an object with an #inspect string" do
it "returns the #<> format of the object (never use inspect)" do
o = Object.new
def o.inspect; "a" * VC_MAX_LENGTH; end
Pry.view_clip(o, VC_MAX_LENGTH).should =~ /#<Object/
end
end
describe "given the 'main' object" do
it "returns the #to_s of main (special case)" do
o = TOPLEVEL_BINDING.eval('self')
Pry.view_clip(o, VC_MAX_LENGTH).should == o.to_s
end
end
describe "given the a Numeric, String or Symbol object" do
[1, 2.0, -5, "hello", :test].each do |o|
it "returns the #inspect of the special-cased immediate object: #{o}" do
Pry.view_clip(o, VC_MAX_LENGTH).should == o.inspect
end
end
# only testing with String here :)
it "returns #<> format of the special-cased immediate object if #inspect is longer than maximum" do
o = "o" * (VC_MAX_LENGTH + 1)
Pry.view_clip(o, VC_MAX_LENGTH).should =~ /#<String/
end
end
describe "given an object with an #inspect string as long as the maximum specified" do
it "returns the #<> format of the object (never use inspect)" do
o = Object.new
def o.inspect; "a" * VC_MAX_LENGTH; end
Pry.view_clip(o, VC_MAX_LENGTH).should =~ /#<Object/
end
end
describe "given a regular object with an #inspect string longer than the maximum specified" do
describe "when the object is a regular one" do
it "returns a string of the #<class name:object idish> format" do
o = Object.new
def o.inspect; "a" * (VC_MAX_LENGTH + 1); end
Pry.view_clip(o, VC_MAX_LENGTH).should =~ /#<Object/
end
end
describe "when the object is a Class or a Module" do
describe "without a name (usually a c = Class.new)" do
it "returns a string of the #<class name:object idish> format" do
c, m = Class.new, Module.new
Pry.view_clip(c, VC_MAX_LENGTH).should =~ /#<Class/
Pry.view_clip(m, VC_MAX_LENGTH).should =~ /#<Module/
end
end
describe "with a #name longer than the maximum specified" do
it "returns a string of the #<class name:object idish> format" do
c, m = Class.new, Module.new
def c.name; "a" * (VC_MAX_LENGTH + 1); end
def m.name; "a" * (VC_MAX_LENGTH + 1); end
Pry.view_clip(c, VC_MAX_LENGTH).should =~ /#<Class/
Pry.view_clip(m, VC_MAX_LENGTH).should =~ /#<Module/
end
end
describe "with a #name shorter than or equal to the maximum specified" do
it "returns a string of the #<class name:object idish> format" do
c, m = Class.new, Module.new
def c.name; "a" * VC_MAX_LENGTH; end
def m.name; "a" * VC_MAX_LENGTH; end
Pry.view_clip(c, VC_MAX_LENGTH).should == c.name
Pry.view_clip(m, VC_MAX_LENGTH).should == m.name
end
end
end
end
end
it 'should set the hooks default, and the default should be overridable' do
Pry.input = InputTester.new("exit-all")
Pry.hooks = {
:before_session => proc { |out,_,_| out.puts "HELLO" },
:after_session => proc { |out,_,_| out.puts "BYE" }
}
str_output = StringIO.new
Pry.new(:output => str_output).repl
str_output.string.should =~ /HELLO/
str_output.string.should =~ /BYE/
Pry.input.rewind
str_output = StringIO.new
Pry.new(:output => str_output,
:hooks => {
:before_session => proc { |out,_,_| out.puts "MORNING" },
:after_session => proc { |out,_,_| out.puts "EVENING" }
}
).repl
str_output.string.should =~ /MORNING/
str_output.string.should =~ /EVENING/
# try below with just defining one hook
Pry.input.rewind
str_output = StringIO.new
Pry.new(:output => str_output,
:hooks => {
:before_session => proc { |out,_,_| out.puts "OPEN" }
}
).repl
str_output.string.should =~ /OPEN/
Pry.input.rewind
str_output = StringIO.new
Pry.new(:output => str_output,
:hooks => {
:after_session => proc { |out,_,_| out.puts "CLOSE" }
}
).repl
str_output.string.should =~ /CLOSE/
Pry.reset_defaults
Pry.color = false
end
end
end
end
end