diff --git a/CHANGELOG.md b/CHANGELOG.md index 05c2af327..da2829d05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ * Implemented support for CDPATH for ShellCommand ([#1433](https://github.com/pry/pry/issues/1433), [#1434](https://github.com/pry/pry/issues/1434)) * `Pry::CLI.parse_options` does not start Pry anymore ([#1393](https://github.com/pry/pry/pull/1393)) * The gem uses CPU-less platforms for Windows now ([#1410](https://github.com/pry/pry/pull/1410)) +* Add `Pry::Config::Lazy` to make it easier to reimplement `Pry::Config::Default` without knowing its implementation [#1503](https://github.com/pry/pry/pull/1503/) ### 0.10.1 diff --git a/lib/pry/config.rb b/lib/pry/config.rb index 11b0cd34c..9ac184b87 100644 --- a/lib/pry/config.rb +++ b/lib/pry/config.rb @@ -1,6 +1,7 @@ require_relative 'basic_object' class Pry::Config < Pry::BasicObject require_relative 'config/behavior' + require_relative 'config/lazy' require_relative 'config/default' require_relative 'config/convenience' include Pry::Config::Behavior diff --git a/lib/pry/config/behavior.rb b/lib/pry/config/behavior.rb index da17c7256..04c55d94f 100644 --- a/lib/pry/config/behavior.rb +++ b/lib/pry/config/behavior.rb @@ -142,7 +142,7 @@ def keys def eager_load! local_last_default = last_default - local_last_default.default_keys.each do |key| + local_last_default.lazy_keys.each do |key| self[key] = local_last_default.public_send(key) end end diff --git a/lib/pry/config/default.rb b/lib/pry/config/default.rb index bf50bb46b..8c7a1dfa1 100644 --- a/lib/pry/config/default.rb +++ b/lib/pry/config/default.rb @@ -1,7 +1,8 @@ class Pry::Config::Default include Pry::Config::Behavior + include Pry::Config::Lazy - default = { + lazy_implement({ input: proc { lazy_readline }, @@ -114,7 +115,7 @@ class Pry::Config::Default exec_string: proc { "" } - } + }) def initialize super(nil) @@ -122,18 +123,7 @@ def initialize configure_history end - default.each do |key, value| - define_method(key) do - if default[key].equal?(value) - default[key] = instance_eval(&value) - end - default[key] - end - end - - define_method(:default_keys) { default.keys } - -private + private # TODO: # all of this configure_* stuff is a relic of old code. # we should try move this code to being command-local. diff --git a/lib/pry/config/lazy.rb b/lib/pry/config/lazy.rb new file mode 100644 index 000000000..59c705fc1 --- /dev/null +++ b/lib/pry/config/lazy.rb @@ -0,0 +1,25 @@ +module Pry::Config::Lazy + LAZY_KEYS = Hash.new {|h,k| h[k] = [] } + + module ClassMethods + def lazy_implement(method_name_to_func) + method_name_to_func.each do |method_name, func| + define_method(method_name) do + if method_name_to_func[method_name].equal?(func) + LAZY_KEYS[self.class] |= method_name_to_func.keys + method_name_to_func[method_name] = instance_eval(&func) + end + method_name_to_func[method_name] + end + end + end + end + + def self.included(includer) + includer.extend(ClassMethods) + end + + def lazy_keys + LAZY_KEYS[self.class] + end +end diff --git a/spec/config/behavior_spec.rb b/spec/config/behavior_spec.rb new file mode 100644 index 000000000..5f62991fc --- /dev/null +++ b/spec/config/behavior_spec.rb @@ -0,0 +1,16 @@ +require 'helper' +RSpec.describe Pry::Config::Behavior do + let(:behavior) do + Class.new do + include Pry::Config::Behavior + end + end + + describe "#last_default" do + it "returns the last default in a list of defaults" do + last = behavior.from_hash({}, nil) + middle = behavior.from_hash({}, last) + expect(behavior.from_hash({}, middle).last_default).to be(last) + end + end +end diff --git a/spec/config/lazy_spec.rb b/spec/config/lazy_spec.rb new file mode 100644 index 000000000..69884f20a --- /dev/null +++ b/spec/config/lazy_spec.rb @@ -0,0 +1,22 @@ +require 'helper' +RSpec.describe Pry::Config::Lazy do + let(:lazyobj) do + Class.new do + include Pry::Config::Lazy + lazy_implement({foo: proc {"foo"}, bar: proc {"bar"}}) + end.new + end + + describe "on call of a lazy method" do + it "memoizes the return value" do + expect(lazyobj.foo).to be(lazyobj.foo) + end + end + + describe "#lazy_keys" do + it "tracks a list of lazy keys" do + lazyobj.foo # at least one lazy method has to be called before #lazy_keys could return a non-empty array. + expect(lazyobj.lazy_keys).to eq([:foo, :bar]) + end + end +end