redis-namespace 1.7.0 → 1.10.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
2
  SHA256:
3
- metadata.gz: 9ebbb9000d7b34a0a8386ac9d72e2f63f4573720b22a8eb7e3676c0c1759200b
4
- data.tar.gz: ec5c495b22e58cc98d4c759f7873f2d2f9f69c8205b750062207b6f4b1f45897
3
+ metadata.gz: 8c4fe7070f484a694ce41f97a0297e03d92cfa67746903d9fb74fa8439410494
4
+ data.tar.gz: 0cbfe04c2ca7b2d42ee603f0d67ba21c13cb938832cc99f89a2323842bb828a3
5
5
  SHA512:
6
- metadata.gz: e05aa113c14df634a64fdfad7891781ace6a5060a533e9417f94476235f3e05fd33859c4653fcbe8f417582e9257cdf20b1599ac1b2e4cbe38ccaf7c88af2dba
7
- data.tar.gz: 220e3ec476e5613dd3a8529f2f7b30f7aba9433a1f4ab4402c55be555ef00ff5651738824ddc583e83e7cbad9297d1f1a107bd61e4b44df5e8c9efa50589cfea
6
+ metadata.gz: ec085b7e9fba5241cb2e2ad4ccf22d4282001a0ee37731e408a2135ea5e5439747441046cc6c48a2a372afe99f2fb6a67401867a20c8605e41206954eca72078
7
+ data.tar.gz: 0eff5c268bba88cb8bd5e0ab8115a404fed3180e82ebc4297ab8675da6c73e13b3bb943e77ec0392de4460683488589bbc227d95515aa5dc70cdb4236b58801d
data/README.md CHANGED
@@ -33,6 +33,13 @@ redis_connection.get('ns:foo')
33
33
  # => nil
34
34
  ```
35
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
+ ```
42
+
36
43
  Installation
37
44
  ============
38
45
 
@@ -79,7 +86,7 @@ namespaced.redis.flushall()
79
86
 
80
87
  As mentioned above, 2.0 will remove blind passthrough and the administrative command passthrough.
81
88
  By default in 1.5+, deprecation warnings are present and enabled;
82
- 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.
83
90
 
84
91
  Early opt-in
85
92
  ------------
@@ -2,6 +2,6 @@
2
2
 
3
3
  class Redis
4
4
  class Namespace
5
- VERSION = '1.7.0'
5
+ VERSION = '1.10.0'
6
6
  end
7
7
  end
@@ -68,12 +68,14 @@ class Redis
68
68
  "decrby" => [ :first ],
69
69
  "del" => [ :all ],
70
70
  "dump" => [ :first ],
71
- "exists" => [ :first ],
71
+ "exists" => [ :all ],
72
+ "exists?" => [ :all ],
72
73
  "expire" => [ :first ],
73
74
  "expireat" => [ :first ],
74
75
  "eval" => [ :eval_style ],
75
76
  "evalsha" => [ :eval_style ],
76
77
  "get" => [ :first ],
78
+ "getex" => [ :first ],
77
79
  "getbit" => [ :first ],
78
80
  "getrange" => [ :first ],
79
81
  "getset" => [ :first ],
@@ -136,6 +138,7 @@ class Redis
136
138
  "rpush" => [ :first ],
137
139
  "rpushx" => [ :first ],
138
140
  "sadd" => [ :first ],
141
+ "sadd?" => [ :first ],
139
142
  "scard" => [ :first ],
140
143
  "scan" => [ :scan_style, :second ],
141
144
  "scan_each" => [ :scan_style, :all ],
@@ -150,6 +153,7 @@ class Redis
150
153
  "sinterstore" => [ :all ],
151
154
  "sismember" => [ :first ],
152
155
  "smembers" => [ :first ],
156
+ "smismember" => [ :first ],
153
157
  "smove" => [ :exclude_last ],
154
158
  "sort" => [ :sort ],
155
159
  "spop" => [ :first ],
