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 * ^C no longer captured
* got rid of Pry.active_instance, Pry.last_exception and friends. * 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') * 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 * 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 /` * 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. # Command contexts are the objects runing each command.
# Helper modules can be mixed into this class. # Helper modules can be mixed into this class.
class CommandContext 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 :output
attr_accessor :target attr_accessor :target
attr_accessor :captures attr_accessor :captures
@ -10,6 +17,7 @@ class Pry
attr_accessor :opts attr_accessor :opts
attr_accessor :command_set attr_accessor :command_set
attr_accessor :command_processor attr_accessor :command_processor
attr_accessor :void
attr_accessor :_pry_ attr_accessor :_pry_
# Run a command from another command. # Run a command from another command.

View File

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

View File

@ -15,7 +15,11 @@ class Pry
context.instance_eval(&stub_block) context.instance_eval(&stub_block)
else else
ret = context.instance_exec(*correct_arg_arity(block.arity, args), &block) 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
end end

View File

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

View File

@ -108,7 +108,7 @@ class Pry
end end
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| opts = Slop.parse!(args) do |opt|
opt.banner "Usage: edit [OPTIONS] [FILE]\n" \ opt.banner "Usage: edit [OPTIONS] [FILE]\n" \
"Edit the method FILE in an editor.\n" \ "Edit the method FILE in an editor.\n" \

View File

@ -278,7 +278,7 @@ class Pry
# @param [String] val The input string. # @param [String] val The input string.
# @return [Boolean] Whether the input is null. # @return [Boolean] Whether the input is null.
def null_input?(val) 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 end
# Read a line of input and check for ^d, also determine prompt to use. # 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 [String] eval_string The cumulative lines of input.
# @param [Binding] target The target of the Pry session. # @param [Binding] target The target of the Pry session.
def process_line(val, eval_string, target) 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" eval_string << "Thread.current[:__pry_cmd_ret_value__]\n"
else else
# only commands (with no ret_value) should have an empty `val` so this ignores their result # 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' @set.commands['foo'].description.should == 'baz'
end 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.command('foo') { 3 }
@set.run_command(nil, 'foo').should == nil @set.run_command(nil, 'foo').should == Pry::CommandContext::VOID_VALUE
end end
it 'should be able to keep return values' do it 'should be able to keep return values' do
@ -122,6 +122,11 @@ describe Pry::CommandSet do
@set.run_command(nil, 'foo').should == 3 @set.run_command(nil, 'foo').should == 3
end 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 it 'should be able to have its own helpers' do
@set.command('foo') do @set.command('foo') do
should.respond_to :my_helper should.respond_to :my_helper

View File

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