redis-namespace 1.6.0 → 1.11.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 +5 -5
- data/LICENSE +17 -16
- data/README.md +22 -18
- data/lib/redis/namespace/version.rb +1 -1
- data/lib/redis/namespace.rb +144 -35
- data/spec/deprecation_spec.rb +5 -5
- data/spec/redis_spec.rb +466 -186
- data/spec/spec_helper.rb +5 -0
- metadata +51 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e003f4015162bfd465e79dd90e54b44ae46f0ec269118e10c08215d639166296
|
4
|
+
data.tar.gz: 16078b51e1bdab24977aa2b6fb7d0cd4761a7c41c340fcdacfb96dd32216c061
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb965b575fe3ec2f2f45b99a71839f569f647681939b16576c053ab3e25bf85db1db030941bbe6eaeecc624eeeaf8c0497c58c53c4231440896e9e116bc189e3
|
7
|
+
data.tar.gz: 07b2b2e20c4a152b3e3a4cfbf6abad773f335e098067a9b213e29dd80cfc4519f3d27c43febe6cf8261ffe95e73184e23a1b9ff557007eb7a8308e43a398bbb1
|
data/LICENSE
CHANGED
@@ -1,20 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
1
3
|
Copyright (c) 2009 Chris Wanstrath
|
2
4
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
the following conditions:
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
10
11
|
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
13
14
|
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
OF
|
20
|
-
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -3,13 +3,13 @@ redis-namespace
|
|
3
3
|
|
4
4
|
Redis::Namespace provides an interface to a namespaced subset of your [redis][] keyspace (e.g., keys with a common beginning), and requires the [redis-rb][] gem.
|
5
5
|
|
6
|
-
|
6
|
+
```ruby
|
7
7
|
require 'redis-namespace'
|
8
8
|
# => true
|
9
9
|
|
10
10
|
redis_connection = Redis.new
|
11
11
|
# => #<Redis client v3.1.0 for redis://127.0.0.1:6379/0>
|
12
|
-
namespaced_redis = Redis::Namespace.new(:ns, :
|
12
|
+
namespaced_redis = Redis::Namespace.new(:ns, redis: redis_connection)
|
13
13
|
# => #<Redis::Namespace v1.5.0 with client v3.1.0 for redis://127.0.0.1:6379/0/ns>
|
14
14
|
|
15
15
|
namespaced_redis.set('foo', 'bar') # redis_connection.set('ns:foo', 'bar')
|
@@ -20,6 +20,8 @@ namespaced_redis.set('foo', 'bar') # redis_connection.set('ns:foo', 'bar')
|
|
20
20
|
|
21
21
|
namespaced_redis.get('foo')
|
22
22
|
# => "bar"
|
23
|
+
redis_connection.get('foo')
|
24
|
+
# => nil
|
23
25
|
redis_connection.get('ns:foo')
|
24
26
|
# => "bar"
|
25
27
|
|
@@ -29,7 +31,14 @@ namespaced_redis.get('foo')
|
|
29
31
|
# => nil
|
30
32
|
redis_connection.get('ns:foo')
|
31
33
|
# => nil
|
32
|
-
|
34
|
+
```
|
35
|
+
|
36
|
+
Redis::Namespace also supports `Proc` as a namespace and will take the result string as namespace at runtime.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
redis_connection = Redis.new
|
40
|
+
namespaced_redis = Redis::Namespace.new(Proc.new { Tenant.current_tenant }, redis: redis_connection)
|
41
|
+
```
|
33
42
|
|
34
43
|
Installation
|
35
44
|
============
|
@@ -42,20 +51,18 @@ From the command line:
|
|
42
51
|
|
43
52
|
Or in your Gemfile:
|
44
53
|
|
45
|
-
|
54
|
+
```ruby
|
46
55
|
gem 'redis-namespace'
|
47
|
-
|
56
|
+
```
|
48
57
|
|
49
58
|
Caveats
|
50
59
|
=======
|
51
60
|
|
52
|
-
`Redis::Namespace` provides a namespaced interface to `Redis` by keeping an internal registry of the method signatures in `Redis` provided by the redis-rb gem;
|
53
|
-
we keep track of which arguments need the namespace added, and which return values need the namespace removed.
|
61
|
+
`Redis::Namespace` provides a namespaced interface to `Redis` by keeping an internal registry of the method signatures in `Redis` provided by the [redis-rb][] gem; we keep track of which arguments need the namespace added, and which return values need the namespace removed.
|
54
62
|
|
55
63
|
Blind Passthrough
|
56
64
|
-----------------
|
57
|
-
If your version of this gem doesn't know about a particular command, it can't namespace it.
|
58
|
-
Historically, this has meant that Redis::Namespace blindly passes unknown commands on to the underlying redis connection without modification which can lead to surprising effects.
|
65
|
+
If your version of this gem doesn't know about a particular command, it can't namespace it. Historically, this has meant that Redis::Namespace blindly passes unknown commands on to the underlying redis connection without modification which can lead to surprising effects.
|
59
66
|
|
60
67
|
As of v1.5.0, blind passthrough has been deprecated, and the functionality will be removed entirely in 2.0.
|
61
68
|
|
@@ -63,26 +70,23 @@ If you come across a command that is not yet supported, please open an issue on
|
|
63
70
|
|
64
71
|
Administrative Commands
|
65
72
|
-----------------------
|
66
|
-
The effects of some redis commands cannot be limited to a particular namespace (e.g., `FLUSHALL`, which literally truncates all databases in your redis server, regardless of keyspace).
|
67
|
-
Historically, this has meant that Redis::Namespace intentionally passes administrative commands on to the underlying redis connection without modification, which can lead to surprising effects.
|
73
|
+
The effects of some redis commands cannot be limited to a particular namespace (e.g., `FLUSHALL`, which literally truncates all databases in your redis server, regardless of keyspace). Historically, this has meant that Redis::Namespace intentionally passes administrative commands on to the underlying redis connection without modification, which can lead to surprising effects.
|
68
74
|
|
69
|
-
As of v1.6.0, the direct use of administrative commands has been deprecated, and the functionality will be removed entirely in 2.0;
|
70
|
-
while such commands are often useful for testing or administration, their meaning is inherently hidden when placed behind an interface that implies it will namespace everything.
|
75
|
+
As of v1.6.0, the direct use of administrative commands has been deprecated, and the functionality will be removed entirely in 2.0; while such commands are often useful for testing or administration, their meaning is inherently hidden when placed behind an interface that implies it will namespace everything.
|
71
76
|
|
72
|
-
The prefered way to send an administrative command is on the redis connection
|
73
|
-
itself, which is publicly exposed as `Redis::Namespace#redis`:
|
77
|
+
The prefered way to send an administrative command is on the redis connection itself, which is publicly exposed as `Redis::Namespace#redis`:
|
74
78
|
|
75
|
-
|
79
|
+
```ruby
|
76
80
|
namespaced.redis.flushall()
|
77
81
|
# => "OK"
|
78
|
-
|
82
|
+
```
|
79
83
|
|
80
84
|
2.x Planned Breaking Changes
|
81
85
|
============================
|
82
86
|
|
83
87
|
As mentioned above, 2.0 will remove blind passthrough and the administrative command passthrough.
|
84
88
|
By default in 1.5+, deprecation warnings are present and enabled;
|
85
|
-
they can be silenced by initializing `Redis::Namespace` with `
|
89
|
+
they can be silenced by initializing `Redis::Namespace` with `warning: false` or by setting the `REDIS_NAMESPACE_QUIET` environment variable.
|
86
90
|
|
87
91
|
Early opt-in
|
88
92
|
------------
|
data/lib/redis/namespace.rb
CHANGED
@@ -57,20 +57,26 @@ class Redis
|
|
57
57
|
"append" => [ :first ],
|
58
58
|
"bitcount" => [ :first ],
|
59
59
|
"bitop" => [ :exclude_first ],
|
60
|
+
"bitpos" => [ :first ],
|
60
61
|
"blpop" => [ :exclude_last, :first ],
|
61
62
|
"brpop" => [ :exclude_last, :first ],
|
62
63
|
"brpoplpush" => [ :exclude_last ],
|
64
|
+
"bzpopmin" => [ :first ],
|
65
|
+
"bzpopmax" => [ :first ],
|
63
66
|
"debug" => [ :exclude_first ],
|
64
67
|
"decr" => [ :first ],
|
65
68
|
"decrby" => [ :first ],
|
66
69
|
"del" => [ :all ],
|
67
70
|
"dump" => [ :first ],
|
68
|
-
"exists" => [ :
|
71
|
+
"exists" => [ :all ],
|
72
|
+
"exists?" => [ :all ],
|
69
73
|
"expire" => [ :first ],
|
70
74
|
"expireat" => [ :first ],
|
75
|
+
"expiretime" => [ :first ],
|
71
76
|
"eval" => [ :eval_style ],
|
72
77
|
"evalsha" => [ :eval_style ],
|
73
78
|
"get" => [ :first ],
|
79
|
+
"getex" => [ :first ],
|
74
80
|
"getbit" => [ :first ],
|
75
81
|
"getrange" => [ :first ],
|
76
82
|
"getset" => [ :first ],
|
@@ -117,6 +123,7 @@ class Redis
|
|
117
123
|
"persist" => [ :first ],
|
118
124
|
"pexpire" => [ :first ],
|
119
125
|
"pexpireat" => [ :first ],
|
126
|
+
"pexpiretime" => [ :first ],
|
120
127
|
"pfadd" => [ :first ],
|
121
128
|
"pfcount" => [ :all ],
|
122
129
|
"pfmerge" => [ :all ],
|
@@ -133,6 +140,7 @@ class Redis
|
|
133
140
|
"rpush" => [ :first ],
|
134
141
|
"rpushx" => [ :first ],
|
135
142
|
"sadd" => [ :first ],
|
143
|
+
"sadd?" => [ :first ],
|
136
144
|
"scard" => [ :first ],
|
137
145
|
"scan" => [ :scan_style, :second ],
|
138
146
|
"scan_each" => [ :scan_style, :all ],
|
@@ -147,11 +155,13 @@ class Redis
|
|
147
155
|
"sinterstore" => [ :all ],
|
148
156
|
"sismember" => [ :first ],
|
149
157
|
"smembers" => [ :first ],
|
158
|
+
"smismember" => [ :first ],
|
150
159
|
"smove" => [ :exclude_last ],
|
151
160
|
"sort" => [ :sort ],
|
152
161
|
"spop" => [ :first ],
|
153
162
|
"srandmember" => [ :first ],
|
154
163
|
"srem" => [ :first ],
|
164
|
+
"srem?" => [ :first ],
|
155
165
|
"sscan" => [ :first ],
|
156
166
|
"sscan_each" => [ :first ],
|
157
167
|
"strlen" => [ :first ],
|
@@ -160,27 +170,31 @@ class Redis
|
|
160
170
|
"sunionstore" => [ :all ],
|
161
171
|
"ttl" => [ :first ],
|
162
172
|
"type" => [ :first ],
|
173
|
+
"unlink" => [ :all ],
|
163
174
|
"unsubscribe" => [ :all ],
|
164
175
|
"zadd" => [ :first ],
|
165
176
|
"zcard" => [ :first ],
|
166
177
|
"zcount" => [ :first ],
|
167
178
|
"zincrby" => [ :first ],
|
168
179
|
"zinterstore" => [ :exclude_options ],
|
180
|
+
"zpopmin" => [ :first ],
|
181
|
+
"zpopmax" => [ :first ],
|
169
182
|
"zrange" => [ :first ],
|
170
183
|
"zrangebyscore" => [ :first ],
|
184
|
+
"zrangebylex" => [ :first ],
|
171
185
|
"zrank" => [ :first ],
|
172
186
|
"zrem" => [ :first ],
|
173
187
|
"zremrangebyrank" => [ :first ],
|
174
188
|
"zremrangebyscore" => [ :first ],
|
189
|
+
"zremrangebylex" => [ :first ],
|
175
190
|
"zrevrange" => [ :first ],
|
176
191
|
"zrevrangebyscore" => [ :first ],
|
192
|
+
"zrevrangebylex" => [ :first ],
|
177
193
|
"zrevrank" => [ :first ],
|
178
194
|
"zscan" => [ :first ],
|
179
195
|
"zscan_each" => [ :first ],
|
180
196
|
"zscore" => [ :first ],
|
181
|
-
"zunionstore" => [ :exclude_options ]
|
182
|
-
"[]" => [ :first ],
|
183
|
-
"[]=" => [ :first ]
|
197
|
+
"zunionstore" => [ :exclude_options ]
|
184
198
|
}
|
185
199
|
TRANSACTION_COMMANDS = {
|
186
200
|
"discard" => [],
|
@@ -192,6 +206,7 @@ class Redis
|
|
192
206
|
HELPER_COMMANDS = {
|
193
207
|
"auth" => [],
|
194
208
|
"disconnect!" => [],
|
209
|
+
"close" => [],
|
195
210
|
"echo" => [],
|
196
211
|
"ping" => [],
|
197
212
|
"time" => [],
|
@@ -228,13 +243,23 @@ class Redis
|
|
228
243
|
# Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
|
229
244
|
Enumerator = Enumerable::Enumerator unless defined?(::Enumerator)
|
230
245
|
|
246
|
+
# This is used by the Redis gem to determine whether or not to display that deprecation message.
|
247
|
+
@sadd_returns_boolean = true
|
248
|
+
|
249
|
+
# This is used by the Redis gem to determine whether or not to display that deprecation message.
|
250
|
+
@srem_returns_boolean = true
|
251
|
+
|
252
|
+
class << self
|
253
|
+
attr_accessor :sadd_returns_boolean, :srem_returns_boolean
|
254
|
+
end
|
255
|
+
|
231
256
|
attr_writer :namespace
|
232
257
|
attr_reader :redis
|
233
258
|
attr_accessor :warning
|
234
259
|
|
235
260
|
def initialize(namespace, options = {})
|
236
261
|
@namespace = namespace
|
237
|
-
@redis = options[:redis] || Redis.
|
262
|
+
@redis = options[:redis] || Redis.new
|
238
263
|
@warning = !!options.fetch(:warning) do
|
239
264
|
!ENV['REDIS_NAMESPACE_QUIET']
|
240
265
|
end
|
@@ -253,8 +278,8 @@ class Redis
|
|
253
278
|
end
|
254
279
|
|
255
280
|
def client
|
256
|
-
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client" +
|
257
|
-
"method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method
|
281
|
+
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
|
282
|
+
"method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
|
258
283
|
_client
|
259
284
|
end
|
260
285
|
|
@@ -272,7 +297,9 @@ class Redis
|
|
272
297
|
|
273
298
|
# emulate Ruby 1.9+ and keep respond_to_missing? logic together.
|
274
299
|
def respond_to?(command, include_private=false)
|
275
|
-
|
300
|
+
return !deprecations? if DEPRECATED_COMMANDS.include?(command.to_s.downcase)
|
301
|
+
|
302
|
+
respond_to_missing?(command, include_private) or super
|
276
303
|
end
|
277
304
|
|
278
305
|
def keys(query = nil)
|
@@ -297,7 +324,15 @@ class Redis
|
|
297
324
|
:redis => @redis)
|
298
325
|
end
|
299
326
|
|
300
|
-
@namespace
|
327
|
+
@namespace.respond_to?(:call) ? @namespace.call : @namespace
|
328
|
+
end
|
329
|
+
|
330
|
+
def full_namespace
|
331
|
+
redis.is_a?(Namespace) ? "#{redis.full_namespace}:#{namespace}" : namespace.to_s
|
332
|
+
end
|
333
|
+
|
334
|
+
def connection
|
335
|
+
@redis.connection.tap { |info| info[:namespace] = namespace }
|
301
336
|
end
|
302
337
|
|
303
338
|
def exec
|
@@ -307,16 +342,40 @@ class Redis
|
|
307
342
|
def eval(*args)
|
308
343
|
call_with_namespace(:eval, *args)
|
309
344
|
end
|
345
|
+
ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
|
346
|
+
|
347
|
+
# This operation can run for a very long time if the namespace contains lots of keys!
|
348
|
+
# It should be used in tests, or when the namespace is small enough
|
349
|
+
# and you are sure you know what you are doing.
|
350
|
+
def clear
|
351
|
+
if warning?
|
352
|
+
warn("This operation can run for a very long time if the namespace contains lots of keys! " +
|
353
|
+
"It should be used in tests, or when the namespace is small enough " +
|
354
|
+
"and you are sure you know what you are doing.")
|
355
|
+
end
|
310
356
|
|
311
|
-
|
312
|
-
|
357
|
+
batch_size = 1000
|
358
|
+
|
359
|
+
if supports_scan?
|
360
|
+
cursor = "0"
|
361
|
+
begin
|
362
|
+
cursor, keys = scan(cursor, count: batch_size)
|
363
|
+
del(*keys) unless keys.empty?
|
364
|
+
end until cursor == "0"
|
365
|
+
else
|
366
|
+
all_keys = keys("*")
|
367
|
+
all_keys.each_slice(batch_size) do |keys|
|
368
|
+
del(*keys)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
ADMINISTRATIVE_COMMANDS.keys.each do |command|
|
374
|
+
define_method(command) do |*args, &block|
|
375
|
+
raise NoMethodError if deprecations?
|
313
376
|
|
314
|
-
if ADMINISTRATIVE_COMMANDS.include?(normalized_command)
|
315
|
-
# administrative commands usage is deprecated and will be removed in 2.0
|
316
|
-
# redis-namespace cannot safely apply a namespace to their effects.
|
317
|
-
return super if deprecations?
|
318
377
|
if warning?
|
319
|
-
warn("Passing '#{
|
378
|
+
warn("Passing '#{command}' command to redis as is; " +
|
320
379
|
"administrative commands cannot be effectively namespaced " +
|
321
380
|
"and should be called on the redis connection directly; " +
|
322
381
|
"passthrough has been deprecated and will be removed in " +
|
@@ -324,8 +383,25 @@ class Redis
|
|
324
383
|
)
|
325
384
|
end
|
326
385
|
call_with_namespace(command, *args, &block)
|
327
|
-
|
386
|
+
end
|
387
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
388
|
+
end
|
389
|
+
|
390
|
+
COMMANDS.keys.each do |command|
|
391
|
+
next if ADMINISTRATIVE_COMMANDS.include?(command)
|
392
|
+
next if method_defined?(command)
|
393
|
+
|
394
|
+
define_method(command) do |*args, &block|
|
328
395
|
call_with_namespace(command, *args, &block)
|
396
|
+
end
|
397
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
398
|
+
end
|
399
|
+
|
400
|
+
def method_missing(command, *args, &block)
|
401
|
+
normalized_command = command.to_s.downcase
|
402
|
+
|
403
|
+
if COMMANDS.include?(normalized_command)
|
404
|
+
send(normalized_command, *args, &block)
|
329
405
|
elsif @redis.respond_to?(normalized_command) && !deprecations?
|
330
406
|
# blind passthrough is deprecated and will be removed in 2.0
|
331
407
|
# redis-namespace does not know how to handle this command.
|
@@ -336,23 +412,23 @@ class Redis
|
|
336
412
|
"passthrough has been deprecated and will be removed in " +
|
337
413
|
"redis-namespace 2.0 (at #{call_site})")
|
338
414
|
end
|
339
|
-
|
415
|
+
|
416
|
+
wrapped_send(@redis, command, args, &block)
|
340
417
|
else
|
341
418
|
super
|
342
419
|
end
|
343
420
|
end
|
421
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
344
422
|
|
345
423
|
def inspect
|
346
424
|
"<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
|
347
|
-
"for #{@redis.id}/#{
|
425
|
+
"for #{@redis.id}/#{full_namespace}>"
|
348
426
|
end
|
349
427
|
|
350
428
|
def respond_to_missing?(command, include_all=false)
|
351
429
|
normalized_command = command.to_s.downcase
|
352
430
|
|
353
431
|
case
|
354
|
-
when DEPRECATED_COMMANDS.include?(normalized_command)
|
355
|
-
!deprecations?
|
356
432
|
when COMMANDS.include?(normalized_command)
|
357
433
|
true
|
358
434
|
when !deprecations? && redis.respond_to?(command, include_all)
|
@@ -378,6 +454,7 @@ class Redis
|
|
378
454
|
case before
|
379
455
|
when :first
|
380
456
|
args[0] = add_namespace(args[0]) if args[0]
|
457
|
+
args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
|
381
458
|
when :all
|
382
459
|
args = add_namespace(args)
|
383
460
|
when :exclude_first
|
@@ -390,13 +467,14 @@ class Redis
|
|
390
467
|
args.push(last) if last
|
391
468
|
when :exclude_options
|
392
469
|
if args.last.is_a?(Hash)
|
393
|
-
last = args.pop
|
470
|
+
last = ruby2_keywords_hash(args.pop)
|
394
471
|
args = add_namespace(args)
|
395
472
|
args.push(last)
|
396
473
|
else
|
397
474
|
args = add_namespace(args)
|
398
475
|
end
|
399
476
|
when :alternate
|
477
|
+
args = args.flatten
|
400
478
|
args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
|
401
479
|
when :sort
|
402
480
|
args[0] = add_namespace(args[0]) if args[0]
|
@@ -410,6 +488,7 @@ class Redis
|
|
410
488
|
args[1][:get].each_index do |i|
|
411
489
|
args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
|
412
490
|
end
|
491
|
+
args[1] = ruby2_keywords_hash(args[1])
|
413
492
|
end
|
414
493
|
when :eval_style
|
415
494
|
# redis.eval() and evalsha() can either take the form:
|
@@ -430,7 +509,7 @@ class Redis
|
|
430
509
|
when :scan_style
|
431
510
|
options = (args.last.kind_of?(Hash) ? args.pop : {})
|
432
511
|
options[:match] = add_namespace(options.fetch(:match, '*'))
|
433
|
-
args << options
|
512
|
+
args << ruby2_keywords_hash(options)
|
434
513
|
|
435
514
|
if block
|
436
515
|
original_block = block
|
@@ -439,7 +518,7 @@ class Redis
|
|
439
518
|
end
|
440
519
|
|
441
520
|
# Dispatch the command to Redis and store the result.
|
442
|
-
result = @redis
|
521
|
+
result = wrapped_send(@redis, command, args, &block)
|
443
522
|
|
444
523
|
# Don't try to remove namespace from a Redis::Future, you can't.
|
445
524
|
return result if result.is_a?(Redis::Future)
|
@@ -456,9 +535,36 @@ class Redis
|
|
456
535
|
|
457
536
|
result
|
458
537
|
end
|
538
|
+
ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
|
539
|
+
|
540
|
+
protected
|
541
|
+
|
542
|
+
def redis=(redis)
|
543
|
+
@redis = redis
|
544
|
+
end
|
459
545
|
|
460
546
|
private
|
461
547
|
|
548
|
+
if Hash.respond_to?(:ruby2_keywords_hash)
|
549
|
+
def ruby2_keywords_hash(kwargs)
|
550
|
+
Hash.ruby2_keywords_hash(kwargs)
|
551
|
+
end
|
552
|
+
else
|
553
|
+
def ruby2_keywords_hash(kwargs)
|
554
|
+
kwargs
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
def wrapped_send(redis_client, command, args = [], &block)
|
559
|
+
if redis_client.class.name == "ConnectionPool"
|
560
|
+
redis_client.with do |pool_connection|
|
561
|
+
pool_connection.send(command, *args, &block)
|
562
|
+
end
|
563
|
+
else
|
564
|
+
redis_client.send(command, *args, &block)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
462
568
|
# Avoid modifying the caller's (pass-by-reference) arguments.
|
463
569
|
def clone_args(arg)
|
464
570
|
if arg.is_a?(Array)
|
@@ -475,18 +581,16 @@ class Redis
|
|
475
581
|
end
|
476
582
|
|
477
583
|
def namespaced_block(command, &block)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
@redis = original
|
484
|
-
end
|
584
|
+
if block.arity == 0
|
585
|
+
wrapped_send(redis, command, &block)
|
586
|
+
else
|
587
|
+
outer_block = proc { |r| copy = dup; copy.redis = r; yield copy }
|
588
|
+
wrapped_send(redis, command, &outer_block)
|
485
589
|
end
|
486
590
|
end
|
487
591
|
|
488
592
|
def add_namespace(key)
|
489
|
-
return key unless key &&
|
593
|
+
return key unless key && namespace
|
490
594
|
|
491
595
|
case key
|
492
596
|
when Array
|
@@ -495,12 +599,12 @@ class Redis
|
|
495
599
|
key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
|
496
600
|
key
|
497
601
|
else
|
498
|
-
"#{
|
602
|
+
"#{namespace}:#{key}"
|
499
603
|
end
|
500
604
|
end
|
501
605
|
|
502
606
|
def rem_namespace(key)
|
503
|
-
return key unless key &&
|
607
|
+
return key unless key && namespace
|
504
608
|
|
505
609
|
case key
|
506
610
|
when Array
|
@@ -512,7 +616,7 @@ class Redis
|
|
512
616
|
key.each { |k| yielder.yield rem_namespace(k) }
|
513
617
|
end
|
514
618
|
else
|
515
|
-
key.to_s.sub(/\A#{
|
619
|
+
key.to_s.sub(/\A#{namespace}:/, '')
|
516
620
|
end
|
517
621
|
end
|
518
622
|
|
@@ -527,5 +631,10 @@ class Redis
|
|
527
631
|
Enumerator.new(&block)
|
528
632
|
end
|
529
633
|
end
|
634
|
+
|
635
|
+
def supports_scan?
|
636
|
+
redis_version = @redis.info["redis_version"]
|
637
|
+
Gem::Version.new(redis_version) >= Gem::Version.new("2.8.0")
|
638
|
+
end
|
530
639
|
end
|
531
640
|
end
|
data/spec/deprecation_spec.rb
CHANGED
@@ -31,7 +31,7 @@ describe Redis::Namespace do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
before(:each) do
|
34
|
-
allow(redis).to receive(:unhandled) do |*args|
|
34
|
+
allow(redis).to receive(:unhandled) do |*args|
|
35
35
|
"unhandled(#{args.inspect})"
|
36
36
|
end
|
37
37
|
allow(redis).to receive(:flushdb).and_return("OK")
|
@@ -43,7 +43,7 @@ describe Redis::Namespace do
|
|
43
43
|
its(:deprecations?) { should be true }
|
44
44
|
|
45
45
|
context('with an unhandled command') do
|
46
|
-
it {
|
46
|
+
it { is_expected.not_to respond_to :unhandled }
|
47
47
|
|
48
48
|
it('raises a NoMethodError') do
|
49
49
|
expect do
|
@@ -53,7 +53,7 @@ describe Redis::Namespace do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
context('with an administrative command') do
|
56
|
-
it {
|
56
|
+
it { is_expected.not_to respond_to :flushdb }
|
57
57
|
|
58
58
|
it('raises a NoMethodError') do
|
59
59
|
expect do
|
@@ -69,7 +69,7 @@ describe Redis::Namespace do
|
|
69
69
|
its(:deprecations?) { should be false }
|
70
70
|
|
71
71
|
context('with an an unhandled command') do
|
72
|
-
it {
|
72
|
+
it { is_expected.to respond_to :unhandled }
|
73
73
|
|
74
74
|
it 'blindly passes through' do
|
75
75
|
expect(redis).to receive(:unhandled)
|
@@ -106,7 +106,7 @@ describe Redis::Namespace do
|
|
106
106
|
end
|
107
107
|
|
108
108
|
context('with an administrative command') do
|
109
|
-
it {
|
109
|
+
it { is_expected.to respond_to :flushdb }
|
110
110
|
it 'processes the command' do
|
111
111
|
expect(redis).to receive(:flushdb)
|
112
112
|
capture_stderr { namespaced.flushdb }
|