@@ -199,6 +203,7 @@ class Redis
199
203
  HELPER_COMMANDS = {
200
204
  "auth" => [],
201
205
  "disconnect!" => [],
206
+ "close" => [],
202
207
  "echo" => [],
203
208
  "ping" => [],
204
209
  "time" => [],
@@ -235,13 +240,20 @@ class Redis
235
240
  # Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
236
241
  Enumerator = Enumerable::Enumerator unless defined?(::Enumerator)
237
242
 
243
+ # This is used by the Redis gem to determine whether or not to display that deprecation message.
244
+ @sadd_returns_boolean = true
245
+
246
+ class << self
247
+ attr_accessor :sadd_returns_boolean
248
+ end
249
+
238
250
  attr_writer :namespace
239
251
  attr_reader :redis
240
252
  attr_accessor :warning
241
253
 
242
254
  def initialize(namespace, options = {})
243
255
  @namespace = namespace
244
- @redis = options[:redis] || Redis.current
256
+ @redis = options[:redis] || Redis.new
245
257
  @warning = !!options.fetch(:warning) do
246
258
  !ENV['REDIS_NAMESPACE_QUIET']
247
259
  end
@@ -260,7 +272,7 @@ class Redis
260
272
  end
261
273
 
262
274
  def client
263
- warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client" +
275
+ warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
264
276
  "method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
265
277
  _client
266
278
  end
@@ -306,7 +318,7 @@ class Redis
306
318
  :redis => @redis)
307
319
  end
308
320
 
309
- @namespace
321
+ @namespace.respond_to?(:call) ? @namespace.call : @namespace
310
322
  end
311
323
 
312
324
  def full_namespace
@@ -314,7 +326,7 @@ class Redis
314
326
  end
315
327
 
316
328
  def connection
317
- @redis.connection.tap { |info| info[:namespace] = @namespace }
329
+ @redis.connection.tap { |info| info[:namespace] = namespace }
318
330
  end
319
331
 
320
332
  def exec
@@ -324,6 +336,33 @@ class Redis
324
336
  def eval(*args)
325
337
  call_with_namespace(:eval, *args)
326
338
  end
339
+ ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
340
+
341
+ # This operation can run for a very long time if the namespace contains lots of keys!
342
+ # It should be used in tests, or when the namespace is small enough
343
+ # and you are sure you know what you are doing.
344
+ def clear
345
+ if warning?
346
+ warn("This operation can run for a very long time if the namespace contains lots of keys! " +
347
+ "It should be used in tests, or when the namespace is small enough " +
348
+ "and you are sure you know what you are doing.")
349
+ end
350
+
351
+ batch_size = 1000
352
+
353
+ if supports_scan?
354
+ cursor = "0"
355
+ begin
356
+ cursor, keys = scan(cursor, count: batch_size)
357
+ del(*keys) unless keys.empty?
358
+ end until cursor == "0"
359
+ else
360
+ all_keys = keys("*")
361
+ all_keys.each_slice(batch_size) do |keys|
362
+ del(*keys)
363
+ end
364
+ end
365
+ end
327
366
 
328
367
  ADMINISTRATIVE_COMMANDS.keys.each do |command|
329
368
  define_method(command) do |*args, &block|
@@ -339,6 +378,7 @@ class Redis
339
378
  end
340
379
  call_with_namespace(command, *args, &block)
341
380
  end
381
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
342
382
  end
343
383
 
344
384
  COMMANDS.keys.each do |command|
@@ -348,6 +388,7 @@ class Redis
348
388
  define_method(command) do |*args, &block|
349
389
  call_with_namespace(command, *args, &block)
350
390
  end
391
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
351
392
  end
352
393
 
353
394
  def method_missing(command, *args, &block)
@@ -365,15 +406,17 @@ class Redis
365
406
  "passthrough has been deprecated and will be removed in " +
366
407
  "redis-namespace 2.0 (at #{call_site})")
367
408
  end
368
- @redis.send(command, *args, &block)
409
+
410
+ wrapped_send(@redis, command, args, &block)
369
411
  else
370
412
  super
371
413
  end
372
414
  end
415
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
373
416
 
374
417
  def inspect
375
418
  "<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
376
- "for #{@redis.id}/#{@namespace}>"
419
+ "for #{@redis.id}/#{full_namespace}>"
377
420
  end
378
421
 
379
422
  def respond_to_missing?(command, include_all=false)
@@ -405,6 +448,7 @@ class Redis
405
448
  case before
406
449
  when :first
407
450
  args[0] = add_namespace(args[0]) if args[0]
451
+ args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
408
452
  when :all
409
453
  args = add_namespace(args)
410
454
  when :exclude_first
@@ -417,13 +461,14 @@ class Redis
417
461
  args.push(last) if last
