redis-namespace 1.6.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 }
|