lib/memo_wise.rb in memo_wise-0.3.0 vs lib/memo_wise.rb in memo_wise-0.4.0
- old
+ new
@@ -37,15 +37,45 @@
# This approach supports memoization on frozen (immutable) objects -- for
# example, classes created by the
# [Values](https://github.com/tcrayford/Values)
# [gem](https://rubygems.org/gems/values).
#
- def initialize(*)
- MemoWise.create_memo_wise_state!(self)
- super
- end
+ # To support syntax differences with keyword and positional arguments starting
+ # with ruby 2.7, we have to set up the initializer with some slightly
+ # different syntax for the different versions. This variance in syntax is not
+ # included in coverage reports since the branch chosen will never differ
+ # within a single ruby version. This means it is impossible for us to get
+ # 100% coverage of this line within a single CI run.
+ #
+ # See
+ # [this article](https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/)
+ # for more information.
+ #
+ # :nocov:
+ all_args = RUBY_VERSION < "2.7" ? "*" : "..."
+ # :nocov:
+ class_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
+ # On Ruby 2.7 or greater:
+ #
+ # def initialize(...)
+ # MemoWise.create_memo_wise_state!(self)
+ # super
+ # end
+ #
+ # On Ruby 2.6 or lower:
+ #
+ # def initialize(*)
+ # MemoWise.create_memo_wise_state!(self)
+ # super
+ # end
+ def initialize(#{all_args})
+ MemoWise.create_memo_wise_state!(self)
+ super
+ end
+ END_OF_METHOD
+
# @private
#
# Determine whether `method` takes any *positional* args.
#
# These are the types of positional args:
@@ -180,14 +210,11 @@
# Object in which to create mutable state to store future memoized values
#
# @return [Object] the passed-in obj
def self.create_memo_wise_state!(obj)
unless obj.instance_variables.include?(:@_memo_wise)
- obj.instance_variable_set(
- :@_memo_wise,
- Hash.new { |h, k| h[k] = {} }
- )
+ obj.instance_variable_set(:@_memo_wise, {})
end
obj
end
@@ -267,11 +294,11 @@
# Zero-arg methods can use simpler/more performant logic because the
# hash key is just the method name.
if method.arity.zero?
klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
# def foo
- # @_memo_wise.fetch(:foo}) do
+ # @_memo_wise.fetch(:foo) do
# @_memo_wise[:foo] = _memo_wise_original_foo
# end
# end
def #{method_name}
@@ -301,18 +328,22 @@
# Note that we don't need to freeze args before using it as a hash key
# because Ruby always copies argument arrays when splatted.
klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
# def foo(*args, **kwargs)
- # hash = @_memo_wise[:foo]
+ # hash = @_memo_wise.fetch(:foo) do
+ # @_memo_wise[:foo] = {}
+ # end
# hash.fetch([args, kwargs].freeze) do
# hash[[args, kwargs].freeze] = _memo_wise_original_foo(*args, **kwargs)
# end
# end
def #{method_name}#{args_str}
- hash = @_memo_wise[:#{method_name}]
+ hash = @_memo_wise.fetch(:#{method_name}) do
+ @_memo_wise[:#{method_name}] = {}
+ end
hash.fetch(#{fetch_key}) do
hash[#{fetch_key}] = #{original_memo_wised_name}#{args_str}
end
end
END_OF_METHOD
@@ -371,11 +402,11 @@
#
# NOTE: Currently, no attempt is made to validate that the given arguments are
# valid for the given method.
#
# @param method_name [Symbol]
- # Name of a method previously setup with `#memo_wise`.
+ # Name of a method previously set up with `#memo_wise`.
#
# @param args [Array]
# (Optional) If the method takes positional args, these are the values of
# position args for which the given block's result will be preset as the
# memoized result.
@@ -422,11 +453,14 @@
validate_params!(method_name, args)
if method(method_name).arity.zero?
@_memo_wise[method_name] = yield
else
- @_memo_wise[method_name][fetch_key(method_name, *args, **kwargs)] = yield
+ hash = @_memo_wise.fetch(method_name) do
+ @_memo_wise[method_name] = {}
+ end
+ hash[fetch_key(method_name, *args, **kwargs)] = yield
end
end
# Resets memoized results of a given method, or all methods.
#
@@ -447,11 +481,11 @@
#
# - If *not* given `method_name`:
# - Resets all memoized results of calling *all methods*.
#
# @param method_name [Symbol, nil]
- # (Optional) Name of a method previously setup with `#memo_wise`. If not
+ # (Optional) Name of a method previously set up with `#memo_wise`. If not
# given, will reset *all* memoized results for *all* methods.
#
# @param args [Array]
# (Optional) If the method takes positional args, these are the values of
# position args for which the memoized result will be reset.
@@ -519,10 +553,10 @@
validate_memo_wised!(method_name)
if args.empty? && kwargs.empty?
@_memo_wise.delete(method_name)
else
- @_memo_wise[method_name].delete(fetch_key(method_name, *args, **kwargs))
+ @_memo_wise[method_name]&.delete(fetch_key(method_name, *args, **kwargs))
end
end
private