418
462
  when :exclude_options
419
463
  if args.last.is_a?(Hash)
420
- last = args.pop
464
+ last = ruby2_keywords_hash(args.pop)
421
465
  args = add_namespace(args)
422
466
  args.push(last)
423
467
  else
424
468
  args = add_namespace(args)
425
469
  end
426
470
  when :alternate
471
+ args = args.flatten
427
472
  args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
428
473
  when :sort
429
474
  args[0] = add_namespace(args[0]) if args[0]
@@ -437,6 +482,7 @@ class Redis
437
482
  args[1][:get].each_index do |i|
438
483
  args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
439
484
  end
485
+ args[1] = ruby2_keywords_hash(args[1])
440
486
  end
441
487
  when :eval_style
442
488
  # redis.eval() and evalsha() can either take the form:
@@ -457,7 +503,7 @@ class Redis
457
503
  when :scan_style
458
504
  options = (args.last.kind_of?(Hash) ? args.pop : {})
459
505
  options[:match] = add_namespace(options.fetch(:match, '*'))
460
- args << options
506
+ args << ruby2_keywords_hash(options)
461
507
 
462
508
  if block
463
509
  original_block = block
@@ -466,7 +512,7 @@ class Redis
466
512
  end
467
513
 
468
514
  # Dispatch the command to Redis and store the result.
469
- result = @redis.send(command, *args, &block)
515
+ result = wrapped_send(@redis, command, args, &block)
470
516
 
471
517
  # Don't try to remove namespace from a Redis::Future, you can't.
472
518
  return result if result.is_a?(Redis::Future)
@@ -483,9 +529,36 @@ class Redis
483
529
 
484
530
  result
485
531
  end
532
+ ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
533
+
534
+ protected
535
+
536
+ def redis=(redis)
537
+ @redis = redis
538
+ end
486
539
 
487
540
  private
488
541
 
542
+ if Hash.respond_to?(:ruby2_keywords_hash)
543
+ def ruby2_keywords_hash(kwargs)
544
+ Hash.ruby2_keywords_hash(kwargs)
545
+ end
546
+ else
547
+ def ruby2_keywords_hash(kwargs)
548
+ kwargs
549
+ end
550
+ end
551
+
552
+ def wrapped_send(redis_client, command, args = [], &block)
553
+ if redis_client.class.name == "ConnectionPool"
554
+ redis_client.with do |pool_connection|
555
+ pool_connection.send(command, *args, &block)
556
+ end
557
+ else
558
+ redis_client.send(command, *args, &block)
559
+ end
560
+ end
561
+
489
562
  # Avoid modifying the caller's (pass-by-reference) arguments.
490
563
  def clone_args(arg)
491
564
  if arg.is_a?(Array)
@@ -502,18 +575,16 @@ class Redis
502
575
  end
503
576
 
504
577
  def namespaced_block(command, &block)
505
- redis.send(command) do |r|
506
- begin
507
- original, @redis = @redis, r
508
- yield self
509
- ensure
510
- @redis = original
511
- end
578
+ if block.arity == 0
579
+ wrapped_send(redis, command, &block)
580
+ else
581
+ outer_block = proc { |r| copy = dup; copy.redis = r; yield copy }
582
+ wrapped_send(redis, command, &outer_block)
512
583
  end
513
584
  end
514
585
 
515
586
  def add_namespace(key)
516
- return key unless key && @namespace
587
+ return key unless key && namespace
517
588
 
518
589
  case key
519
590
  when Array
@@ -522,12 +593,12 @@ class Redis
522
593
  key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
523
594
  key
524
595
  else
525
- "#{@namespace}:#{key}"
596
+ "#{namespace}:#{key}"
526
597
  end
527
598
  end
528
599
 
529
600
  def rem_namespace(key)
530
- return key unless key && @namespace
601
+ return key unless key && namespace
531
602
 
532
603
  case key
533
604
  when Array
@@ -539,7 +610,7 @@ class Redis
539
610
  key.each { |k| yielder.yield rem_namespace(k) }
540
611
  end
541
612
  else
