redis-namespace 1.7.0 → 1.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ebbb9000d7b34a0a8386ac9d72e2f63f4573720b22a8eb7e3676c0c1759200b
4
- data.tar.gz: ec5c495b22e58cc98d4c759f7873f2d2f9f69c8205b750062207b6f4b1f45897
3
+ metadata.gz: e003f4015162bfd465e79dd90e54b44ae46f0ec269118e10c08215d639166296
4
+ data.tar.gz: 16078b51e1bdab24977aa2b6fb7d0cd4761a7c41c340fcdacfb96dd32216c061
5
5
  SHA512:
6
- metadata.gz: e05aa113c14df634a64fdfad7891781ace6a5060a533e9417f94476235f3e05fd33859c4653fcbe8f417582e9257cdf20b1599ac1b2e4cbe38ccaf7c88af2dba
7
- data.tar.gz: 220e3ec476e5613dd3a8529f2f7b30f7aba9433a1f4ab4402c55be555ef00ff5651738824ddc583e83e7cbad9297d1f1a107bd61e4b44df5e8c9efa50589cfea
6
+ metadata.gz: fb965b575fe3ec2f2f45b99a71839f569f647681939b16576c053ab3e25bf85db1db030941bbe6eaeecc624eeeaf8c0497c58c53c4231440896e9e116bc189e3
7
+ data.tar.gz: 07b2b2e20c4a152b3e3a4cfbf6abad773f335e098067a9b213e29dd80cfc4519f3d27c43febe6cf8261ffe95e73184e23a1b9ff557007eb7a8308e43a398bbb1
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.11.0'
6
6
  end
7
7
  end
@@ -68,12 +68,15 @@ 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 ],
75
+ "expiretime" => [ :first ],
74
76
  "eval" => [ :eval_style ],
75
77
  "evalsha" => [ :eval_style ],
76
78
  "get" => [ :first ],
79
+ "getex" => [ :first ],
77
80
  "getbit" => [ :first ],
78
81
  "getrange" => [ :first ],
79
82
  "getset" => [ :first ],
@@ -120,6 +123,7 @@ class Redis
120
123
  "persist" => [ :first ],
121
124
  "pexpire" => [ :first ],
122
125
  "pexpireat" => [ :first ],
126
+ "pexpiretime" => [ :first ],
123
127
  "pfadd" => [ :first ],
124
128
  "pfcount" => [ :all ],
125
129
  "pfmerge" => [ :all ],
@@ -136,6 +140,7 @@ class Redis
136
140
  "rpush" => [ :first ],
137
141
  "rpushx" => [ :first ],
138
142
  "sadd" => [ :first ],
143
+ "sadd?" => [ :first ],
139
144
  "scard" => [ :first ],
140
145
  "scan" => [ :scan_style, :second ],
141
146
  "scan_each" => [ :scan_style, :all ],
@@ -150,11 +155,13 @@ class Redis
150
155
  "sinterstore" => [ :all ],
151
156
  "sismember" => [ :first ],
152
157
  "smembers" => [ :first ],
158
+ "smismember" => [ :first ],
153
159
  "smove" => [ :exclude_last ],
154
160
  "sort" => [ :sort ],
155
161
  "spop" => [ :first ],
156
162
  "srandmember" => [ :first ],
157
163
  "srem" => [ :first ],
164
+ "srem?" => [ :first ],
158
165
  "sscan" => [ :first ],
159
166
  "sscan_each" => [ :first ],
160
167
  "strlen" => [ :first ],
@@ -199,6 +206,7 @@ class Redis
199
206
  HELPER_COMMANDS = {
200
207
  "auth" => [],
201
208
  "disconnect!" => [],
209
+ "close" => [],
202
210
  "echo" => [],
203
211
  "ping" => [],
204
212
  "time" => [],
@@ -235,13 +243,23 @@ class Redis
235
243
  # Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
236
244
  Enumerator = Enumerable::Enumerator unless defined?(::Enumerator)
237
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
+
238
256
  attr_writer :namespace
239
257
  attr_reader :redis
240
258
  attr_accessor :warning
241
259
 
242
260
  def initialize(namespace, options = {})
243
261
  @namespace = namespace
244
- @redis = options[:redis] || Redis.current
262
+ @redis = options[:redis] || Redis.new
245
263
  @warning = !!options.fetch(:warning) do
246
264
  !ENV['REDIS_NAMESPACE_QUIET']
247
265
  end
@@ -260,7 +278,7 @@ class Redis
260
278
  end
261
279
 
262
280
  def client
263
- warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client" +
281
+ warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
264
282
  "method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
265
283
  _client
266
284
  end
@@ -306,7 +324,7 @@ class Redis
306
324
  :redis => @redis)
