object-cache 0.0.2 → 0.0.3
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/.rubocop.yml +0 -3
- data/README.md +57 -4
- data/lib/object/cache.rb +22 -2
- data/lib/object/cache/version.rb +1 -1
- data/test/cache_test.rb +36 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d2f1ec4b3467a87297e809f094d3f75461b3fa9
|
4
|
+
data.tar.gz: bf7eef92986a7ddb52c5f7ec2aa3110ddbaa791d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 323e1806f012635837d50ac2111d607232714308376d16e9ab32718cc2217fe760d745298b3e20165b1d3e70f339b90acca9aada9ec81cf44f5b75e971403006
|
7
|
+
data.tar.gz: 7b0cd11b83029e6e2b9701804a7426679e6002578777192916301c75af7faaf9780a61acd5ef8a32a8df52de45e977a5d86be1954f1a56dfdbd876bb7ea15dc7
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,7 @@ Easy caching of Ruby objects, using [Redis](http://redis.io) as a backend store.
|
|
8
8
|
* [marshaling data](#marshaling-data)
|
9
9
|
* [ttl](#ttl)
|
10
10
|
* [namespaced keys](#namespaced-keys)
|
11
|
+
* [key prefixes](#key-prefixes)
|
11
12
|
* [redis replicas](#redis-replicas)
|
12
13
|
* [core extension](#core-extension)
|
13
14
|
* [License](#license)
|
@@ -128,6 +129,58 @@ merged together with the file name and line number of the cache request, so you
|
|
128
129
|
can re-use that same `email` namespace in different locations, without worrying
|
129
130
|
about any naming collisions.
|
130
131
|
|
132
|
+
#### key prefixes
|
133
|
+
|
134
|
+
By default, the eventual key ending up in Redis is a 6-character long digest,
|
135
|
+
based on the file name, line number, and optional key passed into the Cache
|
136
|
+
object:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
Cache.new { 'hello world' }
|
140
|
+
Cache.backend.keys # => ["22abcc"]
|
141
|
+
```
|
142
|
+
|
143
|
+
This makes working with keys quick and easy, without worying about conflicting
|
144
|
+
keys.
|
145
|
+
|
146
|
+
However, this does make it more difficult to selectively delete keys from the
|
147
|
+
backend, if you want to purge the cache of specific keys, before their TTL
|
148
|
+
expires.
|
149
|
+
|
150
|
+
To support this use-case, you can use the `key_prefix` attribute:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
Cache.new(key_prefix: 'hello') { 'hello world' }
|
154
|
+
Cache.backend.keys # => ["hello_22abcc"]
|
155
|
+
```
|
156
|
+
|
157
|
+
This allows you to selectively purge keys from Redis:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
Cache.backend.del('hello_')
|
161
|
+
```
|
162
|
+
|
163
|
+
You can also use the special value `:method_name` to dynamically set the key
|
164
|
+
prefix based on where the cached object was created:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
Cache.new(key_prefix: :method_name) { 'hello world' }
|
168
|
+
Cache.backend.keys # => ["test_key_prefix_method_name_22abcc"]
|
169
|
+
```
|
170
|
+
|
171
|
+
Or, use `:class_name` to group keys in the same class together:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
Cache.new(key_prefix: :class_name) { 'hello world' }
|
175
|
+
Cache.backend.keys # => ["CacheTest_22abcc"]
|
176
|
+
```
|
177
|
+
|
178
|
+
You can also define these options globally:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
Cache.default_key_prefix = :method_name
|
182
|
+
```
|
183
|
+
|
131
184
|
#### redis replicas
|
132
185
|
|
133
186
|
Before, we used the following setup to connect `Object::Cache` to a redis
|
@@ -137,7 +190,7 @@ backend:
|
|
137
190
|
Cache.backend = Redis.new
|
138
191
|
```
|
139
192
|
|
140
|
-
The Ruby Redis library has primary/replicas support [
|
193
|
+
The Ruby Redis library has primary/replicas support [built-in using Redis
|
141
194
|
Sentinel][sentinel].
|
142
195
|
|
143
196
|
If however, you have your own setup, and want the writes and reads to be
|
@@ -151,7 +204,7 @@ Cache.backend = { primary: Redis.new, replicas: [Redis.new, Redis.new] }
|
|
151
204
|
When writing the initial object to the backend, the `primary` Redis is used. On
|
152
205
|
subsequent requests, a random replica is used to retrieve the stored value.
|
153
206
|
|
154
|
-
The above example
|
207
|
+
The above example obviously only works if the replicas receive the written data
|
155
208
|
from the primary instance.
|
156
209
|
|
157
210
|
#### core extension
|
@@ -167,8 +220,8 @@ cache('hello', ttl: 60) { 'hello world' }
|
|
167
220
|
Cache.new('hello', ttl: 60) { 'hello world' }
|
168
221
|
```
|
169
222
|
|
170
|
-
|
171
|
-
|
223
|
+
You can also call this method directly on any instances inheriting from
|
224
|
+
`Object`:
|
172
225
|
|
173
226
|
```ruby
|
174
227
|
require 'object/cache/core_extension'
|
data/lib/object/cache.rb
CHANGED
@@ -10,6 +10,7 @@ class Cache
|
|
10
10
|
class << self
|
11
11
|
attr_accessor :backend
|
12
12
|
attr_accessor :default_ttl
|
13
|
+
attr_accessor :default_key_prefix
|
13
14
|
|
14
15
|
# new
|
15
16
|
#
|
@@ -43,10 +44,10 @@ class Cache
|
|
43
44
|
# Cache.new { item } # item is only stored once, and then always
|
44
45
|
# # retrieved, even if it is a different item
|
45
46
|
#
|
46
|
-
def new(key = nil, ttl: default_ttl)
|
47
|
+
def new(key = nil, ttl: default_ttl, key_prefix: default_key_prefix)
|
47
48
|
return yield unless replica
|
48
49
|
|
49
|
-
key =
|
50
|
+
key = build_key(key, key_prefix, Proc.new)
|
50
51
|
|
51
52
|
if (cached_value = replica.get(key)).nil?
|
52
53
|
yield.tap { |value| update_cache(key, value, ttl: ttl) }
|
@@ -94,5 +95,24 @@ class Cache
|
|
94
95
|
def replica
|
95
96
|
replicas.sample
|
96
97
|
end
|
98
|
+
|
99
|
+
def build_key(key, key_prefix, proc)
|
100
|
+
hash = Digest::SHA1.hexdigest([key, proc.source_location].flatten.join)[0..5]
|
101
|
+
prefix = build_key_prefix(key_prefix, proc)
|
102
|
+
|
103
|
+
[prefix, hash].compact.join('_')
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_key_prefix(key_prefix, proc)
|
107
|
+
case key_prefix
|
108
|
+
when :method_name
|
109
|
+
location = caller_locations.find { |l| "#{l.path}#{l.lineno}" == proc.source_location.join }
|
110
|
+
location&.base_label
|
111
|
+
when :class_name
|
112
|
+
proc.binding.receiver.class.to_s
|
113
|
+
else
|
114
|
+
key_prefix
|
115
|
+
end
|
116
|
+
end
|
97
117
|
end
|
98
118
|
end
|
data/lib/object/cache/version.rb
CHANGED
data/test/cache_test.rb
CHANGED
@@ -147,4 +147,40 @@ class CacheTest < Minitest::Test # rubocop:disable Metrics/ClassLength
|
|
147
147
|
assert_equal 1, primary.keys.count
|
148
148
|
assert_equal 0, replica.keys.count
|
149
149
|
end
|
150
|
+
|
151
|
+
def test_default_key_prefix_custom
|
152
|
+
Cache.default_key_prefix = 'hello'
|
153
|
+
|
154
|
+
Cache.new { 'hello world' }
|
155
|
+
assert_match(/^hello/, redis.keys.first)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_default_key_prefix_method_name
|
159
|
+
Cache.default_key_prefix = :method_name
|
160
|
+
|
161
|
+
Cache.new { 'hello world' }
|
162
|
+
assert_match(/^test_default_key_prefix_method_name/, redis.keys.first)
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_default_key_prefix_class_name
|
166
|
+
Cache.default_key_prefix = :class_name
|
167
|
+
|
168
|
+
Cache.new { 'hello world' }
|
169
|
+
assert_match(/^CacheTest/, redis.keys.first)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_key_prefix_custom
|
173
|
+
Cache.new(key_prefix: 'hello') { 'hello world' }
|
174
|
+
assert_match(/^hello/, redis.keys.first)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_key_prefix_method_name
|
178
|
+
Cache.new(key_prefix: :method_name) { 'hello world' }
|
179
|
+
assert_match(/^test_key_prefix_method_name/, redis.keys.first)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_key_prefix_class_name
|
183
|
+
Cache.new(key_prefix: :class_name) { 'hello world' }
|
184
|
+
assert_match(/^CacheTest/, redis.keys.first)
|
185
|
+
end
|
150
186
|
end
|