542
- key.to_s.sub(/\A#{@namespace}:/, '')
613
+ key.to_s.sub(/\A#{namespace}:/, '')
543
614
  end
544
615
  end
545
616
 
@@ -554,5 +625,10 @@ class Redis
554
625
  Enumerator.new(&block)
555
626
  end
556
627
  end
628
+
629
+ def supports_scan?
630
+ redis_version = @redis.info["redis_version"]
631
+ Gem::Version.new(redis_version) >= Gem::Version.new("2.8.0")
632
+ end
557
633
  end
558
634
  end
@@ -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")
data/spec/redis_spec.rb CHANGED
@@ -1,30 +1,20 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require File.dirname(__FILE__) + '/spec_helper'
4
+ require 'connection_pool'
4
5
 
5
6
  describe "redis" do
6
- @redis_version = Gem::Version.new(Redis.current.info["redis_version"])
7
+ @redis_version = Gem::Version.new(Redis.new.info["redis_version"])
7
8
  let(:redis_client) { @redis.respond_to?(:_client) ? @redis._client : @redis.client}
8
9
 
9
- before(:all) do
10
+ before(:each) do
10
11
  # use database 15 for testing so we dont accidentally step on your real data
11
12
  @redis = Redis.new :db => 15
12
- end
13
-
14
- before(:each) do
15
- @namespaced = Redis::Namespace.new(:ns, :redis => @redis)
16
13
  @redis.flushdb
14
+ @namespaced = Redis::Namespace.new(:ns, :redis => @redis)
17
15
  @redis.set('foo', 'bar')
18
16
  end
19
17
 
20
- after(:each) do
21
- @redis.flushdb
22
- end
23
-
24
- after(:all) do
25
- @redis.quit
26
- end
27
-
28
18
  # redis-rb 3.3.4+
29
19
  it "should inject :namespace into connection info" do
30
20
  info = @redis.connection.merge(:namespace => :ns)
@@ -52,6 +42,17 @@ describe "redis" do
52
42
  expect(@namespaced.type('counter')).to eq('string')
53
43
  end
54
44
 
45
+ it "should work with Proc namespaces" do
46
+ namespace = Proc.new { :dynamic_ns }
47
+ namespaced = Redis::Namespace.new(namespace, redis: @redis)
48
+
49
+ expect(namespaced.get('foo')).to eq(nil)
50
+ namespaced.set('foo', 'chris')
51
+ expect(namespaced.get('foo')).to eq('chris')
52
+ @redis.set('foo', 'bob')
53
+ expect(@redis.get('foo')).to eq('bob')
54
+ end
55
+
55
56
  context 'when sending capital commands (issue 68)' do
56
57
  it 'should be able to use a namespace' do
57
58
  @namespaced.send('SET', 'fubar', 'quux')
@@ -106,6 +107,13 @@ describe "redis" do
106
107
  expect(@namespaced.lrange('bar',0,-1)).to eq(['bar'])
107
108
  end
108
109
 
110
+ it "should be able to use a namespace with getex" do
111
+ expect(@namespaced.set('mykey', 'Hello')).to eq('OK')
112
+ expect(@namespaced.getex('mykey', ex: 50)).to eq('Hello')
113
+ expect(@namespaced.get('mykey')).to eq('Hello')
114
+ expect(@namespaced.ttl('mykey')).to eq(50)
115
+ end
116
+
109
117
  it 'should be able to use a namespace with getbit' do
110
118
  @namespaced.set('foo','bar')
111
119
  expect(@namespaced.getbit('foo',1)).to eq(1)
@@ -140,10 +148,22 @@ describe "redis" do
140
148
 
141
149
  it 'should be able to use a namespace with setbit' do
142
150
  @namespaced.setbit('virgin_key', 1, 1)
143
- expect(@namespaced.exists('virgin_key')).to be true
151
+ expect(@namespaced.exists?('virgin_key')).to be true
144
152
  expect(@namespaced.get('virgin_key')).to eq(@namespaced.getrange('virgin_key',0,-1))
145
153
  end
146
154
 
155
+ it 'should be able to use a namespace with exists' do
156
+ @namespaced.set('foo', 1000)
157
+ @namespaced.set('bar', 2000)
158
+ expect(@namespaced.exists('foo', 'bar')).to eq(2)
159
+ end
160
+
161
+ it 'should be able to use a namespace with exists?' do
162
+ @namespaced.set('foo', 1000)
163
+ @namespaced.set('bar', 2000)
164
+ expect(@namespaced.exists?('does_not_exist', 'bar')).to eq(true)
165
+ end
166
+
147
167
  it 'should be able to use a namespace with bitpos' do
148
168
  @namespaced.setbit('bit_map', 42, 1)
149
169
  expect(@namespaced.bitpos('bit_map', 0)).to eq(0)
@@ -165,19 +185,44 @@ describe "redis" do
165
185
  expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({'foo'=>'1000', 'bar'=>'2000', 'baz' => nil})
166
186
  end
167
187
 
188
+ it "should utilize connection_pool while using a namespace with mget" do
189
+ memo = @namespaced
190
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
191
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
192
+
193
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
194
+ expect(arg).to be(an_instance_of(Redis))
195
+ end.at_least(:once)
196
+
197
+ @namespaced.set('foo', 1000)
198
+ @namespaced.set('bar', 2000)
199
+ expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
200
+ expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({'foo'=>'1000', 'bar'=>'2000', 'baz' => nil})
201
+ @redis.get('foo').should eq('bar')
202
+
203
+ @namespaced = memo
204
+ end
205
+
168
206
  it "should be able to use a namespace with mset" do
169
207
  @namespaced.mset('foo', '1000', 'bar', '2000')
170
208
  expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
171
209
  expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil})