307
325
  end
308
326
 
309
- @namespace
327
+ @namespace.respond_to?(:call) ? @namespace.call : @namespace
310
328
  end
311
329
 
312
330
  def full_namespace
@@ -314,7 +332,7 @@ class Redis
314
332
  end
315
333
 
316
334
  def connection
317
- @redis.connection.tap { |info| info[:namespace] = @namespace }
335
+ @redis.connection.tap { |info| info[:namespace] = namespace }
318
336
  end
319
337
 
320
338
  def exec
@@ -324,6 +342,33 @@ class Redis
324
342
  def eval(*args)
325
343
  call_with_namespace(:eval, *args)
326
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
356
+
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
327
372
 
328
373
  ADMINISTRATIVE_COMMANDS.keys.each do |command|
329
374
  define_method(command) do |*args, &block|
@@ -339,6 +384,7 @@ class Redis
339
384
  end
340
385
  call_with_namespace(command, *args, &block)
341
386
  end
387
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
342
388
  end
343
389
 
344
390
  COMMANDS.keys.each do |command|
@@ -348,6 +394,7 @@ class Redis
348
394
  define_method(command) do |*args, &block|
349
395
  call_with_namespace(command, *args, &block)
350
396
  end
397
+ ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
351
398
  end
352
399
 
353
400
  def method_missing(command, *args, &block)
@@ -365,15 +412,17 @@ class Redis
365
412
  "passthrough has been deprecated and will be removed in " +
366
413
  "redis-namespace 2.0 (at #{call_site})")
367
414
  end
368
- @redis.send(command, *args, &block)
415
+
416
+ wrapped_send(@redis, command, args, &block)
369
417
  else
370
418
  super
371
419
  end
372
420
  end
421
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
373
422
 
374
423
  def inspect
375
424
  "<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
376
- "for #{@redis.id}/#{@namespace}>"
425
+ "for #{@redis.id}/#{full_namespace}>"
377
426
  end
378
427
 
379
428
  def respond_to_missing?(command, include_all=false)
@@ -405,6 +454,7 @@ class Redis
405
454
  case before
406
455
  when :first
407
456
  args[0] = add_namespace(args[0]) if args[0]
457
+ args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
408
458
  when :all
409
459
  args = add_namespace(args)
410
460
  when :exclude_first
@@ -417,13 +467,14 @@ class Redis
417
467
  args.push(last) if last
418
468
  when :exclude_options
419
469
  if args.last.is_a?(Hash)
420
- last = args.pop
470
+ last = ruby2_keywords_hash(args.pop)
421
471
  args = add_namespace(args)
422
472
  args.push(last)
423
473
  else
424
474
  args = add_namespace(args)
425
475
  end
426
476
  when :alternate
477
+ args = args.flatten
427
478
  args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
428
479
  when :sort
429
480
  args[0] = add_namespace(args[0]) if args[0]
@@ -437,6 +488,7 @@ class Redis
437
488
  args[1][:get].each_index do |i|
438
489
  args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
439
490
  end
491
+ args[1] = ruby2_keywords_hash(args[1])
440
492
  end
441
493
  when :eval_style
442
494
  # redis.eval() and evalsha() can either take the form:
@@ -457,7 +509,7 @@ class Redis
457
509
  when :scan_style
458
510
  options = (args.last.kind_of?(Hash) ? args.pop : {})
459
511
  options[:match] = add_namespace(options.fetch(:match, '*'))
460
- args << options
512
+ args << ruby2_keywords_hash(options)
461
513
 
462
514
  if block
463
515
  original_block = block
@@ -466,7 +518,7 @@ class Redis
466
518
  end
467
519
 
468
520
  # Dispatch the command to Redis and store the result.
469
- result = @redis.send(command, *args, &block)
521
+ result = wrapped_send(@redis, command, args, &block)
470
522
 
471
523
  # Don't try to remove namespace from a Redis::Future, you can't.
472
524
  return result if result.is_a?(Redis::Future)
@@ -483,9 +535,36 @@ class Redis
483
535
 
484
536
  result
485
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
486
545
 
487
546
  private
488
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
+
489
568
  # Avoid modifying the caller's (pass-by-reference) arguments.
