object-cache 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3be3bd853f9ffd24ff89cff95d2762241021a1f
4
- data.tar.gz: 48fc790b6f2a15b13d945a9fe6f0483355bc9995
3
+ metadata.gz: 1d2f1ec4b3467a87297e809f094d3f75461b3fa9
4
+ data.tar.gz: bf7eef92986a7ddb52c5f7ec2aa3110ddbaa791d
5
5
  SHA512:
6
- metadata.gz: 6e1cd521b1b326ab8a381b71a0c39677fc37885dd0f714c8e8db010d7cc22dd5e88067827be3c4a863bda017f847ff63f77ab5814be6de0e20d527f986b4cf2e
7
- data.tar.gz: 12f817db636a6d87ed92dbc80885d999f0b19b11b507aab5283fcf1ee7d9941495e430b0ff47571ab2601c559a5017703dde3de97f7d8666f04b6bf97dd4f4ae
6
+ metadata.gz: 323e1806f012635837d50ac2111d607232714308376d16e9ab32718cc2217fe760d745298b3e20165b1d3e70f339b90acca9aada9ec81cf44f5b75e971403006
7
+ data.tar.gz: 7b0cd11b83029e6e2b9701804a7426679e6002578777192916301c75af7faaf9780a61acd5ef8a32a8df52de45e977a5d86be1954f1a56dfdbd876bb7ea15dc7
data/.rubocop.yml CHANGED
@@ -6,8 +6,5 @@ AllCops:
6
6
  Metrics/MethodLength:
7
7
  Max: 15
8
8
 
9
- Metrics/AbcSize:
10
- Max: 16
11
-
12
9
  Metrics/LineLength:
13
10
  Max: 100
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 [buit-in using Redis
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 obiously only works if the replicas receive the written data
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
- Since the core extension adds the `cache` method to the `Object` class, you can
171
- also call this method directly on any instances inheriting from `Object`:
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 = Digest::SHA1.hexdigest([key, Proc.new.source_location].flatten.join)[0..5]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Cache
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.3'
5
5
  end
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: object-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean