redis-namespace 1.6.0 → 1.8.2
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 +15 -18
- data/lib/redis/namespace/version.rb +1 -1
- data/lib/redis/namespace.rb +77 -25
- data/spec/deprecation_spec.rb +4 -4
- data/spec/redis_spec.rb +302 -177
- data/spec/spec_helper.rb +5 -0
- metadata +33 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0541ad1ce3251b5dc3c035e47aa0690d334d32b9c5b29e335604570cb5847dac
|
4
|
+
data.tar.gz: '0877ceadbd1afa44a38fd1b7bb7af4b0e9e87a3426f688c891c847853588f65a'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c8cd0be52f98f4fe16b551ac261faba1db4da269a07ac9c85e4a8a4b20347c0a4646036bc5fb64cab3d5863d88b308f15ea96996fd19bfad8bd85980ccf5081
|
7
|
+
data.tar.gz: 1d6e8e911c9bf887ff00cead444978ecfcccd6f2b04c56549fd28542864e7971ca9f4e5510d2e7473efb91bac50be8ac7d7cd9555fea5ca0da63d8b374d3e793
|
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,7 @@ namespaced_redis.get('foo')
|
|
29
31
|
# => nil
|
30
32
|
redis_connection.get('ns:foo')
|
31
33
|
# => nil
|
32
|
-
|
34
|
+
```
|
33
35
|
|
34
36
|
Installation
|
35
37
|
============
|
@@ -42,20 +44,18 @@ From the command line:
|
|
42
44
|
|
43
45
|
Or in your Gemfile:
|
44
46
|
|
45
|
-
|
47
|
+
```ruby
|
46
48
|
gem 'redis-namespace'
|
47
|
-
|
49
|
+
```
|
48
50
|
|
49
51
|
Caveats
|
50
52
|
=======
|
51
53
|
|
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.
|
54
|
+
`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
55
|
|
55
56
|
Blind Passthrough
|
56
57
|
-----------------
|
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.
|
58
|
+
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
59
|
|
60
60
|
As of v1.5.0, blind passthrough has been deprecated, and the functionality will be removed entirely in 2.0.
|
61
61
|
|
@@ -63,26 +63,23 @@ If you come across a command that is not yet supported, please open an issue on
|
|
63
63
|
|
64
64
|
Administrative Commands
|
65
65
|
-----------------------
|
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.
|
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). 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
67
|
|
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.
|
68
|
+
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
69
|
|
72
|
-
The prefered way to send an administrative command is on the redis connection
|
73
|
-
itself, which is publicly exposed as `Redis::Namespace#redis`:
|
70
|
+
The prefered way to send an administrative command is on the redis connection itself, which is publicly exposed as `Redis::Namespace#redis`:
|
74
71
|
|
75
|
-
|
72
|
+
```ruby
|
76
73
|
namespaced.redis.flushall()
|
77
74
|
# => "OK"
|
78
|
-
|
75
|
+
```
|
79
76
|
|
80
77
|
2.x Planned Breaking Changes
|
81
78
|
============================
|
82
79
|
|
83
80
|
As mentioned above, 2.0 will remove blind passthrough and the administrative command passthrough.
|
84
81
|
By default in 1.5+, deprecation warnings are present and enabled;
|
85
|
-
they can be silenced by initializing `Redis::Namespace` with `
|
82
|
+
they can be silenced by initializing `Redis::Namespace` with `warning: false` or by setting the `REDIS_NAMESPACE_QUIET` environment variable.
|
86
83
|
|
87
84
|
Early opt-in
|
88
85
|
------------
|
data/lib/redis/namespace.rb
CHANGED
@@ -57,15 +57,19 @@ 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 ],
|
71
75
|
"eval" => [ :eval_style ],
|
@@ -160,27 +164,31 @@ class Redis
|
|
160
164
|
"sunionstore" => [ :all ],
|
161
165
|
"ttl" => [ :first ],
|
162
166
|
"type" => [ :first ],
|
167
|
+
"unlink" => [ :all ],
|
163
168
|
"unsubscribe" => [ :all ],
|
164
169
|
"zadd" => [ :first ],
|
165
170
|
"zcard" => [ :first ],
|
166
171
|
"zcount" => [ :first ],
|
167
172
|
"zincrby" => [ :first ],
|
168
173
|
"zinterstore" => [ :exclude_options ],
|
174
|
+
"zpopmin" => [ :first ],
|
175
|
+
"zpopmax" => [ :first ],
|
169
176
|
"zrange" => [ :first ],
|
170
177
|
"zrangebyscore" => [ :first ],
|
178
|
+
"zrangebylex" => [ :first ],
|
171
179
|
"zrank" => [ :first ],
|
172
180
|
"zrem" => [ :first ],
|
173
181
|
"zremrangebyrank" => [ :first ],
|
174
182
|
"zremrangebyscore" => [ :first ],
|
183
|
+
"zremrangebylex" => [ :first ],
|
175
184
|
"zrevrange" => [ :first ],
|
176
185
|
"zrevrangebyscore" => [ :first ],
|
186
|
+
"zrevrangebylex" => [ :first ],
|
177
187
|
"zrevrank" => [ :first ],
|
178
188
|
"zscan" => [ :first ],
|
179
189
|
"zscan_each" => [ :first ],
|
180
190
|
"zscore" => [ :first ],
|
181
|
-
"zunionstore" => [ :exclude_options ]
|
182
|
-
"[]" => [ :first ],
|
183
|
-
"[]=" => [ :first ]
|
191
|
+
"zunionstore" => [ :exclude_options ]
|
184
192
|
}
|
185
193
|
TRANSACTION_COMMANDS = {
|
186
194
|
"discard" => [],
|
@@ -254,7 +262,7 @@ class Redis
|
|
254
262
|
|
255
263
|
def client
|
256
264
|
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
|
265
|
+
"method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
|
258
266
|
_client
|
259
267
|
end
|
260
268
|
|
@@ -272,7 +280,9 @@ class Redis
|
|
272
280
|
|
273
281
|
# emulate Ruby 1.9+ and keep respond_to_missing? logic together.
|
274
282
|
def respond_to?(command, include_private=false)
|
275
|
-
|
283
|
+
return !deprecations? if DEPRECATED_COMMANDS.include?(command.to_s.downcase)
|
284
|
+
|
285
|
+
respond_to_missing?(command, include_private) or super
|
276
286
|
end
|
277
287
|
|
278
288
|
def keys(query = nil)
|
@@ -300,6 +310,14 @@ class Redis
|
|
300
310
|
@namespace
|
301
311
|
end
|
302
312
|
|
313
|
+
def full_namespace
|
314
|
+
redis.is_a?(Namespace) ? "#{redis.full_namespace}:#{namespace}" : namespace.to_s
|
315
|
+
end
|
316
|
+
|
317
|
+
def connection
|
318
|
+
@redis.connection.tap { |info| info[:namespace] = @namespace }
|
319
|
+
end
|
320
|
+
|
303
321
|
def exec
|
304
322
|
call_with_namespace(:exec)
|
305
323
|
end
|
@@ -307,16 +325,14 @@ class Redis
|
|
307
325
|
def eval(*args)
|
308
326
|
call_with_namespace(:eval, *args)
|
309
327
|
end
|
328
|
+
ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
|
310
329
|
|
311
|
-
|
312
|
-
|
330
|
+
ADMINISTRATIVE_COMMANDS.keys.each do |command|
|
331
|
+
define_method(command) do |*args, &block|
|
332
|
+
raise NoMethodError if deprecations?
|
313
333
|
|
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
334
|
if warning?
|
319
|
-
warn("Passing '#{
|
335
|
+
warn("Passing '#{command}' command to redis as is; " +
|
320
336
|
"administrative commands cannot be effectively namespaced " +
|
321
337
|
"and should be called on the redis connection directly; " +
|
322
338
|
"passthrough has been deprecated and will be removed in " +
|
@@ -324,8 +340,25 @@ class Redis
|
|
324
340
|
)
|
325
341
|
end
|
326
342
|
call_with_namespace(command, *args, &block)
|
327
|
-
|
343
|
+
end
|
344
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
345
|
+
end
|
346
|
+
|
347
|
+
COMMANDS.keys.each do |command|
|
348
|
+
next if ADMINISTRATIVE_COMMANDS.include?(command)
|
349
|
+
next if method_defined?(command)
|
350
|
+
|
351
|
+
define_method(command) do |*args, &block|
|
328
352
|
call_with_namespace(command, *args, &block)
|
353
|
+
end
|
354
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
355
|
+
end
|
356
|
+
|
357
|
+
def method_missing(command, *args, &block)
|
358
|
+
normalized_command = command.to_s.downcase
|
359
|
+
|
360
|
+
if COMMANDS.include?(normalized_command)
|
361
|
+
send(normalized_command, *args, &block)
|
329
362
|
elsif @redis.respond_to?(normalized_command) && !deprecations?
|
330
363
|
# blind passthrough is deprecated and will be removed in 2.0
|
331
364
|
# redis-namespace does not know how to handle this command.
|
@@ -341,18 +374,17 @@ class Redis
|
|
341
374
|
super
|
342
375
|
end
|
343
376
|
end
|
377
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
344
378
|
|
345
379
|
def inspect
|
346
380
|
"<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
|
347
|
-
"for #{@redis.id}/#{
|
381
|
+
"for #{@redis.id}/#{full_namespace}>"
|
348
382
|
end
|
349
383
|
|
350
384
|
def respond_to_missing?(command, include_all=false)
|
351
385
|
normalized_command = command.to_s.downcase
|
352
386
|
|
353
387
|
case
|
354
|
-
when DEPRECATED_COMMANDS.include?(normalized_command)
|
355
|
-
!deprecations?
|
356
388
|
when COMMANDS.include?(normalized_command)
|
357
389
|
true
|
358
390
|
when !deprecations? && redis.respond_to?(command, include_all)
|
@@ -378,6 +410,7 @@ class Redis
|
|
378
410
|
case before
|
379
411
|
when :first
|
380
412
|
args[0] = add_namespace(args[0]) if args[0]
|
413
|
+
args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
|
381
414
|
when :all
|
382
415
|
args = add_namespace(args)
|
383
416
|
when :exclude_first
|
@@ -390,7 +423,7 @@ class Redis
|
|
390
423
|
args.push(last) if last
|
391
424
|
when :exclude_options
|
392
425
|
if args.last.is_a?(Hash)
|
393
|
-
last = args.pop
|
426
|
+
last = ruby2_keywords_hash(args.pop)
|
394
427
|
args = add_namespace(args)
|
395
428
|
args.push(last)
|
396
429
|
else
|
@@ -410,6 +443,7 @@ class Redis
|
|
410
443
|
args[1][:get].each_index do |i|
|
411
444
|
args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
|
412
445
|
end
|
446
|
+
args[1] = ruby2_keywords_hash(args[1])
|
413
447
|
end
|
414
448
|
when :eval_style
|
415
449
|
# redis.eval() and evalsha() can either take the form:
|
@@ -430,7 +464,7 @@ class Redis
|
|
430
464
|
when :scan_style
|
431
465
|
options = (args.last.kind_of?(Hash) ? args.pop : {})
|
432
466
|
options[:match] = add_namespace(options.fetch(:match, '*'))
|
433
|
-
args << options
|
467
|
+
args << ruby2_keywords_hash(options)
|
434
468
|
|
435
469
|
if block
|
436
470
|
original_block = block
|
@@ -456,9 +490,26 @@ class Redis
|
|
456
490
|
|
457
491
|
result
|
458
492
|
end
|
493
|
+
ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
|
494
|
+
|
495
|
+
protected
|
496
|
+
|
497
|
+
def redis=(redis)
|
498
|
+
@redis = redis
|
499
|
+
end
|
459
500
|
|
460
501
|
private
|
461
502
|
|
503
|
+
if Hash.respond_to?(:ruby2_keywords_hash)
|
504
|
+
def ruby2_keywords_hash(kwargs)
|
505
|
+
Hash.ruby2_keywords_hash(kwargs)
|
506
|
+
end
|
507
|
+
else
|
508
|
+
def ruby2_keywords_hash(kwargs)
|
509
|
+
kwargs
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
462
513
|
# Avoid modifying the caller's (pass-by-reference) arguments.
|
463
514
|
def clone_args(arg)
|
464
515
|
if arg.is_a?(Array)
|
@@ -475,12 +526,13 @@ class Redis
|
|
475
526
|
end
|
476
527
|
|
477
528
|
def namespaced_block(command, &block)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
529
|
+
if block.arity == 0
|
530
|
+
redis.send(command, &block)
|
531
|
+
else
|
532
|
+
redis.send(command) do |r|
|
533
|
+
copy = dup
|
534
|
+
copy.redis = r
|
535
|
+
yield copy
|
484
536
|
end
|
485
537
|
end
|
486
538
|
end
|
data/spec/deprecation_spec.rb
CHANGED
@@ -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 }
|