lib/memo_wise.rb in memo_wise-1.2.0 vs lib/memo_wise.rb in memo_wise-1.3.0
- old
+ new
@@ -54,11 +54,11 @@
# for more information.
#
# :nocov:
all_args = RUBY_VERSION < "2.7" ? "*" : "..."
# :nocov:
- class_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
+ class_eval <<~HEREDOC, __FILE__, __LINE__ + 1
# On Ruby 2.7 or greater:
#
# def initialize(...)
# MemoWise::InternalAPI.create_memo_wise_state!(self)
# super
@@ -73,11 +73,11 @@
def initialize(#{all_args})
MemoWise::InternalAPI.create_memo_wise_state!(self)
super
end
- END_OF_METHOD
+ HEREDOC
# @private
#
# Private setup method, called automatically by `prepend MemoWise` in a class.
#
@@ -154,10 +154,21 @@
# {Class#singleton_class}.
# See: https://medium.com/@leo_hetsch/demystifying-singleton-classes-in-ruby-caf3fa4c9d91
klass = klass.singleton_class
end
+ if klass.singleton_class?
+ # This ensures that a memoized method defined on a parent class can
+ # still be used in a child class.
+ klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
+ def inherited(subclass)
+ super
+ MemoWise::InternalAPI.create_memo_wise_state!(subclass)
+ end
+ HEREDOC
+ end
+
raise ArgumentError, "#{method_name.inspect} must be a Symbol" unless method_name.is_a?(Symbol)
api = MemoWise::InternalAPI.new(klass)
visibility = api.method_visibility(method_name)
original_memo_wised_name = MemoWise::InternalAPI.original_memo_wised_name(method_name)
@@ -165,53 +176,41 @@
klass.send(:alias_method, original_memo_wised_name, method_name)
klass.send(:private, original_memo_wised_name)
method_arguments = MemoWise::InternalAPI.method_arguments(method)
- # `@_memo_wise_indices` stores the `@_memo_wise` indices of different
- # method names. We only use this data structure when resetting or
- # presetting memoization. It looks like:
- # {
- # single_arg_method_name: 0,
- # other_single_arg_method_name: 1
- # }
- memo_wise_indices = klass.instance_variable_get(:@_memo_wise_indices)
- memo_wise_indices ||= klass.instance_variable_set(:@_memo_wise_indices, {})
- index = klass.instance_variable_get(:@_memo_wise_index_counter) || 0
+ index = MemoWise::InternalAPI.next_index!(klass, method_name)
- memo_wise_indices[method_name] = index
- klass.instance_variable_set(:@_memo_wise_index_counter, index + 1)
-
case method_arguments
when MemoWise::InternalAPI::NONE
# Zero-arg methods can use simpler/more performant logic because the
# hash key is just the method name.
- klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
+ klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
def #{method_name}
- _memo_wise_output = @_memo_wise[#{index}]
- if _memo_wise_output || @_memo_wise_sentinels[#{index}]
- _memo_wise_output
+ if @_memo_wise_sentinels[#{index}]
+ @_memo_wise[#{index}]
else
+ ret = @_memo_wise[#{index}] = #{original_memo_wised_name}
@_memo_wise_sentinels[#{index}] = true
- @_memo_wise[#{index}] = #{original_memo_wised_name}
+ ret
end
end
- END_OF_METHOD
+ HEREDOC
when MemoWise::InternalAPI::ONE_REQUIRED_POSITIONAL, MemoWise::InternalAPI::ONE_REQUIRED_KEYWORD
key = method.parameters.first.last
- klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
+ klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
_memo_wise_hash = (@_memo_wise[#{index}] ||= {})
_memo_wise_output = _memo_wise_hash[#{key}]
if _memo_wise_output || _memo_wise_hash.key?(#{key})
_memo_wise_output
else
_memo_wise_hash[#{key}] = #{original_memo_wised_name}(#{MemoWise::InternalAPI.call_str(method)})
end
end
- END_OF_METHOD
+ HEREDOC
# MemoWise::InternalAPI::MULTIPLE_REQUIRED, MemoWise::InternalAPI::SPLAT,
# MemoWise::InternalAPI::DOUBLE_SPLAT, MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
else
# NOTE: When benchmarking this implementation against something like:
#
@@ -223,21 +222,21 @@
# is because this case uses a more complex hash key (see
# `MemoWise::InternalAPI.key_str`), and hashing that key has less
# consistent performance. In general, this should still be faster for
# truthy results because `Hash#[]` generally performs hash lookups
# faster than `Hash#fetch`.
- klass.module_eval <<-END_OF_METHOD, __FILE__, __LINE__ + 1
+ klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
_memo_wise_hash = (@_memo_wise[#{index}] ||= {})
_memo_wise_key = #{MemoWise::InternalAPI.key_str(method)}
_memo_wise_output = _memo_wise_hash[_memo_wise_key]
if _memo_wise_output || _memo_wise_hash.key?(_memo_wise_key)
_memo_wise_output
else
_memo_wise_hash[_memo_wise_key] = #{original_memo_wised_name}(#{MemoWise::InternalAPI.call_str(method)})
end
end
- END_OF_METHOD
+ HEREDOC
end
klass.send(visibility, method_name)
end
end