Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove OpenStruct usage from Pry::CommandState #2307

Merged
merged 1 commit into from Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/pry/command.rb
Expand Up @@ -200,7 +200,7 @@ def group(name = nil)
end

def state
Pry::CommandState.default.state_for(match)
Pry::CommandState.default.state_for(self)
end
end

Expand Down
17 changes: 11 additions & 6 deletions lib/pry/command_state.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require 'ostruct'

class Pry
# CommandState is a data structure to hold per-command state.
#
Expand All @@ -20,12 +18,19 @@ def initialize
@command_state = {}
end

def state_for(command_name)
@command_state[command_name] ||= OpenStruct.new
def state_for(command_class)
@command_state[command_class] ||= command_struct(command_class)
end

def reset(command_class)
@command_state[command_class] = command_struct(command_class)
end

def reset(command_name)
@command_state[command_name] = OpenStruct.new
private

def command_struct(command_class)
Struct.new(:command, *command_class.command_options[:state])
.new(command: command_class)
end
end
end
2 changes: 2 additions & 0 deletions lib/pry/commands/cd.rb
Expand Up @@ -22,6 +22,8 @@ class Cd < Pry::ClassCommand
https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope
BANNER

command_options state: %i[old_stack]

def process
state.old_stack ||= []

Expand Down
2 changes: 2 additions & 0 deletions lib/pry/commands/edit.rb
Expand Up @@ -22,6 +22,8 @@ class Edit < Pry::ClassCommand
https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command
BANNER

command_options state: %i[dynamical_ex_file]

def options(opt)
opt.on :e, :ex, "Open the file that raised the most recent exception " \
"(_ex_.file)",
Expand Down
2 changes: 1 addition & 1 deletion lib/pry/commands/shell_command.rb
Expand Up @@ -7,7 +7,7 @@ class ShellCommand < Pry::ClassCommand
group 'Input and Output'
description "All text following a '.' is forwarded to the shell."
command_options listing: '.<shell command>', use_prefix: false,
takes_block: true
takes_block: true, state: %i[old_pwd]

banner <<-'BANNER'
Usage: .COMMAND_NAME
Expand Down
1 change: 1 addition & 0 deletions lib/pry/commands/shell_mode.rb
Expand Up @@ -6,6 +6,7 @@ class ShellMode < Pry::ClassCommand
match 'shell-mode'
group 'Input and Output'
description 'Toggle shell mode. Bring in pwd prompt and file completion.'
command_options state: %i[disabled prev_prompt]

banner <<-'BANNER'
Toggle shell mode. Bring in pwd prompt and file completion.
Expand Down
2 changes: 1 addition & 1 deletion lib/pry/commands/watch_expression.rb
Expand Up @@ -7,7 +7,7 @@ class WatchExpression < Pry::ClassCommand
group 'Context'
description 'Watch the value of an expression and print a notification ' \
'whenever it changes.'
command_options use_prefix: false
command_options use_prefix: false, state: %i[watch_expressions]

banner <<-'BANNER'
Usage: watch [EXPRESSION]
Expand Down
2 changes: 1 addition & 1 deletion lib/pry/control_d_handler.rb
Expand Up @@ -19,7 +19,7 @@ def self.default(pry_instance)
else
# Otherwise, saves current binding stack as old stack and pops last
# binding out of binding stack (the old stack still has that binding).
cd_state = Pry::CommandState.default.state_for('cd')
cd_state = Pry::CommandState.default.state_for(Pry::Command::Cd)
cd_state.old_stack = pry_instance.binding_stack.dup
pry_instance.binding_stack.pop
end
Expand Down
11 changes: 2 additions & 9 deletions spec/command_spec.rb
Expand Up @@ -420,7 +420,7 @@ def self.name

describe ".state" do
it "returns a command state" do
expect(described_class.state).to be_an(OpenStruct)
expect(described_class.state).to be_an(Struct)
end
end

Expand Down Expand Up @@ -478,17 +478,10 @@ def process; end
end

describe "#state" do
let(:target) { binding }

subject { Class.new(described_class).new(pry_instance: Pry.new) }

it "returns a state object" do
expect(subject.state).to be_an(OpenStruct)
end

it "remembers the state" do
subject.state.foo = :bar
expect(subject.state.foo).to eq(:bar)
expect(subject.state).to be_an(Struct)
end
end

Expand Down
26 changes: 14 additions & 12 deletions spec/command_state_spec.rb
Expand Up @@ -17,33 +17,35 @@

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)
subject.state_for(Pry::Command::Cd).old_stack = 1
expect(subject.state_for(Pry::Command::Cd).old_stack).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'))
expect(subject.state_for(Pry::Command::Cd))
.not_to equal(subject.state_for(Pry::Command::Play))
end

it "memoizes state for the same command" do
expect(subject.state_for('command')).to equal(subject.state_for('command'))
state_a = subject.state_for(Pry::Command::Cd)
state_b = subject.state_for(Pry::Command::Cd)
expect(state_a).to equal(state_b)
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
subject.state_for(Pry::Command::Cd).old_stack = 1
subject.reset(Pry::Command::Cd)
expect(subject.state_for(Pry::Command::Cd).old_stack).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')
subject.state_for(Pry::Command::Cd).old_stack = 1
subject.state_for(Pry::Command::WatchExpression).watch_expressions = 1
subject.reset(Pry::Command::Cd)

expect(subject.state_for('other-command').foobar).to eq(1)
expect(subject.state_for(Pry::Command::WatchExpression).watch_expressions).to eq(1)
end
end
end
2 changes: 1 addition & 1 deletion spec/commands/cd_spec.rb
Expand Up @@ -27,7 +27,7 @@ def old_stack
end
end

after { Pry::CommandState.default.reset('cd') }
after { Pry::CommandState.default.reset(Pry::Command::Cd) }

describe 'old stack toggling with `cd -`' do
describe 'in fresh pry instance' do
Expand Down
4 changes: 2 additions & 2 deletions spec/commands/shell_command_spec.rb
Expand Up @@ -7,12 +7,12 @@

@t = pry_tester(@o) do
def command_state
Pry::CommandState.default.state_for(Pry::Command::ShellCommand.match)
Pry::CommandState.default.state_for(Pry::Command::ShellCommand)
end
end
end

after { Pry::CommandState.default.reset(Pry::Command::ShellCommand.match) }
after { Pry::CommandState.default.reset(Pry::Command::ShellCommand) }

describe ".cd" do
before do
Expand Down