210
+
172
211
  @namespaced.mapped_mset('foo' => '3000', 'bar' => '5000')
173
212
  expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000' })
174
213
  expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000', 'baz' => nil})
214
+
215
+ @namespaced.mset(['foo', '4000'], ['baz', '6000'])
216
+ expect(@namespaced.mapped_mget('foo', 'bar', 'baz')).to eq({ 'foo' => '4000', 'bar' => '5000', 'baz' => '6000' })
175
217
  end
176
218
 
177
219
  it "should be able to use a namespace with msetnx" do
178
220
  @namespaced.msetnx('foo', '1000', 'bar', '2000')
179
221
  expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
180
222
  expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil})
223
+
224
+ @namespaced.msetnx(['baz', '4000'])
225
+ expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => '4000'})
181
226
  end
182
227
 
183
228
  it "should be able to use a namespace with mapped_msetnx" do
@@ -239,7 +284,7 @@ describe "redis" do
239
284
  @namespaced.zadd('sort2', 2, 2)
240
285
  @namespaced.zadd('sort2', 3, 3)
241
286
  @namespaced.zadd('sort2', 4, 4)
242
- @namespaced.zunionstore('union', ['sort1', 'sort2'], :weights => [2, 1])
287
+ @namespaced.zunionstore('union', ['sort1', 'sort2'], weights: [2, 1])
243
288
  expect(@namespaced.zrevrange('union', 0, -1)).to eq(%w( 2 4 3 1 ))
244
289
  end
245
290
 
@@ -313,6 +358,11 @@ describe "redis" do
313
358
  expect(values).to match_array(['banana', 'eggplant'])
314
359
  end
315
360
 
361
+ it "should add a new member" do
362
+ expect(@namespaced.sadd?('foo', 1)).to eq(true)
363
+ expect(@namespaced.sadd?('foo', 1)).to eq(false)
364
+ end
365
+
316
366
  it "should add namespace to sort" do
317
367
  @namespaced.sadd('foo', 1)
318
368
  @namespaced.sadd('foo', 2)
@@ -350,6 +400,26 @@ describe "redis" do
350
400
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
351
401
  end
352
402
 
403
+ it "should utilize connection_pool while adding namepsace to multi blocks" do
404
+ memo = @namespaced
405
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
406
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
407
+
408
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
409
+ expect(arg).to be(an_instance_of(Redis))
410
+ end.at_least(:once)
411
+
412
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
413
+ @namespaced.multi do |r|
414
+ r.del "foo"
415
+ r.mapped_hmset "foo", {"key1" => "value1"}
416
+ end
417
+ expect(@redis.get("foo")).to eq("bar")
418
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
419
+
420
+ @namespaced = memo
421
+ end
422
+
353
423
  it "should pass through multi commands without block" do
354
424
  @namespaced.mapped_hmset "foo", {"key" => "value"}
355
425
 
@@ -361,6 +431,28 @@ describe "redis" do
361
431
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
362
432
  end
363
433
 
