Module: RedisMemo::MemoizeMethod
- Defined in:
- lib/redis_memo/memoize_method.rb
Class Method Summary collapse
-
.exclude_anonymous_args(depends_on, ref, args) ⇒ Object
We only look at named method parameters in the dependency block in order to define its dependent memos and ignore anonymous parameters, following the convention that nil or :_ is an anonymous parameter.
- .extract_dependencies(ref, *method_args, &depends_on) ⇒ Object
- .get_or_extract_dependencies(ref, *method_args, &depends_on) ⇒ Object
- .method_id(ref, method_name) ⇒ Object
Instance Method Summary collapse
Class Method Details
.exclude_anonymous_args(depends_on, ref, args) ⇒ Object
We only look at named method parameters in the dependency block in order to define its dependent memos and ignore anonymous parameters, following the convention that nil or :_ is an anonymous parameter. Example: “‘
def method(param1, param2)
end
memoize_method :method do |_, _, param2|`
depends_on RedisMemo::Memoizable.new(param2: param2)
end
“‘
`exclude_anonymous_args(depends_on, ref, [1, 2])` returns [2]
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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/redis_memo/memoize_method.rb', line 105 def self.exclude_anonymous_args(depends_on, ref, args) return [] if depends_on.parameters.empty? or args.empty? positional_args = [] kwargs = {} depends_on_args = [ref] + args = depends_on_args. # Keep track of the splat start index, and the number of positional args before and after the splat, # so we can map which args belong to positional args and which args belong to the splat. named_splat = false splat_index = nil num_positional_args_after_splat = 0 num_positional_args_before_splat = 0 depends_on.parameters.each_with_index do |param, i| # Defined by https://github.com/ruby/ruby/blob/22b8ddfd1049c3fd1e368684c4fd03bceb041b3a/proc.c#L3048-L3059 case param.first when :opt, :req if splat_index num_positional_args_after_splat += 1 else num_positional_args_before_splat += 1 end when :rest named_splat = is_named?(param) splat_index = i when :key, :keyreq kwargs[param.last] = [param.last] if is_named?(param) when :keyrest kwargs.merge!() if is_named?(param) else raise(RedisMemo::ArgumentError, "#{param.first} argument isn't supported in the dependency block") end end # Determine the named positional and splat arguments after we know the # of pos. arguments before and after splat after_splat_index = depends_on_args.size - num_positional_args_after_splat depends_on_args.each_with_index do |arg, i| # if the index is within the splat if i >= num_positional_args_before_splat && i < after_splat_index positional_args << arg if named_splat else j = i < num_positional_args_before_splat ? i : i - (after_splat_index - splat_index) - 1 positional_args << arg if is_named?(depends_on.parameters[j]) end end if !kwargs.empty? positional_args + [kwargs] elsif named_splat && !.empty? positional_args + [] else positional_args end end |
.extract_dependencies(ref, *method_args, &depends_on) ⇒ Object
74 75 76 77 78 79 80 |
# File 'lib/redis_memo/memoize_method.rb', line 74 def self.extract_dependencies(ref, *method_args, &depends_on) dependency = RedisMemo::Memoizable::Dependency.new # Resolve the dependency recursively dependency.instance_exec(ref, *method_args, &depends_on) dependency end |
.get_or_extract_dependencies(ref, *method_args, &depends_on) ⇒ Object
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/redis_memo/memoize_method.rb', line 82 def self.get_or_extract_dependencies(ref, *method_args, &depends_on) if RedisMemo::Cache.local_dependency_cache RedisMemo::Cache.local_dependency_cache[ref.class] ||= {} RedisMemo::Cache.local_dependency_cache[ref.class][depends_on] ||= {} named_args = exclude_anonymous_args(depends_on, ref, method_args) RedisMemo::Cache.local_dependency_cache[ref.class][depends_on][named_args] ||= extract_dependencies(ref, *method_args, &depends_on) else extract_dependencies(ref, *method_args, &depends_on) end end |
.method_id(ref, method_name) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/redis_memo/memoize_method.rb', line 67 def self.method_id(ref, method_name) is_class_method = ref.class == Class class_name = is_class_method ? ref.name : ref.class.name "#{class_name}#{is_class_method ? '::' : '#'}#{method_name}" end |
Instance Method Details
#memoize_method(method_name, method_id: nil, **options, &depends_on) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/redis_memo/memoize_method.rb', line 9 def memoize_method(method_name, method_id: nil, **, &depends_on) method_name_without_memo = :"_redis_memo_#{method_name}_without_memo" method_name_with_memo = :"_redis_memo_#{method_name}_with_memo" alias_method method_name_without_memo, method_name define_method method_name_with_memo do |*args| return send(method_name_without_memo, *args) if RedisMemo.without_memo? dependent_memos = nil if depends_on dependency = RedisMemo::MemoizeMethod.get_or_extract_dependencies(self, *args, &depends_on) dependent_memos = dependency.memos end future = RedisMemo::Future.new( self, case method_id when NilClass RedisMemo::MemoizeMethod.method_id(self, method_name) when String, Symbol method_id else method_id.call(self, *args) end, args, dependent_memos, , method_name_without_memo, ) if RedisMemo::Batch.current RedisMemo::Batch.current << future return future end future.execute rescue RedisMemo::WithoutMemoization send(method_name_without_memo, *args) end alias_method method_name, method_name_with_memo @__redis_memo_method_dependencies ||= Hash.new @__redis_memo_method_dependencies[method_name] = depends_on define_method :dependency_of do |method_name, *method_args| method_depends_on = self.class.instance_variable_get(:@__redis_memo_method_dependencies)[method_name] unless method_depends_on raise( RedisMemo::ArgumentError, "#{method_name} is not a memoized method" ) end RedisMemo::MemoizeMethod.get_or_extract_dependencies(self, *method_args, &method_depends_on) end end |