redis-namespace 1.5.3 → 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: d8a331998a5b4c5b9f5f323da912dc2e4555a2db
4
- data.tar.gz: da08789df8269adf261ff47f7c1da894718ddc88
2
+ SHA256:
3
+ metadata.gz: 88bd88ddb249a9424c8bcc002b84f097a96b4de6450944bc66096e6524115431
4
+ data.tar.gz: 1b9b4d59744b77a65ec523a77ea438de1f0923494a838c94a8c312893dce1fa6
5
5
  SHA512:
6
- metadata.gz: 68d3325257b3c5a9ba0a7e461c39d30ce9de639304e8926e809e5f51256c5da41a8cdb2f29a5c2cd5c700032dc6d4e5b42be3e29327bcdaf0439c93f4db03f0a
7
- data.tar.gz: cffdb70935cade3a38e66e46a71ad9082afb074ebbbc05627113b6504e5b6337ec8c917734eeaf871e6dea271e9483bdfa11b22bdf1b772eab04e0f973fc3bdc
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.5.3'
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,13 +244,14 @@ 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
241
251
  @deprecations = !!options.fetch(:deprecations) do
242
252
  ENV['REDIS_NAMESPACE_DEPRECATIONS']
243
253
  end
254
+ @has_new_client_method = @redis.respond_to?(:_client)
244
255
  end
245
256
 
246
257
  def deprecations?
@@ -252,7 +263,13 @@ class Redis
252
263
  end
253
264
 
254
265
  def client
255
- @redis.client
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?
268
+ _client
269
+ end
270
+
271
+ def _client
272
+ @has_new_client_method ? @redis._client : @redis.client # for redis-4.0.0
256
273
  end
257
274
 
258
275
  # Ruby defines a now deprecated type method so we need to override it here
@@ -265,7 +282,9 @@ class Redis
265
282
 
266
283
  # emulate Ruby 1.9+ and keep respond_to_missing? logic together.
267
284
  def respond_to?(command, include_private=false)
268
- 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
269
288
  end
270
289
 
271
290
  def keys(query = nil)
@@ -290,7 +309,15 @@ class Redis
290
309
  :redis => @redis)
291
310
  end
292
311
 
293
- @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 }
294
321
  end
295
322
 
296
323
  def exec
@@ -300,16 +327,14 @@ class Redis
300
327
  def eval(*args)
301
328
  call_with_namespace(:eval, *args)
302
329
  end
330
+ ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
303
331
 
304
- def method_missing(command, *args, &block)
305
- 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?
306
335
 
307
- if ADMINISTRATIVE_COMMANDS.include?(normalized_command)
308
- # administrative commands usage is deprecated and will be removed in 2.0
309
- # redis-namespace cannot safely apply a namespace to their effects.
310
- return super if deprecations?
311
336
  if warning?
312
- warn("Passing '#{normalized_command}' command to redis as is; " +
337
+ warn("Passing '#{command}' command to redis as is; " +
313
338
  "administrative commands cannot be effectively namespaced " +
314
339
  "and should be called on the redis connection directly; " +
315
340
  "passthrough has been deprecated and will be removed in " +
@@ -317,8 +342,25 @@ class Redis
317
342
  )
318
343
  end
319
344
  call_with_namespace(command, *args, &block)
320
- 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|
321
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)
322
364
  elsif @redis.respond_to?(normalized_command) && !deprecations?
323
365
  # blind passthrough is deprecated and will be removed in 2.0
324
366
  # redis-namespace does not know how to handle this command.
@@ -334,18 +376,17 @@ class Redis
334
376
  super
335
377
  end
336
378
  end
379
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
337
380
 
338
381
  def inspect
339
382
  "<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
340
- "for #{@redis.id}/#{@namespace}>"
383
+ "for #{@redis.id}/#{full_namespace}>"
341
384
  end
342
385
 
343
386
  def respond_to_missing?(command, include_all=false)
344
387
  normalized_command = command.to_s.downcase
345
388
 
346
389
  case
347
- when DEPRECATED_COMMANDS.include?(normalized_command)
348
- !deprecations?
349
390
  when COMMANDS.include?(normalized_command)
350
391
  true
351
392
  when !deprecations? && redis.respond_to?(command, include_all)
@@ -371,6 +412,7 @@ class Redis
371
412
  case before
372
413
  when :first
373
414
  args[0] = add_namespace(args[0]) if args[0]
415
+ args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
374
416
  when :all
375
417
  args = add_namespace(args)
376
418
  when :exclude_first
@@ -383,13 +425,14 @@ class Redis
383
425
  args.push(last) if last
384
426
  when :exclude_options
385
427
  if args.last.is_a?(Hash)
386
- last = args.pop
428
+ last = ruby2_keywords_hash(args.pop)
387
429
  args = add_namespace(args)
388
430
  args.push(last)
389
431
  else
390
432
  args = add_namespace(args)
391
433
  end
392
434
  when :alternate
435
+ args = args.flatten
393
436
  args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
394
437
  when :sort
395
438
  args[0] = add_namespace(args[0]) if args[0]
@@ -403,6 +446,7 @@ class Redis
403
446
  args[1][:get].each_index do |i|
404
447
  args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
405
448
  end
449
+ args[1] = ruby2_keywords_hash(args[1])
406
450
  end
407
451
  when :eval_style
408
452
  # redis.eval() and evalsha() can either take the form:
@@ -423,7 +467,7 @@ class Redis
423
467
  when :scan_style
424
468
  options = (args.last.kind_of?(Hash) ? args.pop : {})
425
469
  options[:match] = add_namespace(options.fetch(:match, '*'))
426
- args << options
470
+ args << ruby2_keywords_hash(options)
427
471
 
428
472
  if block
429
473
  original_block = block
@@ -449,9 +493,26 @@ class Redis
449
493
 
450
494
  result
451
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
452
503
 
453
504
  private
454
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
+
455
516
  # Avoid modifying the caller's (pass-by-reference) arguments.
456
517
  def clone_args(arg)
457
518
  if arg.is_a?(Array)
@@ -468,18 +529,19 @@ class Redis
468
529
  end
469
530
 
470
531
  def namespaced_block(command, &block)
471
- redis.send(command) do |r|
472
- begin
473
- original, @redis = @redis, r
474
- yield self
475
- ensure
476
- @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
477
539
  end
478
540
  end
479
541
  end
480
542
 
481
543
  def add_namespace(key)
482
- return key unless key && @namespace
544
+ return key unless key && namespace
483
545
 
484
546
  case key
485
547
  when Array
@@ -488,12 +550,12 @@ class Redis
488
550
  key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
489
551
  key
490
552
  else
491
- "#{@namespace}:#{key}"
553
+ "#{namespace}:#{key}"
492
554
  end
493
555
  end
494
556
 
495
557
  def rem_namespace(key)
496
- return key unless key && @namespace
558
+ return key unless key && namespace
497
559
 
498
560
  case key
499
561
  when Array
@@ -505,7 +567,7 @@ class Redis
505
567
  key.each { |k| yielder.yield rem_namespace(k) }
506
568
  end
507
569
  else
508
- key.to_s.sub(/\A#{@namespace}:/, '')
570
+ key.to_s.sub(/\A#{namespace}:/, '')
509
571
  end
510
572
  end
511
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 }