typed_cache 0.3.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52137d39af663110c085558e5d6885fbe22d02b4a185f7a1ef3f4aa2dbe6a619
4
- data.tar.gz: 030bf378a6effe782ab28fdb876c64c73d8997e5a3a9ec543735abe55973e421
3
+ metadata.gz: 68662a3e64b70950b86c466f7435aa4dc0ba5c31a87637244ece41685aa2cc00
4
+ data.tar.gz: 07fae7547c15ca5e7bfd900f9f74bb2f40443102bca143ce0f8cee8dc79c4069
5
5
  SHA512:
6
- metadata.gz: 38641da2ef43033f286833d84492b02f09dcfca291e7eab53c93bf6c9f737de5f077984a4f742de06c62a0c90db19d00bbc03cb032485143e9a542576fb5f90c
7
- data.tar.gz: 2fb8cd40d84bb43a3f9905ccc7c0d30d853cdf0b030cf192a6e17517545ac94f256a3371f85bcd068e4f08d12c7a32a937f8eb3a87622b8b3a16429e772bd8bb
6
+ metadata.gz: f81441fdceb975a4251d9f9d816cf71a40847e8ad1f9a3adea0d92075617ef0c9c85ed980b7707b9327221a75dc385459b954bd492e82ff08416fdb835fd6ba6
7
+ data.tar.gz: ef41b5392bb1f6adb0b2ccbf7f73ea6363c562b3e0621990f94c52445c048c598b9a0c875ad1d4ffaa03907576f68673614098281620d220ba96d6812b70531a
checksums.yaml.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TypedCache
2
2
 
