diff --git a/lib/pry/command.rb b/lib/pry/command.rb index c0e80768..9d9b0b67 100644 --- a/lib/pry/command.rb +++ b/lib/pry/command.rb @@ -225,9 +225,20 @@ class Pry self._pry_ = context[:pry_instance] end - # The value of {self} inside the {target} binding. + # @return [Object] The value of `self` inside the `target` binding. def target_self; target.eval('self'); end + # @return [Hash] Pry commands can store arbitrary state + # here. This state persists between subsequent command invocations. + # All state saved here is unique to the command, it does not + # need to be namespaced. + # @example + # state.my_state = "my state" # this will not conflict with any + # # `state.my_state` used in another command. + def state + _pry_.command_state[match] ||= OpenStruct.new + end + # Revaluate the string (str) and perform interpolation. # @param [String] str The string to reevaluate with interpolation. # diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb index d9f930b2..fbc9ec68 100644 --- a/lib/pry/pry_instance.rb +++ b/lib/pry/pry_instance.rb @@ -28,6 +28,9 @@ class Pry attr_accessor :extra_sticky_locals + # This is exposed via Pry::Command#state. + attr_reader :command_state + # Special treatment for hooks as we want to alert people of the # changed API attr_reader :hooks @@ -59,6 +62,7 @@ class Pry @binding_stack = [] @indent = Pry::Indent.new + @command_state = {} end # Refresh the Pry instance settings from the Pry class. diff --git a/test/test_command.rb b/test/test_command.rb index a4ce3647..d2ed8f02 100644 --- a/test/test_command.rb +++ b/test/test_command.rb @@ -623,4 +623,74 @@ describe "Pry::Command" do mock_pry("show-command my-test").should =~ /output.puts command_name/ end end + + describe "commands can save state" do + before do + @set = Pry::CommandSet.new do + create_command "litella", "desc" do + def process + state.my_state ||= 0 + state.my_state += 1 + end + end + + create_command "sanders", "desc" do + def process + state.my_state = "wood" + end + end + + create_command /[Hh]ello-world/, "desc" do + def process + state.my_state ||= 0 + state.my_state += 2 + end + end + + end.import Pry::Commands + end + + it 'should save state for the command on the Pry#command_state hash' do + instance = nil + redirect_pry_io(InputTester.new("litella", + "exit-all")) do + instance = Pry.new(:commands => @set) + instance.repl + end + + instance.command_state["litella"].my_state.should == 1 + end + + it 'should ensure state is maintained between multiple invocations of command' do + instance = nil + redirect_pry_io(InputTester.new("litella", "litella", + "exit-all")) do + instance = Pry.new(:commands => @set) + instance.repl + end + + instance.command_state["litella"].my_state.should == 2 + end + + it 'should ensure state with same name stored stored seperately for each command' do + instance = nil + redirect_pry_io(InputTester.new("litella", "sanders", "exit-all")) do + instance = Pry.new(:commands => @set) + instance.repl + end + + instance.command_state["litella"].my_state.should == 1 + instance.command_state["sanders"].my_state.should =="wood" + end + + it 'should ensure state can is properly saved for regex commands' do + instance = nil + redirect_pry_io(InputTester.new("hello-world", "Hello-world", "exit-all")) do + instance = Pry.new(:commands => @set) + instance.repl + end + + instance.command_state[/[Hh]ello-world/].my_state.should == 4 + end + end end