redis-namespace 1.6.0 → 1.9.0

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
- SHA1:
3
- metadata.gz: '08244a1c35f2f0164e72385ebd64aae7c57354b6'
4
- data.tar.gz: dd76131303f0cbb576780146d9c5e3a759302e57
2
+ SHA256:
3
+ metadata.gz: 88bd88ddb249a9424c8bcc002b84f097a96b4de6450944bc66096e6524115431
4
+ data.tar.gz: 1b9b4d59744b77a65ec523a77ea438de1f0923494a838c94a8c312893dce1fa6
5
5
  SHA512:
6
- metadata.gz: 4ca1e49aaf2c9e213a0859d1a0bda67f988ddf3a5af08bbf08388a8582298659d6a6869b7d8ee035501d8abf35779be20164dff5b849110f75f173cafb3444e5
7
- data.tar.gz: ca1151681a327f2206370a12f63729ee4f9a0891830274fc0e219353137f09216757421cfb4d4d29c18f73ca2f6e2b7bcf8ff4a0dc55a88324cd0aa7957f2993
6
+ metadata.gz: 2007d2f5396aec757c50d77de437dc01630b10de02eaeb852f7858233729476582036cf8214ba6e893f3e26b574c22169530a44bf9fb24c39fa2f2d5958e7ee5
7
+ data.tar.gz: af47dc4b2ce8357f8751c99ed71d05dc213a75a8092a3d54f016cef36b327967445b915bfaed32565639b0b2c16dbd02ef0026fbabcbf07c8965d3bb42b04f16
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
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
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
- included in all copies or substantial portions of the Software.
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
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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
- ~~~ irb
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, :redis => redis_connection)
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
- ~~~ ruby
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
- ~~~ ruby
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 `warnings: false` or by setting the `REDIS_NAMESPACE_QUIET` environment variable.
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
  ------------
@@ -2,6 +2,6 @@
2
2
 
3
3
  class Redis
4
4
  class Namespace
5
- VERSION = '1.6.0'
5
+ VERSION = '1.9.0'
6
6
  end
7
7
  end
@@ -57,20 +57,25 @@ 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" => [ :first ],
71
+ "exists" => [ :all ],
72
+ "exists?" => [ :all ],
69
73
  "expire" => [ :first ],
70
74
  "expireat" => [ :first ],
71
75
  "eval" => [ :eval_style ],
72
76
  "evalsha" => [ :eval_style ],
73
77
  "get" => [ :first ],
78
+ "getex" => [ :first ],
74
79
  "getbit" => [ :first ],
75
80
  "getrange" => [ :first ],
76
81
  "getset" => [ :first ],
@@ -147,6 +152,7 @@ class Redis
147
152
  "sinterstore" => [ :all ],
148
153
  "sismember" => [ :first ],
149
154
  "smembers" => [ :first ],
155
+ "smismember" => [ :first ],
150
156
  "smove" => [ :exclude_last ],
151
157
  "sort" => [ :sort ],
152
158
  "spop" => [ :first ],
@@ -160,27 +166,31 @@ class Redis
160
166
  "sunionstore" => [ :all ],
161
167
  "ttl" => [ :first ],
162
168
  "type" => [ :first ],
169
+ "unlink" => [ :all ],
163
170
  "unsubscribe" => [ :all ],
164
171
  "zadd" => [ :first ],
165
172
  "zcard" => [ :first ],
166
173
  "zcount" => [ :first ],
167
174
  "zincrby" => [ :first ],
168
175
  "zinterstore" => [ :exclude_options ],
176
+ "zpopmin" => [ :first ],
177
+ "zpopmax" => [ :first ],
169
178
  "zrange" => [ :first ],
170
179
  "zrangebyscore" => [ :first ],
180
+ "zrangebylex" => [ :first ],
171
181
  "zrank" => [ :first ],
172
182
  "zrem" => [ :first ],
173
183
  "zremrangebyrank" => [ :first ],
174
184
  "zremrangebyscore" => [ :first ],
185
+ "zremrangebylex" => [ :first ],
175
186
  "zrevrange" => [ :first ],
176
187
  "zrevrangebyscore" => [ :first ],
188
+ "zrevrangebylex" => [ :first ],
177
189
  "zrevrank" => [ :first ],
178
190
  "zscan" => [ :first ],