3
- ![Gem Version](https://img.shields.io/gem/v/typed_cache?style=flat-square&logo=rubygems)
3
+ [![Gem Version](https://img.shields.io/gem/v/typed_cache?style=flat-square&logo=rubygems)](https://rubygems.org/gems/typed_cache)
4
4
  ![GitHub Release Date](https://img.shields.io/github/release-date/glossawy/typed_cache?style=flat-square&label=released&logo=semanticrelease)
5
5
  ![GitHub last commit](https://img.shields.io/github/last-commit/glossawy/typed_cache?style=flat-square&logo=git)
6
6
 
@@ -88,7 +88,7 @@ TypedCache::Decorators.available # => [:instrumented]
88
88
  ```ruby
89
89
  class RedisBackend
90
90
  include TypedCache::Backend
91
- # … implement #get, #set, etc.
91
+ # … implement #read, #write, etc.
92
92
  end
93
93
 
94
94
  TypedCache::Backends.register(:redis, RedisBackend)
@@ -98,9 +98,9 @@ TypedCache::Backends.register(:redis, RedisBackend)
98
98
  class LogDecorator
99
99
  include TypedCache::Decorator
100
100
  def initialize(store) = @store = store
101
- def set(key, value)
102
- puts "[cache] SET #{key}"
103
- @store.set(key, value)
101
+ def write(key, value)
102
+ puts "[cache] WRITE #{key}"
103
+ @store.write(key, value)
104
104
  end
105
105
  # delegate the rest …
106
106
  end
@@ -127,7 +127,7 @@ result.fold(
127
127
 
128
128
  ## The `CacheRef` and `Store` APIs
129
129
 
130
- While you can call `get`, `set`, and `fetch` directly on the `store`, the more powerful way to work with TypedCache is via the `CacheRef` object. It provides a rich, monadic API for a single cache key. The `Store` also provides `fetch_all` for batch operations.
130
+ While you can call `read`, `write`, and `fetch` directly on the `store`, the more powerful way to work with TypedCache is via the `CacheRef` object. It provides a rich, monadic API for a single cache key. The `Store` also provides `fetch_all` for batch operations.
131
131
 
132
132
  You get a `CacheRef` by calling `store.ref(key)`:
133
133
 
@@ -196,7 +196,7 @@ store = TypedCache.builder
196
196
  .build.value
197
197
  ```
198
198
 
199
- Events are published to a topic like `typed_cache.<operation>` (e.g., `typed_cache.get`). The topic namespace can be configured.
199
+ Events are published to a topic like `typed_cache.<operation>` (e.g., `typed_cache.write`). The topic namespace can be configured.
200
200
 
201
201
  Payload keys include: `:namespace, :key, :operation, :duration`, and `cache_hit`.
202
202
 
@@ -204,13 +204,13 @@ You can subscribe to these events like so:
204
204
 
205
205
  ```ruby
206
206
  # Example for ActiveSupport
207
- ActiveSupport::Notifications.subscribe("typed_cache.get") do |name, start, finish, id, payload|
207
+ ActiveSupport::Notifications.subscribe("typed_cache.write") do |name, start, finish, id, payload|
208
208
 
209
209
  # Or you can subscribe via the store object itself
210
210
  instrumenter = store.instrumenter
211
- instrumenter.subscribe("get") do |event|
211
+ instrumenter.subscribe("write") do |event|
212
212
  payload = event.payload
213
- puts "Cache GET for key #{payload[:key]} took #{payload[:duration]}ms. Hit? #{payload[:cache_hit]}"
213
+ puts "Cache WRITE for key #{payload[:key]} took #{payload[:duration]}ms. Hit? #{payload[:cache_hit]}"
214
214
  end
215
215
  ```
216
216
 
data/examples.md CHANGED
@@ -19,7 +19,7 @@ users_store = builder.build(TypedCache::Namespace.at("users")).value
19
19
  user_ref = users_store.ref("123")
20
20
 
21
21
  # Set a value
22
- user_ref.set({ id: 123, name: "Jane" })
22
+ user_ref.write({ id: 123, name: "Jane" })
23
23
  ```
24
24
 
25
25
  ## Rails Integration
@@ -51,7 +51,7 @@ result = TypedCache.builder
51
51
 
52
52
  case result
53
53
  in TypedCache::Either::Right(store)
54
- store.set(store.namespace.key("greeting"), "Hello")
54
+ store.write(store.namespace.key("greeting"), "Hello")
55
55
  in TypedCache::Either::Left(error)
56
56
  warn "Failed to set up cache: #{error.message}"
57
57
  end
@@ -84,7 +84,7 @@ puts ns2.to_s # => "app:v1:users"
84
84
 
85
85
  # You can then build a store with this complex namespace
86
86
  user_store = base_builder.build(ns1).value
87
- user_store.ref("123").set({ name: "Deeply Nested" })
87
+ user_store.ref("123").write({ name: "Deeply Nested" })
88
88
  ```
89
89
 
90
90
  ## CacheRef and Store APIs
@@ -95,12 +95,12 @@ The `CacheRef` is the most powerful way to interact with a single cache key, whi
95
95
  ref = store.ref("some-key") # => CacheRef
96
96
  ```
97
97
 
98
- ### Get a value
98
+ ### Read a value
99
99
 
100
- The `get` method returns an `Either[Error, Snapshot]`.
100
+ The `read` method returns an `Either[Error, Snapshot]`.
101
101
 
102
102
  ```ruby
103
- result = ref.get
103
+ result = ref.read
104
104
  result.fold(
105
105
  ->(error) { puts "Cache miss or error: #{error.message}" },
106
106
  ->(snapshot) { puts "Found: #{snapshot.value} (from cache: #{snapshot.from_cache?})" }
@@ -140,7 +140,7 @@ You can transform the value inside the cache reference without breaking the mona
140
140
  # user_ref holds { id: 1, name: "John" }
141
141
  name_ref = user_ref.map { |user| user[:name] }
142
142
 
143
- name_snapshot = name_ref.get.value # => Snapshot(value: "John", ...)
143
+ name_snapshot = name_ref.read.value # => Snapshot(value: "John", ...)
144
144
  ```
145
145
 
146
146
  ### Chaining operations with `bind`
@@ -150,7 +150,7 @@ For more complex logic, you can use `bind` (or `flat_map`) to chain operations t
150
150
  ```ruby
151
151
  user_ref.bind do |user|
152
152
  if user.active?
153
- posts_ref.set(user.posts)
153
+ posts_ref.write(user.posts)
154
154
  else
155
155
  TypedCache::Either.left(StandardError.new("User is not active"))
156
156
  end
@@ -178,12 +178,12 @@ class SimpleStore
178
178
  @data = {}
179
179
  end
180
180
 
181
- def get(key)
181
+ def read(key)
182
182
  value = @data[key]
183
183
  value ? TypedCache::Either.right(value) : TypedCache::Either.left(TypedCache::CacheMissError.new(key))
184
184
  end
185
185
 
186
- def set(key, value)
186
+ def write(key, value)
187
187
  @data[key] = value
188
188
  TypedCache::Either.right(value)
189
189
  end
@@ -239,12 +239,12 @@ logging_cache = TypedCache.builder
239
239
  .build.value
240
240
 
241
241
  # Subscribe to an event
242
- logging_cache.instrumenter.subscribe("get")
242
+ logging_cache.instrumenter.subscribe("write")
243
243
 
244
244
  # Operations will now be logged
245
- logging_cache.ref("test").set("hello")
246
- # => [CACHE] Starting: set for key test
247
- # => [CACHE] Finished: set for key test
245
+ logging_cache.ref("test").write("hello")
246
+ # => [CACHE] Starting: write for key test
247
+ # => [CACHE] Finished: write for key test
248
248
  ```
249
249
 
250
250
  ## Thread Safety
@@ -257,7 +257,7 @@ shared_store = TypedCache.builder
257
257
  .build.value
258
258
 
259
259
  threads = 10.times.map do |i|
260
- Thread.new { shared_store.set(shared_store.namespace.key(i.to_s), "data_") }
260
+ Thread.new { shared_store.write(shared_store.namespace.key(i.to_s), "data_") }
261
261
  end
262
262
  threads.each(&:join)
263
263
  ```
@@ -273,7 +273,7 @@ spec_store = TypedCache.builder
273
273
 
274
274
  RSpec.describe "cache" do
275
275
  it "stores data" do
276
- result = spec_store.set(spec_store.namespace.key("id"), 1)
276
+ result = spec_store.write(spec_store.namespace.key("id"), 1)
277
277
  expect(result).to be_right
278
278
  end
279
279
  end
@@ -19,10 +19,10 @@ module TypedCache
19
19
  end
20
20
 
21
21
  # @rbs override
22
- #: (cache_key) -> either[Error, Snapshot[V]]
23
- def read(key)
22
+ #: (cache_key, **top) -> either[Error, Snapshot[V]]
23
+ def read(key, **kwargs)
24
24
  cache_key_str = namespaced_key(key).to_s
25
- raw_value = cache_store.read(cache_key_str, default_options)
25
+ raw_value = cache_store.read(cache_key_str, default_options.merge(**kwargs))
26
26
  return Either.left(CacheMissError.new(key)) if raw_value.nil?
27
27
 
28
28
  Either.right(Snapshot.cached(key, raw_value))
@@ -31,10 +31,10 @@ module TypedCache
31
31
  end
32
32
 
33
33
  # @rbs override
34
- #: (cache_key, V) -> either[Error, Snapshot[V]]
35
- def write(key, value)
34
+ #: (cache_key, V, **top) -> either[Error, Snapshot[V]]
35
+ def write(key, value, **kwargs)
36
36
  cache_key_str = namespaced_key(key).to_s
37
- success = cache_store.write(cache_key_str, value, default_options)
37
+ success = cache_store.write(cache_key_str, value, default_options.merge(**kwargs))
38
38
 
39
39
  if success
40
40
  Either.right(Snapshot.cached(key, value))
@@ -46,9 +46,9 @@ module TypedCache
46
46
  end
47
47
 
48
48
  # @rbs override
49
- #: (Hash[cache_key, V]) -> either[Error, Array[Snapshot[V]]]
50
- def write_all(values)
51
- results = cache_store.write_multi(values.map { |key, value| [namespaced_key(key).to_s, value] }.to_h, default_options)
49
+ #: (Hash[cache_key, V], **top) -> either[Error, Array[Snapshot[V]]]
50
+ def write_all(values, **kwargs)
51
+ results = cache_store.write_multi(values.map { |key, value| [namespaced_key(key).to_s, value] }.to_h, default_options.merge(**kwargs))
52
52
  Either.right(results.map { |key, value| Snapshot.cached(key, value) })
53
53
  rescue => e
54
54
  Either.left(StoreError.new(:set_all, values, "Failed to write to cache: #{e.message}", e))
@@ -70,20 +70,20 @@ module TypedCache
70
70
  end
71
71
 
72
72
  # @rbs override
73
- #: (Array[cache_key]) -> either[Error, Array[Snapshot[V]]]
74
- def read_all(keys)
75
- results = cache_store.read_multi(*keys.map { |key| namespaced_key(key).to_s }, default_options)
73
+ #: (Array[cache_key], **top) -> either[Error, Array[Snapshot[V]]]
74
+ def read_all(keys, **kwargs)
75
+ results = cache_store.read_multi(*keys.map { |key| namespaced_key(key).to_s }, default_options.merge(**kwargs))
76
76
  Either.right(results.map { |key, value| [key, Snapshot.cached(key, value)] }.to_h)
77
77
  end
78
78
 
79
79
  # @rbs override
80
- #: (Array[cache_key]) { (CacheKey) -> V? } -> either[Error, Array[Snapshot[V]]]
81
- def fetch_all(keys, &block)
80
+ #: (Array[cache_key], **top) { (CacheKey) -> V? } -> either[Error, Array[Snapshot[V]]]
81
+ def fetch_all(keys, **kwargs, &block)
82
82
  cache_keys = keys.map { |key| namespaced_key(key) }
83
83
  key_map = cache_keys.index_by(&:to_s)
84
84
 
85
85
  computed_keys = Set.new #: Set[String]
86
- results = cache_store.fetch_multi(*key_map.keys, default_options) do |key|
86
+ results = cache_store.fetch_multi(*key_map.keys, default_options.merge(**kwargs)) do |key|
87
87
  computed_keys << key
88
88
  yield(key_map[key])
89
89
  end
@@ -68,8 +68,8 @@ module TypedCache
68
68
  end
69
69
 
70
70
  # @rbs override
71
- #: (cache_key) -> either[Error, Snapshot[V]]
72
- def read(key)
71
+ #: (cache_key, **top) -> either[Error, Snapshot[V]]
72
+ def read(key, **kwargs)
73
73
  key = namespaced_key(key)
74
74
  return Either.left(CacheMissError.new(key)) unless backing_store.key?(key)
75
75
 
@@ -84,10 +84,9 @@ module TypedCache
84
84
  end
85
85
 
86
86
  # @rbs override
87
- #: (cache_key, V) -> either[Error, Snapshot[V]]
88
- def write(key, value)
87
+ #: (cache_key, V, expires_in: Integer, expires_at: Time, **top) -> either[Error, Snapshot[V]]
88
+ def write(key, value, expires_in: @ttl, expires_at: Clock.now + expires_in, **kwargs)
89
89
  key = namespaced_key(key)
90
- expires_at = Clock.now + @ttl
91
90
  entry = Entry.new(value: value, expires_at: expires_at)
92
91
  backing_store[key] = entry
93
92
  Either.right(Snapshot.cached(key, value))
@@ -45,14 +45,14 @@ module TypedCache
45
45
  end
46
46
 
47
47
  # Retrieves a value from the cache
48
- # @rbs (cache_key) -> either[Error, Snapshot[V]]
49
- def read(key)
48
+ # @rbs (cache_key, **top) -> either[Error, Snapshot[V]]
49
+ def read(key, **kwargs)
50
50
  Either.left(NotImplementedError.new("#{self.class} must implement #read"))
51
51
  end
52
52
 
53
- # @rbs (Array[cache_key]) -> either[Error, Hash[cache_key, Snapshot[V]]]
54
- def read_all(keys)
55
- keys.map { |key| read(key) }.reduce(Either.right({})) do |acc, result|
53
+ # @rbs (Array[cache_key], **top) -> either[Error, Hash[cache_key, Snapshot[V]]]
54
+ def read_all(keys, **kwargs)
55
+ keys.map { |key| read(key, **kwargs) }.reduce(Either.right({})) do |acc, result|
56
56
  acc.bind do |values|
57
57
  result.map { |value| values.merge(value.key => value) }
58
58
  end
@@ -66,14 +66,14 @@ module TypedCache
66
66
  end
67
67
 
68
68
  # Stores a value in the cache
69
- # @rbs (cache_key, V) -> either[Error, Snapshot[V]]
70
- def write(key, value)
69
+ # @rbs (cache_key, V, **top) -> either[Error, Snapshot[V]]
70
+ def write(key, value, **kwargs)
71
71
  Either.left(NotImplementedError.new("#{self.class} must implement #write"))
72
72
  end
73
73
 
74
- # @rbs (Hash[cache_key, V]) -> either[Error, Hash[cache_key, Snapshot[V]]]
75
- def write_all(values)
76
- values.map { |key, value| write(key, value) }.reduce(Either.right({})) do |acc, result|
74
+ # @rbs (Hash[cache_key, V], **top) -> either[Error, Hash[cache_key, Snapshot[V]]]
75
+ def write_all(values, **kwargs)
76
+ values.map { |key, value| write(key, value, **kwargs) }.reduce(Either.right({})) do |acc, result|
77
77
  acc.bind do |values|
78
78
  result.map { |value| values.merge(value.key => value) }
79
79
  end
@@ -100,8 +100,8 @@ module TypedCache
100
100
 
101
101
  # Fetches a value from cache, computing and storing it if not found
102
102
  # This is an atomic operation that combines read and write
103
- # @rbs (cache_key) { () -> V } -> either[Error, Snapshot[V]]
104
- def fetch(key, &block)
103
+ # @rbs (cache_key, **top) { () -> V } -> either[Error, Snapshot[V]]
104
+ def fetch(key, **kwargs, &block)
105
105
  # Default implementation using read/write pattern
106
106
  read_result = read(key)
107
107
  return read_result if read_result.right?
@@ -112,19 +112,19 @@ module TypedCache
112
112
  # Compute and store new value
113
113
  begin
114
114
  computed_value = yield
115
- write(key, computed_value)
115
+ write(key, computed_value, **kwargs)
116
116
  Either.right(Snapshot.computed(key, computed_value))
117
117
  rescue => e
118
118
  Either.left(StoreError.new(:fetch, key, "Failed to compute value for key '#{key}': #{e.message}", e))
119
119
  end
120
120
  end
121
121
 
122
- # @rbs (Array[cache_key]) { (CacheKey) -> V } -> either[Error, Array[Snapshot[V]]]
123
- def fetch_all(keys, &block)
122
+ # @rbs (Array[cache_key], **top) { (CacheKey) -> V } -> either[Error, Array[Snapshot[V]]]
123
+ def fetch_all(keys, **kwargs, &block)
124
124
  keys = keys.map { |key| namespaced_key(key) }
125
125
  keys.reduce(Either.right([])) do |acc, key|
126
126
  acc.bind do |values|
127
- fetch(key) { yield(key) }.map { |value| values + [value] }
127
+ fetch(key. **kwargs) { yield(key) }.map { |value| values + [value] }
128
128
  end
129
129
  end
130
130
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TypedCache
4
- VERSION = '0.3.0'
4
+ VERSION = '0.3.1'
5
5
  end
@@ -12,17 +12,17 @@ module TypedCache
12
12
  Key = T.type_alias { T.any(String, ::TypedCache::CacheKey) }
13
13
  private_constant :Error, :Key
14
14
 
15
- sig { params(key: Key).returns(::TypedCache::Either[Error, CachedType]) }
16
- def read(key); end
15
+ sig { params(key: Key, kwargs: T::Hash[Symbol, T.untyped]).returns(::TypedCache::Either[Error, CachedType]) }
16
+ def read(key, **kwargs); end
17
17
 
18
- sig { params(keys: T::Array[Key]).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
19
- def read_all(keys); end
18
+ sig { params(keys: T::Array[Key], kwargs: T::Hash[Symbol, T.untyped]).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
19
+ def read_all(keys, **kwargs); end
20
20
 
21
- sig { params(key: Key, value: CachedType).returns(::TypedCache::Either[Error, ::TypedCache::Snapshot[CachedType]]) }
22
- def write(key, value); end
21
+ sig { params(key: Key, value: CachedType, kwargs: T::Hash[Symbol, T.untyped]).returns(::TypedCache::Either[Error, ::TypedCache::Snapshot[CachedType]]) }
22
+ def write(key, value, **kwargs); end
23
23
 
24
- sig { params(values: T::Hash[Key, CachedType]).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
25
- def write_all(values); end
24
+ sig { params(values: T::Hash[Key, CachedType], kwargs: T::Hash[Symbol, T.untyped]).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
25
+ def write_all(values, **kwargs); end
26
26
 
27
27
  sig { params(key: Key).returns(::TypedCache::Either[Error, ::TypedCache::Snapshot[CachedType]]) }
28
28
  def delete(key); end
@@ -36,11 +36,11 @@ module TypedCache
36
36
  sig { params(key: Key).returns(T::Boolean) }
37
37
  def key?(key); end
38
38
 
39
- sig { params(key: Key, block: T.proc.returns(T.nilable(CachedType))).returns(::TypedCache::Either[Error, ::TypedCache::Snapshot[::TypedCache::Maybe[CachedType]]]) }
40
- def fetch(key, &block); end
39
+ sig { params(key: Key, kwargs: T::Hash[Symbol, T.untyped], block: T.proc.returns(T.nilable(CachedType))).returns(::TypedCache::Either[Error, ::TypedCache::Snapshot[::TypedCache::Maybe[CachedType]]]) }
40
+ def fetch(key, **kwargs, &block); end
41
41
 
42
- sig { params(keys: T::Array[Key], block: T.proc.params(key: ::TypedCache::CacheKey).returns(T.nilable(CachedType))).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
43
- def fetch_all(keys, &block); end
42
+ sig { params(keys: T::Array[Key], kwargs: T::Hash[Symbol, T.untyped], block: T.proc.params(key: ::TypedCache::CacheKey).returns(T.nilable(CachedType))).returns(::TypedCache::Either[Error, T::Array[::TypedCache::Snapshot[CachedType]]]) }
43
+ def fetch_all(keys, **kwargs, &block); end
44
44
 
45
45
  sig { returns(::TypedCache::Namespace) }
46
46
  def namespace; 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.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Autumn Winter
@@ -220,7 +220,7 @@ licenses:
220
220
  - Apache-2.0
221
221
  metadata:
222
222
  issue_tracker_uri: https://github.com/glossawy/typed_cache/issues
223
- changelog_uri: https://github.com/glossawy/typed_cache/blob/main/VERSIONS.adoc#030
223
+ changelog_uri: https://github.com/glossawy/typed_cache/blob/main/VERSIONS.adoc#031
224
224
  license_uri: https://github.com/glossawy/typed_cache/blob/main/LICENSE
225
225
  label: caching
226
226
  labels: typed_cache,ruby,caching,type-safety,rails,rbs
metadata.gz.sig CHANGED
Binary file