From a04e56012ab396f343cd931b6ba5ba3e7372769c Mon Sep 17 00:00:00 2001 From: John Mair Date: Sun, 4 Sep 2011 13:30:20 +1200 Subject: [PATCH] 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. --- CHANGELOG | 1 + lib/pry/command_context.rb | 8 ++++++++ lib/pry/command_processor.rb | 8 +++++++- lib/pry/command_set.rb | 6 +++++- lib/pry/default_commands/context.rb | 4 ++-- lib/pry/default_commands/introspection.rb | 2 +- lib/pry/pry_instance.rb | 6 +++--- test/test_command_set.rb | 9 +++++++-- test/test_pry.rb | 23 +++++++++++++++++++++++ 9 files changed, 57 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5779e299..2017877f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 /` diff --git a/lib/pry/command_context.rb b/lib/pry/command_context.rb index 743e7045..ea45eccd 100644 --- a/lib/pry/command_context.rb +++ b/lib/pry/command_context.rb @@ -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. diff --git a/lib/pry/command_processor.rb b/lib/pry/command_processor.rb index 4e5c9c5b..504a4118 100644 --- a/lib/pry/command_processor.rb +++ b/lib/pry/command_processor.rb @@ -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 diff --git a/lib/pry/command_set.rb b/lib/pry/command_set.rb index 97e884b9..3d409bb4 100644 --- a/lib/pry/command_set.rb +++ b/lib/pry/command_set.rb @@ -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 diff --git a/lib/pry/default_commands/context.rb b/lib/pry/default_commands/context.rb index 739d3e92..0728415a 100644 --- a/lib/pry/default_commands/context.rb +++ b/lib/pry/default_commands/context.rb @@ -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 diff --git a/lib/pry/default_commands/introspection.rb b/lib/pry/default_commands/introspection.rb index 1ff2a4b6..20f0bae6 100644 --- a/lib/pry/default_commands/introspection.rb +++ b/lib/pry/default_commands/introspection.rb @@ -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" \ diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index 4cd778dc..1987cb25 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -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 diff --git a/test/test_command_set.rb b/test/test_command_set.rb index 1caaee4c..ad396152 100644 --- a/test/test_command_set.rb +++ b/test/test_command_set.rb @@ -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 diff --git a/test/test_pry.rb b/test/test_pry.rb index efde0205..680bf7f5 100644 --- a/test/test_pry.rb +++ b/test/test_pry.rb @@ -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