class Dry::Core::Memoizable::Memoizer
@api private
Public Class Methods
new(klass, names)
click to toggle source
@api private
Calls superclass method
# File lib/dry/core/memoizable.rb, line 56 def initialize(klass, names) super() names.each do |name| define_memoizable( method: klass.instance_method(name) ) end end
Private Instance Methods
declaration(definition, lookup)
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 117 def declaration(definition, lookup) params = [] binds = [] defined = {} definition.each do |type, name| mapped_type = map_bind_type(type, name, lookup, defined) do raise ::NotImplementedError, "type: #{type}, name: #{name}" end if mapped_type defined[mapped_type] = true bind = name_from_param(name) || make_bind_name(binds.size) binds << bind params << param(bind, mapped_type) end end [params, binds] end
define_memoizable(method:)
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 68 def define_memoizable(method:) # rubocop:disable Metrics/AbcSize parameters = method.parameters if parameters.empty? key = method.name.hash module_eval(<<~RUBY, __FILE__, __LINE__ + 1) def #{method.name} # def slow_fetch if @__memoized__.key?(#{key}) # if @__memoized__.key?(12345678) @__memoized__[#{key}] # @__memoized__[12345678] else # else @__memoized__[#{key}] = super # @__memoized__[12345678] = super end # end end # end RUBY else mapping = parameters.to_h { |k, v = nil| [k, v] } params, binds = declaration(parameters, mapping) last_param = parameters.last if last_param[0].eql?(:block) && !last_param[1].eql?(:&) Deprecations.warn(<<~WARN) Memoization for block-accepting methods isn't safe. Every call creates a new block instance bloating cached results. In the future, blocks will still be allowed but won't participate in cache key calculation. WARN end m = module_eval(<<~RUBY, __FILE__, __LINE__ + 1) def #{method.name}(#{params.join(", ")}) # def slow_calc(arg1, arg2, arg3) key = [:"#{method.name}", #{binds.join(", ")}].hash # [:slow_calc, arg1, arg2, arg3].hash # if @__memoized__.key?(key) # if @__memoized__.key?(key) @__memoized__[key] # @__memoized__[key] else # else @__memoized__[key] = super # @__memoized__[key] = super end # end end # end RUBY if respond_to?(:ruby2_keywords, true) && mapping.key?(:reyrest) ruby2_keywords(method.name) end m end end
make_bind_name(idx)
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 149 def make_bind_name(idx) :"__lv_#{idx}__" end
map_bind_type(type, name, original_params, defined_types) { || ... }
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 154 def map_bind_type(type, name, original_params, defined_types) # rubocop:disable Metrics/PerceivedComplexity case type when :req :reqular when :rest, :keyreq, :keyrest type when :block if name.eql?(:&) # most likely this is a case of delegation # rather than actual block nil else type end when :opt if original_params.key?(:rest) || defined_types[:rest] nil else :rest end when :key if original_params.key?(:keyrest) || defined_types[:keyrest] nil else :keyrest end else yield end end
name_from_param(name)
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 140 def name_from_param(name) if PARAM_PLACEHOLDERS.include?(name) nil else name end end
param(name, type)
click to toggle source
@api private
# File lib/dry/core/memoizable.rb, line 186 def param(name, type) case type when :reqular name when :rest "*#{name}" when :keyreq "#{name}:" when :keyrest "**#{name}" when :block "&#{name}" end end