490
569
  def clone_args(arg)
491
570
  if arg.is_a?(Array)
@@ -502,18 +581,16 @@ class Redis
502
581
  end
503
582
 
504
583
  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
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)
512
589
  end
513
590
  end
514
591
 
515
592
  def add_namespace(key)
516
- return key unless key && @namespace
593
+ return key unless key && namespace
517
594
 
518
595
  case key
519
596
  when Array
@@ -522,12 +599,12 @@ class Redis
522
599
  key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
523
600
  key
524
601
  else
525
- "#{@namespace}:#{key}"
602
+ "#{namespace}:#{key}"
526
603
  end
527
604
  end
528
605
 
529
606
  def rem_namespace(key)
530
- return key unless key && @namespace
607
+ return key unless key && namespace
531
608
 
532
609
  case key
533
610
  when Array
@@ -539,7 +616,7 @@ class Redis
539
616
  key.each { |k| yielder.yield rem_namespace(k) }
540
617
  end
541
618
  else
542
- key.to_s.sub(/\A#{@namespace}:/, '')
619
+ key.to_s.sub(/\A#{namespace}:/, '')
543
620
  end
544
621
  end
545
622
 
@@ -554,5 +631,10 @@ class Redis
554
631
  Enumerator.new(&block)
555
632
  end
556
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
557
639
  end
558
640
  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,17 @@ 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
+
366
+ it "should remove members" do
367
+ @namespaced.sadd('foo', 1)
368
+ expect(@namespaced.srem?('foo', 1)).to eq(true)
369
+ expect(@namespaced.srem?('foo', 1)).to eq(false)
370
+ end
371
+
316
372
  it "should add namespace to sort" do
317
373
  @namespaced.sadd('foo', 1)
318
374
  @namespaced.sadd('foo', 2)
@@ -350,6 +406,26 @@ describe "redis" do
350
406
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
351
407
  end
352
408
 
409
+ it "should utilize connection_pool while adding namepsace to multi blocks" do
410
+ memo = @namespaced
411
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
412
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
413
+
414
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
415
+ expect(arg).to be(an_instance_of(Redis))
416
+ end.at_least(:once)
417
+
418
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
419
+ @namespaced.multi do |r|
420
+ r.del "foo"
421
+ r.mapped_hmset "foo", {"key1" => "value1"}
422
+ end
423
+ expect(@redis.get("foo")).to eq("bar")
424
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
425
+
426
+ @namespaced = memo
427
+ end
428
+
353
429
  it "should pass through multi commands without block" do
354
430
  @namespaced.mapped_hmset "foo", {"key" => "value"}
355
431
 
@@ -361,6 +437,28 @@ describe "redis" do
361
437
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
362
438
  end
363
439
 
440
+ it "should utilize connection_pool while passing through multi commands without block" do
441
+ memo = @namespaced
442
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
443
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
444
+
445
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
446
+ expect(arg).to be(an_instance_of(Redis))
447
+ end.at_least(:once)
448
+
449
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
450
+
451
+ @namespaced.multi
452
+ @namespaced.del "foo"
453
+ @namespaced.mapped_hmset "foo", {"key1" => "value1"}
454
+ @namespaced.exec
455
+
456
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
457
+ expect(@redis.get("foo")).to eq("bar")
458
+
459
+ @namespaced = memo
460
+ end
461
+
364
462
  it 'should return futures without attempting to remove namespaces' do
365
463
  @namespaced.multi do
366
464
  @future = @namespaced.keys('*')
@@ -377,6 +475,26 @@ describe "redis" do
377
475
  expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
378
476
  end
379
477
 
478
+ it "should utilize connection_pool while adding namespace to pipelined blocks" do
479
+ memo = @namespaced
480
+ connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
481
+ @namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
482
+
483
+ expect(connection_pool).to receive(:with).and_call_original do |arg|
484
+ expect(arg).to be(an_instance_of(Redis))
485
+ end.at_least(:once)
486
+
487
+ @namespaced.mapped_hmset "foo", {"key" => "value"}
488
+ @namespaced.pipelined do |r|
489
+ r.del "foo"
490
+ r.mapped_hmset "foo", {"key1" => "value1"}
491
+ end
492
+ expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
493
+ expect(@redis.get("foo")).to eq("bar")
494
+
495
+ @namespaced = memo
496
+ end
497
+
380
498
  it "should returned response array from pipelined block" do
381
499
  @namespaced.mset "foo", "bar", "key", "value"
382
500
  result = @namespaced.pipelined do |r|
@@ -386,6 +504,27 @@ describe "redis" do
386
504
  expect(result).to eq(["bar", "value"])
387
505
  end
388
506
 
507
+ it "is thread safe for multi blocks" do
508
+ mon = Monitor.new
509
+ entered = false
510
+ entered_cond = mon.new_cond
511
+
512
+ thread = Thread.new do
513
+ mon.synchronize do
514
+ entered_cond.wait_until { entered }
515
+ @namespaced.multi
516
+ end
517
+ end
518
+
519
+ @namespaced.multi do |transaction|
520
+ entered = true
521
+ mon.synchronize { entered_cond.signal }
522
+ thread.join(0.1)
523
+ transaction.get("foo")
524
+ end
525
+ thread.join
526
+ end
527
+
389
528
  it "should add namespace to strlen" do
390
529
  @namespaced.set("mykey", "123456")
391
530
  expect(@namespaced.strlen("mykey")).to eq(6)
@@ -442,6 +581,45 @@ describe "redis" do
442
581
  expect { @namespaced.unknown('foo') }.to raise_exception NoMethodError
443
582
  end
444
583
 
584
+ describe '#inspect' do
585
+ let(:single_level_names) { %i[first] }
586
+ let(:double_level_names) { %i[first second] }
587
+ let(:triple_level_names) { %i[first second third] }
588
+ let(:namespace_builder) do
589
+ ->(redis, *namespaces) { namespaces.reduce(redis) { |r, n| Redis::Namespace.new(n, redis: r) } }
590
+ end
591
+ let(:regexp_builder) do
592
+ ->(*namespaces) { %r{/#{namespaces.join(':')}>\z} }
593
+ end
594
+
595
+ context 'when one namespace' do
596
+ let(:single_namespaced) { namespace_builder.call(@redis, *single_level_names) }
597
+ let(:regexp) { regexp_builder.call(*single_level_names) }
598
+
599
+ it 'should have correct ending of inspect string' do
600
+ expect(regexp =~ single_namespaced.inspect).not_to be(nil)
601
+ end
602
+ end
603
+
604
+ context 'when two namespaces' do
605
+ let(:double_namespaced) { namespace_builder.call(@redis, *double_level_names) }
606
+ let(:regexp) { regexp_builder.call(*double_level_names) }
607
+
608
+ it 'should have correct ending of inspect string' do
609
+ expect(regexp =~ double_namespaced.inspect).not_to be(nil)
610
+ end
611
+ end
612
+
613
+ context 'when three namespaces' do
614
+ let(:triple_namespaced) { namespace_builder.call(@redis, *triple_level_names) }
615
+ let(:regexp) { regexp_builder.call(*triple_level_names) }
616
+
617
+ it 'should have correct ending of inspect string' do
618
+ expect(regexp =~ triple_namespaced.inspect).not_to be(nil)
619
+ end
620
+ end
621
+ end
622
+
445
623
  # Redis 2.6 RC reports its version as 2.5.
446
624
  if @redis_version >= Gem::Version.new("2.5.0")
447
625
  describe "redis 2.6 commands" do
@@ -488,6 +666,12 @@ describe "redis" do
488
666
  expect(@redis.ttl("ns:foo")).to satisfy {|v| (0..1).include?(v) }
489
667
  end
490
668
 
669
+ it "should namespace expiretime" do
670
+ @namespaced.set('mykey', 'Hello')
671
+ @namespaced.expireat('mykey', 2000000000)
672
+ expect(@namespaced.expiretime('mykey')).to eq(2000000000)
673
+ end
674
+
491
675
  it "should namespace hincrbyfloat" do
492
676
  @namespaced.hset('mykey', 'field', 10.50)
493
677
  expect(@namespaced.hincrbyfloat('mykey', 'field', 0.1)).to eq(10.6)
@@ -520,6 +704,12 @@ describe "redis" do
520
704
  expect(@namespaced.pexpire('mykey', 1555555555005)).to eq(true)
521
705
  end
522
706
 
707
+ it "should namespace pexpiretime" do
708
+ @namespaced.set('mykey', 'Hello')
709
+ @namespaced.pexpireat('mykey', 2000000000000)
710
+ expect(@namespaced.pexpiretime('mykey')).to eq(2000000000000)
711
+ end
712
+
523
713
  it "should namespace psetex" do
524
714
  expect(@namespaced.psetex('mykey', 10000, 'Hello')).to eq('OK')
525
715
  expect(@namespaced.get('mykey')).to eq('Hello')
@@ -626,7 +816,7 @@ describe "redis" do
626
816
  expect(result).to match_array(namespaced_keys)
627
817
  end
628
818
  end
629
- end if Redis.current.respond_to?(:scan)
819
+ end if Redis.new.respond_to?(:scan)
630
820
 
631
821
  context '#scan_each' do
632
822
  context 'when :match supplied' do
@@ -659,7 +849,7 @@ describe "redis" do
659
849
  end
660
850
  end
661
851
  end
662
- end if Redis.current.respond_to?(:scan_each)
852
+ end if Redis.new.respond_to?(:scan_each)
663
853
  end
664
854
 
665
855
  context 'hash scan methods' do
@@ -687,7 +877,7 @@ describe "redis" do
687
877
  expect(results).to match_array(@redis.hgetall('ns:hsh').to_a)
688
878
  end
689
879
  end
690
- end if Redis.current.respond_to?(:hscan)
880
+ end if Redis.new.respond_to?(:hscan)
691
881
 
692
882
  context '#hscan_each' do
693
883
  context 'when :match supplied' do
@@ -720,7 +910,7 @@ describe "redis" do
720
910
  end
721
911
  end
722
912
  end
723
- end if Redis.current.respond_to?(:hscan_each)
913
+ end if Redis.new.respond_to?(:hscan_each)
724
914
  end
725
915
 
726
916
  context 'set scan methods' do
@@ -748,7 +938,7 @@ describe "redis" do
748
938
  expect(results).to match_array(set)
749
939
  end
750
940
  end
751
- end if Redis.current.respond_to?(:sscan)
941
+ end if Redis.new.respond_to?(:sscan)
752
942
 
753
943
  context '#sscan_each' do
754
944
  context 'when :match supplied' do
@@ -781,7 +971,7 @@ describe "redis" do
781
971
  end
782
972
  end
783
973
  end
784
- end if Redis.current.respond_to?(:sscan_each)
974
+ end if Redis.new.respond_to?(:sscan_each)
785
975
  end
786
976
 
787
977
  context 'zset scan methods' do
@@ -811,7 +1001,7 @@ describe "redis" do
811
1001
  expect(results).to match_array(hash.to_a)
812
1002
  end
813
1003
  end
814
- end if Redis.current.respond_to?(:zscan)
1004
+ end if Redis.new.respond_to?(:zscan)
815
1005
 
816
1006
  context '#zscan_each' do
817
1007
  context 'when :match supplied' do
@@ -844,7 +1034,7 @@ describe "redis" do
844
1034
  end
845
1035
  end
846
1036
  end
847
- end if Redis.current.respond_to?(:zscan_each)
1037
+ end if Redis.new.respond_to?(:zscan_each)
848
1038
  end
849
1039
  end
850
1040
  end
@@ -881,4 +1071,30 @@ describe "redis" do
881
1071
  expect(sub_sub_namespaced.full_namespace).to eql("ns:sub1:sub2")
882
1072
  end
883
1073
  end
1074
+
1075
+ describe :clear do
1076
+ it "warns with helpful output" do
1077
+ expect { @namespaced.clear }.to output(/can run for a very long time/).to_stderr
1078
+ end
1079
+
1080
+ it "should delete all the keys" do
1081
+ @redis.set("foo", "bar")
1082
+ @namespaced.mset("foo1", "bar", "foo2", "bar")
1083
+ capture_stderr { @namespaced.clear }
1084
+
1085
+ expect(@redis.keys).to eq ["foo"]
1086
+ expect(@namespaced.keys).to be_empty
1087
+ end
1088
+
1089
+ it "should delete all the keys in older redis" do
1090
+ allow(@redis).to receive(:info).and_return({ "redis_version" => "2.7.0" })
1091
+
1092
+ @redis.set("foo", "bar")
1093
+ @namespaced.mset("foo1", "bar", "foo2", "bar")
1094
+ capture_stderr { @namespaced.clear }
1095
+
1096
+ expect(@redis.keys).to eq ["foo"]
1097
+ expect(@namespaced.keys).to be_empty
1098
+ end
1099
+ end
884
1100
  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.11.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: 2023-06-08 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.11.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.4.1
134
+ signing_key:
115
135
  specification_version: 4
116
136
  summary: Namespaces Redis commands.
117
137
  test_files: []