typed_cache 0.1.1 → 0.3.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
- checksums.yaml.gz.sig +0 -0
- data/README.md +139 -20
- data/examples.md +140 -50
- data/lib/typed_cache/backends/active_support.rb +50 -5
- data/lib/typed_cache/backends/memory.rb +14 -11
- data/lib/typed_cache/backends.rb +6 -8
- data/lib/typed_cache/cache_builder.rb +72 -19
- data/lib/typed_cache/cache_key.rb +11 -1
- data/lib/typed_cache/cache_ref.rb +20 -16
- data/lib/typed_cache/clock.rb +31 -14
- data/lib/typed_cache/decorator.rb +25 -0
- data/lib/typed_cache/decorators/instrumented.rb +92 -0
- data/lib/typed_cache/decorators.rb +7 -3
- data/lib/typed_cache/either.rb +22 -0
- data/lib/typed_cache/errors.rb +9 -1
- data/lib/typed_cache/instrumenter.rb +43 -0
- data/lib/typed_cache/instrumenters/active_support.rb +28 -0
- data/lib/typed_cache/instrumenters/mixins/namespaced_singleton.rb +55 -0
- data/lib/typed_cache/instrumenters/mixins.rb +8 -0
- data/lib/typed_cache/instrumenters/monitor.rb +27 -0
- data/lib/typed_cache/instrumenters/null.rb +26 -0
- data/lib/typed_cache/instrumenters.rb +39 -0
- data/lib/typed_cache/maybe.rb +18 -0
- data/lib/typed_cache/namespace.rb +33 -6
- data/lib/typed_cache/railtie.rb +15 -0
- data/lib/typed_cache/registry.rb +15 -0
- data/lib/typed_cache/snapshot.rb +18 -10
- data/lib/typed_cache/store.rb +50 -15
- data/lib/typed_cache/version.rb +1 -1
- data/lib/typed_cache.rb +34 -14
- data/rbi/typed_cache/backend.rbi +9 -0
- data/rbi/typed_cache/backends/active_support.rbi +13 -0
- data/rbi/typed_cache/backends/memory.rbi +13 -0
- data/rbi/typed_cache/backends.rbi +19 -0
- data/rbi/typed_cache/cache_builder.rbi +23 -0
- data/rbi/typed_cache/cache_key.rbi +16 -0
- data/rbi/typed_cache/cache_ref.rbi +56 -0
- data/rbi/typed_cache/decorator.rbi +67 -0
- data/rbi/typed_cache/decorators/instrumented.rbi +13 -0
- data/rbi/typed_cache/decorators.rbi +19 -0
- data/rbi/typed_cache/either.rbi +122 -0
- data/rbi/typed_cache/errors.rbi +20 -0
- data/rbi/typed_cache/instrumenter.rbi +45 -0
- data/rbi/typed_cache/instrumenters/mixins/namedspaced_singleton.rbi +33 -0
- data/rbi/typed_cache/instrumenters.rbi +19 -0
- data/rbi/typed_cache/maybe.rbi +108 -0
- data/rbi/typed_cache/namespace.rbi +30 -0
- data/rbi/typed_cache/snapshot.rbi +54 -0
- data/rbi/typed_cache/store.rbi +71 -0
- data/rbi/typed_cache/version.rbi +5 -0
- data/rbi/typed_cache.rbi +49 -0
- data/sig/generated/typed_cache/backends/active_support.rbs +14 -2
- data/sig/generated/typed_cache/backends/memory.rbs +2 -2
- data/sig/generated/typed_cache/backends.rbs +2 -0
- data/sig/generated/typed_cache/cache_builder.rbs +13 -2
- data/sig/generated/typed_cache/cache_key.rbs +5 -0
- data/sig/generated/typed_cache/cache_ref.rbs +4 -4
- data/sig/generated/typed_cache/clock.rbs +19 -9
- data/sig/generated/typed_cache/decorator.rbs +12 -0
- data/sig/generated/typed_cache/decorators/instrumented.rbs +35 -0
- data/sig/generated/typed_cache/decorators.rbs +2 -0
- data/sig/generated/typed_cache/either.rbs +24 -0
- data/sig/generated/typed_cache/errors.rbs +2 -0
- data/sig/generated/typed_cache/instrumenter.rbs +31 -0
- data/sig/generated/typed_cache/instrumenters/active_support.rbs +20 -0
- data/sig/generated/typed_cache/instrumenters/mixins/namespaced_singleton.rbs +36 -0
- data/sig/generated/typed_cache/instrumenters/mixins.rbs +8 -0
- data/sig/generated/typed_cache/instrumenters/monitor.rbs +19 -0
- data/sig/generated/typed_cache/instrumenters/null.rbs +21 -0
- data/sig/generated/typed_cache/instrumenters.rbs +26 -0
- data/sig/generated/typed_cache/maybe.rbs +20 -0
- data/sig/generated/typed_cache/namespace.rbs +24 -3
- data/sig/generated/typed_cache/railtie.rbs +6 -0
- data/sig/generated/typed_cache/registry.rbs +8 -0
- data/sig/generated/typed_cache/snapshot.rbs +12 -6
- data/sig/generated/typed_cache/store/instrumented.rbs +2 -6
- data/sig/generated/typed_cache/store.rbs +26 -8
- data/sig/generated/typed_cache.rbs +8 -6
- data/typed_cache.gemspec +5 -4
- data.tar.gz.sig +0 -0
- metadata +48 -27
- metadata.gz.sig +0 -0
- data/lib/typed_cache/instrumentation.rb +0 -112
- data/lib/typed_cache/store/instrumented.rb +0 -83
- data/sig/generated/typed_cache/instrumentation.rbs +0 -30
- data/sig/handwritten/gems/zeitwerk/2.7/zeitwerk.rbs +0 -9
@@ -4,14 +4,16 @@ module TypedCache
|
|
4
4
|
# Immutable snapshot of a cached value with metadata about its source and age
|
5
5
|
# @rbs generic V
|
6
6
|
class Snapshot[V]
|
7
|
+
attr_reader key: CacheKey
|
8
|
+
|
7
9
|
attr_reader value: V
|
8
10
|
|
9
11
|
attr_reader retrieved_at: Time
|
10
12
|
|
11
13
|
attr_reader source: Symbol
|
12
14
|
|
13
|
-
# : (V, source: Symbol, retrieved_at: Time) -> void
|
14
|
-
def initialize: (V, source: Symbol, retrieved_at: Time) -> void
|
15
|
+
# : (CacheKey, V, source: Symbol, retrieved_at: Time) -> void
|
16
|
+
def initialize: (CacheKey, V, source: Symbol, retrieved_at: Time) -> void
|
15
17
|
|
16
18
|
# Age of the snapshot in seconds
|
17
19
|
# : -> Float
|
@@ -39,12 +41,16 @@ module TypedCache
|
|
39
41
|
|
40
42
|
alias flat_map bind
|
41
43
|
|
44
|
+
# Creates a snapshot for a cached value
|
45
|
+
# : [V] (CacheKey, V) -> Snapshot[V]
|
46
|
+
def self.cached: [V] (CacheKey, V) -> Snapshot[V]
|
47
|
+
|
42
48
|
# Creates a snapshot for a computed value
|
43
|
-
# : [V] (V) -> Snapshot[V]
|
44
|
-
def self.computed: [V] (V) -> Snapshot[V]
|
49
|
+
# : [V] (CacheKey, V) -> Snapshot[V]
|
50
|
+
def self.computed: [V] (CacheKey, V) -> Snapshot[V]
|
45
51
|
|
46
52
|
# Creates a snapshot for an updated value
|
47
|
-
# : [V] (V) -> Snapshot[V]
|
48
|
-
def self.updated: [V] (V) -> Snapshot[V]
|
53
|
+
# : [V] (CacheKey, V) -> Snapshot[V]
|
54
|
+
def self.updated: [V] (CacheKey, V) -> Snapshot[V]
|
49
55
|
end
|
50
56
|
end
|
@@ -14,8 +14,8 @@ module TypedCache
|
|
14
14
|
# @rbs (Symbol, ?operation: String) ?{ (*untyped, **untyped) -> String } -> void
|
15
15
|
private def self.instrument: (Symbol, ?operation: String) ?{ (*untyped, **untyped) -> String } -> void
|
16
16
|
|
17
|
-
# : (TypedCache::Store[V]) -> void
|
18
|
-
def initialize: (TypedCache::Store[V]) -> void
|
17
|
+
# : (TypedCache::Store[V], instrumenter: Instrumenter) -> void
|
18
|
+
def initialize: (TypedCache::Store[V], instrumenter: Instrumenter) -> void
|
19
19
|
|
20
20
|
# @rbs override
|
21
21
|
# : -> String
|
@@ -25,10 +25,6 @@ module TypedCache
|
|
25
25
|
# : -> String
|
26
26
|
def store_type: ...
|
27
27
|
|
28
|
-
# @rbs override
|
29
|
-
# : (cache_key) -> either[Error, CacheRef[V]]
|
30
|
-
def ref: ...
|
31
|
-
|
32
28
|
# Additional methods that might exist on the wrapped store
|
33
29
|
def respond_to_missing?: (untyped method_name, ?untyped include_private) -> untyped
|
34
30
|
|
@@ -13,11 +13,15 @@ module TypedCache
|
|
13
13
|
type cache_key = String | CacheKey
|
14
14
|
|
15
15
|
interface _Store[V]
|
16
|
-
def
|
16
|
+
def read: (cache_key) -> either[Error, Snapshot[V]]
|
17
|
+
|
18
|
+
def read_all: (Array[cache_key]) -> either[Error, Array[Snapshot[V]]]
|
17
19
|
|
18
20
|
def ref: (cache_key) -> CacheRef[V]
|
19
21
|
|
20
|
-
def
|
22
|
+
def write: (cache_key, V) -> either[Error, Snapshot[V]]
|
23
|
+
|
24
|
+
def write_all: (Hash[cache_key, V]) -> either[Error, Array[Snapshot[V]]]
|
21
25
|
|
22
26
|
def delete: (cache_key) -> either[Error, Snapshot[V]]
|
23
27
|
|
@@ -25,7 +29,9 @@ module TypedCache
|
|
25
29
|
|
26
30
|
def clear: () -> maybe[Error]
|
27
31
|
|
28
|
-
def fetch: (cache_key) { () -> V } -> either[Error, Snapshot[V]]
|
32
|
+
def fetch: (cache_key) { () -> V? } -> either[Error, Snapshot[maybe[V]]]
|
33
|
+
|
34
|
+
def fetch_all: (Array[cache_key]) { (CacheKey) -> V? } -> either[Error, Array[Snapshot[V]]]
|
29
35
|
|
30
36
|
def namespace: () -> Namespace
|
31
37
|
|
@@ -45,7 +51,10 @@ module TypedCache
|
|
45
51
|
|
46
52
|
# Retrieves a value from the cache
|
47
53
|
# @rbs (cache_key) -> either[Error, Snapshot[V]]
|
48
|
-
def
|
54
|
+
def read: (cache_key) -> either[Error, Snapshot[V]]
|
55
|
+
|
56
|
+
# @rbs (Array[cache_key]) -> either[Error, Hash[cache_key, Snapshot[V]]]
|
57
|
+
def read_all: (Array[cache_key]) -> either[Error, Hash[cache_key, Snapshot[V]]]
|
49
58
|
|
50
59
|
# Retrieves a cache reference for a key
|
51
60
|
# @rbs (cache_key) -> CacheRef[V]
|
@@ -53,7 +62,10 @@ module TypedCache
|
|
53
62
|
|
54
63
|
# Stores a value in the cache
|
55
64
|
# @rbs (cache_key, V) -> either[Error, Snapshot[V]]
|
56
|
-
def
|
65
|
+
def write: (cache_key, V) -> either[Error, Snapshot[V]]
|
66
|
+
|
67
|
+
# @rbs (Hash[cache_key, V]) -> either[Error, Hash[cache_key, Snapshot[V]]]
|
68
|
+
def write_all: (Hash[cache_key, V]) -> either[Error, Hash[cache_key, Snapshot[V]]]
|
57
69
|
|
58
70
|
# Removes a value from the cache, returning the removed value
|
59
71
|
# @rbs (cache_key) -> either[Error, Snapshot[V]]
|
@@ -68,18 +80,24 @@ module TypedCache
|
|
68
80
|
def clear: () -> maybe[Error]
|
69
81
|
|
70
82
|
# Fetches a value from cache, computing and storing it if not found
|
71
|
-
# This is an atomic operation that combines
|
83
|
+
# This is an atomic operation that combines read and write
|
72
84
|
# @rbs (cache_key) { () -> V } -> either[Error, Snapshot[V]]
|
73
85
|
def fetch: (cache_key) { () -> V } -> either[Error, Snapshot[V]]
|
74
86
|
|
87
|
+
# @rbs (Array[cache_key]) { (CacheKey) -> V } -> either[Error, Array[Snapshot[V]]]
|
88
|
+
def fetch_all: (Array[cache_key]) { (CacheKey) -> V } -> either[Error, Array[Snapshot[V]]]
|
89
|
+
|
90
|
+
# @rbs () -> Instrumenter
|
91
|
+
def instrumenter: () -> Instrumenter
|
92
|
+
|
75
93
|
# Returns the namespace for this store (for instrumentation/debugging)
|
76
94
|
# @rbs () -> Namespace
|
77
95
|
def namespace: () -> Namespace
|
78
96
|
|
79
97
|
# Accepts a String segment or a fully-formed Namespace and returns a cloned
|
80
98
|
# store scoped to that namespace.
|
81
|
-
#
|
82
|
-
def with_namespace: (Namespace | String) -> Store[V]
|
99
|
+
# : (Namespace | String | Array[String]) -> Store[V]
|
100
|
+
def with_namespace: (Namespace | String | Array[String]) -> Store[V]
|
83
101
|
|
84
102
|
# Returns the store type identifier for instrumentation/debugging
|
85
103
|
# @rbs () -> String
|
@@ -12,6 +12,8 @@ module TypedCache
|
|
12
12
|
interface _TypedCacheConfig
|
13
13
|
def default_namespace: () -> String
|
14
14
|
|
15
|
+
def cache_delimiter: () -> String
|
16
|
+
|
15
17
|
def instrumentation: () -> _TypedCacheInstrumentationConfig
|
16
18
|
end
|
17
19
|
|
@@ -23,12 +25,12 @@ module TypedCache
|
|
23
25
|
|
24
26
|
def config: () -> _TypedCacheConfig
|
25
27
|
|
26
|
-
# @rbs () -> singleton(
|
27
|
-
def self.
|
28
|
+
# @rbs () -> singleton(Backends)
|
29
|
+
def self.backends: () -> singleton(Backends)
|
28
30
|
|
29
|
-
# @rbs () ->
|
30
|
-
def self.
|
31
|
+
# @rbs () -> singleton(Decorators)
|
32
|
+
def self.decorators: () -> singleton(Decorators)
|
31
33
|
|
32
|
-
# @rbs () ->
|
33
|
-
def self.
|
34
|
+
# @rbs () -> singleton(Instrumenters)
|
35
|
+
def self.instrumenters: () -> singleton(Instrumenters)
|
34
36
|
end
|
data/typed_cache.gemspec
CHANGED
@@ -29,14 +29,15 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.cert_chain = [Gem.default_cert_path]
|
30
30
|
|
31
31
|
spec.required_ruby_version = '>= 3.2.0'
|
32
|
-
|
33
|
-
spec.add_dependency('concurrent-ruby
|
32
|
+
|
33
|
+
spec.add_dependency('concurrent-ruby', '~> 1.0')
|
34
|
+
|
34
35
|
spec.add_dependency('dry-configurable', '~> 1.0')
|
36
|
+
spec.add_dependency('dry-monitor', '~>1.0')
|
35
37
|
spec.add_dependency('dry-struct', '~> 1.0')
|
36
38
|
spec.add_dependency('dry-types', '~>1.0')
|
37
39
|
spec.add_dependency('multi_json', '~> 1.17')
|
38
|
-
spec.add_dependency('zeitwerk', '~> 2.7')
|
39
40
|
|
40
41
|
spec.extra_rdoc_files = Dir['README*', 'LICENSE*', 'examples*']
|
41
|
-
spec.files = Dir['*.gemspec', 'lib/**/*', 'sig/**/*']
|
42
|
+
spec.files = Dir['*.gemspec', 'lib/**/*', 'sig/**/*', 'rbi/**/*']
|
42
43
|
end
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typed_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Autumn Winter
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
uuhUq525FXA3gYeLAfnCSHNm7D1H7whsXYd3z+gKvEhSEQPb3mSBQ+31TDFmA5k7
|
36
36
|
q7YL3dwhxKPXtnAboI+30XBImpdizFG9Nyqgzgj/kD0QwVzL0QsVdVWnNTJXrm4n
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2025-
|
38
|
+
date: 2025-08-16 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: concurrent-ruby
|
@@ -43,30 +43,30 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 1.
|
46
|
+
version: '1.0'
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 1.
|
53
|
+
version: '1.0'
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
55
|
+
name: dry-configurable
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0
|
60
|
+
version: '1.0'
|
61
61
|
type: :runtime
|
62
62
|
prerelease: false
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0
|
67
|
+
version: '1.0'
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
|
-
name: dry-
|
69
|
+
name: dry-monitor
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
@@ -121,20 +121,6 @@ dependencies:
|
|
121
121
|
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '1.17'
|
124
|
-
- !ruby/object:Gem::Dependency
|
125
|
-
name: zeitwerk
|
126
|
-
requirement: !ruby/object:Gem::Requirement
|
127
|
-
requirements:
|
128
|
-
- - "~>"
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: '2.7'
|
131
|
-
type: :runtime
|
132
|
-
prerelease: false
|
133
|
-
version_requirements: !ruby/object:Gem::Requirement
|
134
|
-
requirements:
|
135
|
-
- - "~>"
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: '2.7'
|
138
124
|
description: |
|
139
125
|
TypedCache is a Ruby caching library designed to eliminate common caching pitfalls by providing a monadic, type-safe API that makes cache operations explicit and predictable. Cache interactions are first-class operations with
|
140
126
|
comprehensive error handling and transparent state management. The library supports wrapping other caching libraries via custom backends and ActiveSupport::Cache is supported out of the box.
|
@@ -161,16 +147,44 @@ files:
|
|
161
147
|
- lib/typed_cache/clock.rb
|
162
148
|
- lib/typed_cache/decorator.rb
|
163
149
|
- lib/typed_cache/decorators.rb
|
150
|
+
- lib/typed_cache/decorators/instrumented.rb
|
164
151
|
- lib/typed_cache/either.rb
|
165
152
|
- lib/typed_cache/errors.rb
|
166
|
-
- lib/typed_cache/
|
153
|
+
- lib/typed_cache/instrumenter.rb
|
154
|
+
- lib/typed_cache/instrumenters.rb
|
155
|
+
- lib/typed_cache/instrumenters/active_support.rb
|
156
|
+
- lib/typed_cache/instrumenters/mixins.rb
|
157
|
+
- lib/typed_cache/instrumenters/mixins/namespaced_singleton.rb
|
158
|
+
- lib/typed_cache/instrumenters/monitor.rb
|
159
|
+
- lib/typed_cache/instrumenters/null.rb
|
167
160
|
- lib/typed_cache/maybe.rb
|
168
161
|
- lib/typed_cache/namespace.rb
|
162
|
+
- lib/typed_cache/railtie.rb
|
169
163
|
- lib/typed_cache/registry.rb
|
170
164
|
- lib/typed_cache/snapshot.rb
|
171
165
|
- lib/typed_cache/store.rb
|
172
|
-
- lib/typed_cache/store/instrumented.rb
|
173
166
|
- lib/typed_cache/version.rb
|
167
|
+
- rbi/typed_cache.rbi
|
168
|
+
- rbi/typed_cache/backend.rbi
|
169
|
+
- rbi/typed_cache/backends.rbi
|
170
|
+
- rbi/typed_cache/backends/active_support.rbi
|
171
|
+
- rbi/typed_cache/backends/memory.rbi
|
172
|
+
- rbi/typed_cache/cache_builder.rbi
|
173
|
+
- rbi/typed_cache/cache_key.rbi
|
174
|
+
- rbi/typed_cache/cache_ref.rbi
|
175
|
+
- rbi/typed_cache/decorator.rbi
|
176
|
+
- rbi/typed_cache/decorators.rbi
|
177
|
+
- rbi/typed_cache/decorators/instrumented.rbi
|
178
|
+
- rbi/typed_cache/either.rbi
|
179
|
+
- rbi/typed_cache/errors.rbi
|
180
|
+
- rbi/typed_cache/instrumenter.rbi
|
181
|
+
- rbi/typed_cache/instrumenters.rbi
|
182
|
+
- rbi/typed_cache/instrumenters/mixins/namedspaced_singleton.rbi
|
183
|
+
- rbi/typed_cache/maybe.rbi
|
184
|
+
- rbi/typed_cache/namespace.rbi
|
185
|
+
- rbi/typed_cache/snapshot.rbi
|
186
|
+
- rbi/typed_cache/store.rbi
|
187
|
+
- rbi/typed_cache/version.rbi
|
174
188
|
- sig/generated/typed_cache.rbs
|
175
189
|
- sig/generated/typed_cache/backend.rbs
|
176
190
|
- sig/generated/typed_cache/backends.rbs
|
@@ -182,24 +196,31 @@ files:
|
|
182
196
|
- sig/generated/typed_cache/clock.rbs
|
183
197
|
- sig/generated/typed_cache/decorator.rbs
|
184
198
|
- sig/generated/typed_cache/decorators.rbs
|
199
|
+
- sig/generated/typed_cache/decorators/instrumented.rbs
|
185
200
|
- sig/generated/typed_cache/either.rbs
|
186
201
|
- sig/generated/typed_cache/errors.rbs
|
187
|
-
- sig/generated/typed_cache/
|
202
|
+
- sig/generated/typed_cache/instrumenter.rbs
|
203
|
+
- sig/generated/typed_cache/instrumenters.rbs
|
204
|
+
- sig/generated/typed_cache/instrumenters/active_support.rbs
|
205
|
+
- sig/generated/typed_cache/instrumenters/mixins.rbs
|
206
|
+
- sig/generated/typed_cache/instrumenters/mixins/namespaced_singleton.rbs
|
207
|
+
- sig/generated/typed_cache/instrumenters/monitor.rbs
|
208
|
+
- sig/generated/typed_cache/instrumenters/null.rbs
|
188
209
|
- sig/generated/typed_cache/maybe.rbs
|
189
210
|
- sig/generated/typed_cache/namespace.rbs
|
211
|
+
- sig/generated/typed_cache/railtie.rbs
|
190
212
|
- sig/generated/typed_cache/registry.rbs
|
191
213
|
- sig/generated/typed_cache/snapshot.rbs
|
192
214
|
- sig/generated/typed_cache/store.rbs
|
193
215
|
- sig/generated/typed_cache/store/instrumented.rbs
|
194
216
|
- sig/generated/typed_cache/version.rbs
|
195
|
-
- sig/handwritten/gems/zeitwerk/2.7/zeitwerk.rbs
|
196
217
|
- typed_cache.gemspec
|
197
218
|
homepage: https://github.com/glossawy/typed_cache
|
198
219
|
licenses:
|
199
220
|
- Apache-2.0
|
200
221
|
metadata:
|
201
222
|
issue_tracker_uri: https://github.com/glossawy/typed_cache/issues
|
202
|
-
changelog_uri: https://github.com/glossawy/typed_cache/blob/main/VERSIONS.adoc#
|
223
|
+
changelog_uri: https://github.com/glossawy/typed_cache/blob/main/VERSIONS.adoc#030
|
203
224
|
license_uri: https://github.com/glossawy/typed_cache/blob/main/LICENSE
|
204
225
|
label: caching
|
205
226
|
labels: typed_cache,ruby,caching,type-safety,rails,rbs
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,112 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'dry/configurable'
|
4
|
-
|
5
|
-
module TypedCache
|
6
|
-
# Instrumentation hooks for ActiveSupport::Notifications integration
|
7
|
-
# All instrumentation is explicit and opt-in - no automatic behavior
|
8
|
-
module Instrumentation
|
9
|
-
class << self
|
10
|
-
# @rbs! type config = TypedCache::_TypedCacheInstrumentationConfig
|
11
|
-
|
12
|
-
# @rbs () -> config
|
13
|
-
def config
|
14
|
-
TypedCache.config.instrumentation
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check if ActiveSupport::Notifications is available
|
18
|
-
# @rbs () -> bool
|
19
|
-
def notifications_available?
|
20
|
-
defined?(ActiveSupport::Notifications)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Main instrumentation method
|
24
|
-
#: [T] (String, String, String, Hash[Symbol, untyped]) { -> T } -> T
|
25
|
-
def instrument(operation, namespace, key, payload = {})
|
26
|
-
return yield unless config.enabled && notifications_available?
|
27
|
-
|
28
|
-
event_name = "#{operation}.#{config.namespace}"
|
29
|
-
start_time = current_time
|
30
|
-
|
31
|
-
begin
|
32
|
-
result = yield
|
33
|
-
|
34
|
-
# Determine success and extract metadata
|
35
|
-
success, snapshot_data = extract_result_metadata(result)
|
36
|
-
|
37
|
-
final_payload = base_payload(namespace, key, start_time).merge(payload).merge({
|
38
|
-
success: success,
|
39
|
-
**snapshot_data,
|
40
|
-
})
|
41
|
-
|
42
|
-
ActiveSupport::Notifications.instrument(event_name, final_payload) do
|
43
|
-
# This block is called by subscribers who want the result
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
|
-
result
|
48
|
-
rescue => error
|
49
|
-
error_payload = base_payload(namespace, key, start_time).merge(payload).merge({
|
50
|
-
success: false,
|
51
|
-
error: error.class.name,
|
52
|
-
error_message: error.message,
|
53
|
-
})
|
54
|
-
|
55
|
-
ActiveSupport::Notifications.instrument(event_name, error_payload)
|
56
|
-
raise
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
# Cross-platform current time helper (uses Time.current when available)
|
63
|
-
#: -> Time
|
64
|
-
def current_time
|
65
|
-
if Time.respond_to?(:current)
|
66
|
-
Time.current
|
67
|
-
else
|
68
|
-
Time.now
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# @rbs (String, String, Time) -> Hash[Symbol, untyped]
|
73
|
-
def base_payload(namespace, key, start_time)
|
74
|
-
{
|
75
|
-
namespace: namespace,
|
76
|
-
key: key,
|
77
|
-
duration: (current_time - start_time) * 1000.0, # milliseconds
|
78
|
-
store_type: nil, # Will be set by caller if available
|
79
|
-
}
|
80
|
-
end
|
81
|
-
|
82
|
-
# @rbs (Either[StandardError, Snapshot]) -> [bool, Hash[Symbol, untyped]]
|
83
|
-
def extract_result_metadata(result)
|
84
|
-
case result
|
85
|
-
when Either
|
86
|
-
if result.right?
|
87
|
-
snapshot = result.value
|
88
|
-
if snapshot.is_a?(Snapshot)
|
89
|
-
[true, {
|
90
|
-
cache_hit: snapshot.from_cache?,
|
91
|
-
cache_miss: !snapshot.from_cache?,
|
92
|
-
source: snapshot.source,
|
93
|
-
snapshot_age: snapshot.age,
|
94
|
-
},]
|
95
|
-
else
|
96
|
-
[true, { cache_hit: false, cache_miss: true }]
|
97
|
-
end
|
98
|
-
else
|
99
|
-
error_data = {
|
100
|
-
cache_hit: false,
|
101
|
-
cache_miss: true,
|
102
|
-
error_type: result.error.class.name,
|
103
|
-
}
|
104
|
-
[false, error_data]
|
105
|
-
end
|
106
|
-
else
|
107
|
-
[true, {}]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TypedCache
|
4
|
-
# Decorator that adds instrumentation to any Store implementation
|
5
|
-
# This decorator can wrap any store to add ActiveSupport::Notifications
|
6
|
-
# @rbs generic V
|
7
|
-
class Store::Instrumented # rubocop:disable Style/ClassAndModuleChildren
|
8
|
-
include Decorator #[V]
|
9
|
-
|
10
|
-
extend Forwardable
|
11
|
-
|
12
|
-
attr_reader :store #: TypedCache::Store[V]
|
13
|
-
|
14
|
-
class << self
|
15
|
-
private
|
16
|
-
|
17
|
-
# @rbs (Symbol, ?operation: String) ?{ (*untyped, **untyped) -> String } -> void
|
18
|
-
def instrument(method_name, operation: method_name.to_s, &key_selector)
|
19
|
-
define_method(:"#{method_name}_with_instrumentation") do |*args, **kwargs, &block|
|
20
|
-
key = key_selector.call(*args, **kwargs) if key_selector # rubocop:disable Performance/RedundantBlockCall
|
21
|
-
|
22
|
-
Instrumentation.instrument(operation, namespace, key || 'n/a', store_type: store_type) do
|
23
|
-
send(:"#{method_name}_without_instrumentation", *args, **kwargs, &block)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
alias_method(:"#{method_name}_without_instrumentation", method_name)
|
28
|
-
alias_method(method_name, :"#{method_name}_with_instrumentation")
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
#: (TypedCache::Store[V]) -> void
|
33
|
-
def initialize(store)
|
34
|
-
@store = store
|
35
|
-
end
|
36
|
-
|
37
|
-
# @rbs override
|
38
|
-
#: -> String
|
39
|
-
def namespace
|
40
|
-
store.namespace
|
41
|
-
end
|
42
|
-
|
43
|
-
# @rbs override
|
44
|
-
#: -> String
|
45
|
-
def store_type
|
46
|
-
# Use polymorphism - delegate to the wrapped store
|
47
|
-
"instrumented(#{store.store_type})"
|
48
|
-
end
|
49
|
-
|
50
|
-
# @rbs override
|
51
|
-
#: (cache_key) -> either[Error, CacheRef[V]]
|
52
|
-
def ref(key)
|
53
|
-
CacheRef.new(self, key)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Additional methods that might exist on the wrapped store
|
57
|
-
def respond_to_missing?(method_name, include_private = false)
|
58
|
-
store.respond_to?(method_name, include_private) || super
|
59
|
-
end
|
60
|
-
|
61
|
-
def method_missing(method_name, *args, &block)
|
62
|
-
if store.respond_to?(method_name)
|
63
|
-
store.send(method_name, *args, &block)
|
64
|
-
else
|
65
|
-
super
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
Store.instance_methods(false).each do |method_name|
|
70
|
-
next if instance_methods(false).include?(method_name)
|
71
|
-
|
72
|
-
def_delegator :store, method_name
|
73
|
-
end
|
74
|
-
|
75
|
-
# Instrument core operations with proper key extraction
|
76
|
-
instrument(:get) { |key, *_| key }
|
77
|
-
instrument(:set) { |key, *_| key }
|
78
|
-
instrument(:delete) { |key, *_| key }
|
79
|
-
instrument(:fetch) { |key, *_| key }
|
80
|
-
instrument(:key?) { |key, *_| key }
|
81
|
-
instrument(:clear) { 'all' }
|
82
|
-
end
|
83
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# Generated from lib/typed_cache/instrumentation.rb with RBS::Inline
|
2
|
-
|
3
|
-
module TypedCache
|
4
|
-
# Instrumentation hooks for ActiveSupport::Notifications integration
|
5
|
-
# All instrumentation is explicit and opt-in - no automatic behavior
|
6
|
-
module Instrumentation
|
7
|
-
type config = TypedCache::_TypedCacheInstrumentationConfig
|
8
|
-
|
9
|
-
# @rbs () -> config
|
10
|
-
def self.config: () -> config
|
11
|
-
|
12
|
-
# Check if ActiveSupport::Notifications is available
|
13
|
-
# @rbs () -> bool
|
14
|
-
def self.notifications_available?: () -> bool
|
15
|
-
|
16
|
-
# Main instrumentation method
|
17
|
-
# : [T] (String, String, String, Hash[Symbol, untyped]) { -> T } -> T
|
18
|
-
def self.instrument: [T] (String, String, String, Hash[Symbol, untyped]) { () -> T } -> T
|
19
|
-
|
20
|
-
# Cross-platform current time helper (uses Time.current when available)
|
21
|
-
# : -> Time
|
22
|
-
private def self.current_time: () -> Time
|
23
|
-
|
24
|
-
# @rbs (String, String, Time) -> Hash[Symbol, untyped]
|
25
|
-
private def self.base_payload: (String, String, Time) -> Hash[Symbol, untyped]
|
26
|
-
|
27
|
-
# @rbs (Either[StandardError, Snapshot]) -> [bool, Hash[Symbol, untyped]]
|
28
|
-
private def self.extract_result_metadata: (Either[StandardError, Snapshot]) -> [ bool, Hash[Symbol, untyped] ]
|
29
|
-
end
|
30
|
-
end
|