2018-12-05 22:18:31 +01:00
|
|
|
RSpec.describe Pry::Config do
|
2019-03-25 02:40:05 +02:00
|
|
|
specify { expect(subject.input).to respond_to(:readline) }
|
|
|
|
specify { expect(subject.output).to be_an(IO) }
|
|
|
|
specify { expect(subject.commands).to be_a(Pry::CommandSet) }
|
|
|
|
specify { expect(subject.prompt_name).to be_a(String) }
|
|
|
|
specify { expect(subject.prompt).to be_a(Pry::Prompt) }
|
|
|
|
specify { expect(subject.prompt_safe_contexts).to be_an(Array) }
|
|
|
|
specify { expect(subject.print).to be_a(Method) }
|
|
|
|
specify { expect(subject.quiet).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.exception_handler).to be_a(Method) }
|
|
|
|
specify { expect(subject.unrescued_exceptions).to be_an(Array) }
|
|
|
|
specify { expect(subject.hooks).to be_a(Pry::Hooks) }
|
|
|
|
specify { expect(subject.pager).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.system).to be_a(Method) }
|
|
|
|
specify { expect(subject.color).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.default_window_size).to be_a(Numeric) }
|
|
|
|
specify { expect(subject.editor).to be_a(String) }
|
|
|
|
specify { expect(subject.should_load_rc).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.should_load_local_rc).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.should_trap_interrupts).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.disable_auto_reload).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.command_prefix).to be_a(String) }
|
|
|
|
specify { expect(subject.auto_indent).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.correct_indent).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.collision_warning).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.output_prefix).to be_a(String) }
|
|
|
|
specify { expect(subject.requires).to be_an(Array) }
|
|
|
|
specify { expect(subject.should_load_requires).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.should_load_plugins).to be(true).or be(false) }
|
|
|
|
specify { expect(subject.windows_console_warning).to be(true).or be(false) }
|
2019-05-04 18:09:57 +03:00
|
|
|
specify { expect(subject.control_d_handler).to respond_to(:call) }
|
2019-03-25 02:40:05 +02:00
|
|
|
specify { expect(subject.memory_size).to be_a(Numeric) }
|
|
|
|
specify { expect(subject.extra_sticky_locals).to be_a(Hash) }
|
|
|
|
specify { expect(subject.command_completions).to be_a(Proc) }
|
|
|
|
specify { expect(subject.file_completions).to be_a(Proc) }
|
|
|
|
specify { expect(subject.ls).to be_an(OpenStruct) }
|
|
|
|
specify { expect(subject.completer).to eq(Pry::InputCompleter) }
|
|
|
|
specify { expect(subject.history).to be_a(Pry::History) }
|
|
|
|
specify { expect(subject.history_save).to eq(true).or be(false) }
|
|
|
|
specify { expect(subject.history_load).to eq(true).or be(false) }
|
|
|
|
specify { expect(subject.history_file).to be_a(String) }
|
|
|
|
specify { expect(subject.exec_string).to be_a(String) }
|
2019-05-03 02:25:25 +03:00
|
|
|
specify { expect(subject.rc_file).to be_a(String) }
|
|
|
|
|
|
|
|
describe "#rc_file" do
|
|
|
|
context "when $PRYRC env variable is set" do
|
|
|
|
before { ENV['PRYRC'] = '/foo/pryrc' }
|
|
|
|
after { ENV.delete('PRYRC') }
|
|
|
|
|
|
|
|
it "defaults to the value of PRYRC env variable" do
|
|
|
|
expect(subject.rc_file).to eq('/foo/pryrc')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when ~/.pryrc exists" do
|
|
|
|
before do
|
|
|
|
allow(File).to receive(:exist?)
|
|
|
|
expect(File).to receive(:exist?)
|
|
|
|
.with(File.expand_path('~/.pryrc')).and_return(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "defaults ~/.pryrc" do
|
|
|
|
expect(subject.rc_file).to eq('~/.pryrc')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when $XDG_CONFIG_HOME is defined" do
|
|
|
|
before do
|
|
|
|
allow(File).to receive(:exist?)
|
|
|
|
expect(File).to receive(:exist?)
|
|
|
|
.with(File.expand_path('~/.pryrc')).and_return(false)
|
|
|
|
|
|
|
|
ENV['XDG_CONFIG_HOME'] = '/xdg_home'
|
|
|
|
end
|
|
|
|
|
|
|
|
after { ENV.delete('XDG_CONFIG_HOME') }
|
|
|
|
|
|
|
|
it "defaults $XDG_CONFIG_HOME/pry/pryrc" do
|
|
|
|
expect(subject.rc_file).to eq('/xdg_home/pry/pryrc')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2018-12-05 22:18:31 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
describe "#merge!" do
|
|
|
|
it "merges given hash with the config instance" do
|
|
|
|
subject.merge!(output_prefix: '~> ', exec_string: '!')
|
2018-12-13 08:46:39 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
expect(subject.output_prefix).to eq('~> ')
|
|
|
|
expect(subject.exec_string).to eq('!')
|
2018-12-13 08:46:39 +01:00
|
|
|
end
|
2018-12-05 22:18:31 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
it "returns self" do
|
|
|
|
config = subject.merge!(output_prefix: '~> ')
|
|
|
|
expect(subject).to eql(config)
|
2016-07-09 02:13:22 +01:00
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
context "when an undefined option is given" do
|
|
|
|
it "adds the option to the config" do
|
|
|
|
subject.merge!(new_option: 1, other_option: 2)
|
2015-07-27 16:10:13 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
expect(subject.new_option).to eq(1)
|
|
|
|
expect(subject.other_option).to eq(2)
|
2014-01-30 01:41:56 +01:00
|
|
|
end
|
2014-01-27 10:06:06 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
describe "#merge" do
|
|
|
|
it "returns a new config object" do
|
|
|
|
expect(subject).not_to equal(subject.merge(new_option: 1, other_option: 2))
|
2014-01-22 00:32:03 +09:00
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
it "doesn't mutate the original config" do
|
|
|
|
subject.merge(new_option: 1, other_option: 2)
|
2014-01-22 00:32:03 +09:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
expect(subject).not_to respond_to(:new_option)
|
|
|
|
expect(subject).not_to respond_to(:other_option)
|
Fix Pry.config.hooks # => parent's hooks
PROBLEM DESCRIPTION
===================
The child caches a dup of the parent's hooks,
so it does the correct thing after being accessed the first time.
But the first time it is called, it doesn't return its cached duped value,
it returns the parent's value. This causes 2 bugs:
1. The first hook declared will get "lost", because it is declared
to the parent hooks, not the child's hooks. And after that first
accessing, only the child's hooks will be used
2. The parent's hooks (which are probably the ones from
[the default](https://github.com/pry/pry/blob/0ff6fa61d4197feace48b422b5e3d3fb5948cbdd/lib/pry/config/default.rb#L35-37))
are going to get hooks declared on them that shouldn't be
(well, presumably shouldn't be, given the explicit check for
this case and duping to avoid it).
So if another config object was initialized with the same parent,
it would wind up with hooks that it didn't want/expect.
I assume all the other keys work fine because they are value objects,
so if anything wanted to change the value, it would reassign the key
to the config object rather than mutating the returned value.
Mutability *sigh* yallknowwhatimsayin
SOLUTION DESCRIPTION
====================
Return the cached duped child value instead of the parent value.
EXAMPLE
=======
This code from
[the docs](https://github.com/pry/pry/blob/0ff6fa61d4197feace48b422b5e3d3fb5948cbdd/lib/pry/hooks.rb#L8-11)
will not print "hello", because it's being declared to the parent hook.
```ruby
Pry.config.hooks.add_hook(:before_session, :say_hi) { puts "hello" }
```
This code will, b/c it's being declared to the cached, duped child hook.
```ruby
Pry.config.hooks
Pry.config.hooks.add_hook(:before_session, :say_hi) { puts "hello" }
```
ISSUE IMPACT
============
Fixes #1254
Might fix or have something to do with these issues:
* #1244 Totally thought I got it, but then couldn't reproduce again later
and just don't understand how JRuby builds, so might just be a problem
with how I was trying to reproduce it.
* #1171 Maybe, depending on if Eclipse integrates with it using the
hooks, alternatively, could be the same issue as the one above,
they might both still be broken. Or both fixed and I can't figure out
how to prove it. Dunno.
OTHER THOUGHTS
==============
I'm writing Github flavoured markdown,
but I'm not actually sure if it will get rendered as such in the PR.
Esp since git considers leading octothorpes as comments and not headers,
and removes them...
Guess we'll see... bottoms up, friends!
2014-07-20 16:04:51 -06:00
|
|
|
end
|
2014-01-22 00:32:03 +09:00
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
describe "#method_missing" do
|
|
|
|
context "when invoked method ends with =" do
|
|
|
|
it "assigns a new custom option" do
|
|
|
|
subject.foo = 1
|
|
|
|
expect(subject.foo).to eq(1)
|
|
|
|
end
|
2014-03-23 10:16:13 +01:00
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
context "when invoked method is not an option" do
|
|
|
|
it "raises NoMethodError" do
|
|
|
|
expect { subject.foo }.to raise_error(NoMethodError)
|
|
|
|
end
|
2014-03-23 10:16:13 +01:00
|
|
|
end
|
2017-11-11 00:51:40 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
context "when invoked method is a LazyValue" do
|
|
|
|
it "defines a callable attribute" do
|
|
|
|
subject.foo = Pry::Config::LazyValue.new { 1 }
|
|
|
|
expect(subject.foo).to eq(1)
|
|
|
|
end
|
2017-11-11 00:51:40 +01:00
|
|
|
end
|
2014-03-23 10:16:13 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "#respond_to?" do
|
2019-03-25 02:40:05 +02:00
|
|
|
context "when checking an undefined option" do
|
|
|
|
it "returns false" do
|
|
|
|
expect(subject.respond_to?(:foo)).to be(false)
|
|
|
|
end
|
2014-03-15 03:05:19 +01:00
|
|
|
end
|
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
context "when checking a defined option" do
|
|
|
|
before { subject.foo = 1 }
|
2014-03-15 03:05:19 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
it "returns true for the reader" do
|
|
|
|
expect(subject.respond_to?(:foo)).to be(true)
|
|
|
|
end
|
2014-03-15 03:05:19 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
it "returns true for the writer" do
|
|
|
|
expect(subject.respond_to?(:foo=)).to be(true)
|
|
|
|
end
|
2014-01-22 00:32:03 +09:00
|
|
|
end
|
|
|
|
end
|
2014-12-13 14:25:03 +00:00
|
|
|
|
|
|
|
describe "#[]" do
|
2019-03-25 02:40:05 +02:00
|
|
|
it "reads the config value" do
|
|
|
|
expect_any_instance_of(Pry::Config::Value).to receive(:call)
|
|
|
|
subject[:foo] = 1
|
|
|
|
subject[:foo]
|
2014-12-13 14:25:03 +00:00
|
|
|
end
|
2018-11-20 14:10:21 +01:00
|
|
|
|
2019-03-25 02:40:05 +02:00
|
|
|
it "returns the config value" do
|
|
|
|
subject[:foo] = 1
|
|
|
|
expect(subject[:foo]).to eq(1)
|
2019-02-04 00:52:30 +01:00
|
|
|
end
|
|
|
|
end
|
2019-05-04 18:09:57 +03:00
|
|
|
|
|
|
|
describe "#control_d_handler=" do
|
|
|
|
context "when the handler expects multiple arguments" do
|
|
|
|
it "prints a warning" do
|
|
|
|
expect(Pry::Warning).to receive(:warn).with(
|
|
|
|
"control_d_handler's arity of 2 parameters was deprecated " \
|
|
|
|
'(eval_string, pry_instance). Now it gets passed just 1 ' \
|
|
|
|
'parameter (pry_instance)'
|
|
|
|
)
|
|
|
|
subject.control_d_handler = proc { |_arg1, _arg2| }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the handler expects just one argument" do
|
|
|
|
it "doesn't print a warning" do
|
|
|
|
expect(Pry::Warning).not_to receive(:warn)
|
|
|
|
subject.control_d_handler = proc { |_arg1| }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#control_d_handler" do
|
|
|
|
let(:pry_instance) { Pry.new }
|
|
|
|
|
|
|
|
context "when it returns a callable accepting one argument" do
|
|
|
|
context "and when it is called with one argument" do
|
|
|
|
it "calls the handler with a pry instance" do
|
|
|
|
subject.control_d_handler = proc do |arg|
|
|
|
|
expect(arg).to eql(pry_instance)
|
|
|
|
end
|
|
|
|
subject.control_d_handler.call(pry_instance)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "and when it is called with multiple arguments" do
|
|
|
|
before { allow(Pry::Warning).to receive(:warn) }
|
|
|
|
|
|
|
|
it "calls the handler with a pry instance" do
|
|
|
|
subject.control_d_handler = proc do |arg|
|
|
|
|
expect(arg).to eql(pry_instance)
|
|
|
|
end
|
|
|
|
subject.control_d_handler.call('', pry_instance)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when it returns a callabale with two arguments" do
|
|
|
|
before { allow(Pry::Warning).to receive(:warn) }
|
|
|
|
|
|
|
|
context "and when it's called with one argument" do
|
|
|
|
it "calls the handler with a eval_string and a pry instance" do
|
|
|
|
subject.control_d_handler = proc do |arg1, arg2|
|
|
|
|
expect(arg1).to eq('')
|
|
|
|
expect(arg2).to eql(pry_instance)
|
|
|
|
end
|
|
|
|
subject.control_d_handler.call(pry_instance)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "and when it's called with multiple arguments" do
|
|
|
|
it "calls the handler with a eval_string and a pry instance" do
|
|
|
|
subject.control_d_handler = proc do |arg1, arg2|
|
|
|
|
expect(arg1).to eq('')
|
|
|
|
expect(arg2).to eql(pry_instance)
|
|
|
|
end
|
|
|
|
subject.control_d_handler.call('', pry_instance)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-01-22 00:32:03 +09:00
|
|
|
end
|