diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce4c592..7cf13bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,9 @@ jobs: - ruby: 2.4.1 - ruby: 2.5.1 - ruby: 2.6.0 + - ruby: 2.7.5 + - ruby: 3.0.3 + - ruby: 3.1.0 - ruby: ruby-head - ruby: jruby-d19 - ruby: jruby-9.1.9.0 diff --git a/.gitignore b/.gitignore index d87d4be..69e4764 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .bundle .config .yardoc +.ruby-version Gemfile.lock InstalledFiles _yardoc diff --git a/lib/memoist.rb b/lib/memoist.rb index c49e102..148abeb 100644 --- a/lib/memoist.rb +++ b/lib/memoist.rb @@ -50,11 +50,11 @@ def self.escape_punctuation(string) string end - def self.memoist_eval(klass, *args, &block) + def self.memoist_eval(klass, *args, **kwargs, &block) if klass.respond_to?(:class_eval) - klass.class_eval(*args, &block) + klass.class_eval(*args, **kwargs, &block) else - klass.singleton_class.class_eval(*args, &block) + klass.singleton_class.class_eval(*args, **kwargs, &block) end end @@ -203,21 +203,21 @@ def #{method_name}(reload = false) # end module_eval <<-EOS, __FILE__, __LINE__ + 1 - def #{method_name}(*args) + def #{method_name}(*args, **kwargs) reload = Memoist.extract_reload!(method(#{unmemoized_method.inspect}), args) - skip_cache = reload || !(instance_variable_defined?(#{memoized_ivar.inspect}) && #{memoized_ivar} && #{memoized_ivar}.has_key?(args)) + skip_cache = reload || !(instance_variable_defined?(#{memoized_ivar.inspect}) && #{memoized_ivar} && #{memoized_ivar}.has_key?(args+kwargs.to_a)) set_cache = skip_cache && !frozen? if skip_cache - value = #{unmemoized_method}(*args) + value = #{unmemoized_method}(*args, **kwargs) else - value = #{memoized_ivar}[args] + value = #{memoized_ivar}[args+kwargs.to_a] end if set_cache #{memoized_ivar} ||= {} - #{memoized_ivar}[args] = value + #{memoized_ivar}[args+kwargs.to_a] = value end value diff --git a/test/memoist_test.rb b/test/memoist_test.rb index 433f119..f439367 100644 --- a/test/memoist_test.rb +++ b/test/memoist_test.rb @@ -93,6 +93,16 @@ def update_attributes_calls @counter.count(:update_attributes) end + def do_with_special(_regular = 10, special_one: true, special_two: true) + @counter.call(:do_with_special) + true + end + memoize :do_with_special + + def do_with_special_calls + @counter.count(:do_with_special) + end + protected def memoize_protected_test @@ -271,6 +281,23 @@ def test_memoize_with_options_hash assert_equal 4, @person.update_attributes_calls end + def test_memoize_with_kwargs + assert_equal true, @person.do_with_special(1, special_one: true) + assert_equal 1, @person.do_with_special_calls + + 3.times { assert_equal true, @person.do_with_special(1, special_one: true) } + assert_equal 1, @person.do_with_special_calls + + assert_equal true, @person.do_with_special(2) + assert_equal 2, @person.do_with_special_calls + + assert_equal true, @person.do_with_special(1, special_one: false) + assert_equal 3, @person.do_with_special_calls + + assert_equal true, @person.do_with_special(1, special_two: false) + assert_equal 4, @person.do_with_special_calls + end + def test_memoization_with_punctuation assert_equal true, @person.name? @@ -361,7 +388,7 @@ def test_all_memoized_structs # Student < Person memoize :name, :identifier => :student # Teacher < Person memoize :seniority - expected = %w[age age? is_developer? memoize_protected_test name name? sleep update update_attributes] + expected = %w[age age? do_with_special is_developer? memoize_protected_test name name? sleep update update_attributes] structs = Person.all_memoized_structs assert_equal expected, structs.collect(&:memoized_method).collect(&:to_s).sort assert_equal '@_memoized_name', structs.detect { |s| s.memoized_method == :name }.ivar