|
1 | 1 | # frozen_string_literal: true
|
2 | 2 |
|
| 3 | +require "ruby2_keywords" |
| 4 | + |
3 | 5 | require "memery/version"
|
4 | 6 |
|
5 | 7 | module Memery
|
6 | 8 | class << self
|
7 |
| - def method_visibility(klass, method_name) |
8 |
| - case |
9 |
| - when klass.private_method_defined?(method_name) |
10 |
| - :private |
11 |
| - when klass.protected_method_defined?(method_name) |
12 |
| - :protected |
13 |
| - when klass.public_method_defined?(method_name) |
14 |
| - :public |
15 |
| - end |
16 |
| - end |
17 |
| - |
18 | 9 | def monotonic_clock
|
19 | 10 | Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
20 | 11 | end
|
@@ -48,39 +39,61 @@ def memoized?(method_name)
|
48 | 39 |
|
49 | 40 | def prepend_memery_module!
|
50 | 41 | return if defined?(@_memery_module)
|
51 |
| - @_memery_module = Module.new |
| 42 | + @_memery_module = Module.new do |
| 43 | + extend MemoizationModule |
| 44 | + end |
52 | 45 | prepend @_memery_module
|
53 | 46 | end
|
54 | 47 |
|
55 |
| - def define_memoized_method!(method_name, condition: nil, ttl: nil) |
56 |
| - visibility = Memery.method_visibility(self, method_name) |
57 |
| - raise ArgumentError, "Method #{method_name} is not defined on #{self}" unless visibility |
| 48 | + def define_memoized_method!(*args, **kwargs) |
| 49 | + @_memery_module.public_send __method__, self, *args, **kwargs |
| 50 | + end |
58 | 51 |
|
59 |
| - method_key = "#{method_name}_#{@_memery_module.object_id}" |
| 52 | + module MemoizationModule |
| 53 | + def define_memoized_method!(klass, method_name, condition: nil, ttl: nil) |
| 54 | + method_key = "#{method_name}_#{object_id}" |
60 | 55 |
|
61 |
| - # Change to regular call of `define_method` after Ruby 2.4 drop |
62 |
| - @_memery_module.send :define_method, method_name, (lambda do |*args, **kwargs, &block| |
63 |
| - if block || (condition && !instance_exec(&condition)) |
64 |
| - return kwargs.any? ? super(*args, **kwargs, &block) : super(*args, &block) |
65 |
| - end |
| 56 | + original_visibility = method_visibility(klass, method_name) |
66 | 57 |
|
67 |
| - args_key = [args, kwargs] |
| 58 | + define_method method_name do |*args, &block| |
| 59 | + if block || (condition && !instance_exec(&condition)) |
| 60 | + return super(*args, &block) |
| 61 | + end |
68 | 62 |
|
69 |
| - store = (@_memery_memoized_values ||= {})[method_key] ||= {} |
| 63 | + store = (@_memery_memoized_values ||= {})[method_key] ||= {} |
70 | 64 |
|
71 |
| - if store.key?(args_key) && |
72 |
| - (ttl.nil? || Memery.monotonic_clock <= store[args_key][:time] + ttl) |
73 |
| - return store[args_key][:result] |
| 65 | + if store.key?(args) && |
| 66 | + (ttl.nil? || Memery.monotonic_clock <= store[args][:time] + ttl) |
| 67 | + return store[args][:result] |
| 68 | + end |
| 69 | + |
| 70 | + result = super(*args) |
| 71 | + @_memery_memoized_values[method_key][args] = |
| 72 | + { result: result, time: Memery.monotonic_clock } |
| 73 | + result |
74 | 74 | end
|
75 | 75 |
|
76 |
| - result = kwargs.any? ? super(*args, **kwargs) : super(*args) |
77 |
| - @_memery_memoized_values[method_key][args_key] = |
78 |
| - { result: result, time: Memery.monotonic_clock } |
79 |
| - result |
80 |
| - end) |
| 76 | + ruby2_keywords method_name |
| 77 | + |
| 78 | + send original_visibility, method_name |
| 79 | + end |
81 | 80 |
|
82 |
| - @_memery_module.send(visibility, method_name) |
| 81 | + private |
| 82 | + |
| 83 | + def method_visibility(klass, method_name) |
| 84 | + if klass.private_method_defined?(method_name) |
| 85 | + :private |
| 86 | + elsif klass.protected_method_defined?(method_name) |
| 87 | + :protected |
| 88 | + elsif klass.public_method_defined?(method_name) |
| 89 | + :public |
| 90 | + else |
| 91 | + raise ArgumentError, "Method #{method_name} is not defined on #{klass}" |
| 92 | + end |
| 93 | + end |
83 | 94 | end
|
| 95 | + |
| 96 | + private_constant :MemoizationModule |
84 | 97 | end
|
85 | 98 |
|
86 | 99 | module InstanceMethods
|
|
0 commit comments