@@ -52,6 +52,12 @@ def self.included(klass)
5252
5353 # @api private
5454 class Memoizer < ::Module
55+ KERNEL = {
56+ signleton : ::Kernel . instance_method ( :singleton_class ) ,
57+ ivar_set : ::Kernel . instance_method ( :instance_variable_set ) ,
58+ frozen : ::Kernel . instance_method ( :frozen? )
59+ } . freeze
60+
5561 # @api private
5662 def initialize ( klass , names )
5763 super ( )
@@ -65,20 +71,44 @@ def initialize(klass, names)
6571 private
6672
6773 # @api private
68- def define_memoizable ( method :) # rubocop:disable Metrics/AbcSize
74+ # rubocop:disable Metrics/AbcSize
75+ # rubocop:disable Metrics/PerceivedComplexity
76+ def define_memoizable ( method :)
6977 parameters = method . parameters
78+ mod = self
79+ kernel = KERNEL
7080
7181 if parameters . empty?
72- key = method . name . hash
73- module_eval ( <<~RUBY , __FILE__ , __LINE__ + 1 )
74- def #{ method . name } # def slow_fetch
75- if @__memoized__.key?(#{ key } ) # if @__memoized__.key?(12345678)
76- @__memoized__[#{ key } ] # @__memoized__[12345678]
77- else # else
78- @__memoized__[#{ key } ] = super # @__memoized__[12345678] = super
79- end # end
80- end # end
81- RUBY
82+ key = method . name . hash . abs
83+
84+ define_method ( method . name ) do
85+ value = super ( )
86+
87+ if kernel [ :frozen ] . bind ( self ) . call
88+ mod . remove_method ( method . name )
89+ mod . module_eval ( <<~RUBY , __FILE__ , __LINE__ + 1 )
90+ def #{ method . name } # def slow_calc
91+ cached = @__memoized__[#{ key } ] # cached = @__memoized__[12345678]
92+ #
93+ if cached || @__memoized__.key?(#{ key } ) # if cached || @__memoized__.key?(12345678)
94+ cached # cached
95+ else # else
96+ @__memoized__[#{ key } ] = super # @__memoized__[12345678] = super
97+ end # end
98+ end # end
99+ RUBY
100+ else
101+ attr_name = :"__memozed_#{ key } __"
102+ ivar_name = :"@#{ attr_name } "
103+ kernel [ :ivar_set ] . bind ( self ) . ( ivar_name , value )
104+ eigenclass = kernel [ :signleton ] . bind ( self ) . call
105+ eigenclass . attr_reader ( attr_name )
106+ eigenclass . alias_method ( method . name , attr_name )
107+ eigenclass . remove_method ( attr_name )
108+ end
109+
110+ value
111+ end
82112 else
83113 mapping = parameters . to_h { |k , v = nil | [ k , v ] }
84114 params , binds = declaration ( parameters , mapping )
@@ -112,6 +142,8 @@ def #{method.name}(#{params.join(", ")}) # def slow_calc(arg1, a
112142 m
113143 end
114144 end
145+ # rubocop:enable Metrics/AbcSize
146+ # rubocop:enable Metrics/PerceivedComplexity
115147
116148 # @api private
117149 def declaration ( definition , lookup )
0 commit comments