safe_memoize 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -1
- data/lib/safe_memoize/cache_metrics_methods.rb +4 -4
- data/lib/safe_memoize/cache_record_methods.rb +1 -0
- data/lib/safe_memoize/cache_store_methods.rb +2 -2
- data/lib/safe_memoize/class_methods.rb +59 -25
- data/lib/safe_memoize/lru_methods.rb +5 -0
- data/lib/safe_memoize/public_methods.rb +17 -2
- data/lib/safe_memoize/version.rb +1 -1
- data/sig/safe_memoize.rbs +10 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c378e971e08b2de42905d7cb00f76b4312c7c7fd596857eb051ee311a0690aed
|
|
4
|
+
data.tar.gz: c0bae56bbdca32caa3b9fa4ff8f0707728e9571298a8dfcb377f9937fe0b8586
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8185afdd3cf81fec90dc3dd02656f394d2d60385d6b6b015b66034c898600c8c68cd20712c5e4ad51ec0957f4bf168d01b5694b1cae036823d01ac17b9d87ffb
|
|
7
|
+
data.tar.gz: 2e37ee4fcf6b57d5deb2fa252b140cb1d1e20ff67d4ad06444ceae6e075eb7699a662010254a22d5322121febe7cc72a520947432ee16bf6077729f71fe758fb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-05-17
|
|
4
|
+
|
|
5
|
+
- Fix TTL clock starting at `memoize` definition time instead of first method call
|
|
6
|
+
- Fix metrics key silently dropping kwargs, causing methods that differ only in kwargs to share a metrics bucket
|
|
7
|
+
- Fix stale LRU references remaining after expired entries are pruned
|
|
8
|
+
- Add `ttl:` option to `warm_memo` so warmed entries can be given an expiry
|
|
9
|
+
- Add `max_size:` support for `shared: true` memoization (class-level LRU eviction)
|
|
10
|
+
- Add `ttl_refresh: true` option on `memoize` for sliding window TTL — resets expiry on every cache hit
|
|
11
|
+
- Add `include_protected:` and `include_private:` options to `memoize_all`
|
|
12
|
+
- Add `memo_ttl_remaining` for TTL introspection — returns seconds until expiry, `nil` for no TTL, `0` for uncached/expired
|
|
13
|
+
|
|
3
14
|
## [0.5.0] - 2026-05-17
|
|
4
15
|
|
|
5
16
|
- Drop support for Ruby 3.2 (EOL); minimum required version is now Ruby 3.3
|
|
@@ -15,7 +26,7 @@
|
|
|
15
26
|
- All instances share one cache; the method is computed only once regardless of how many objects exist
|
|
16
27
|
- Class-level invalidation: `reset_shared_memo`, `reset_all_shared_memos`
|
|
17
28
|
- Class-level inspection: `shared_memoized?`, `shared_memo_count`
|
|
18
|
-
|
|
29
|
+
- Supports `ttl:`, `if:`, and `unless:` options
|
|
19
30
|
- Instance hooks (`on_memo_hit`, `on_memo_miss`, `on_memo_expire`) fire on the calling instance
|
|
20
31
|
- Add `memoize_all` to memoize every public method defined on the class in one call
|
|
21
32
|
- Accepts all options supported by `memoize` (`ttl:`, `max_size:`, `if:`, `unless:`)
|
|
@@ -8,15 +8,15 @@ module SafeMemoize
|
|
|
8
8
|
@__safe_memo_metrics__ ||= {}
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def record_cache_hit(method_name, args)
|
|
12
|
-
cache_key = safe_memo_cache_key(method_name, args,
|
|
11
|
+
def record_cache_hit(method_name, args, kwargs)
|
|
12
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
13
13
|
metrics = memo_metrics_store
|
|
14
14
|
metrics[cache_key] ||= {hits: 0, misses: 0, total_time: 0.0}
|
|
15
15
|
metrics[cache_key][:hits] += 1
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def record_cache_miss(method_name, args, computation_time)
|
|
19
|
-
cache_key = safe_memo_cache_key(method_name, args,
|
|
18
|
+
def record_cache_miss(method_name, args, kwargs, computation_time)
|
|
19
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
20
20
|
metrics = memo_metrics_store
|
|
21
21
|
metrics[cache_key] ||= {hits: 0, misses: 0, total_time: 0.0}
|
|
22
22
|
metrics[cache_key][:misses] += 1
|
|
@@ -39,7 +39,7 @@ module SafeMemoize
|
|
|
39
39
|
memo_record_value(record)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def memo_fetch_or_store(cache_key,
|
|
42
|
+
def memo_fetch_or_store(cache_key, ttl: nil)
|
|
43
43
|
memo_mutex!.synchronize do
|
|
44
44
|
@__safe_memo_cache__ ||= {}
|
|
45
45
|
|
|
@@ -49,7 +49,7 @@ module SafeMemoize
|
|
|
49
49
|
memo_record_value(record)
|
|
50
50
|
else
|
|
51
51
|
value = yield
|
|
52
|
-
@__safe_memo_cache__[cache_key] = memo_record(value, expires_at:
|
|
52
|
+
@__safe_memo_cache__[cache_key] = memo_record(value, expires_at: memo_expires_at(ttl))
|
|
53
53
|
|
|
54
54
|
value
|
|
55
55
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module SafeMemoize
|
|
4
4
|
module ClassMethods
|
|
5
|
-
def memoize(method_name, ttl: nil, max_size: nil, if: nil, unless: nil, shared: false)
|
|
5
|
+
def memoize(method_name, ttl: nil, max_size: nil, ttl_refresh: false, if: nil, unless: nil, shared: false)
|
|
6
6
|
method_name = method_name.to_sym
|
|
7
7
|
visibility = memoized_method_visibility(method_name)
|
|
8
8
|
|
|
@@ -12,6 +12,7 @@ module SafeMemoize
|
|
|
12
12
|
ttl = if ttl.nil?
|
|
13
13
|
nil
|
|
14
14
|
else
|
|
15
|
+
|
|
15
16
|
ttl = Float(ttl)
|
|
16
17
|
raise ArgumentError, "ttl must be non-negative" if ttl < 0
|
|
17
18
|
|
|
@@ -27,7 +28,7 @@ module SafeMemoize
|
|
|
27
28
|
max_size
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
raise ArgumentError, "
|
|
31
|
+
raise ArgumentError, "ttl_refresh: requires a ttl: to be set" if ttl_refresh && ttl.nil?
|
|
31
32
|
|
|
32
33
|
if cond_if && cond_unless
|
|
33
34
|
raise ArgumentError, "cannot specify both :if and :unless"
|
|
@@ -42,8 +43,6 @@ module SafeMemoize
|
|
|
42
43
|
->(result) { !cond_unless.call(result) }
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
expires_at = ttl && Process.clock_gettime(Process::CLOCK_MONOTONIC) + ttl
|
|
46
|
-
|
|
47
46
|
if shared
|
|
48
47
|
klass = self
|
|
49
48
|
shared_mutex = klass.send(:__safe_memo_shared_mutex__)
|
|
@@ -61,7 +60,13 @@ module SafeMemoize
|
|
|
61
60
|
record_live = record && (record[:expires_at].nil? || record[:expires_at] > now)
|
|
62
61
|
|
|
63
62
|
if record_live
|
|
64
|
-
|
|
63
|
+
if max_size
|
|
64
|
+
lru = klass.send(:__safe_memo_shared_lru_order__)[method_name] ||= {}
|
|
65
|
+
lru.delete(cache_key)
|
|
66
|
+
lru[cache_key] = true
|
|
67
|
+
end
|
|
68
|
+
record[:expires_at] = memo_expires_at(ttl) if ttl_refresh
|
|
69
|
+
record_cache_hit(method_name, args, kwargs)
|
|
65
70
|
call_memo_hooks(:on_hit, cache_key, record)
|
|
66
71
|
record[:value]
|
|
67
72
|
else
|
|
@@ -71,10 +76,27 @@ module SafeMemoize
|
|
|
71
76
|
value = super(*args, **kwargs)
|
|
72
77
|
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
73
78
|
|
|
74
|
-
new_record = {value: value, expires_at:
|
|
75
|
-
shared_cache[cache_key] = new_record unless condition && !condition.call(value)
|
|
79
|
+
new_record = {value: value, expires_at: memo_expires_at(ttl)}
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
if !condition || condition.call(value)
|
|
82
|
+
if max_size
|
|
83
|
+
lru = klass.send(:__safe_memo_shared_lru_order__)[method_name] ||= {}
|
|
84
|
+
lru.delete_if { |key, _| !shared_cache.key?(key) }
|
|
85
|
+
if lru.size >= max_size
|
|
86
|
+
lru_key = lru.keys.first
|
|
87
|
+
lru.delete(lru_key)
|
|
88
|
+
evicted = shared_cache.delete(lru_key)
|
|
89
|
+
call_memo_hooks(:on_evict, lru_key, evicted) if evicted
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
shared_cache[cache_key] = new_record
|
|
93
|
+
if max_size
|
|
94
|
+
lru = klass.send(:__safe_memo_shared_lru_order__)[method_name] ||= {}
|
|
95
|
+
lru[cache_key] = true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
78
100
|
call_memo_hooks(:on_miss, cache_key, new_record)
|
|
79
101
|
|
|
80
102
|
value
|
|
@@ -97,13 +119,14 @@ module SafeMemoize
|
|
|
97
119
|
|
|
98
120
|
cache_key = compute_cache_key(method_name, args, kwargs)
|
|
99
121
|
|
|
100
|
-
if max_size || condition
|
|
101
|
-
# Locked path: used when LRU tracking
|
|
122
|
+
if max_size || condition || ttl_refresh
|
|
123
|
+
# Locked path: used when LRU tracking, conditional storage, or TTL refresh is needed.
|
|
102
124
|
memo_mutex!.synchronize do
|
|
103
125
|
record = memo_cache_record(cache_key)
|
|
104
126
|
if record
|
|
105
127
|
lru_touch(method_name, cache_key) if max_size
|
|
106
|
-
|
|
128
|
+
record[:expires_at] = memo_expires_at(ttl) if ttl_refresh
|
|
129
|
+
record_cache_hit(method_name, args, kwargs)
|
|
107
130
|
call_memo_hooks(:on_hit, cache_key, record)
|
|
108
131
|
memo_record_value(record)
|
|
109
132
|
else
|
|
@@ -111,14 +134,14 @@ module SafeMemoize
|
|
|
111
134
|
value = super(*args, **kwargs)
|
|
112
135
|
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
113
136
|
|
|
114
|
-
new_record = memo_record(value, expires_at:
|
|
137
|
+
new_record = memo_record(value, expires_at: memo_expires_at(ttl))
|
|
115
138
|
if !condition || condition.call(value)
|
|
116
139
|
lru_evict_if_over_limit(method_name, max_size) if max_size
|
|
117
140
|
@__safe_memo_cache__ ||= {}
|
|
118
141
|
@__safe_memo_cache__[cache_key] = new_record
|
|
119
142
|
lru_touch(method_name, cache_key) if max_size
|
|
120
143
|
end
|
|
121
|
-
record_cache_miss(method_name, args, elapsed_time)
|
|
144
|
+
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
122
145
|
call_memo_hooks(:on_miss, cache_key, new_record)
|
|
123
146
|
|
|
124
147
|
value
|
|
@@ -127,18 +150,18 @@ module SafeMemoize
|
|
|
127
150
|
else
|
|
128
151
|
# Fast path: check without lock
|
|
129
152
|
if (record = memo_cache_record(cache_key))
|
|
130
|
-
record_cache_hit(method_name, args)
|
|
153
|
+
record_cache_hit(method_name, args, kwargs)
|
|
131
154
|
call_memo_hooks(:on_hit, cache_key, record)
|
|
132
155
|
return memo_record_value(record)
|
|
133
156
|
end
|
|
134
157
|
|
|
135
158
|
# Cache miss - compute and store
|
|
136
159
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
137
|
-
result = memo_fetch_or_store(cache_key,
|
|
160
|
+
result = memo_fetch_or_store(cache_key, ttl: ttl) { super(*args, **kwargs) }
|
|
138
161
|
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
139
162
|
|
|
140
163
|
with_memo_lock do
|
|
141
|
-
record_cache_miss(method_name, args, elapsed_time)
|
|
164
|
+
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
142
165
|
new_record = memo_cache_record(cache_key)
|
|
143
166
|
call_memo_hooks(:on_miss, cache_key, new_record)
|
|
144
167
|
end
|
|
@@ -155,21 +178,23 @@ module SafeMemoize
|
|
|
155
178
|
|
|
156
179
|
def reset_shared_memo(method_name, *args, **kwargs)
|
|
157
180
|
method_name = method_name.to_sym
|
|
158
|
-
|
|
159
|
-
->(key) { key[0] == method_name }
|
|
160
|
-
else
|
|
161
|
-
cache_key = [method_name, args, kwargs]
|
|
162
|
-
->(key) { key == cache_key }
|
|
163
|
-
end
|
|
181
|
+
specific_key = (args.empty? && kwargs.empty?) ? nil : [method_name, args, kwargs]
|
|
164
182
|
|
|
165
183
|
__safe_memo_shared_mutex__.synchronize do
|
|
166
|
-
|
|
184
|
+
if specific_key
|
|
185
|
+
__safe_memo_shared_cache__.delete(specific_key)
|
|
186
|
+
__safe_memo_shared_lru_order__[method_name]&.delete(specific_key)
|
|
187
|
+
else
|
|
188
|
+
__safe_memo_shared_cache__.delete_if { |key, _| key[0] == method_name }
|
|
189
|
+
__safe_memo_shared_lru_order__.delete(method_name)
|
|
190
|
+
end
|
|
167
191
|
end
|
|
168
192
|
end
|
|
169
193
|
|
|
170
194
|
def reset_all_shared_memos
|
|
171
195
|
__safe_memo_shared_mutex__.synchronize do
|
|
172
196
|
@__safe_memo_shared_cache__ = {}
|
|
197
|
+
@__safe_memo_shared_lru_order__ = {}
|
|
173
198
|
end
|
|
174
199
|
end
|
|
175
200
|
|
|
@@ -197,9 +222,14 @@ module SafeMemoize
|
|
|
197
222
|
end
|
|
198
223
|
end
|
|
199
224
|
|
|
200
|
-
def memoize_all(except: [], **options)
|
|
225
|
+
def memoize_all(except: [], include_protected: false, include_private: false, **options)
|
|
201
226
|
excluded = Array(except).map(&:to_sym)
|
|
202
|
-
|
|
227
|
+
|
|
228
|
+
methods = public_instance_methods(false)
|
|
229
|
+
methods |= protected_instance_methods(false) if include_protected
|
|
230
|
+
methods |= private_instance_methods(false) if include_private
|
|
231
|
+
|
|
232
|
+
methods.each do |method_name|
|
|
203
233
|
next if excluded.include?(method_name)
|
|
204
234
|
|
|
205
235
|
memoize(method_name, **options)
|
|
@@ -216,6 +246,10 @@ module SafeMemoize
|
|
|
216
246
|
@__safe_memo_shared_mutex__ ||= Mutex.new
|
|
217
247
|
end
|
|
218
248
|
|
|
249
|
+
def __safe_memo_shared_lru_order__
|
|
250
|
+
@__safe_memo_shared_lru_order__ ||= {}
|
|
251
|
+
end
|
|
252
|
+
|
|
219
253
|
def memoized_method_visibility(method_name)
|
|
220
254
|
return :private if private_method_defined?(method_name)
|
|
221
255
|
return :protected if protected_method_defined?(method_name)
|
|
@@ -38,6 +38,11 @@ module SafeMemoize
|
|
|
38
38
|
call_memo_hooks(:on_evict, lru_cache_key, record) if record
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
# Remove a single cache key from LRU tracking. Called when an entry expires.
|
|
42
|
+
def lru_remove(method_name, cache_key)
|
|
43
|
+
lru_order_store[method_name]&.delete(cache_key)
|
|
44
|
+
end
|
|
45
|
+
|
|
41
46
|
# Clear all LRU tracking state. Called by reset_all_memos.
|
|
42
47
|
def lru_clear_all
|
|
43
48
|
@__safe_memo_lru_order__ = {}
|
|
@@ -12,6 +12,21 @@ module SafeMemoize
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def memo_ttl_remaining(method_name, *args, **kwargs)
|
|
16
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
17
|
+
|
|
18
|
+
with_memo_lock do
|
|
19
|
+
record = memo_cache_record(cache_key)
|
|
20
|
+
return 0 unless record
|
|
21
|
+
|
|
22
|
+
expires_at = record[:expires_at]
|
|
23
|
+
return nil unless expires_at
|
|
24
|
+
|
|
25
|
+
remaining = expires_at - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
26
|
+
(remaining > 0) ? remaining.round(6) : 0
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
15
30
|
def memo_count(*method_name)
|
|
16
31
|
scoped_method = safe_memo_scoped_method(method_name)
|
|
17
32
|
|
|
@@ -66,7 +81,7 @@ module SafeMemoize
|
|
|
66
81
|
end
|
|
67
82
|
end
|
|
68
83
|
|
|
69
|
-
def warm_memo(method_name, *args, **kwargs, &block)
|
|
84
|
+
def warm_memo(method_name, *args, ttl: nil, **kwargs, &block)
|
|
70
85
|
raise ArgumentError, "block required" unless block
|
|
71
86
|
|
|
72
87
|
method_name = method_name.to_sym
|
|
@@ -75,7 +90,7 @@ module SafeMemoize
|
|
|
75
90
|
|
|
76
91
|
with_memo_lock do
|
|
77
92
|
@__safe_memo_cache__ ||= {}
|
|
78
|
-
@__safe_memo_cache__[cache_key] = memo_record(value, expires_at:
|
|
93
|
+
@__safe_memo_cache__[cache_key] = memo_record(value, expires_at: memo_expires_at(ttl))
|
|
79
94
|
end
|
|
80
95
|
|
|
81
96
|
value
|
data/lib/safe_memoize/version.rb
CHANGED
data/sig/safe_memoize.rbs
CHANGED
|
@@ -11,12 +11,13 @@ module SafeMemoize
|
|
|
11
11
|
@__safe_memo_mutex__: Mutex?
|
|
12
12
|
@__safe_memo_shared_cache__: Hash[memo_key, memo_record]?
|
|
13
13
|
@__safe_memo_shared_mutex__: Mutex?
|
|
14
|
+
@__safe_memo_shared_lru_order__: Hash[Symbol, Hash[memo_key, true]]?
|
|
14
15
|
|
|
15
16
|
def self.prepended: (Class base) -> void
|
|
16
17
|
|
|
17
18
|
module ClassMethods
|
|
18
|
-
def memoize: (Symbol | String method_name, ?ttl: Numeric?, ?max_size: Integer?, ?if: (^(untyped result) -> boolish)?, ?unless: (^(untyped result) -> boolish)?, ?shared: bool) -> void
|
|
19
|
-
def memoize_all: (?except: Array[Symbol | String], ?ttl: Numeric?, ?max_size: Integer?, ?if: (^(untyped result) -> boolish)?, ?unless: (^(untyped result) -> boolish)?) -> void
|
|
19
|
+
def memoize: (Symbol | String method_name, ?ttl: Numeric?, ?max_size: Integer?, ?ttl_refresh: bool, ?if: (^(untyped result) -> boolish)?, ?unless: (^(untyped result) -> boolish)?, ?shared: bool) -> void
|
|
20
|
+
def memoize_all: (?except: Array[Symbol | String], ?include_protected: bool, ?include_private: bool, ?ttl: Numeric?, ?max_size: Integer?, ?if: (^(untyped result) -> boolish)?, ?unless: (^(untyped result) -> boolish)?) -> void
|
|
20
21
|
def reset_shared_memo: (Symbol | String method_name, *untyped args, **untyped kwargs) -> void
|
|
21
22
|
def reset_all_shared_memos: () -> void
|
|
22
23
|
def shared_memoized?: (Symbol | String method_name, *untyped args, **untyped kwargs) -> bool
|
|
@@ -26,6 +27,7 @@ module SafeMemoize
|
|
|
26
27
|
|
|
27
28
|
def __safe_memo_shared_cache__: () -> Hash[memo_key, memo_record]
|
|
28
29
|
def __safe_memo_shared_mutex__: () -> Mutex
|
|
30
|
+
def __safe_memo_shared_lru_order__: () -> Hash[Symbol, Hash[memo_key, true]]
|
|
29
31
|
def memoized_method_visibility: (Symbol method_name) -> Symbol
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -33,6 +35,7 @@ module SafeMemoize
|
|
|
33
35
|
@__safe_memo_cache__: Hash[memo_key, memo_record]?
|
|
34
36
|
|
|
35
37
|
def memoized?: (Symbol | String method_name, *untyped args, **untyped kwargs) ?{ () -> untyped } -> bool
|
|
38
|
+
def memo_ttl_remaining: (Symbol | String method_name, *untyped args, **untyped kwargs) -> (Float | Integer | nil)
|
|
36
39
|
def memo_count: (*untyped method_name) -> Integer
|
|
37
40
|
def memo_keys: (*untyped method_name) -> Array[untyped]
|
|
38
41
|
def memo_values: (*untyped method_name) -> Array[untyped]
|
|
@@ -41,7 +44,7 @@ module SafeMemoize
|
|
|
41
44
|
def on_memo_hit: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
42
45
|
def on_memo_miss: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
43
46
|
def clear_memo_hooks: (Symbol? hook_type) -> void
|
|
44
|
-
def warm_memo: (Symbol | String method_name, *untyped args, **untyped kwargs) { () -> untyped } -> untyped
|
|
47
|
+
def warm_memo: (Symbol | String method_name, *untyped args, ?ttl: Numeric?, **untyped kwargs) { () -> untyped } -> untyped
|
|
45
48
|
def dump_memo: (?Symbol | String method_name) -> Hash[memo_key, untyped]
|
|
46
49
|
def load_memo: (Hash[memo_key, untyped] snapshot) -> nil
|
|
47
50
|
def reset_memo: (Symbol | String method_name, *untyped args, **untyped kwargs) -> void
|
|
@@ -59,7 +62,7 @@ module SafeMemoize
|
|
|
59
62
|
def memo_cache_hit?: (memo_key cache_key) -> bool
|
|
60
63
|
def memo_cache_record: (memo_key cache_key) -> memo_record?
|
|
61
64
|
def memo_cache_read: (memo_key cache_key) -> untyped?
|
|
62
|
-
def memo_fetch_or_store: (memo_key cache_key) { () -> untyped } -> untyped
|
|
65
|
+
def memo_fetch_or_store: (memo_key cache_key, ?ttl: Float?) { () -> untyped } -> untyped
|
|
63
66
|
def memo_mutex!: () -> Mutex
|
|
64
67
|
def with_memo_cache: { (Hash[memo_key, memo_record] cache) -> untyped } -> untyped?
|
|
65
68
|
end
|
|
@@ -105,8 +108,8 @@ module SafeMemoize
|
|
|
105
108
|
private
|
|
106
109
|
|
|
107
110
|
def memo_metrics_store: () -> Hash[memo_key, { hits: Integer, misses: Integer, total_time: Float }]
|
|
108
|
-
def record_cache_hit: (Symbol method_name, Array[untyped] args) -> void
|
|
109
|
-
def record_cache_miss: (Symbol method_name, Array[untyped] args, Float computation_time) -> void
|
|
111
|
+
def record_cache_hit: (Symbol method_name, Array[untyped] args, Hash[Symbol, untyped] kwargs) -> void
|
|
112
|
+
def record_cache_miss: (Symbol method_name, Array[untyped] args, Hash[Symbol, untyped] kwargs, Float computation_time) -> void
|
|
110
113
|
def _reset_cache_metrics: () -> void
|
|
111
114
|
end
|
|
112
115
|
|
|
@@ -142,6 +145,7 @@ module SafeMemoize
|
|
|
142
145
|
def lru_order_store: () -> Hash[Symbol, Hash[memo_key, true]]
|
|
143
146
|
def lru_touch: (Symbol method_name, memo_key cache_key) -> void
|
|
144
147
|
def lru_evict_if_over_limit: (Symbol method_name, Integer max_size) -> void
|
|
148
|
+
def lru_remove: (Symbol method_name, memo_key cache_key) -> void
|
|
145
149
|
def lru_clear_all: () -> void
|
|
146
150
|
end
|
|
147
151
|
|