179
191
  "zscan_each" => [ :first ],
180
192
  "zscore" => [ :first ],
181
- "zunionstore" => [ :exclude_options ],
182
- "[]" => [ :first ],
183
- "[]=" => [ :first ]
193
+ "zunionstore" => [ :exclude_options ]
184
194
  }
185
195
  TRANSACTION_COMMANDS = {
186
196
  "discard" => [],
@@ -234,7 +244,7 @@ class Redis
234
244
 
235
245
  def initialize(namespace, options = {})
236
246
  @namespace = namespace
237
- @redis = options[:redis] || Redis.current
247
+ @redis = options[:redis] || Redis.new
238
248
  @warning = !!options.fetch(:warning) do
239
249
  !ENV['REDIS_NAMESPACE_QUIET']
240
250
  end
@@ -253,8 +263,8 @@ class Redis
253
263
  end
254
264
 
255
265
  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
266
+ warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
267
+ "method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
258
268
  _client
259
269
  end
260
270
 
@@ -272,7 +282,9 @@ class Redis
272
282
 
273
283
  # emulate Ruby 1.9+ and keep respond_to_missing? logic together.
274
284
  def respond_to?(command, include_private=false)
275
- super or respond_to_missing?(command, include_private)
285
+ return !deprecations? if DEPRECATED_COMMANDS.include?(command.to_s.downcase)
286
+
287
+ respond_to_missing?(command, include_private) or super
276
288
  end
277
289
 
278
290
  def keys(query = nil)
@@ -297,7 +309,15 @@ class Redis
297
309
  :redis => @redis)
298
310
  end
299
311
 
300
- @namespace
312
+ @namespace.respond_to?(:call) ? @namespace.call : @namespace
313
+ end
314
+
315
+ def full_namespace
316
+ redis.is_a?(Namespace) ? "#{redis.full_namespace}:#{namespace}" : namespace.to_s
317
+ end
318
+
319
+ def connection
320
+ @redis.connection.tap { |info| info[:namespace] = namespace }
301
321
  end
302
322
 
303
323
  def exec
@@ -307,16 +327,14 @@ class Redis
307
327
  def eval(*args)
308
328
  call_with_namespace(:eval, *args)
309
329
  end
330
+ ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
310
331
 
311
- def method_missing(command, *args, &block)
312
- normalized_command = command.to_s.downcase
332
+ ADMINISTRATIVE_COMMANDS.keys.each do |command|
333
+ define_method(command) do |*args, &block|
334
+ raise NoMethodError if deprecations?
313
335
 
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
336
  if warning?
