made it so commands (with :keep_retval => true) can now return nil as a legitimate return value. Created a new 'void' value to use instead when indicating no return value. also updated tests.

'void' method now available to commands, commands must return this when they do not want their result displayed when they use :keep_retval => true. void just maps to a random object Pry::CommandContext::VOID_VALUE.
This commit is contained in:
John Mair 2011-09-04 13:30:20 +12:00
parent fc15407150
commit a04e56012a
9 changed files with 57 additions and 10 deletions

View File

@ -20,6 +20,7 @@
* ^C no longer captured
* got rid of Pry.active_instance, Pry.last_exception and friends.
* also special locals now shared among bindings in a pry instance (i.e _ex_ (and friends) re-injected into new binding entered with 'cd')
* renamed inp and out to _in_ and _out_ (to avoid collisions with actual locals in debugging scope)
* added third parameter to prompts, the pry instance itself (_pry) see https://github.com/pry/pry/issues/233 for why it's important
* cd behaviour when no args performs the same as `cd /`

View File

@ -2,6 +2,13 @@ class Pry
# Command contexts are the objects runing each command.
# Helper modules can be mixed into this class.
class CommandContext
# represents a void return value for a command
VOID_VALUE = Object.new
# give it a nice inspect
def VOID_VALUE.inspect() "void" end
attr_accessor :output
attr_accessor :target
attr_accessor :captures
@ -10,6 +17,7 @@ class Pry
attr_accessor :opts
attr_accessor :command_set
attr_accessor :command_processor
attr_accessor :void
attr_accessor :_pry_
# Run a command from another command.

View File

@ -80,6 +80,8 @@ class Pry
# @param [String] eval_string The cumulative lines of input for
# multi-line input.
# @param [Binding] target The receiver of the commands.
# @return [Object] The value returned by the
# command.
def process_commands(val, eval_string, target)
# no command was matched, so return to caller
@ -100,7 +102,9 @@ class Pry
:captures => captures
}
execute_command(target, command.name, options, *(captures + args))
ret = execute_command(target, command.name, options, *(captures + args))
[ret, command.options[:keep_retval]]
end
# Execute a Pry command.
@ -109,6 +113,7 @@ class Pry
# @param [String] command The name of the command to be run.
# @param [Hash] options The options to set on the Commands object.
# @param [Array] args The command arguments.
# @return [Object] The value returned by the command
def execute_command(target, command, options, *args)
context = CommandContext.new
@ -120,6 +125,7 @@ class Pry
context.eval_string = options[:eval_string]
context.arg_string = options[:arg_string]
context.command_set = commands
context.void = Pry::CommandContext::VOID_VALUE
context._pry_ = @pry_instance
context.command_processor = self

View File

@ -15,7 +15,11 @@ class Pry
context.instance_eval(&stub_block)
else
ret = context.instance_exec(*correct_arg_arity(block.arity, args), &block)
ret if options[:keep_retval]
if options[:keep_retval]
ret
else
Pry::CommandContext::VOID_VALUE
end
end
end

View File

@ -23,10 +23,10 @@ class Pry
nil
when "::"
_pry_.binding_stack.push TOPLEVEL_BINDING
nil
void
else
_pry_.binding_stack.push Pry.binding_for(target.eval(arg_string))
nil
void
end
end

View File

@ -108,7 +108,7 @@ class Pry
end
end
command "edit", "Invoke the default editor on a file. Type `edit --help` for more info" do |*args|
command "edit", "Invoke the default editor on a file. Type `edit --help` for more info", :keep_retval => true do |*args|
opts = Slop.parse!(args) do |opt|
opt.banner "Usage: edit [OPTIONS] [FILE]\n" \
"Edit the method FILE in an editor.\n" \

View File

@ -278,7 +278,7 @@ class Pry
# @param [String] val The input string.
# @return [Boolean] Whether the input is null.
def null_input?(val)
val.empty? && !Thread.current[:__pry_cmd_ret_value__]
val.empty? && Thread.current[:__pry_cmd_ret_value__] == Pry::CommandContext::VOID_VALUE
end
# Read a line of input and check for ^d, also determine prompt to use.
@ -306,9 +306,9 @@ class Pry
# @param [String] eval_string The cumulative lines of input.
# @param [Binding] target The target of the Pry session.
def process_line(val, eval_string, target)
Thread.current[:__pry_cmd_ret_value__] = @command_processor.process_commands(val, eval_string, target)
Thread.current[:__pry_cmd_ret_value__], keep_retval = @command_processor.process_commands(val, eval_string, target)
if Thread.current[:__pry_cmd_ret_value__]
if keep_retval && Thread.current[:__pry_cmd_ret_value__] != Pry::CommandContext::VOID_VALUE
eval_string << "Thread.current[:__pry_cmd_ret_value__]\n"
else
# only commands (with no ret_value) should have an empty `val` so this ignores their result

View File

@ -112,9 +112,9 @@ describe Pry::CommandSet do
@set.commands['foo'].description.should == 'baz'
end
it 'should return nil for commands by default' do
it 'should return Pry::CommandContext::VOID_VALUE for commands by default' do
@set.command('foo') { 3 }
@set.run_command(nil, 'foo').should == nil
@set.run_command(nil, 'foo').should == Pry::CommandContext::VOID_VALUE
end
it 'should be able to keep return values' do
@ -122,6 +122,11 @@ describe Pry::CommandSet do
@set.run_command(nil, 'foo').should == 3
end
it 'should be able to keep return values, even if return value is nil' do
@set.command('foo', '', :keep_retval => true) { nil }
@set.run_command(nil, 'foo').should == nil
end
it 'should be able to have its own helpers' do
@set.command('foo') do
should.respond_to :my_helper

View File

@ -713,6 +713,29 @@ describe Pry do
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 'should set the commands default, and the default should be overridable' do
klass = Pry::CommandSet.new do
command "hello" do