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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +139 -20
  4. data/examples.md +140 -50
  5. data/lib/typed_cache/backends/active_support.rb +50 -5
  6. data/lib/typed_cache/backends/memory.rb +14 -11
  7. data/lib/typed_cache/backends.rb +6 -8
  8. data/lib/typed_cache/cache_builder.rb +72 -19
  9. data/lib/typed_cache/cache_key.rb +11 -1
  10. data/lib/typed_cache/cache_ref.rb +20 -16
  11. data/lib/typed_cache/clock.rb +31 -14
  12. data/lib/typed_cache/decorator.rb +25 -0
  13. data/lib/typed_cache/decorators/instrumented.rb +92 -0
  14. data/lib/typed_cache/decorators.rb +7 -3
  15. data/lib/typed_cache/either.rb +22 -0
  16. data/lib/typed_cache/errors.rb +9 -1
  17. data/lib/typed_cache/instrumenter.rb +43 -0
  18. data/lib/typed_cache/instrumenters/active_support.rb +28 -0
  19. data/lib/typed_cache/instrumenters/mixins/namespaced_singleton.rb +55 -0
  20. data/lib/typed_cache/instrumenters/mixins.rb +8 -0
  21. data/lib/typed_cache/instrumenters/monitor.rb +27 -0
  22. data/lib/typed_cache/instrumenters/null.rb +26 -0
  23. data/lib/typed_cache/instrumenters.rb +39 -0
  24. data/lib/typed_cache/maybe.rb +18 -0
  25. data/lib/typed_cache/namespace.rb +33 -6
  26. data/lib/typed_cache/railtie.rb +15 -0
  27. data/lib/typed_cache/registry.rb +15 -0
  28. data/lib/typed_cache/snapshot.rb +18 -10
  29. data/lib/typed_cache/store.rb +50 -15
  30. data/lib/typed_cache/version.rb +1 -1
  31. data/lib/typed_cache.rb +34 -14
  32. data/rbi/typed_cache/backend.rbi +9 -0
  33. data/rbi/typed_cache/backends/active_support.rbi +13 -0
  34. data/rbi/typed_cache/backends/memory.rbi +13 -0
  35. data/rbi/typed_cache/backends.rbi +19 -0
  36. data/rbi/typed_cache/cache_builder.rbi +23 -0
  37. data/rbi/typed_cache/cache_key.rbi +16 -0
  38. data/rbi/typed_cache/cache_ref.rbi +56 -0
  39. data/rbi/typed_cache/decorator.rbi +67 -0
  40. data/rbi/typed_cache/decorators/instrumented.rbi +13 -0
  41. data/rbi/typed_cache/decorators.rbi +19 -0
  42. data/rbi/typed_cache/either.rbi +122 -0
  43. data/rbi/typed_cache/errors.rbi +20 -0
  44. data/rbi/typed_cache/instrumenter.rbi +45 -0
  45. data/rbi/typed_cache/instrumenters/mixins/namedspaced_singleton.rbi +33 -0
  46. data/rbi/typed_cache/instrumenters.rbi +19 -0
  47. data/rbi/typed_cache/maybe.rbi +108 -0
  48. data/rbi/typed_cache/namespace.rbi +30 -0
  49. data/rbi/typed_cache/snapshot.rbi +54 -0
  50. data/rbi/typed_cache/store.rbi +71 -0
  51. data/rbi/typed_cache/version.rbi +5 -0
  52. data/rbi/typed_cache.rbi +49 -0
  53. data/sig/generated/typed_cache/backends/active_support.rbs +14 -2
  54. data/sig/generated/typed_cache/backends/memory.rbs +2 -2
  55. data/sig/generated/typed_cache/backends.rbs +2 -0
  56. data/sig/generated/typed_cache/cache_builder.rbs +13 -2
  57. data/sig/generated/typed_cache/cache_key.rbs +5 -0
  58. data/sig/generated/typed_cache/cache_ref.rbs +4 -4
  59. data/sig/generated/typed_cache/clock.rbs +19 -9
  60. data/sig/generated/typed_cache/decorator.rbs +12 -0
  61. data/sig/generated/typed_cache/decorators/instrumented.rbs +35 -0
  62. data/sig/generated/typed_cache/decorators.rbs +2 -0
  63. data/sig/generated/typed_cache/either.rbs +24 -0
  64. data/sig/generated/typed_cache/errors.rbs +2 -0
  65. data/sig/generated/typed_cache/instrumenter.rbs +31 -0
  66. data/sig/generated/typed_cache/instrumenters/active_support.rbs +20 -0
  67. data/sig/generated/typed_cache/instrumenters/mixins/namespaced_singleton.rbs +36 -0
  68. data/sig/generated/typed_cache/instrumenters/mixins.rbs +8 -0
  69. data/sig/generated/typed_cache/instrumenters/monitor.rbs +19 -0
  70. data/sig/generated/typed_cache/instrumenters/null.rbs +21 -0
  71. data/sig/generated/typed_cache/instrumenters.rbs +26 -0
  72. data/sig/generated/typed_cache/maybe.rbs +20 -0
  73. data/sig/generated/typed_cache/namespace.rbs +24 -3
  74. data/sig/generated/typed_cache/railtie.rbs +6 -0
  75. data/sig/generated/typed_cache/registry.rbs +8 -0
  76. data/sig/generated/typed_cache/snapshot.rbs +12 -6
  77. data/sig/generated/typed_cache/store/instrumented.rbs +2 -6
  78. data/sig/generated/typed_cache/store.rbs +26 -8
  79. data/sig/generated/typed_cache.rbs +8 -6
  80. data/typed_cache.gemspec +5 -4
  81. data.tar.gz.sig +0 -0
  82. metadata +48 -27
  83. metadata.gz.sig +0 -0
  84. data/lib/typed_cache/instrumentation.rb +0 -112
  85. data/lib/typed_cache/store/instrumented.rb +0 -83
  86. data/sig/generated/typed_cache/instrumentation.rbs +0 -30
  87. 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 get: (cache_key) -> either[Error, Snapshot[V]]
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 set: (cache_key, V) -> either[Error, Snapshot[V]]
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 get: (cache_key) -> either[Error, Snapshot[V]]
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 set: (cache_key, V) -> either[Error, Snapshot[V]]
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 get and set
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
- # @rbs (Namespace | String) -> Store[V]
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(Instrumentation)
27
- def self.instrumentation: () -> singleton(Instrumentation)
28
+ # @rbs () -> singleton(Backends)
29
+ def self.backends: () -> singleton(Backends)
28
30
 
29
- # @rbs () -> Registry[backend[untyped]]
30
- def self.backends: () -> Registry[backend[untyped]]
31
+ # @rbs () -> singleton(Decorators)
32
+ def self.decorators: () -> singleton(Decorators)
31
33
 
32
- # @rbs () -> Register[decorator[untyped]]
33
- def self.decorators: () -> Register[decorator[untyped]]
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
- spec.add_dependency('concurrent-ruby', '~> 1.3.5')
33
- spec.add_dependency('concurrent-ruby-edge', '~>0.7.2')
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.1.1
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-07-21 00:00:00.000000000 Z
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.3.5
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.3.5
53
+ version: '1.0'
54
54
  - !ruby/object:Gem::Dependency
55
- name: concurrent-ruby-edge
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.7.2
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.7.2
67
+ version: '1.0'
68
68
  - !ruby/object:Gem::Dependency
69
- name: dry-configurable
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/instrumentation.rb
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/instrumentation.rbs
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#011
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
@@ -1,9 +0,0 @@
1
-
2
-
3
- module Zeitwerk
4
- class Loader
5
- def self.for_gem: -> instance
6
-
7
- def setup: -> void
8
- end
9
- end