Module: Mize::Memoize
Overview
Memoization entry point, prepended into every ::Module by mize.rb.
Including this module (or relying on the global prepend) exposes
memoize, mize_cache_clear and mize_cache_clear_name on the
receiver. The heavy lifting is delegated to Mize::CacheMethods for
key/state management and Mize::Reload for cache invalidation.
Class Method Summary collapse
-
.compute_result(method_id, orig_method, key, context, args, kargs, freeze) ⇒ Object
private
Compute the real result of a memoized call.
Instance Method Summary collapse
-
#memoize(method: nil, function: nil, freeze: false, store_nil: true) ⇒ Symbol
Memoize either a
methodor afunction. -
#wrap_method(method_id, freeze: false, function: false, store_nil: true) ⇒ Symbol
private
Wrap
method_idwith a memoizing closure.
Methods included from CacheMethods
#__mize_cache__, #__mize_cache__=, #build_key, #build_key_prefix, #memoize_apply_visibility, #mize_cache_clear, #mize_cache_clear_name
Class Method Details
.compute_result(method_id, orig_method, key, context, args, kargs, freeze) ⇒ Object (private)
Compute the real result of a memoized call.
Binds orig_method to context and invokes it with args; when
running under $DEBUG a diagnostic line is emitted to STDERR.
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/mize/memoize.rb', line 72 def compute_result(method_id, orig_method, key, context, args, kargs, freeze) result = orig_method.bind(context).call(*args) if $DEBUG warn "#{context.class} cached method "\ "#{method_id}(#{[ args, kargs ].inspect unless args.size + kargs.size == 0}) = "\ "#{result.inspect} [#{__id__}]" end freeze and result.freeze rescue nil result end |
Instance Method Details
#memoize(method: nil, function: nil, freeze: false, store_nil: true) ⇒ Symbol
Memoize either a method or a function.
In the method case the memoized results do NOT ONLY depend on the
arguments, but ALSO on the object the method is called on (each object
keeps its own cache). In the function case the memoized results ONLY
depend on the arguments, and a single shared cache backs every call.
You must specify exactly one of method: or function:; passing both
or neither raises ArgumentError.
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/mize/memoize.rb', line 40 def memoize(method: nil, function: nil, freeze: false, store_nil: true) Mize.synchronize do if method && function raise ArgumentError, 'memoize a method xor a function' elsif method wrap_method method, freeze: freeze, store_nil: store_nil elsif function wrap_method function, function: true, freeze: freeze, store_nil: store_nil else raise ArgumentError, 'missing keyword: method/function' end end end |
#wrap_method(method_id, freeze: false, function: false, store_nil: true) ⇒ Symbol (private)
Wrap method_id with a memoizing closure.
Idempotency: a [self, method_id, function] target already present in
Mize.wrapped with identical freeze / store_nil options is a
no-op; conflicting options raise ArgumentError.
For instance methods (+function: false+) the receiver gets its own
per-object cache via Mize::CacheMethods and Mize::Reload is
prepended so reload invalidates entries. For bare functions a single
shared cache is used instead.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/mize/memoize.rb', line 102 def wrap_method(method_id, freeze: false, function: false, store_nil: true) verbose, $VERBOSE = $VERBOSE, nil if already_wrapped = Mize.wrapped[ [ self, method_id, function ] ] if already_wrapped == [ freeze, store_nil ] return method_id else raise ArgumentError, "encountered mismatching memoize declaration within #{self} for freeze, store_nil:"\ " #{already_wrapped} != #{ [ freeze, store_nil ] }" end end include CacheMethods function and mc = __mize_cache__ unless function prepend Mize::Reload end method_id = method_id.to_s.to_sym memoize_apply_visibility method_id do orig_method = instance_method(method_id) __send__(:define_method, method_id) do |*args, **kargs| function or mc = __mize_cache__ key = build_key(method_id, *args, **kargs) if mc.exist?(key) mc.read(key) else result = Mize::Memoize.send( :compute_result, method_id, orig_method, key, self, args, kargs, freeze ) if store_nil || !result.nil? mc.write(key, result) end result end end end Mize.wrapped[ [ self, method_id, function ] ] = [ freeze, store_nil ] method_id ensure $VERBOSE = verbose end |