434
+ it "should utilize connection_pool while passing through multi commands without block" do
435
+ memo = @namespaced
436
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
437
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
438
+
439
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
440
+ expect(arg).to be(an_instance_of(Redis))
441
+ end.at_least(:once)
442
+
443
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
444
+
445
+ @namespaced.multi
446
+ @namespaced.del "foo"
447
+ @namespaced.mapped_hmset "foo", {"key1" => "value1"}
448
+ @namespaced.exec
449
+
450
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
451
+ expect(@redis.get("foo")).to eq("bar")
452
+
453
+ @namespaced = memo
454
+ end
455
+
364
456
  it 'should return futures without attempting to remove namespaces' do
365
457
  @namespaced.multi do
366
458
  @future = @namespaced.keys('*')
@@ -377,6 +469,26 @@ describe "redis" do
377
469
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
378
470
  end
379
471
 
472
+ it "should utilize connection_pool while adding namespace to pipelined blocks" do
473
+ memo = @namespaced
474
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
475
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
476
+
477
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
478
+ expect(arg).to be(an_instance_of(Redis))
479
+ end.at_least(:once)
480
+
481
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
482
+ @namespaced.pipelined do |r|
483
+ r.del "foo"
484
+ r.mapped_hmset "foo", {"key1" => "value1"}
485
+ end
486
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
487
+ expect(@redis.get("foo")).to eq("bar")
488
+
489
+ @namespaced = memo
490
+ end
491
+
380
492
  it "should returned response array from pipelined block" do
381
493
  @namespaced.mset "foo", "bar", "key", "value"
382
494
  result = @namespaced.pipelined do |r|
@@ -386,6 +498,27 @@ describe "redis" do
386
498
  expect(result).to eq(["bar", "value"])
387
499
  end
388
500
 
501
+ it "is thread safe for multi blocks" do
502
+ mon = Monitor.new
503
+ entered = false
504
+ entered_cond = mon.new_cond
505
+
506
+ thread = Thread.new do
507
+ mon.synchronize do
508
+ entered_cond.wait_until { entered }
509
+ @namespaced.multi
510
+ end
511
+ end
512
+
513
+ @namespaced.multi do |transaction|
514
+ entered = true
515
+ mon.synchronize { entered_cond.signal }
516
+ thread.join(0.1)
517
+ transaction.get("foo")
518
+ end
519
+ thread.join
520
+ end
521
+
389
522
  it "should add namespace to strlen" do
390
523
  @namespaced.set("mykey", "123456")
391
524
  expect(@namespaced.strlen("mykey")).to eq(6)
@@ -442,6 +575,45 @@ describe "redis" do
442
575
  expect { @namespaced.unknown('foo') }.to raise_exception NoMethodError
443
576
  end
444
577
 
