safe_memoize 0.6.3 → 0.7.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 +36 -0
- data/lib/safe_memoize/cache_metrics_methods.rb +6 -0
- data/lib/safe_memoize/cache_record_methods.rb +1 -1
- data/lib/safe_memoize/class_methods.rb +55 -2
- data/lib/safe_memoize/configuration.rb +12 -0
- data/lib/safe_memoize/custom_key_methods.rb +6 -9
- data/lib/safe_memoize/hooks_methods.rb +3 -3
- data/lib/safe_memoize/public_methods.rb +78 -2
- data/lib/safe_memoize/public_metrics_methods.rb +6 -2
- data/lib/safe_memoize/version.rb +1 -1
- data/lib/safe_memoize.rb +13 -0
- data/sig/safe_memoize.rbs +25 -6
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41e3b8e3232ef52d536166c4e701a99a8d7a1e86e2c6d07493d1838d904dbef6
|
|
4
|
+
data.tar.gz: dac922ad348d3ccf14d8946035b5a0e7709cacc899dcc6e0713da77c980ac6ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7f263ac2b16ff248ccf6afa158aaaae5a7fd69cadef68ff6926c3d96257378df8d4295f2eac8278a68de12492128282c1ffea42da95c178de7e5619981c8634
|
|
7
|
+
data.tar.gz: b50610d8ac36d0c7ff4fe9ed174a7f7864654f4178bc5778a9555eda1d934320b7ee0bcf4de53919e9dfacc35d06d8320f0b9dc8e8a25d6fab6808dfb0c0aab4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.7.0] - 2026-05-18
|
|
4
|
+
|
|
5
|
+
- Add `memo_preload` to batch-warm multiple cache entries in one call
|
|
6
|
+
- `obj.memo_preload(:find, [1], [2], [3])` calls the memoized method for each arg set and caches all results
|
|
7
|
+
- Returns an array of results in the same order as the input arg sets
|
|
8
|
+
- Computes each entry only once — subsequent calls return from cache
|
|
9
|
+
- Add `on_memo_store` hook that fires whenever a value is written to the cache
|
|
10
|
+
- Fires on every cache miss (fast path and LRU path)
|
|
11
|
+
- Also fires when entries are written via `warm_memo` or `load_memo`
|
|
12
|
+
- Does not fire on cache hits or when a conditional `:if`/`:unless` prevents storing
|
|
13
|
+
- Fires on the calling instance for `shared: true` misses
|
|
14
|
+
- Completes the full lifecycle hook set: `on_store`, `on_hit`, `on_miss`, `on_expire`, `on_evict`
|
|
15
|
+
- Add per-method `cache_metrics_reset(:method)` to clear stats for a single method without wiping the rest
|
|
16
|
+
- `cache_metrics_reset` (no args) still clears all metrics as before
|
|
17
|
+
- Add `SafeMemoize.configure` for global default options
|
|
18
|
+
- `SafeMemoize.configure { |c| c.default_ttl = 60 }` applies a TTL to all subsequently memoized methods
|
|
19
|
+
- `SafeMemoize.configure { |c| c.default_max_size = 100 }` sets a global LRU size limit
|
|
20
|
+
- Per-call options (`ttl:`, `max_size:`) override the global defaults
|
|
21
|
+
- `SafeMemoize.reset_configuration!` restores defaults to `nil`
|
|
22
|
+
- Add `memo_touch` to reset the expiry clock on a cached entry without recomputing
|
|
23
|
+
- `memo_touch(:method, *args)` extends the entry's TTL from now using the original TTL window
|
|
24
|
+
- `memo_touch(:method, *args, ttl: 30)` sets a new TTL explicitly
|
|
25
|
+
- Returns `true` on success, `false` if the entry is not cached or already expired
|
|
26
|
+
- Add `shared_memo_age` class method to inspect how long ago a shared entry was cached
|
|
27
|
+
- Add `shared_memo_stale?` class method to check whether a shared entry's TTL has elapsed
|
|
28
|
+
- Update RBS type signatures for all new methods and the `Configuration` class
|
|
29
|
+
- Add `key:` option to `memoize` for class-level cache key generation
|
|
30
|
+
- `memoize :method, key: ->(a, b) { a }` defines a key generator at the class level — calls whose key block returns the same value share one cache entry
|
|
31
|
+
- Instance-level `memoize_with_custom_key` still takes priority over `key:`
|
|
32
|
+
- Composes with all existing options (`ttl:`, `max_size:`, `shared:`, `if:`, etc.)
|
|
33
|
+
- Raises `ArgumentError` if `key:` is not callable
|
|
34
|
+
- Add `shared:` support to `memoize_all` (was already functional via `**options` passthrough; now tested and documented)
|
|
35
|
+
- Add `memo_refresh` to force-recompute a cached entry and store the new value in one call
|
|
36
|
+
- Add `memo_age` to return how many seconds ago an entry was cached (`nil` if not cached or expired)
|
|
37
|
+
- Add `memo_stale?` to check whether a cached entry exists but its TTL has elapsed
|
|
38
|
+
|
|
3
39
|
## [0.6.3] - 2026-05-18
|
|
4
40
|
|
|
5
41
|
- Upgrade `softprops/action-gh-release` from v2 to v3 to resolve Node.js 20 deprecation warning in release workflow
|
|
@@ -26,5 +26,11 @@ module SafeMemoize
|
|
|
26
26
|
def _reset_cache_metrics
|
|
27
27
|
@__safe_memo_metrics__ = {}
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def _reset_cache_metrics_for(method_name)
|
|
31
|
+
return unless defined?(@__safe_memo_metrics__) && @__safe_memo_metrics__
|
|
32
|
+
|
|
33
|
+
@__safe_memo_metrics__.delete_if { |key, _| key[0] == method_name }
|
|
34
|
+
end
|
|
29
35
|
end
|
|
30
36
|
end
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module SafeMemoize
|
|
4
4
|
module ClassMethods
|
|
5
|
-
def memoize(method_name, ttl: nil, max_size: nil, ttl_refresh: false, 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, key: nil)
|
|
6
6
|
method_name = method_name.to_sym
|
|
7
7
|
visibility = memoized_method_visibility(method_name)
|
|
8
8
|
|
|
9
|
+
config = SafeMemoize.configuration
|
|
10
|
+
ttl = config.default_ttl if ttl.nil?
|
|
11
|
+
max_size = config.default_max_size if max_size.nil?
|
|
12
|
+
|
|
9
13
|
# :if and :unless are reserved Ruby keywords, so they can't be referenced
|
|
10
14
|
# as local variables directly. binding.local_variable_get is the only way
|
|
11
15
|
# to read keyword arguments with those names inside the method body.
|
|
@@ -38,6 +42,9 @@ module SafeMemoize
|
|
|
38
42
|
end
|
|
39
43
|
raise ArgumentError, ":if must be callable" if cond_if && !cond_if.respond_to?(:call)
|
|
40
44
|
raise ArgumentError, ":unless must be callable" if cond_unless && !cond_unless.respond_to?(:call)
|
|
45
|
+
raise ArgumentError, ":key must be callable" if key && !key.respond_to?(:call)
|
|
46
|
+
|
|
47
|
+
__safe_memo_class_key_generators__[method_name] = key if key
|
|
41
48
|
|
|
42
49
|
# Normalize to a single "should cache?" predicate
|
|
43
50
|
condition = if cond_if
|
|
@@ -79,7 +86,7 @@ module SafeMemoize
|
|
|
79
86
|
value = super(*args, **kwargs)
|
|
80
87
|
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
81
88
|
|
|
82
|
-
new_record =
|
|
89
|
+
new_record = memo_record(value, expires_at: memo_expires_at(ttl))
|
|
83
90
|
|
|
84
91
|
if !condition || condition.call(value)
|
|
85
92
|
if max_size
|
|
@@ -97,6 +104,7 @@ module SafeMemoize
|
|
|
97
104
|
lru = klass.send(:__safe_memo_shared_lru_order__)[method_name] ||= {}
|
|
98
105
|
lru[cache_key] = true
|
|
99
106
|
end
|
|
107
|
+
call_memo_hooks(:on_store, cache_key, new_record)
|
|
100
108
|
end
|
|
101
109
|
|
|
102
110
|
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
@@ -143,6 +151,7 @@ module SafeMemoize
|
|
|
143
151
|
@__safe_memo_cache__ ||= {}
|
|
144
152
|
@__safe_memo_cache__[cache_key] = new_record
|
|
145
153
|
lru_touch(method_name, cache_key) if max_size
|
|
154
|
+
call_memo_hooks(:on_store, cache_key, new_record)
|
|
146
155
|
end
|
|
147
156
|
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
148
157
|
call_memo_hooks(:on_miss, cache_key, new_record)
|
|
@@ -166,6 +175,7 @@ module SafeMemoize
|
|
|
166
175
|
with_memo_lock do
|
|
167
176
|
record_cache_miss(method_name, args, kwargs, elapsed_time)
|
|
168
177
|
new_record = memo_cache_record(cache_key)
|
|
178
|
+
call_memo_hooks(:on_store, cache_key, new_record)
|
|
169
179
|
call_memo_hooks(:on_miss, cache_key, new_record)
|
|
170
180
|
end
|
|
171
181
|
|
|
@@ -225,6 +235,45 @@ module SafeMemoize
|
|
|
225
235
|
end
|
|
226
236
|
end
|
|
227
237
|
|
|
238
|
+
def shared_memo_age(method_name, *args, **kwargs)
|
|
239
|
+
method_name = method_name.to_sym
|
|
240
|
+
cache_key = [method_name, args, kwargs]
|
|
241
|
+
|
|
242
|
+
__safe_memo_shared_mutex__.synchronize do
|
|
243
|
+
cache = @__safe_memo_shared_cache__
|
|
244
|
+
return nil unless cache
|
|
245
|
+
|
|
246
|
+
record = cache[cache_key]
|
|
247
|
+
return nil unless record
|
|
248
|
+
|
|
249
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
250
|
+
return nil if record[:expires_at] && record[:expires_at] <= now
|
|
251
|
+
|
|
252
|
+
cached_at = record[:cached_at]
|
|
253
|
+
return nil unless cached_at
|
|
254
|
+
|
|
255
|
+
(now - cached_at).round(6)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def shared_memo_stale?(method_name, *args, **kwargs)
|
|
260
|
+
method_name = method_name.to_sym
|
|
261
|
+
cache_key = [method_name, args, kwargs]
|
|
262
|
+
|
|
263
|
+
__safe_memo_shared_mutex__.synchronize do
|
|
264
|
+
cache = @__safe_memo_shared_cache__
|
|
265
|
+
return false unless cache
|
|
266
|
+
|
|
267
|
+
record = cache[cache_key]
|
|
268
|
+
return false unless record
|
|
269
|
+
|
|
270
|
+
expires_at = record[:expires_at]
|
|
271
|
+
return false unless expires_at
|
|
272
|
+
|
|
273
|
+
expires_at <= Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
228
277
|
def memoize_all(except: [], include_protected: false, include_private: false, **options)
|
|
229
278
|
excluded = Array(except).map(&:to_sym)
|
|
230
279
|
|
|
@@ -253,6 +302,10 @@ module SafeMemoize
|
|
|
253
302
|
@__safe_memo_shared_lru_order__ ||= {}
|
|
254
303
|
end
|
|
255
304
|
|
|
305
|
+
def __safe_memo_class_key_generators__
|
|
306
|
+
@__safe_memo_class_key_generators__ ||= {}
|
|
307
|
+
end
|
|
308
|
+
|
|
256
309
|
def memoized_method_visibility(method_name)
|
|
257
310
|
return :private if private_method_defined?(method_name)
|
|
258
311
|
return :protected if protected_method_defined?(method_name)
|
|
@@ -18,16 +18,13 @@ module SafeMemoize
|
|
|
18
18
|
def compute_cache_key(method_name, args, kwargs)
|
|
19
19
|
method_name = method_name.to_sym
|
|
20
20
|
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# Wrap in a standard format: [method, custom_key]
|
|
28
|
-
[method_name, custom_key]
|
|
21
|
+
# Instance-level key generator takes priority over class-level
|
|
22
|
+
key_block = custom_key_store[method_name] ||
|
|
23
|
+
self.class.send(:__safe_memo_class_key_generators__)[method_name]
|
|
24
|
+
|
|
25
|
+
if key_block
|
|
26
|
+
[method_name, key_block.call(*args, **kwargs)]
|
|
29
27
|
else
|
|
30
|
-
# Use default key generation
|
|
31
28
|
safe_memo_cache_key(method_name, args, kwargs)
|
|
32
29
|
end
|
|
33
30
|
end
|
|
@@ -5,13 +5,13 @@ module SafeMemoize
|
|
|
5
5
|
private
|
|
6
6
|
|
|
7
7
|
def memo_hook_store
|
|
8
|
-
@__safe_memo_hooks__ ||= {on_expire: [], on_evict: [], on_hit: [], on_miss: []}
|
|
8
|
+
@__safe_memo_hooks__ ||= {on_expire: [], on_evict: [], on_hit: [], on_miss: [], on_store: []}
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def register_memo_hook(hook_type, &block)
|
|
12
12
|
raise ArgumentError, "block required" unless block
|
|
13
13
|
|
|
14
|
-
valid_hooks = [:on_expire, :on_evict, :on_hit, :on_miss]
|
|
14
|
+
valid_hooks = [:on_expire, :on_evict, :on_hit, :on_miss, :on_store]
|
|
15
15
|
raise ArgumentError, "invalid hook type: #{hook_type}" unless valid_hooks.include?(hook_type)
|
|
16
16
|
|
|
17
17
|
memo_hook_store[hook_type] << block
|
|
@@ -26,7 +26,7 @@ module SafeMemoize
|
|
|
26
26
|
if hook_type
|
|
27
27
|
memo_hook_store[hook_type] = []
|
|
28
28
|
else
|
|
29
|
-
@__safe_memo_hooks__ = {on_expire: [], on_evict: [], on_hit: [], on_miss: []}
|
|
29
|
+
@__safe_memo_hooks__ = {on_expire: [], on_evict: [], on_hit: [], on_miss: [], on_store: []}
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -75,6 +75,12 @@ module SafeMemoize
|
|
|
75
75
|
register_memo_hook(:on_miss, &block)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
def on_memo_store(&block)
|
|
79
|
+
raise ArgumentError, "block required" unless block
|
|
80
|
+
|
|
81
|
+
register_memo_hook(:on_store, &block)
|
|
82
|
+
end
|
|
83
|
+
|
|
78
84
|
def clear_memo_hooks(hook_type = nil)
|
|
79
85
|
with_memo_lock do
|
|
80
86
|
_clear_memo_hooks(hook_type)
|
|
@@ -90,12 +96,21 @@ module SafeMemoize
|
|
|
90
96
|
|
|
91
97
|
with_memo_lock do
|
|
92
98
|
@__safe_memo_cache__ ||= {}
|
|
93
|
-
|
|
99
|
+
record = memo_record(value, expires_at: memo_expires_at(ttl))
|
|
100
|
+
@__safe_memo_cache__[cache_key] = record
|
|
101
|
+
call_memo_hooks(:on_store, cache_key, record)
|
|
94
102
|
end
|
|
95
103
|
|
|
96
104
|
value
|
|
97
105
|
end
|
|
98
106
|
|
|
107
|
+
def memo_preload(method_name, *arg_sets)
|
|
108
|
+
method_name = method_name.to_sym
|
|
109
|
+
arg_sets.map do |args|
|
|
110
|
+
send(method_name, *Array(args))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
99
114
|
def dump_memo(method_name = nil)
|
|
100
115
|
method_name = method_name&.to_sym
|
|
101
116
|
|
|
@@ -113,13 +128,74 @@ module SafeMemoize
|
|
|
113
128
|
with_memo_lock do
|
|
114
129
|
@__safe_memo_cache__ ||= {}
|
|
115
130
|
snapshot.each do |cache_key, value|
|
|
116
|
-
|
|
131
|
+
record = memo_record(value, expires_at: nil)
|
|
132
|
+
@__safe_memo_cache__[cache_key] = record
|
|
133
|
+
call_memo_hooks(:on_store, cache_key, record)
|
|
117
134
|
end
|
|
118
135
|
end
|
|
119
136
|
|
|
120
137
|
nil
|
|
121
138
|
end
|
|
122
139
|
|
|
140
|
+
def memo_touch(method_name, *args, ttl: nil, **kwargs)
|
|
141
|
+
method_name = method_name.to_sym
|
|
142
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
143
|
+
|
|
144
|
+
with_memo_lock do
|
|
145
|
+
cache = memo_cache_or_nil
|
|
146
|
+
return false unless cache
|
|
147
|
+
|
|
148
|
+
record = cache[cache_key]
|
|
149
|
+
return false unless record && memo_record_live?(record)
|
|
150
|
+
|
|
151
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
152
|
+
|
|
153
|
+
effective_ttl = if ttl
|
|
154
|
+
ttl
|
|
155
|
+
elsif record[:expires_at] && record[:cached_at]
|
|
156
|
+
record[:expires_at] - record[:cached_at]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
record[:expires_at] = effective_ttl ? now + effective_ttl : nil
|
|
160
|
+
record[:cached_at] = now
|
|
161
|
+
true
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def memo_refresh(method_name, *args, **kwargs)
|
|
166
|
+
method_name = method_name.to_sym
|
|
167
|
+
reset_memo(method_name, *args, **kwargs)
|
|
168
|
+
send(method_name, *args, **kwargs)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def memo_age(method_name, *args, **kwargs)
|
|
172
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
173
|
+
|
|
174
|
+
with_memo_lock do
|
|
175
|
+
record = memo_cache_record(cache_key)
|
|
176
|
+
return nil unless record
|
|
177
|
+
|
|
178
|
+
cached_at = record[:cached_at]
|
|
179
|
+
return nil unless cached_at
|
|
180
|
+
|
|
181
|
+
(Process.clock_gettime(Process::CLOCK_MONOTONIC) - cached_at).round(6)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def memo_stale?(method_name, *args, **kwargs)
|
|
186
|
+
cache_key = safe_memo_cache_key(method_name, args, kwargs)
|
|
187
|
+
|
|
188
|
+
with_memo_lock do
|
|
189
|
+
cache = memo_cache_or_nil
|
|
190
|
+
return false unless cache
|
|
191
|
+
|
|
192
|
+
record = cache[cache_key]
|
|
193
|
+
return false unless record
|
|
194
|
+
|
|
195
|
+
!memo_record_live?(record)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
123
199
|
def reset_memo(method_name, *args, **kwargs)
|
|
124
200
|
method_name = method_name.to_sym
|
|
125
201
|
|
|
@@ -30,9 +30,13 @@ module SafeMemoize
|
|
|
30
30
|
cache_stats[:miss_rate]
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def cache_metrics_reset
|
|
33
|
+
def cache_metrics_reset(method_name = nil)
|
|
34
34
|
with_memo_lock do
|
|
35
|
-
|
|
35
|
+
if method_name
|
|
36
|
+
_reset_cache_metrics_for(method_name.to_sym)
|
|
37
|
+
else
|
|
38
|
+
_reset_cache_metrics
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
end
|
|
38
42
|
|
data/lib/safe_memoize/version.rb
CHANGED
data/lib/safe_memoize.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "safe_memoize/version"
|
|
4
|
+
require_relative "safe_memoize/configuration"
|
|
4
5
|
require_relative "safe_memoize/class_methods"
|
|
5
6
|
require_relative "safe_memoize/public_methods"
|
|
6
7
|
require_relative "safe_memoize/cache_store_methods"
|
|
@@ -22,4 +23,16 @@ module SafeMemoize
|
|
|
22
23
|
def self.prepended(base)
|
|
23
24
|
base.extend(ClassMethods)
|
|
24
25
|
end
|
|
26
|
+
|
|
27
|
+
def self.configure
|
|
28
|
+
yield configuration
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.configuration
|
|
32
|
+
@configuration ||= Configuration.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.reset_configuration!
|
|
36
|
+
@configuration = Configuration.new
|
|
37
|
+
end
|
|
25
38
|
end
|
data/sig/safe_memoize.rbs
CHANGED
|
@@ -5,7 +5,7 @@ module SafeMemoize
|
|
|
5
5
|
type default_memo_key = [Symbol, Array[untyped], Hash[Symbol, untyped]]
|
|
6
6
|
type custom_memo_key = [Symbol, untyped]
|
|
7
7
|
type memo_key = default_memo_key | custom_memo_key
|
|
8
|
-
type memo_record = { value: untyped, expires_at: Float
|
|
8
|
+
type memo_record = { value: untyped, expires_at: Float?, cached_at: Float }
|
|
9
9
|
|
|
10
10
|
@__safe_memo_cache__: Hash[memo_key, memo_record]?
|
|
11
11
|
@__safe_memo_mutex__: Mutex?
|
|
@@ -14,20 +14,33 @@ module SafeMemoize
|
|
|
14
14
|
@__safe_memo_shared_lru_order__: Hash[Symbol, Hash[memo_key, true]]?
|
|
15
15
|
|
|
16
16
|
def self.prepended: (Class base) -> void
|
|
17
|
+
def self.configure: () { (Configuration) -> void } -> void
|
|
18
|
+
def self.configuration: () -> Configuration
|
|
19
|
+
def self.reset_configuration!: () -> Configuration
|
|
20
|
+
|
|
21
|
+
class Configuration
|
|
22
|
+
attr_accessor default_ttl: Numeric?
|
|
23
|
+
attr_accessor default_max_size: Integer?
|
|
24
|
+
|
|
25
|
+
def initialize: () -> void
|
|
26
|
+
end
|
|
17
27
|
|
|
18
28
|
module ClassMethods
|
|
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
|
|
29
|
+
def memoize: (Symbol | String method_name, ?ttl: Numeric?, ?max_size: Integer?, ?ttl_refresh: bool, ?if: (^(untyped result) -> boolish)?, ?unless: (^(untyped result) -> boolish)?, ?shared: bool, ?key: (^(*untyped args, **untyped kwargs) -> untyped)?) -> void
|
|
30
|
+
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)?, ?shared: bool, ?key: (^(*untyped args, **untyped kwargs) -> untyped)?) -> void
|
|
21
31
|
def reset_shared_memo: (Symbol | String method_name, *untyped args, **untyped kwargs) -> void
|
|
22
32
|
def reset_all_shared_memos: () -> void
|
|
23
33
|
def shared_memoized?: (Symbol | String method_name, *untyped args, **untyped kwargs) -> bool
|
|
24
34
|
def shared_memo_count: (?Symbol | String method_name) -> Integer
|
|
35
|
+
def shared_memo_age: (Symbol | String method_name, *untyped args, **untyped kwargs) -> Float?
|
|
36
|
+
def shared_memo_stale?: (Symbol | String method_name, *untyped args, **untyped kwargs) -> bool
|
|
25
37
|
|
|
26
38
|
private
|
|
27
39
|
|
|
28
40
|
def __safe_memo_shared_cache__: () -> Hash[memo_key, memo_record]
|
|
29
41
|
def __safe_memo_shared_mutex__: () -> Mutex
|
|
30
42
|
def __safe_memo_shared_lru_order__: () -> Hash[Symbol, Hash[memo_key, true]]
|
|
43
|
+
def __safe_memo_class_key_generators__: () -> Hash[Symbol, Proc]
|
|
31
44
|
def memoized_method_visibility: (Symbol method_name) -> Symbol
|
|
32
45
|
end
|
|
33
46
|
|
|
@@ -43,10 +56,16 @@ module SafeMemoize
|
|
|
43
56
|
def on_memo_evict: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
44
57
|
def on_memo_hit: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
45
58
|
def on_memo_miss: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
59
|
+
def on_memo_store: { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
46
60
|
def clear_memo_hooks: (Symbol? hook_type) -> void
|
|
47
61
|
def warm_memo: (Symbol | String method_name, *untyped args, ?ttl: Numeric?, **untyped kwargs) { () -> untyped } -> untyped
|
|
62
|
+
def memo_preload: (Symbol | String method_name, *Array[untyped] arg_sets) -> Array[untyped]
|
|
48
63
|
def dump_memo: (?Symbol | String method_name) -> Hash[memo_key, untyped]
|
|
49
64
|
def load_memo: (Hash[memo_key, untyped] snapshot) -> nil
|
|
65
|
+
def memo_touch: (Symbol | String method_name, *untyped args, ?ttl: Numeric?, **untyped kwargs) -> bool
|
|
66
|
+
def memo_refresh: (Symbol | String method_name, *untyped args, **untyped kwargs) -> untyped
|
|
67
|
+
def memo_age: (Symbol | String method_name, *untyped args, **untyped kwargs) -> Float?
|
|
68
|
+
def memo_stale?: (Symbol | String method_name, *untyped args, **untyped kwargs) -> bool
|
|
50
69
|
def reset_memo: (Symbol | String method_name, *untyped args, **untyped kwargs) -> void
|
|
51
70
|
def reset_all_memos: () -> void
|
|
52
71
|
end
|
|
@@ -92,11 +111,11 @@ module SafeMemoize
|
|
|
92
111
|
end
|
|
93
112
|
|
|
94
113
|
module HooksMethods
|
|
95
|
-
@__safe_memo_hooks__: { on_expire: Array[Proc], on_evict: Array[Proc], on_hit: Array[Proc], on_miss: Array[Proc] }?
|
|
114
|
+
@__safe_memo_hooks__: { on_expire: Array[Proc], on_evict: Array[Proc], on_hit: Array[Proc], on_miss: Array[Proc], on_store: Array[Proc] }?
|
|
96
115
|
|
|
97
116
|
private
|
|
98
117
|
|
|
99
|
-
def memo_hook_store: () -> { on_expire: Array[Proc], on_evict: Array[Proc], on_hit: Array[Proc], on_miss: Array[Proc] }
|
|
118
|
+
def memo_hook_store: () -> { on_expire: Array[Proc], on_evict: Array[Proc], on_hit: Array[Proc], on_miss: Array[Proc], on_store: Array[Proc] }
|
|
100
119
|
def register_memo_hook: (Symbol hook_type) { (memo_key cache_key, memo_record record) -> untyped } -> void
|
|
101
120
|
def call_memo_hooks: (Symbol hook_type, memo_key cache_key, memo_record record) -> void
|
|
102
121
|
def _clear_memo_hooks: (Symbol? hook_type) -> void
|
|
@@ -118,7 +137,7 @@ module SafeMemoize
|
|
|
118
137
|
def cache_stats_for: (Symbol | String method_name) -> Hash[Symbol, untyped]
|
|
119
138
|
def cache_hit_rate: () -> Float
|
|
120
139
|
def cache_miss_rate: () -> Float
|
|
121
|
-
def cache_metrics_reset: () -> void
|
|
140
|
+
def cache_metrics_reset: (?Symbol | String method_name) -> void
|
|
122
141
|
|
|
123
142
|
private
|
|
124
143
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: safe_memoize
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -50,6 +50,7 @@ files:
|
|
|
50
50
|
- lib/safe_memoize/cache_record_methods.rb
|
|
51
51
|
- lib/safe_memoize/cache_store_methods.rb
|
|
52
52
|
- lib/safe_memoize/class_methods.rb
|
|
53
|
+
- lib/safe_memoize/configuration.rb
|
|
53
54
|
- lib/safe_memoize/custom_key_methods.rb
|
|
54
55
|
- lib/safe_memoize/hooks_methods.rb
|
|
55
56
|
- lib/safe_memoize/inspection_methods.rb
|