summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyrylo Silin <silin@kyrylo.org>2019-04-29 19:21:54 +0300
committerKyrylo Silin <silin@kyrylo.org>2019-04-29 20:06:51 +0300
commit09ebd358e19ca169b5c5e5debdbc021dfaccf524 (patch)
tree2af260903896bee9498d2dff0bdd701a9fe719d3
parentba18ef32adf0c43bfe4130251b612be44513d990 (diff)
downloadpry-09ebd358e19ca169b5c5e5debdbc021dfaccf524.tar.gz
pry_instance: factor out command state to be globalcommand-global-state
This change is aimed to simplify #1843 (Rework the Pry config). Current command state implementation gets in the way. We would like to simplify the Config class. The current implementation penetrates Pry codebase everywhere, and during my rework of the config I discovered that `watch` uses global command state. It means the state should survive `Pry.new` calls. With my (unpublished yet) implementation, the `watch` command fails to do so. I realised that we can refactor command state implementation to be global. It makes sense to me and also helps with the Config refactoring. With help of a dedicated class we can easily manage the command state (resetting).
-rw-r--r--lib/pry.rb1
-rw-r--r--lib/pry/command.rb6
-rw-r--r--lib/pry/command_state.rb29
-rw-r--r--lib/pry/control_d_handler.rb4
-rw-r--r--lib/pry/pry_instance.rb2
-rw-r--r--spec/command_spec.rb8
-rw-r--r--spec/command_state_spec.rb47
-rw-r--r--spec/commands/cd_spec.rb10
-rw-r--r--spec/commands/shell_command_spec.rb4
-rw-r--r--spec/control_d_handler_spec.rb2
10 files changed, 98 insertions, 15 deletions
diff --git a/lib/pry.rb b/lib/pry.rb
index 3b4bcfe1..fbbaa2ab 100644
--- a/lib/pry.rb
+++ b/lib/pry.rb
@@ -24,6 +24,7 @@ require 'pry/color_printer'
require 'pry/exception_handler'
require 'pry/system_command_handler'
require 'pry/control_d_handler'
+require 'pry/command_state'
Pry::Commands = Pry::CommandSet.new unless defined?(Pry::Commands)
diff --git a/lib/pry/command.rb b/lib/pry/command.rb
index 81cded01..fa6d2e51 100644
--- a/lib/pry/command.rb
+++ b/lib/pry/command.rb
@@ -196,6 +196,10 @@ class Pry
end
end
end
+
+ def state
+ Pry::CommandState.default.state_for(match)
+ end
end
# Properties of one execution of a command (passed by {Pry#run_command} as a hash of
@@ -305,7 +309,7 @@ class Pry
# state.my_state = "my state" # this will not conflict with any
# # `state.my_state` used in another command.
def state
- pry_instance.command_state[match] ||= Pry::Config.from_hash({})
+ self.class.state
end
# Revaluate the string (str) and perform interpolation.
diff --git a/lib/pry/command_state.rb b/lib/pry/command_state.rb
new file mode 100644
index 00000000..263d14d8
--- /dev/null
+++ b/lib/pry/command_state.rb
@@ -0,0 +1,29 @@
+require 'ostruct'
+
+class Pry
+ # CommandState is a data structure to hold per-command state.
+ #
+ # Pry commands can store arbitrary state here. This state persists between
+ # subsequent command invocations. All state saved here is unique to the
+ # command.
+ #
+ # @since ?.?.?
+ # @api private
+ class CommandState
+ def self.default
+ @default ||= new
+ end
+
+ def initialize
+ @command_state = {}
+ end
+
+ def state_for(command_name)
+ @command_state[command_name] ||= OpenStruct.new
+ end
+
+ def reset(command_name)
+ @command_state[command_name] = OpenStruct.new
+ end
+ end
+end
diff --git a/lib/pry/control_d_handler.rb b/lib/pry/control_d_handler.rb
index d02e2110..1021c767 100644
--- a/lib/pry/control_d_handler.rb
+++ b/lib/pry/control_d_handler.rb
@@ -16,8 +16,8 @@ class Pry
else
# Otherwise, saves current binding stack as old stack and pops last
# binding out of binding stack (the old stack still has that binding).
- pry_instance.command_state['cd'] ||= Pry::Config.from_hash({})
- pry_instance.command_state['cd'].old_stack = pry_instance.binding_stack.dup
+ cd_state = Pry::CommandState.default.state_for('cd')
+ cd_state.old_stack = pry_instance.binding_stack.dup
pry_instance.binding_stack.pop
end
end
diff --git a/lib/pry/pry_instance.rb b/lib/pry/pry_instance.rb
index 9269ded7..e1309ce9 100644
--- a/lib/pry/pry_instance.rb
+++ b/lib/pry/pry_instance.rb
@@ -34,7 +34,6 @@ class Pry
attr_accessor :last_dir
attr_reader :last_exception
- attr_reader :command_state
attr_reader :exit_value
# @since v0.12.0
@@ -72,7 +71,6 @@ class Pry
def initialize(options = {})
@binding_stack = []
@indent = Pry::Indent.new
- @command_state = {}
@eval_string = ""
@backtrace = options.delete(:backtrace) || caller
target = options.delete(:target)
diff --git a/spec/command_spec.rb b/spec/command_spec.rb
index f56d92db..5991304f 100644
--- a/spec/command_spec.rb
+++ b/spec/command_spec.rb
@@ -416,6 +416,12 @@ RSpec.describe Pry::Command do
end
end
+ describe ".state" do
+ it "returns a command state" do
+ expect(described_class.state).to be_an(OpenStruct)
+ end
+ end
+
describe "#run" do
let(:command_set) do
set = Pry::CommandSet.new
@@ -475,7 +481,7 @@ RSpec.describe Pry::Command do
subject { Class.new(described_class).new(pry_instance: Pry.new) }
it "returns a state hash" do
- expect(subject.state).to be_a(Pry::Config)
+ expect(subject.state).to be_an(OpenStruct)
end
it "remembers the state" do
diff --git a/spec/command_state_spec.rb b/spec/command_state_spec.rb
new file mode 100644
index 00000000..10097b2b
--- /dev/null
+++ b/spec/command_state_spec.rb
@@ -0,0 +1,47 @@
+RSpec.describe Pry::CommandState do
+ describe ".default" do
+ it "returns the default command state" do
+ expect(described_class.default).to be_a(described_class)
+ end
+
+ context "when called multiple times" do
+ it "returns the same command state" do
+ first_state = described_class.default
+ second_state = described_class.default
+ expect(first_state).to eql(second_state)
+ end
+ end
+ end
+
+ describe "#state_for" do
+ it "returns a state for the matching command" do
+ subject.state_for('command').foobar = 1
+ expect(subject.state_for('command').foobar).to eq(1)
+ end
+
+ it "returns new state for new command" do
+ expect(subject.state_for('command'))
+ .not_to equal(subject.state_for('other-command'))
+ end
+
+ it "memoizes state for the same command" do
+ expect(subject.state_for('command')).to equal(subject.state_for('command'))
+ end
+ end
+
+ describe "#reset" do
+ it "resets the command state for the given command" do
+ subject.state_for('command').foobar = 1
+ subject.reset('command')
+ expect(subject.state_for('command').foobar).to be_nil
+ end
+
+ it "doesn't reset command state for other commands" do
+ subject.state_for('command').foobar = 1
+ subject.state_for('other-command').foobar = 1
+ subject.reset('command')
+
+ expect(subject.state_for('other-command').foobar).to eq(1)
+ end
+ end
+end
diff --git a/spec/commands/cd_spec.rb b/spec/commands/cd_spec.rb
index d2120a6e..38830ace 100644
--- a/spec/commands/cd_spec.rb
+++ b/spec/commands/cd_spec.rb
@@ -16,20 +16,16 @@ describe 'cd' do
end
def command_state
- pry.command_state["cd"]
+ pry.commands['cd'].state
end
def old_stack
- pry.command_state['cd'].old_stack.dup
+ pry.commands['cd'].state.old_stack.dup
end
end
end
- describe 'state' do
- it 'should not to be set up in fresh instance' do
- expect(@t.command_state).to equal nil
- end
- end
+ after { Pry::CommandState.default.reset('cd') }
describe 'old stack toggling with `cd -`' do
describe 'in fresh pry instance' do
diff --git a/spec/commands/shell_command_spec.rb b/spec/commands/shell_command_spec.rb
index 4417f0ee..62526b3c 100644
--- a/spec/commands/shell_command_spec.rb
+++ b/spec/commands/shell_command_spec.rb
@@ -5,11 +5,13 @@ describe Pry::Command::ShellCommand do
@t = pry_tester(@o) do
def command_state
- pry.command_state[Pry::Command::ShellCommand.match]
+ Pry::CommandState.default.state_for(Pry::Command::ShellCommand.match)
end
end
end
+ after { Pry::CommandState.default.reset(Pry::Command::ShellCommand.match) }
+
describe ".cd" do
before do
allow(Dir).to receive(:chdir)
diff --git a/spec/control_d_handler_spec.rb b/spec/control_d_handler_spec.rb
index 2c5a45ae..5e21ccbe 100644
--- a/spec/control_d_handler_spec.rb
+++ b/spec/control_d_handler_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe Pry::ControlDHandler do
it "saves a dup of the current binding stack in the 'cd' command" do
described_class.default(eval_string, pry_instance)
- cd_state = pry_instance.command_state['cd']
+ cd_state = pry_instance.commands['cd'].state
expect(cd_state.old_stack).to eq([binding1, binding2])
end