319
- warn("Passing '#{normalized_command}' command to redis as is; " +
337
+ warn("Passing '#{command}' command to redis as is; " +
320
338
  "administrative commands cannot be effectively namespaced " +
321
339
  "and should be called on the redis connection directly; " +
322
340
  "passthrough has been deprecated and will be removed in " +
@@ -324,8 +342,25 @@ class Redis
324
342
  )
325
343
  end
326
344
  call_with_namespace(command, *args, &block)
327
- elsif COMMANDS.include?(normalized_command)
345
+ end
346
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
347
+ end
348
+
349
+ COMMANDS.keys.each do |command|
350
+ next if ADMINISTRATIVE_COMMANDS.include?(command)
351
+ next if method_defined?(command)
352
+
353
+ define_method(command) do |*args, &block|
328
354
  call_with_namespace(command, *args, &block)
355
+ end
356
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
357
+ end
358
+
359
+ def method_missing(command, *args, &block)
360
+ normalized_command = command.to_s.downcase
361
+
362
+ if COMMANDS.include?(normalized_command)
363
+ send(normalized_command, *args, &block)
329
364
  elsif @redis.respond_to?(normalized_command) && !deprecations?
330
365
  # blind passthrough is deprecated and will be removed in 2.0
331
366
  # redis-namespace does not know how to handle this command.
@@ -341,18 +376,17 @@ class Redis
341
376
  super
342
377
  end
343
378
  end
379
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
344
380
 
345
381
  def inspect
346
382
  "<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
347
- "for #{@redis.id}/#{@namespace}>"
383
+ "for #{@redis.id}/#{full_namespace}>"
348
384
  end
349
385
 
350
386
  def respond_to_missing?(command, include_all=false)
351
387
  normalized_command = command.to_s.downcase
352
388
 
353
389
  case
354
- when DEPRECATED_COMMANDS.include?(normalized_command)
355
- !deprecations?
356
390
  when COMMANDS.include?(normalized_command)
357
391
  true
358
392
  when !deprecations? && redis.respond_to?(command, include_all)
@@ -378,6 +412,7 @@ class Redis
378
412
  case before
379
413
  when :first
380
414
  args[0] = add_namespace(args[0]) if args[0]
415
+ args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
381
416
  when :all
382
417
  args = add_namespace(args)
383
418
  when :exclude_first
@@ -390,13 +425,14 @@ class Redis
390
425
  args.push(last) if last
391
426
  when :exclude_options
392
427
  if args.last.is_a?(Hash)
393
- last = args.pop
428
+ last = ruby2_keywords_hash(args.pop)
394
429
  args = add_namespace(args)
395
430
  args.push(last)
396
431
  else
397
432
  args = add_namespace(args)
398
433
  end
399
434
  when :alternate
435
+ args = args.flatten
400
436
  args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
401
437
  when :sort
402
438
  args[0] = add_namespace(args[0]) if args[0]
@@ -410,6 +446,7 @@ class Redis
410
446
  args[1][:get].each_index do |i|
411
447
  args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
412
448
  end
449
+ args[1] = ruby2_keywords_hash(args[1])
413
450
  end
414
451
  when :eval_style
415
452
  # redis.eval() and evalsha() can either take the form:
@@ -430,7 +467,7 @@ class Redis
430
467
  when :scan_style
431
468
  options = (args.last.kind_of?(Hash) ? args.pop : {})
432
469
  options[:match] = add_namespace(options.fetch(:match, '*'))
433
- args << options
470
+ args << ruby2_keywords_hash(options)
434
471
 
435
472
  if block
436
473
  original_block = block
@@ -456,9 +493,26 @@ class Redis
456
493
 
457
494
  result
458
495
  end
496
+ ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
497
+
498
+ protected
499
+
500
+ def redis=(redis)
501
+ @redis = redis
502
+ end
459
503
 
460
504
  private
461
505
 
506
+ if Hash.respond_to?(:ruby2_keywords_hash)
507
+ def ruby2_keywords_hash(kwargs)
508
+ Hash.ruby2_keywords_hash(kwargs)
509
+ end
510
+ else
511
+ def ruby2_keywords_hash(kwargs)
512
+ kwargs
513
+ end
514
+ end
515
+
462
516
  # Avoid modifying the caller's (pass-by-reference) arguments.
463
517
  def clone_args(arg)
464
518
  if arg.is_a?(Array)
@@ -475,18 +529,19 @@ class Redis
475
529
  end
476
530
 
477
531
  def namespaced_block(command, &block)
478
- redis.send(command) do |r|
479
- begin
480
- original, @redis = @redis, r
481
- yield self
482
- ensure
483
- @redis = original
532
+ if block.arity == 0
533
+ redis.send(command, &block)
534
+ else
535
+ redis.send(command) do |r|
536
+ copy = dup
537
+ copy.redis = r
538
+ yield copy
484
539
  end
485
540
  end
486
541
  end
487
542
 
488
543
  def add_namespace(key)
489
- return key unless key && @namespace
544
+ return key unless key && namespace
490
545
 
491
546
  case key
492
547
  when Array
@@ -495,12 +550,12 @@ class Redis
495
550
  key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
496
551
  key
497
552
  else
498
- "#{@namespace}:#{key}"
553
+ "#{namespace}:#{key}"
499
554
  end
500
555
  end
501
556
 
502
557
  def rem_namespace(key)
503
- return key unless key && @namespace
558
+ return key unless key && namespace
504
559
 
505
560
  case key
506
561
  when Array
@@ -512,7 +567,7 @@ class Redis
512
567
  key.each { |k| yielder.yield rem_namespace(k) }
513
568
  end
514
569
  else
515
- key.to_s.sub(/\A#{@namespace}:/, '')
570
+ key.to_s.sub(/\A#{namespace}:/, '')
516
571
  end
517
572
  end
518
573
 
@@ -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 { should_not respond_to :unhandled }
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 { should_not respond_to :flushdb }
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 { should respond_to :unhandled }
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 { should respond_to :flushdb }
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 }