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