578
+ describe '#inspect' do
579
+ let(:single_level_names) { %i[first] }
580
+ let(:double_level_names) { %i[first second] }
581
+ let(:triple_level_names) { %i[first second third] }
582
+ let(:namespace_builder) do
583
+ ->(redis, *namespaces) { namespaces.reduce(redis) { |r, n| Redis::Namespace.new(n, redis: r) } }
584
+ end
585
+ let(:regexp_builder) do
586
+ ->(*namespaces) { %r{/#{namespaces.join(':')}>\z} }
587
+ end
588
+
589
+ context 'when one namespace' do
590
+ let(:single_namespaced) { namespace_builder.call(@redis, *single_level_names) }
591
+ let(:regexp) { regexp_builder.call(*single_level_names) }
592
+
593
+ it 'should have correct ending of inspect string' do
594
+ expect(regexp =~ single_namespaced.inspect).not_to be(nil)
595
+ end
596
+ end
597
+
598
+ context 'when two namespaces' do
599
+ let(:double_namespaced) { namespace_builder.call(@redis, *double_level_names) }
600
+ let(:regexp) { regexp_builder.call(*double_level_names) }
601
+
602
+ it 'should have correct ending of inspect string' do
603
+ expect(regexp =~ double_namespaced.inspect).not_to be(nil)
604
+ end
605
+ end
606
+
607
+ context 'when three namespaces' do
608
+ let(:triple_namespaced) { namespace_builder.call(@redis, *triple_level_names) }
609
+ let(:regexp) { regexp_builder.call(*triple_level_names) }
610
+
611
+ it 'should have correct ending of inspect string' do
612
+ expect(regexp =~ triple_namespaced.inspect).not_to be(nil)
613
+ end
614
+ end
615
+ end
616
+
445
617
  # Redis 2.6 RC reports its version as 2.5.
446
618
  if @redis_version >= Gem::Version.new("2.5.0")
447
619
  describe "redis 2.6 commands" do
@@ -626,7 +798,7 @@ describe "redis" do
626
798
  expect(result).to match_array(namespaced_keys)
627
799
  end
628
800
  end
629
- end if Redis.current.respond_to?(:scan)
801
+ end if Redis.new.respond_to?(:scan)
630
802
 
631
803
  context '#scan_each' do
632
804
  context 'when :match supplied' do
@@ -659,7 +831,7 @@ describe "redis" do
659
831
  end
660
832
  end
661
833
  end
662
- end if Redis.current.respond_to?(:scan_each)
834
+ end if Redis.new.respond_to?(:scan_each)
663
835
  end
664
836
 
665
837
  context 'hash scan methods' do
@@ -687,7 +859,7 @@ describe "redis" do
687
859
  expect(results).to match_array(@redis.hgetall('ns:hsh').to_a)
688
860
  end
689
861
  end
690
- end if Redis.current.respond_to?(:hscan)
862
+ end if Redis.new.respond_to?(:hscan)
691
863
 
692
864
  context '#hscan_each' do
693
865
  context 'when :match supplied' do
@@ -720,7 +892,7 @@ describe "redis" do
720
892
  end
721
893
  end
722
894
  end
723
- end if Redis.current.respond_to?(:hscan_each)
895
+ end if Redis.new.respond_to?(:hscan_each)
724
896
  end
725
897
 
726
898
  context 'set scan methods' do
@@ -748,7 +920,7 @@ describe "redis" do
748
920
  expect(results).to match_array(set)
749
921
  end
750
922
  end
751
- end if Redis.current.respond_to?(:sscan)
923
+ end if Redis.new.respond_to?(:sscan)
752
924
 
753
925
  context '#sscan_each' do
754
926
  context 'when :match supplied' do
@@ -781,7 +953,7 @@ describe "redis" do
781
953
  end
782
954
  end
783
955
  end
784
- end if Redis.current.respond_to?(:sscan_each)
956
+ end if Redis.new.respond_to?(:sscan_each)
785
957
  end
786
958
 
787
959
  context 'zset scan methods' do
@@ -811,7 +983,7 @@ describe "redis" do
811
983
  expect(results).to match_array(hash.to_a)
812
984
  end
813
985
  end
814
- end if Redis.current.respond_to?(:zscan)
986
+ end if Redis.new.respond_to?(:zscan)
815
987
 
816
988
  context '#zscan_each' do
817
989
  context 'when :match supplied' do
@@ -844,7 +1016,7 @@ describe "redis" do
844
1016
  end
845
1017
  end
846
1018
  end
847
- end if Redis.current.respond_to?(:zscan_each)
1019
+ end if Redis.new.respond_to?(:zscan_each)
848
1020
  end
849
1021
  end
850
1022
  end
@@ -881,4 +1053,30 @@ describe "redis" do
881
1053
  expect(sub_sub_namespaced.full_namespace).to eql("ns:sub1:sub2")
882
1054
  end
883
1055
  end
1056
+
1057
+ describe :clear do
1058
+ it "warns with helpful output" do
1059
+ expect { @namespaced.clear }.to output(/can run for a very long time/).to_stderr
1060
+ end
1061
+
1062
+ it "should delete all the keys" do
1063
+ @redis.set("foo", "bar")
1064
+ @namespaced.mset("foo1", "bar", "foo2", "bar")
1065
+ capture_stderr { @namespaced.clear }
1066
+
1067
+ expect(@redis.keys).to eq ["foo"]
1068
+ expect(@namespaced.keys).to be_empty
1069
+ end
1070
+
1071
+ it "should delete all the keys in older redis" do
1072
+ allow(@redis).to receive(:info).and_return({ "redis_version" => "2.7.0" })
1073
+
1074
+ @redis.set("foo", "bar")
1075
+ @namespaced.mset("foo1", "bar", "foo2", "bar")
1076
+ capture_stderr { @namespaced.clear }
1077
+
1078
+ expect(@redis.keys).to eq ["foo"]
1079
+ expect(@namespaced.keys).to be_empty
1080
+ end
1081
+ end
884
1082
  end
data/spec/spec_helper.rb CHANGED
@@ -12,6 +12,10 @@ $TESTING=true
12
12
  $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
13
13
  require 'redis/namespace'
14
14
 
15
+ if Redis.respond_to?(:exists_returns_integer=)
16
+ Redis.exists_returns_integer = true
17
+ end
18
+
15
19
  module Helper
16
20
  def capture_stderr(io = nil)
17
21
  require 'stringio'
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-namespace
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Wanstrath
8
8
  - Terence Lee
9
9
  - Steve Klabnik
10
10
  - Ryan Biesemeyer
11
- autorequire:
11
+ - Mike Bianco
12
+ autorequire:
12
13
  bindir: bin
13
14
  cert_chain: []
14
- date: 2019-12-11 00:00:00.000000000 Z
15
+ date: 2022-12-20 00:00:00.000000000 Z
15
16
  dependencies:
16
17
  - !ruby/object:Gem::Dependency
17
18
  name: redis
@@ -19,28 +20,28 @@ dependencies:
19
20
  requirements:
20
21
  - - ">="
21
22
  - !ruby/object:Gem::Version
22
- version: 3.0.4
23
+ version: '4'
23
24
  type: :runtime
24
25
  prerelease: false
25
26
  version_requirements: !ruby/object:Gem::Requirement
26
27
  requirements:
27
28
  - - ">="
28
29
  - !ruby/object:Gem::Version
29
- version: 3.0.4
30
+ version: '4'
30
31
  - !ruby/object:Gem::Dependency
31
32
  name: rake
32
33
  requirement: !ruby/object:Gem::Requirement
33
34
  requirements:
34
- - - "~>"
35
+ - - ">="
35
36
  - !ruby/object:Gem::Version
36
- version: '10.1'
37
+ version: '0'
37
38
  type: :development
38
39
  prerelease: false
39
40
  version_requirements: !ruby/object:Gem::Requirement
40
41
  requirements:
41
- - - "~>"
42
+ - - ">="
42
43
  - !ruby/object:Gem::Version
43
- version: '10.1'
44
+ version: '0'
44
45
  - !ruby/object:Gem::Dependency
45
46
  name: rspec
46
47
  requirement: !ruby/object:Gem::Requirement
@@ -69,6 +70,20 @@ dependencies:
69
70
  - - ">="
70
71
  - !ruby/object:Gem::Version
71
72
  version: '0'
73
+ - !ruby/object:Gem::Dependency
74
+ name: connection_pool
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
72
87
  description: |
73
88
  Adds a Redis::Namespace class which can be used to namespace calls
74
89
  to Redis. This is useful when using a single instance of Redis with
@@ -78,6 +93,7 @@ email:
78
93
  - hone02@gmail.com
79
94
  - steve@steveklabnik.com
80
95
  - me@yaauie.com
96
+ - mike@mikebian.co
81
97
  executables: []
82
98
  extensions: []
83
99
  extra_rdoc_files: []
@@ -91,17 +107,21 @@ files:
91
107
  - spec/deprecation_spec.rb
92
108
  - spec/redis_spec.rb
93
109
  - spec/spec_helper.rb
94
- homepage: http://github.com/resque/redis-namespace
110
+ homepage: https://github.com/resque/redis-namespace
95
111
  licenses:
96
112
  - MIT
97
- metadata: {}
98
- post_install_message:
113
+ metadata:
114
+ bug_tracker_uri: https://github.com/resque/redis-namespace/issues
115
+ changelog_uri: https://github.com/resque/redis-namespace/blob/master/CHANGELOG.md
116
+ documentation_uri: https://www.rubydoc.info/gems/redis-namespace/1.10.0
117
+ rubygems_mfa_required: 'true'
118
+ post_install_message:
99
119
  rdoc_options: []
100
120
  require_paths:
101
121
  - lib
102
122
  required_ruby_version: !ruby/object:Gem::Requirement
103
123
  requirements:
104
- - - "~>"
124
+ - - ">="
105
125
  - !ruby/object:Gem::Version
106
126
  version: '2.4'
107
127
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -110,8 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
130
  - !ruby/object:Gem::Version
111
131
  version: '0'
112
132
  requirements: []
113
- rubygems_version: 3.0.3
114
- signing_key:
133
+ rubygems_version: 3.3.15
134
+ signing_key:
115
135
  specification_version: 4
116
136
  summary: Namespaces Redis commands.
117
137
  test_files: []