redis 4.1.2 → 4.2.2

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: c0b16163b5714933ba20edb9595d7669c7270502586546f3e8758192039113c1
4
- data.tar.gz: 150dacb8ae77a51536e3f2bc6813144b0176415d008adaa5d5e6c4d7f25624a1
3
+ metadata.gz: 28eb23d20152436fc47f334f517c6fa62855e8e4711b44979cb05d86f8dcdd34
4
+ data.tar.gz: 46d01b3f5539800142582aeb7ebeabe4327bce970e31ce2048dcba027dfe6eb1
5
5
  SHA512:
6
- metadata.gz: 90a9fcfdefc41f5feaedfea2bde2be1ad39308dee10f0045ec227577d067d795aaaede4aec200ed6f5777167842540ff5adb6a927fe6a0a0e5ac46ea8eeaf737
7
- data.tar.gz: 90c74c87892ef96d0d6ef2bd5934f8e3064d30064a9310fc2b1e31aba066ccb6a005d030458a35d9ad09ed403749e3356df3072927e6a749fc21caedee75f936
6
+ metadata.gz: f2f11269c6a3a030231eeb93dfa6bee54b340ff5ad244df6d79074c95f111e3d2081f49f77756576cb8225640e8b8cad144884c8519bcf1b0e7bedea3ca1b00f
7
+ data.tar.gz: 44ec06531632060b497cf1d02e6678c3d087ec3371cba86f53f9687848f73bb4e02c166b11d4db9e6b531b62ba2ca830649d71114063560f6dd764ca2ef10f07
@@ -1,8 +1,46 @@
1
1
  # Unreleased
2
2
 
3
- # 4.1.2
3
+ # 4.2.2
4
+
5
+ * Fix `WATCH` support for `Redis::Distributed`. See #941.
6
+ * Fix handling of empty stream responses. See #905, #929.
7
+
8
+ # 4.2.1
9
+
10
+ * Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
11
+ * Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
12
+
13
+ # 4.2.0
14
+
15
+ * Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
16
+ * Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
17
+ * Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
18
+ * Add `Redis#exists?` to get a Boolean if any of the keys exists.
19
+ * `Redis#exists` when called with a single key will warn that future versions will return an Integer.
20
+ Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
21
+ * Support `keepttl` ooption in `set`. See #913.
22
+ * Optimized initialization of Redis::Cluster. See #912.
23
+ * Accept sentinel options even with string key. See #599.
24
+ * Verify TLS connections by default. See #900.
25
+ * Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
26
+
27
+ # 4.1.4
28
+
29
+ * Alias `Redis#disconnect` as `#close`. See #901.
30
+ * Handle clusters with multiple slot ranges. See #894.
31
+ * Fix password authentication to a redis cluster. See #889.
32
+ * Handle recursive MOVED responses. See #882.
33
+ * Increase buffer size in the ruby connector. See #880.
34
+ * Fix thread safety of `Redis.queue`. See #878.
35
+ * Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
36
+ * Support `KEEPTTL` option for SET command. See #913.
37
+
38
+ # 4.1.3
4
39
 
5
40
  * Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
41
+
42
+ # 4.1.2
43
+
6
44
  * Fix several authentication problems with sentinel. See #850 and #856.
7
45
  * Explicitly drop Ruby 2.2 support.
8
46
 
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
- # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link]
1
+ # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link] ![](https://github.com/redis/redis-rb/workflows/Test/badge.svg?branch=master)
2
2
 
3
3
  A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
4
4
  providing an idiomatic interface.
5
5
 
6
+ See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
6
7
 
7
8
  ## Getting started
8
9
 
@@ -34,6 +35,9 @@ You can also specify connection options as a [`redis://` URL][redis-url]:
34
35
  redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
35
36
  ```
36
37
 
38
+ The client expects passwords with special chracters to be URL-encoded (i.e.
39
+ `CGI.escape(password)`).
40
+
37
41
  By default, the client will try to read the `REDIS_URL` environment variable
38
42
  and use that as URL to connect to. The above statement is therefore equivalent
39
43
  to setting this environment variable and calling `Redis.new` without arguments.
@@ -142,12 +146,13 @@ redis.mget('{key}1', '{key}2')
142
146
  ```
143
147
 
144
148
  * The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
149
+ * The client support permanent node failures, and will reroute requests to promoted slaves.
145
150
  * The client supports `MOVED` and `ASK` redirections transparently.
146
151
 
147
152
  ## Storing objects
148
153
 
149
- Redis only stores strings as values. If you want to store an object, you
150
- can use a serialization mechanism such as JSON:
154
+ Redis "string" types can be used to store serialized Ruby objects, for
155
+ example with JSON:
151
156
 
152
157
  ```ruby
153
158
  require "json"
@@ -321,7 +326,7 @@ This library supports natively terminating client side SSL/TLS connections
321
326
  when talking to Redis via a server-side proxy such as [stunnel], [hitch],
322
327
  or [ghostunnel].
323
328
 
324
- To enable SSL support, pass the `:ssl => :true` option when configuring the
329
+ To enable SSL support, pass the `:ssl => true` option when configuring the
325
330
  Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
326
331
  You will also need to pass in an `:ssl_params => { ... }` hash used to
327
332
  configure the `OpenSSL::SSL::SSLContext` object used for the connection:
@@ -436,6 +441,10 @@ redis = Redis.new(:driver => :synchrony)
436
441
  This library is tested against recent Ruby and Redis versions.
437
442
  Check [Travis][travis-link] for the exact versions supported.
438
443
 
444
+ ## See Also
445
+
446
+ - [async-redis](https://github.com/socketry/async-redis) — An [async](https://github.com/socketry/async) compatible Redis client.
447
+
439
448
  ## Contributors
440
449
 
441
450
  Several people contributed to redis-rb, but we would like to especially
@@ -446,7 +455,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
446
455
  ## Contributing
447
456
 
448
457
  [Fork the project](https://github.com/redis/redis-rb) and send pull
449
- requests. You can also ask for help at `#redis-rb` on Freenode.
458
+ requests.
450
459
 
451
460
 
452
461
  [inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
@@ -4,13 +4,26 @@ require "monitor"
4
4
  require_relative "redis/errors"
5
5
 
6
6
  class Redis
7
+ class << self
8
+ attr_reader :exists_returns_integer
7
9
 
8
- def self.current
9
- @current ||= Redis.new
10
+ def exists_returns_integer=(value)
11
+ unless value
12
+ message = "`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
13
+ "disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
14
+ "`exists?` instead."
15
+
16
+ ::Kernel.warn(message)
17
+ end
18
+
19
+ @exists_returns_integer = value
20
+ end
21
+
22
+ attr_writer :current
10
23
  end
11
24
 
12
- def self.current=(redis)
13
- @current = redis
25
+ def self.current
26
+ @current ||= Redis.new
14
27
  end
15
28
 
16
29
  include MonitorMixin
@@ -18,18 +31,22 @@ class Redis
18
31
  # Create a new client instance
19
32
  #
20
33
  # @param [Hash] options
21
- # @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection: `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket connection: `unix://[path to Redis socket]`. This overrides all other options.
34
+ # @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
35
+ # `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
36
+ # connection: `unix://[path to Redis socket]`. This overrides all other options.
22
37
  # @option options [String] :host ("127.0.0.1") server hostname
23
- # @option options [Fixnum] :port (6379) server port
38
+ # @option options [Integer] :port (6379) server port
24
39
  # @option options [String] :path path to server socket (overrides host and port)
25
40
  # @option options [Float] :timeout (5.0) timeout in seconds
26
41
  # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
27
42
  # @option options [String] :password Password to authenticate against server
28
- # @option options [Fixnum] :db (0) Database to select after initial connect
43
+ # @option options [Integer] :db (0) Database to select after initial connect
29
44
  # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
30
- # @option options [String] :id ID for the client connection, assigns name to current connection by sending `CLIENT SETNAME`
31
- # @option options [Hash, Fixnum] :tcp_keepalive Keepalive values, if Fixnum `intvl` and `probe` are calculated based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Fixnum
32
- # @option options [Fixnum] :reconnect_attempts Number of attempts trying to connect
45
+ # @option options [String] :id ID for the client connection, assigns name to current connection by sending
46
+ # `CLIENT SETNAME`
47
+ # @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
48
+ # based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
49
+ # @option options [Integer] :reconnect_attempts Number of attempts trying to connect
33
50
  # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
34
51
  # @option options [Array] :sentinels List of sentinels to contact
35
52
  # @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
@@ -53,7 +70,7 @@ class Redis
53
70
  end
54
71
 
55
72
  # Run code with the client reconnecting
56
- def with_reconnect(val=true, &blk)
73
+ def with_reconnect(val = true, &blk)
57
74
  synchronize do |client|
58
75
  client.with_reconnect(val, &blk)
59
76
  end
@@ -96,7 +113,9 @@ class Redis
96
113
  # See http://redis.io/topics/pipelining for more details.
97
114
  #
98
115
  def queue(*command)
99
- @queue[Thread.current.object_id] << command
116
+ synchronize do
117
+ @queue[Thread.current.object_id] << command
118
+ end
100
119
  end
101
120
 
102
121
  # Sends all commands in the queue.
@@ -135,7 +154,7 @@ class Redis
135
154
 
136
155
  # Change the selected database for the current connection.
137
156
  #
138
- # @param [Fixnum] db zero-based index of the DB to use (0 to 15)
157
+ # @param [Integer] db zero-based index of the DB to use (0 to 15)
139
158
  # @return [String] `OK`
140
159
  def select(db)
141
160
  synchronize do |client|
@@ -204,7 +223,7 @@ class Redis
204
223
  def config(action, *args)
205
224
  synchronize do |client|
206
225
  client.call([:config, action] + args) do |reply|
207
- if reply.kind_of?(Array) && action == :get
226
+ if reply.is_a?(Array) && action == :get
208
227
  Hashify.call(reply)
209
228
  else
210
229
  reply
@@ -234,7 +253,7 @@ class Redis
234
253
 
235
254
  # Return the number of keys in the selected database.
236
255
  #
237
- # @return [Fixnum]
256
+ # @return [Integer]
238
257
  def dbsize
239
258
  synchronize do |client|
240
259
  client.call([:dbsize])
@@ -255,7 +274,7 @@ class Redis
255
274
  def flushall(options = nil)
256
275
  synchronize do |client|
257
276
  if options && options[:async]
258
- client.call([:flushall, :async])
277
+ client.call(%i[flushall async])
259
278
  else
260
279
  client.call([:flushall])
261
280
  end
@@ -270,7 +289,7 @@ class Redis
270
289
  def flushdb(options = nil)
271
290
  synchronize do |client|
272
291
  if options && options[:async]
273
- client.call([:flushdb, :async])
292
+ client.call(%i[flushdb async])
274
293
  else
275
294
  client.call([:flushdb])
276
295
  end
@@ -284,7 +303,7 @@ class Redis
284
303
  def info(cmd = nil)
285
304
  synchronize do |client|
286
305
  client.call([:info, cmd].compact) do |reply|
287
- if reply.kind_of?(String)
306
+ if reply.is_a?(String)
288
307
  reply = HashifyInfo.call(reply)
289
308
 
290
309
  if cmd && cmd.to_s == "commandstats"
@@ -303,7 +322,7 @@ class Redis
303
322
 
304
323
  # Get the UNIX time stamp of the last successful save to disk.
305
324
  #
306
- # @return [Fixnum]
325
+ # @return [Integer]
307
326
  def lastsave
308
327
  synchronize do |client|
309
328
  client.call([:lastsave])
@@ -355,9 +374,9 @@ class Redis
355
374
  # Interact with the slowlog (get, len, reset)
356
375
  #
357
376
  # @param [String] subcommand e.g. `get`, `len`, `reset`
358
- # @param [Fixnum] length maximum number of entries to return
359
- # @return [Array<String>, Fixnum, String] depends on subcommand
360
- def slowlog(subcommand, length=nil)
377
+ # @param [Integer] length maximum number of entries to return
378
+ # @return [Array<String>, Integer, String] depends on subcommand
379
+ def slowlog(subcommand, length = nil)
361
380
  synchronize do |client|
362
381
  args = [:slowlog, subcommand]
363
382
  args << length if length
@@ -377,12 +396,12 @@ class Redis
377
396
  # @example
378
397
  # r.time # => [ 1333093196, 606806 ]
379
398
  #
380
- # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
399
+ # @return [Array<Integer>] tuple of seconds since UNIX epoch and
381
400
  # microseconds in the current second
382
401
  def time
383
402
  synchronize do |client|
384
403
  client.call([:time]) do |reply|
385
- reply.map(&:to_i) if reply
404
+ reply&.map(&:to_i)
386
405
  end
387
406
  end
388
407
  end
@@ -400,7 +419,7 @@ class Redis
400
419
  # Set a key's time to live in seconds.
401
420
  #
402
421
  # @param [String] key
403
- # @param [Fixnum] seconds time to live
422
+ # @param [Integer] seconds time to live
404
423
  # @return [Boolean] whether the timeout was set or not
405
424
  def expire(key, seconds)
406
425
  synchronize do |client|
@@ -411,7 +430,7 @@ class Redis
411
430
  # Set the expiration for a key as a UNIX timestamp.
412
431
  #
413
432
  # @param [String] key
414
- # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
433
+ # @param [Integer] unix_time expiry time specified as a UNIX timestamp
415
434
  # @return [Boolean] whether the timeout was set or not
416
435
  def expireat(key, unix_time)
417
436
  synchronize do |client|
@@ -422,7 +441,7 @@ class Redis
422
441
  # Get the time to live (in seconds) for a key.
423
442
  #
424
443
  # @param [String] key
425
- # @return [Fixnum] remaining time to live in seconds.
444
+ # @return [Integer] remaining time to live in seconds.
426
445
  #
427
446
  # In Redis 2.6 or older the command returns -1 if the key does not exist or if
428
447
  # the key exist but has no associated expire.
@@ -440,7 +459,7 @@ class Redis
440
459
  # Set a key's time to live in milliseconds.
441
460
  #
442
461
  # @param [String] key
443
- # @param [Fixnum] milliseconds time to live
462
+ # @param [Integer] milliseconds time to live
444
463
  # @return [Boolean] whether the timeout was set or not
445
464
  def pexpire(key, milliseconds)
446
465
  synchronize do |client|
@@ -451,7 +470,7 @@ class Redis
451
470
  # Set the expiration for a key as number of milliseconds from UNIX Epoch.
452
471
  #
453
472
  # @param [String] key
454
- # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
473
+ # @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
455
474
  # @return [Boolean] whether the timeout was set or not
456
475
  def pexpireat(key, ms_unix_time)
457
476
  synchronize do |client|
@@ -462,7 +481,7 @@ class Redis
462
481
  # Get the time to live (in milliseconds) for a key.
463
482
  #
464
483
  # @param [String] key
465
- # @return [Fixnum] remaining time to live in milliseconds
484
+ # @return [Integer] remaining time to live in milliseconds
466
485
  # In Redis 2.6 or older the command returns -1 if the key does not exist or if
467
486
  # the key exist but has no associated expire.
468
487
  #
@@ -495,9 +514,9 @@ class Redis
495
514
  # - `:replace => Boolean`: if false, raises an error if key already exists
496
515
  # @raise [Redis::CommandError]
497
516
  # @return [String] `"OK"`
498
- def restore(key, ttl, serialized_value, options = {})
517
+ def restore(key, ttl, serialized_value, replace: nil)
499
518
  args = [:restore, key, ttl, serialized_value]
500
- args << 'REPLACE' if options[:replace]
519
+ args << 'REPLACE' if replace
501
520
 
502
521
  synchronize do |client|
503
522
  client.call(args)
@@ -532,7 +551,7 @@ class Redis
532
551
  # Delete one or more keys.
533
552
  #
534
553
  # @param [String, Array<String>] keys
535
- # @return [Fixnum] number of keys that were deleted
554
+ # @return [Integer] number of keys that were deleted
536
555
  def del(*keys)
537
556
  synchronize do |client|
538
557
  client.call([:del] + keys)
@@ -542,20 +561,50 @@ class Redis
542
561
  # Unlink one or more keys.
543
562
  #
544
563
  # @param [String, Array<String>] keys
545
- # @return [Fixnum] number of keys that were unlinked
564
+ # @return [Integer] number of keys that were unlinked
546
565
  def unlink(*keys)
547
566
  synchronize do |client|
548
567
  client.call([:unlink] + keys)
549
568
  end
550
569
  end
551
570
 
552
- # Determine if a key exists.
571
+ # Determine how many of the keys exists.
553
572
  #
554
- # @param [String] key
573
+ # @param [String, Array<String>] keys
574
+ # @return [Integer]
575
+ def exists(*keys)
576
+ if !Redis.exists_returns_integer && keys.size == 1
577
+ if Redis.exists_returns_integer.nil?
578
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
579
+ "should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
580
+ "true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
581
+ "`Redis.exists_returns_integer = false`, but this option will be removed in 5.0. " \
582
+ "(#{::Kernel.caller(1, 1).first})\n"
583
+
584
+ ::Kernel.warn(message)
585
+ end
586
+
587
+ exists?(*keys)
588
+ else
589
+ _exists(*keys)
590
+ end
591
+ end
592
+
593
+ def _exists(*keys)
594
+ synchronize do |client|
595
+ client.call([:exists, *keys])
596
+ end
597
+ end
598
+
599
+ # Determine if any of the keys exists.
600
+ #
601
+ # @param [String, Array<String>] keys
555
602
  # @return [Boolean]
556
- def exists(key)
603
+ def exists?(*keys)
557
604
  synchronize do |client|
558
- client.call([:exists, key], &Boolify)
605
+ client.call([:exists, *keys]) do |value|
606
+ value > 0
607
+ end
559
608
  end
560
609
  end
561
610
 
@@ -566,7 +615,7 @@ class Redis
566
615
  def keys(pattern = "*")
567
616
  synchronize do |client|
568
617
  client.call([:keys, pattern]) do |reply|
569
- if reply.kind_of?(String)
618
+ if reply.is_a?(String)
570
619
  reply.split(" ")
571
620
  else
572
621
  reply
@@ -592,7 +641,7 @@ class Redis
592
641
  # # => "bar"
593
642
  #
594
643
  # @param [String] key
595
- # @param [Fixnum] db
644
+ # @param [Integer] db
596
645
  # @return [Boolean] whether the key was moved or not
597
646
  def move(key, db)
598
647
  synchronize do |client|
@@ -656,36 +705,33 @@ class Redis
656
705
  # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
657
706
  # - `:store => String`: key to store the result at
658
707
  #
659
- # @return [Array<String>, Array<Array<String>>, Fixnum]
708
+ # @return [Array<String>, Array<Array<String>>, Integer]
660
709
  # - when `:get` is not specified, or holds a single element, an array of elements
661
710
  # - when `:get` is specified, and holds more than one element, an array of
662
711
  # elements where every element is an array with the result for every
663
712
  # element specified in `:get`
664
713
  # - when `:store` is specified, the number of elements in the stored result
665
- def sort(key, options = {})
666
- args = []
667
-
668
- by = options[:by]
669
- args.concat(["BY", by]) if by
714
+ def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
715
+ args = [:sort, key]
716
+ args << "BY" << by if by
670
717
 
671
- limit = options[:limit]
672
- args.concat(["LIMIT"] + limit) if limit
718
+ if limit
719
+ args << "LIMIT"
720
+ args.concat(limit)
721
+ end
673
722
 
674
- get = Array(options[:get])
675
- args.concat(["GET"].product(get).flatten) unless get.empty?
723
+ get = Array(get)
724
+ get.each do |item|
725
+ args << "GET" << item
726
+ end
676
727
 
677
- order = options[:order]
678
728
  args.concat(order.split(" ")) if order
679
-
680
- store = options[:store]
681
- args.concat(["STORE", store]) if store
729
+ args << "STORE" << store if store
682
730
 
683
731
  synchronize do |client|
684
- client.call([:sort, key] + args) do |reply|
732
+ client.call(args) do |reply|
685
733
  if get.size > 1 && !store
686
- if reply
687
- reply.each_slice(get.size).to_a
688
- end
734
+ reply.each_slice(get.size).to_a if reply
689
735
  else
690
736
  reply
691
737
  end
@@ -710,7 +756,7 @@ class Redis
710
756
  # # => 4
711
757
  #
712
758
  # @param [String] key
713
- # @return [Fixnum] value after decrementing it
759
+ # @return [Integer] value after decrementing it
714
760
  def decr(key)
715
761
  synchronize do |client|
716
762
  client.call([:decr, key])
@@ -724,8 +770,8 @@ class Redis
724
770
  # # => 0
725
771
  #
726
772
  # @param [String] key
727
- # @param [Fixnum] decrement
728
- # @return [Fixnum] value after decrementing it
773
+ # @param [Integer] decrement
774
+ # @return [Integer] value after decrementing it
729
775
  def decrby(key, decrement)
730
776
  synchronize do |client|
731
777
  client.call([:decrby, key, decrement])
@@ -739,7 +785,7 @@ class Redis
739
785
  # # => 6
740
786
  #
741
787
  # @param [String] key
742
- # @return [Fixnum] value after incrementing it
788
+ # @return [Integer] value after incrementing it
743
789
  def incr(key)
744
790
  synchronize do |client|
745
791
  client.call([:incr, key])
@@ -753,8 +799,8 @@ class Redis
753
799
  # # => 10
754
800
  #
755
801
  # @param [String] key
756
- # @param [Fixnum] increment
757
- # @return [Fixnum] value after incrementing it
802
+ # @param [Integer] increment
803
+ # @return [Integer] value after incrementing it
758
804
  def incrby(key, increment)
759
805
  synchronize do |client|
760
806
  client.call([:incrby, key, increment])
@@ -781,31 +827,25 @@ class Redis
781
827
  # @param [String] key
782
828
  # @param [String] value
783
829
  # @param [Hash] options
784
- # - `:ex => Fixnum`: Set the specified expire time, in seconds.
785
- # - `:px => Fixnum`: Set the specified expire time, in milliseconds.
830
+ # - `:ex => Integer`: Set the specified expire time, in seconds.
831
+ # - `:px => Integer`: Set the specified expire time, in milliseconds.
786
832
  # - `:nx => true`: Only set the key if it does not already exist.
787
833
  # - `:xx => true`: Only set the key if it already exist.
834
+ # - `:keepttl => true`: Retain the time to live associated with the key.
788
835
  # @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
789
- def set(key, value, options = {})
790
- args = []
791
-
792
- ex = options[:ex]
793
- args.concat(["EX", ex]) if ex
794
-
795
- px = options[:px]
796
- args.concat(["PX", px]) if px
797
-
798
- nx = options[:nx]
799
- args.concat(["NX"]) if nx
800
-
801
- xx = options[:xx]
802
- args.concat(["XX"]) if xx
836
+ def set(key, value, ex: nil, px: nil, nx: nil, xx: nil, keepttl: nil)
837
+ args = [:set, key, value.to_s]
838
+ args << "EX" << ex if ex
839
+ args << "PX" << px if px
840
+ args << "NX" if nx
841
+ args << "XX" if xx
842
+ args << "KEEPTTL" if keepttl
803
843
 
804
844
  synchronize do |client|
805
845
  if nx || xx
806
- client.call([:set, key, value.to_s] + args, &BoolifySet)
846
+ client.call(args, &BoolifySet)
807
847
  else
808
- client.call([:set, key, value.to_s] + args)
848
+ client.call(args)
809
849
  end
810
850
  end
811
851
  end
@@ -813,7 +853,7 @@ class Redis
813
853
  # Set the time to live in seconds of a key.
814
854
  #
815
855
  # @param [String] key
816
- # @param [Fixnum] ttl
856
+ # @param [Integer] ttl
817
857
  # @param [String] value
818
858
  # @return [String] `"OK"`
819
859
  def setex(key, ttl, value)
@@ -825,7 +865,7 @@ class Redis
825
865
  # Set the time to live in milliseconds of a key.
826
866
  #
827
867
  # @param [String] key
828
- # @param [Fixnum] ttl
868
+ # @param [Integer] ttl
829
869
  # @param [String] value
830
870
  # @return [String] `"OK"`
831
871
  def psetex(key, ttl, value)
@@ -887,7 +927,7 @@ class Redis
887
927
  # @see #mapped_msetnx
888
928
  def msetnx(*args)
889
929
  synchronize do |client|
890
- client.call([:msetnx] + args, &Boolify)
930
+ client.call([:msetnx, *args], &Boolify)
891
931
  end
892
932
  end
893
933
 
@@ -918,7 +958,7 @@ class Redis
918
958
  # Get the values of all the given keys.
919
959
  #
920
960
  # @example
921
- # redis.mget("key1", "key1")
961
+ # redis.mget("key1", "key2")
922
962
  # # => ["v1", "v2"]
923
963
  #
924
964
  # @param [Array<String>] keys
@@ -927,7 +967,7 @@ class Redis
927
967
  # @see #mapped_mget
928
968
  def mget(*keys, &blk)
929
969
  synchronize do |client|
930
- client.call([:mget] + keys, &blk)
970
+ client.call([:mget, *keys], &blk)
931
971
  end
932
972
  end
933
973
 
@@ -943,7 +983,7 @@ class Redis
943
983
  # @see #mget
944
984
  def mapped_mget(*keys)
945
985
  mget(*keys) do |reply|
946
- if reply.kind_of?(Array)
986
+ if reply.is_a?(Array)
947
987
  Hash[keys.zip(reply)]
948
988
  else
949
989
  reply
@@ -954,9 +994,9 @@ class Redis
954
994
  # Overwrite part of a string at key starting at the specified offset.
955
995
  #
956
996
  # @param [String] key
957
- # @param [Fixnum] offset byte offset
997
+ # @param [Integer] offset byte offset
958
998
  # @param [String] value
959
- # @return [Fixnum] length of the string after it was modified
999
+ # @return [Integer] length of the string after it was modified
960
1000
  def setrange(key, offset, value)
961
1001
  synchronize do |client|
962
1002
  client.call([:setrange, key, offset, value.to_s])
@@ -966,10 +1006,10 @@ class Redis
966
1006
  # Get a substring of the string stored at a key.
967
1007
  #
968
1008
  # @param [String] key
969
- # @param [Fixnum] start zero-based start offset
970
- # @param [Fixnum] stop zero-based end offset. Use -1 for representing
1009
+ # @param [Integer] start zero-based start offset
1010
+ # @param [Integer] stop zero-based end offset. Use -1 for representing
971
1011
  # the end of the string
972
- # @return [Fixnum] `0` or `1`
1012
+ # @return [Integer] `0` or `1`
973
1013
  def getrange(key, start, stop)
974
1014
  synchronize do |client|
975
1015
  client.call([:getrange, key, start, stop])
@@ -979,9 +1019,9 @@ class Redis
979
1019
  # Sets or clears the bit at offset in the string value stored at key.
980
1020
  #
981
1021
  # @param [String] key
982
- # @param [Fixnum] offset bit offset
983
- # @param [Fixnum] value bit value `0` or `1`
984
- # @return [Fixnum] the original bit value stored at `offset`
1022
+ # @param [Integer] offset bit offset
1023
+ # @param [Integer] value bit value `0` or `1`
1024
+ # @return [Integer] the original bit value stored at `offset`
985
1025
  def setbit(key, offset, value)
986
1026
  synchronize do |client|
987
1027
  client.call([:setbit, key, offset, value])
@@ -991,8 +1031,8 @@ class Redis
991
1031
  # Returns the bit value at offset in the string value stored at key.
992
1032
  #
993
1033
  # @param [String] key
994
- # @param [Fixnum] offset bit offset
995
- # @return [Fixnum] `0` or `1`
1034
+ # @param [Integer] offset bit offset
1035
+ # @return [Integer] `0` or `1`
996
1036
  def getbit(key, offset)
997
1037
  synchronize do |client|
998
1038
  client.call([:getbit, key, offset])
@@ -1003,7 +1043,7 @@ class Redis
1003
1043
  #
1004
1044
  # @param [String] key
1005
1045
  # @param [String] value value to append
1006
- # @return [Fixnum] length of the string after appending
1046
+ # @return [Integer] length of the string after appending
1007
1047
  def append(key, value)
1008
1048
  synchronize do |client|
1009
1049
  client.call([:append, key, value])
@@ -1013,9 +1053,9 @@ class Redis
1013
1053
  # Count the number of set bits in a range of the string value stored at key.
1014
1054
  #
1015
1055
  # @param [String] key
1016
- # @param [Fixnum] start start index
1017
- # @param [Fixnum] stop stop index
1018
- # @return [Fixnum] the number of bits set to 1
1056
+ # @param [Integer] start start index
1057
+ # @param [Integer] stop stop index
1058
+ # @return [Integer] the number of bits set to 1
1019
1059
  def bitcount(key, start = 0, stop = -1)
1020
1060
  synchronize do |client|
1021
1061
  client.call([:bitcount, key, start, stop])
@@ -1027,25 +1067,23 @@ class Redis
1027
1067
  # @param [String] operation e.g. `and`, `or`, `xor`, `not`
1028
1068
  # @param [String] destkey destination key
1029
1069
  # @param [String, Array<String>] keys one or more source keys to perform `operation`
1030
- # @return [Fixnum] the length of the string stored in `destkey`
1070
+ # @return [Integer] the length of the string stored in `destkey`
1031
1071
  def bitop(operation, destkey, *keys)
1032
1072
  synchronize do |client|
1033
- client.call([:bitop, operation, destkey] + keys)
1073
+ client.call([:bitop, operation, destkey, *keys])
1034
1074
  end
1035
1075
  end
1036
1076
 
1037
1077
  # Return the position of the first bit set to 1 or 0 in a string.
1038
1078
  #
1039
1079
  # @param [String] key
1040
- # @param [Fixnum] bit whether to look for the first 1 or 0 bit
1041
- # @param [Fixnum] start start index
1042
- # @param [Fixnum] stop stop index
1043
- # @return [Fixnum] the position of the first 1/0 bit.
1080
+ # @param [Integer] bit whether to look for the first 1 or 0 bit
1081
+ # @param [Integer] start start index
1082
+ # @param [Integer] stop stop index
1083
+ # @return [Integer] the position of the first 1/0 bit.
1044
1084
  # -1 if looking for 1 and it is not found or start and stop are given.
1045
- def bitpos(key, bit, start=nil, stop=nil)
1046
- if stop and not start
1047
- raise(ArgumentError, 'stop parameter specified without start parameter')
1048
- end
1085
+ def bitpos(key, bit, start = nil, stop = nil)
1086
+ raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
1049
1087
 
1050
1088
  synchronize do |client|
1051
1089
  command = [:bitpos, key, bit]
@@ -1070,7 +1108,7 @@ class Redis
1070
1108
  # Get the length of the value stored in a key.
1071
1109
  #
1072
1110
  # @param [String] key
1073
- # @return [Fixnum] the length of the value stored in the key, or 0
1111
+ # @return [Integer] the length of the value stored in the key, or 0
1074
1112
  # if the key does not exist
1075
1113
  def strlen(key)
1076
1114
  synchronize do |client|
@@ -1081,7 +1119,7 @@ class Redis
1081
1119
  # Get the length of a list.
1082
1120
  #
1083
1121
  # @param [String] key
1084
- # @return [Fixnum]
1122
+ # @return [Integer]
1085
1123
  def llen(key)
1086
1124
  synchronize do |client|
1087
1125
  client.call([:llen, key])
@@ -1092,7 +1130,7 @@ class Redis
1092
1130
  #
1093
1131
  # @param [String] key
1094
1132
  # @param [String, Array<String>] value string value, or array of string values to push
1095
- # @return [Fixnum] the length of the list after the push operation
1133
+ # @return [Integer] the length of the list after the push operation
1096
1134
  def lpush(key, value)
1097
1135
  synchronize do |client|
1098
1136
  client.call([:lpush, key, value])
@@ -1103,7 +1141,7 @@ class Redis
1103
1141
  #
1104
1142
  # @param [String] key
1105
1143
  # @param [String] value
1106
- # @return [Fixnum] the length of the list after the push operation
1144
+ # @return [Integer] the length of the list after the push operation
1107
1145
  def lpushx(key, value)
1108
1146
  synchronize do |client|
1109
1147
  client.call([:lpushx, key, value])
@@ -1114,7 +1152,7 @@ class Redis
1114
1152
  #
1115
1153
  # @param [String] key
1116
1154
  # @param [String, Array<String>] value string value, or array of string values to push
1117
- # @return [Fixnum] the length of the list after the push operation
1155
+ # @return [Integer] the length of the list after the push operation
1118
1156
  def rpush(key, value)
1119
1157
  synchronize do |client|
1120
1158
  client.call([:rpush, key, value])
@@ -1125,7 +1163,7 @@ class Redis
1125
1163
  #
1126
1164
  # @param [String] key
1127
1165
  # @param [String] value
1128
- # @return [Fixnum] the length of the list after the push operation
1166
+ # @return [Integer] the length of the list after the push operation
1129
1167
  def rpushx(key, value)
1130
1168
  synchronize do |client|
1131
1169
  client.call([:rpushx, key, value])
@@ -1164,21 +1202,21 @@ class Redis
1164
1202
  end
1165
1203
 
1166
1204
  def _bpop(cmd, args, &blk)
1167
- options = {}
1168
-
1169
- if args.last.is_a?(Hash)
1205
+ timeout = if args.last.is_a?(Hash)
1170
1206
  options = args.pop
1207
+ options[:timeout]
1171
1208
  elsif args.last.respond_to?(:to_int)
1172
1209
  # Issue deprecation notice in obnoxious mode...
1173
- options[:timeout] = args.pop.to_int
1210
+ args.pop.to_int
1174
1211
  end
1175
1212
 
1213
+ timeout ||= 0
1214
+
1176
1215
  if args.size > 1
1177
1216
  # Issue deprecation notice in obnoxious mode...
1178
1217
  end
1179
1218
 
1180
1219
  keys = args.flatten
1181
- timeout = options[:timeout] || 0
1182
1220
 
1183
1221
  synchronize do |client|
1184
1222
  command = [cmd, keys, timeout]
@@ -1203,7 +1241,7 @@ class Redis
1203
1241
  # @param [String, Array<String>] keys one or more keys to perform the
1204
1242
  # blocking pop on
1205
1243
  # @param [Hash] options
1206
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1244
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1207
1245
  #
1208
1246
  # @return [nil, [String, String]]
1209
1247
  # - `nil` when the operation timed out
@@ -1217,7 +1255,7 @@ class Redis
1217
1255
  # @param [String, Array<String>] keys one or more keys to perform the
1218
1256
  # blocking pop on
1219
1257
  # @param [Hash] options
1220
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1258
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1221
1259
  #
1222
1260
  # @return [nil, [String, String]]
1223
1261
  # - `nil` when the operation timed out
@@ -1234,20 +1272,12 @@ class Redis
1234
1272
  # @param [String] source source key
1235
1273
  # @param [String] destination destination key
1236
1274
  # @param [Hash] options
1237
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1275
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1238
1276
  #
1239
1277
  # @return [nil, String]
1240
1278
  # - `nil` when the operation timed out
1241
1279
  # - the element was popped and pushed otherwise
1242
- def brpoplpush(source, destination, options = {})
1243
- case options
1244
- when Integer
1245
- # Issue deprecation notice in obnoxious mode...
1246
- options = { :timeout => options }
1247
- end
1248
-
1249
- timeout = options[:timeout] || 0
1250
-
1280
+ def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
1251
1281
  synchronize do |client|
1252
1282
  command = [:brpoplpush, source, destination, timeout]
1253
1283
  timeout += client.timeout if timeout > 0
@@ -1258,7 +1288,7 @@ class Redis
1258
1288
  # Get an element from a list by its index.
1259
1289
  #
1260
1290
  # @param [String] key
1261
- # @param [Fixnum] index
1291
+ # @param [Integer] index
1262
1292
  # @return [String]
1263
1293
  def lindex(key, index)
1264
1294
  synchronize do |client|
@@ -1272,7 +1302,7 @@ class Redis
1272
1302
  # @param [String, Symbol] where `BEFORE` or `AFTER`
1273
1303
  # @param [String] pivot reference element
1274
1304
  # @param [String] value
1275
- # @return [Fixnum] length of the list after the insert operation, or `-1`
1305
+ # @return [Integer] length of the list after the insert operation, or `-1`
1276
1306
  # when the element `pivot` was not found
1277
1307
  def linsert(key, where, pivot, value)
1278
1308
  synchronize do |client|
@@ -1283,8 +1313,8 @@ class Redis
1283
1313
  # Get a range of elements from a list.
1284
1314
  #
1285
1315
  # @param [String] key
1286
- # @param [Fixnum] start start index
1287
- # @param [Fixnum] stop stop index
1316
+ # @param [Integer] start start index
1317
+ # @param [Integer] stop stop index
1288
1318
  # @return [Array<String>]
1289
1319
  def lrange(key, start, stop)
1290
1320
  synchronize do |client|
@@ -1295,12 +1325,12 @@ class Redis
1295
1325
  # Remove elements from a list.
1296
1326
  #
1297
1327
  # @param [String] key
1298
- # @param [Fixnum] count number of elements to remove. Use a positive
1328
+ # @param [Integer] count number of elements to remove. Use a positive
1299
1329
  # value to remove the first `count` occurrences of `value`. A negative
1300
1330
  # value to remove the last `count` occurrences of `value`. Or zero, to
1301
1331
  # remove all occurrences of `value` from the list.
1302
1332
  # @param [String] value
1303
- # @return [Fixnum] the number of removed elements
1333
+ # @return [Integer] the number of removed elements
1304
1334
  def lrem(key, count, value)
1305
1335
  synchronize do |client|
1306
1336
  client.call([:lrem, key, count, value])
@@ -1310,7 +1340,7 @@ class Redis
1310
1340
  # Set the value of an element in a list by its index.
1311
1341
  #
1312
1342
  # @param [String] key
1313
- # @param [Fixnum] index
1343
+ # @param [Integer] index
1314
1344
  # @param [String] value
1315
1345
  # @return [String] `OK`
1316
1346
  def lset(key, index, value)
@@ -1322,8 +1352,8 @@ class Redis
1322
1352
  # Trim a list to the specified range.
1323
1353
  #
1324
1354
  # @param [String] key
1325
- # @param [Fixnum] start start index
1326
- # @param [Fixnum] stop stop index
1355
+ # @param [Integer] start start index
1356
+ # @param [Integer] stop stop index
1327
1357
  # @return [String] `OK`
1328
1358
  def ltrim(key, start, stop)
1329
1359
  synchronize do |client|
@@ -1334,7 +1364,7 @@ class Redis
1334
1364
  # Get the number of members in a set.
1335
1365
  #
1336
1366
  # @param [String] key
1337
- # @return [Fixnum]
1367
+ # @return [Integer]
1338
1368
  def scard(key)
1339
1369
  synchronize do |client|
1340
1370
  client.call([:scard, key])
@@ -1345,8 +1375,8 @@ class Redis
1345
1375
  #
1346
1376
  # @param [String] key
1347
1377
  # @param [String, Array<String>] member one member, or array of members
1348
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1349
- # holding whether or not adding the member succeeded, or `Fixnum` when an
1378
+ # @return [Boolean, Integer] `Boolean` when a single member is specified,
1379
+ # holding whether or not adding the member succeeded, or `Integer` when an
1350
1380
  # array of members is specified, holding the number of members that were
1351
1381
  # successfully added
1352
1382
  def sadd(key, member)
@@ -1367,8 +1397,8 @@ class Redis
1367
1397
  #
1368
1398
  # @param [String] key
1369
1399
  # @param [String, Array<String>] member one member, or array of members
1370
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1371
- # holding whether or not removing the member succeeded, or `Fixnum` when an
1400
+ # @return [Boolean, Integer] `Boolean` when a single member is specified,
1401
+ # holding whether or not removing the member succeeded, or `Integer` when an
1372
1402
  # array of members is specified, holding the number of members that were
1373
1403
  # successfully removed
1374
1404
  def srem(key, member)
@@ -1389,7 +1419,7 @@ class Redis
1389
1419
  #
1390
1420
  # @param [String] key
1391
1421
  # @return [String]
1392
- # @param [Fixnum] count
1422
+ # @param [Integer] count
1393
1423
  def spop(key, count = nil)
1394
1424
  synchronize do |client|
1395
1425
  if count.nil?
@@ -1403,7 +1433,7 @@ class Redis
1403
1433
  # Get one or more random members from a set.
1404
1434
  #
1405
1435
  # @param [String] key
1406
- # @param [Fixnum] count
1436
+ # @param [Integer] count
1407
1437
  # @return [String]
1408
1438
  def srandmember(key, count = nil)
1409
1439
  synchronize do |client|
@@ -1454,7 +1484,7 @@ class Redis
1454
1484
  # @return [Array<String>] members in the difference
1455
1485
  def sdiff(*keys)
1456
1486
  synchronize do |client|
1457
- client.call([:sdiff] + keys)
1487
+ client.call([:sdiff, *keys])
1458
1488
  end
1459
1489
  end
1460
1490
 
@@ -1462,10 +1492,10 @@ class Redis
1462
1492
  #
1463
1493
  # @param [String] destination destination key
1464
1494
  # @param [String, Array<String>] keys keys pointing to sets to subtract
1465
- # @return [Fixnum] number of elements in the resulting set
1495
+ # @return [Integer] number of elements in the resulting set
1466
1496
  def sdiffstore(destination, *keys)
1467
1497
  synchronize do |client|
1468
- client.call([:sdiffstore, destination] + keys)
1498
+ client.call([:sdiffstore, destination, *keys])
1469
1499
  end
1470
1500
  end
1471
1501
 
@@ -1475,7 +1505,7 @@ class Redis
1475
1505
  # @return [Array<String>] members in the intersection
1476
1506
  def sinter(*keys)
1477
1507
  synchronize do |client|
1478
- client.call([:sinter] + keys)
1508
+ client.call([:sinter, *keys])
1479
1509
  end
1480
1510
  end
1481
1511
 
@@ -1483,10 +1513,10 @@ class Redis
1483
1513
  #
1484
1514
  # @param [String] destination destination key
1485
1515
  # @param [String, Array<String>] keys keys pointing to sets to intersect
1486
- # @return [Fixnum] number of elements in the resulting set
1516
+ # @return [Integer] number of elements in the resulting set
1487
1517
  def sinterstore(destination, *keys)
1488
1518
  synchronize do |client|
1489
- client.call([:sinterstore, destination] + keys)
1519
+ client.call([:sinterstore, destination, *keys])
1490
1520
  end
1491
1521
  end
1492
1522
 
@@ -1496,7 +1526,7 @@ class Redis
1496
1526
  # @return [Array<String>] members in the union
1497
1527
  def sunion(*keys)
1498
1528
  synchronize do |client|
1499
- client.call([:sunion] + keys)
1529
+ client.call([:sunion, *keys])
1500
1530
  end
1501
1531
  end
1502
1532
 
@@ -1504,10 +1534,10 @@ class Redis
1504
1534
  #
1505
1535
  # @param [String] destination destination key
1506
1536
  # @param [String, Array<String>] keys keys pointing to sets to unify
1507
- # @return [Fixnum] number of elements in the resulting set
1537
+ # @return [Integer] number of elements in the resulting set
1508
1538
  def sunionstore(destination, *keys)
1509
1539
  synchronize do |client|
1510
- client.call([:sunionstore, destination] + keys)
1540
+ client.call([:sunionstore, destination, *keys])
1511
1541
  end
1512
1542
  end
1513
1543
 
@@ -1518,7 +1548,7 @@ class Redis
1518
1548
  # # => 4
1519
1549
  #
1520
1550
  # @param [String] key
1521
- # @return [Fixnum]
1551
+ # @return [Integer]
1522
1552
  def zcard(key)
1523
1553
  synchronize do |client|
1524
1554
  client.call([:zcard, key])
@@ -1549,38 +1579,27 @@ class Redis
1549
1579
  # - `:incr => true`: When this option is specified ZADD acts like
1550
1580
  # ZINCRBY; only one score-element pair can be specified in this mode
1551
1581
  #
1552
- # @return [Boolean, Fixnum, Float]
1582
+ # @return [Boolean, Integer, Float]
1553
1583
  # - `Boolean` when a single pair is specified, holding whether or not it was
1554
1584
  # **added** to the sorted set.
1555
- # - `Fixnum` when an array of pairs is specified, holding the number of
1585
+ # - `Integer` when an array of pairs is specified, holding the number of
1556
1586
  # pairs that were **added** to the sorted set.
1557
1587
  # - `Float` when option :incr is specified, holding the score of the member
1558
1588
  # after incrementing it.
1559
- def zadd(key, *args) #, options
1560
- zadd_options = []
1561
- if args.last.is_a?(Hash)
1562
- options = args.pop
1563
-
1564
- nx = options[:nx]
1565
- zadd_options << "NX" if nx
1566
-
1567
- xx = options[:xx]
1568
- zadd_options << "XX" if xx
1569
-
1570
- ch = options[:ch]
1571
- zadd_options << "CH" if ch
1572
-
1573
- incr = options[:incr]
1574
- zadd_options << "INCR" if incr
1575
- end
1589
+ def zadd(key, *args, nx: nil, xx: nil, ch: nil, incr: nil)
1590
+ command = [:zadd, key]
1591
+ command << "NX" if nx
1592
+ command << "XX" if xx
1593
+ command << "CH" if ch
1594
+ command << "INCR" if incr
1576
1595
 
1577
1596
  synchronize do |client|
1578
1597
  if args.size == 1 && args[0].is_a?(Array)
1579
1598
  # Variadic: return float if INCR, integer if !INCR
1580
- client.call([:zadd, key] + zadd_options + args[0], &(incr ? Floatify : nil))
1599
+ client.call(command + args[0], &(incr ? Floatify : nil))
1581
1600
  elsif args.size == 2
1582
1601
  # Single pair: return float if INCR, boolean if !INCR
1583
- client.call([:zadd, key] + zadd_options + args, &(incr ? Floatify : Boolify))
1602
+ client.call(command + args, &(incr ? Floatify : Boolify))
1584
1603
  else
1585
1604
  raise ArgumentError, "wrong number of arguments"
1586
1605
  end
@@ -1615,10 +1634,10 @@ class Redis
1615
1634
  # - a single member
1616
1635
  # - an array of members
1617
1636
  #
1618
- # @return [Boolean, Fixnum]
1637
+ # @return [Boolean, Integer]
1619
1638
  # - `Boolean` when a single member is specified, holding whether or not it
1620
1639
  # was removed from the sorted set
1621
- # - `Fixnum` when an array of pairs is specified, holding the number of
1640
+ # - `Integer` when an array of pairs is specified, holding the number of
1622
1641
  # members that were removed to the sorted set
1623
1642
  def zrem(key, member)
1624
1643
  synchronize do |client|
@@ -1743,18 +1762,16 @@ class Redis
1743
1762
  # # => [["a", 32.0], ["b", 64.0]]
1744
1763
  #
1745
1764
  # @param [String] key
1746
- # @param [Fixnum] start start index
1747
- # @param [Fixnum] stop stop index
1765
+ # @param [Integer] start start index
1766
+ # @param [Integer] stop stop index
1748
1767
  # @param [Hash] options
1749
1768
  # - `:with_scores => true`: include scores in output
1750
1769
  #
1751
1770
  # @return [Array<String>, Array<[String, Float]>]
1752
1771
  # - when `:with_scores` is not specified, an array of members
1753
1772
  # - when `:with_scores` is specified, an array with `[member, score]` pairs
1754
- def zrange(key, start, stop, options = {})
1755
- args = []
1756
-
1757
- with_scores = options[:with_scores] || options[:withscores]
1773
+ def zrange(key, start, stop, withscores: false, with_scores: withscores)
1774
+ args = [:zrange, key, start, stop]
1758
1775
 
1759
1776
  if with_scores
1760
1777
  args << "WITHSCORES"
@@ -1762,7 +1779,7 @@ class Redis
1762
1779
  end
1763
1780
 
1764
1781
  synchronize do |client|
1765
- client.call([:zrange, key, start, stop] + args, &block)
1782
+ client.call(args, &block)
1766
1783
  end
1767
1784
  end
1768
1785
 
@@ -1777,10 +1794,8 @@ class Redis
1777
1794
  # # => [["b", 64.0], ["a", 32.0]]
1778
1795
  #
1779
1796
  # @see #zrange
1780
- def zrevrange(key, start, stop, options = {})
1781
- args = []
1782
-
1783
- with_scores = options[:with_scores] || options[:withscores]
1797
+ def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
1798
+ args = [:zrevrange, key, start, stop]
1784
1799
 
1785
1800
  if with_scores
1786
1801
  args << "WITHSCORES"
@@ -1788,7 +1803,7 @@ class Redis
1788
1803
  end
1789
1804
 
1790
1805
  synchronize do |client|
1791
- client.call([:zrevrange, key, start, stop] + args, &block)
1806
+ client.call(args, &block)
1792
1807
  end
1793
1808
  end
1794
1809
 
@@ -1796,7 +1811,7 @@ class Redis
1796
1811
  #
1797
1812
  # @param [String] key
1798
1813
  # @param [String] member
1799
- # @return [Fixnum]
1814
+ # @return [Integer]
1800
1815
  def zrank(key, member)
1801
1816
  synchronize do |client|
1802
1817
  client.call([:zrank, key, member])
@@ -1808,7 +1823,7 @@ class Redis
1808
1823
  #
1809
1824
  # @param [String] key
1810
1825
  # @param [String] member
1811
- # @return [Fixnum]
1826
+ # @return [Integer]
1812
1827
  def zrevrank(key, member)
1813
1828
  synchronize do |client|
1814
1829
  client.call([:zrevrank, key, member])
@@ -1825,9 +1840,9 @@ class Redis
1825
1840
  # # => 5
1826
1841
  #
1827
1842
  # @param [String] key
1828
- # @param [Fixnum] start start index
1829
- # @param [Fixnum] stop stop index
1830
- # @return [Fixnum] number of members that were removed
1843
+ # @param [Integer] start start index
1844
+ # @param [Integer] stop stop index
1845
+ # @return [Integer] number of members that were removed
1831
1846
  def zremrangebyrank(key, start, stop)
1832
1847
  synchronize do |client|
1833
1848
  client.call([:zremrangebyrank, key, start, stop])
@@ -1851,7 +1866,7 @@ class Redis
1851
1866
  # - inclusive maximum is specified by prefixing `(`
1852
1867
  # - exclusive maximum is specified by prefixing `[`
1853
1868
  #
1854
- # @return [Fixnum] number of members within the specified lexicographical range
1869
+ # @return [Integer] number of members within the specified lexicographical range
1855
1870
  def zlexcount(key, min, max)
1856
1871
  synchronize do |client|
1857
1872
  client.call([:zlexcount, key, min, max])
@@ -1879,14 +1894,16 @@ class Redis
1879
1894
  # `count` members
1880
1895
  #
1881
1896
  # @return [Array<String>, Array<[String, Float]>]
1882
- def zrangebylex(key, min, max, options = {})
1883
- args = []
1897
+ def zrangebylex(key, min, max, limit: nil)
1898
+ args = [:zrangebylex, key, min, max]
1884
1899
 
1885
- limit = options[:limit]
1886
- args.concat(["LIMIT"] + limit) if limit
1900
+ if limit
1901
+ args << "LIMIT"
1902
+ args.concat(limit)
1903
+ end
1887
1904
 
1888
1905
  synchronize do |client|
1889
- client.call([:zrangebylex, key, min, max] + args)
1906
+ client.call(args)
1890
1907
  end
1891
1908
  end
1892
1909
 
@@ -1901,14 +1918,16 @@ class Redis
1901
1918
  # # => ["abbygail", "abby"]
1902
1919
  #
1903
1920
  # @see #zrangebylex
1904
- def zrevrangebylex(key, max, min, options = {})
1905
- args = []
1921
+ def zrevrangebylex(key, max, min, limit: nil)
1922
+ args = [:zrevrangebylex, key, max, min]
1906
1923
 
1907
- limit = options[:limit]
1908
- args.concat(["LIMIT"] + limit) if limit
1924
+ if limit
1925
+ args << "LIMIT"
1926
+ args.concat(limit)
1927
+ end
1909
1928
 
1910
1929
  synchronize do |client|
1911
- client.call([:zrevrangebylex, key, max, min] + args)
1930
+ client.call(args)
1912
1931
  end
1913
1932
  end
1914
1933
 
@@ -1939,21 +1958,21 @@ class Redis
1939
1958
  # @return [Array<String>, Array<[String, Float]>]
1940
1959
  # - when `:with_scores` is not specified, an array of members
1941
1960
  # - when `:with_scores` is specified, an array with `[member, score]` pairs
1942
- def zrangebyscore(key, min, max, options = {})
1943
- args = []
1944
-
1945
- with_scores = options[:with_scores] || options[:withscores]
1961
+ def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
1962
+ args = [:zrangebyscore, key, min, max]
1946
1963
 
1947
1964
  if with_scores
1948
1965
  args << "WITHSCORES"
1949
1966
  block = FloatifyPairs
1950
1967
  end
1951
1968
 
1952
- limit = options[:limit]
1953
- args.concat(["LIMIT"] + limit) if limit
1969
+ if limit
1970
+ args << "LIMIT"
1971
+ args.concat(limit)
1972
+ end
1954
1973
 
1955
1974
  synchronize do |client|
1956
- client.call([:zrangebyscore, key, min, max] + args, &block)
1975
+ client.call(args, &block)
1957
1976
  end
1958
1977
  end
1959
1978
 
@@ -1971,21 +1990,21 @@ class Redis
1971
1990
  # # => [["b", 64.0], ["a", 32.0]]
1972
1991
  #
1973
1992
  # @see #zrangebyscore
1974
- def zrevrangebyscore(key, max, min, options = {})
1975
- args = []
1976
-
1977
- with_scores = options[:with_scores] || options[:withscores]
1993
+ def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
1994
+ args = [:zrevrangebyscore, key, max, min]
1978
1995
 
1979
1996
  if with_scores
1980
- args << ["WITHSCORES"]
1997
+ args << "WITHSCORES"
1981
1998
  block = FloatifyPairs
1982
1999
  end
1983
2000
 
1984
- limit = options[:limit]
1985
- args.concat(["LIMIT"] + limit) if limit
2001
+ if limit
2002
+ args << "LIMIT"
2003
+ args.concat(limit)
2004
+ end
1986
2005
 
1987
2006
  synchronize do |client|
1988
- client.call([:zrevrangebyscore, key, max, min] + args, &block)
2007
+ client.call(args, &block)
1989
2008
  end
1990
2009
  end
1991
2010
 
@@ -2005,7 +2024,7 @@ class Redis
2005
2024
  # @param [String] max
2006
2025
  # - inclusive maximum score is specified verbatim
2007
2026
  # - exclusive maximum score is specified by prefixing `(`
2008
- # @return [Fixnum] number of members that were removed
2027
+ # @return [Integer] number of members that were removed
2009
2028
  def zremrangebyscore(key, min, max)
2010
2029
  synchronize do |client|
2011
2030
  client.call([:zremrangebyscore, key, min, max])
@@ -2028,7 +2047,7 @@ class Redis
2028
2047
  # @param [String] max
2029
2048
  # - inclusive maximum score is specified verbatim
2030
2049
  # - exclusive maximum score is specified by prefixing `(`
2031
- # @return [Fixnum] number of members in within the specified range
2050
+ # @return [Integer] number of members in within the specified range
2032
2051
  def zcount(key, min, max)
2033
2052
  synchronize do |client|
2034
2053
  client.call([:zcount, key, min, max])
@@ -2048,18 +2067,19 @@ class Redis
2048
2067
  # - `:weights => [Float, Float, ...]`: weights to associate with source
2049
2068
  # sorted sets
2050
2069
  # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
2051
- # @return [Fixnum] number of elements in the resulting sorted set
2052
- def zinterstore(destination, keys, options = {})
2053
- args = []
2070
+ # @return [Integer] number of elements in the resulting sorted set
2071
+ def zinterstore(destination, keys, weights: nil, aggregate: nil)
2072
+ args = [:zinterstore, destination, keys.size, *keys]
2054
2073
 
2055
- weights = options[:weights]
2056
- args.concat(["WEIGHTS"] + weights) if weights
2074
+ if weights
2075
+ args << "WEIGHTS"
2076
+ args.concat(weights)
2077
+ end
2057
2078
 
2058
- aggregate = options[:aggregate]
2059
- args.concat(["AGGREGATE", aggregate]) if aggregate
2079
+ args << "AGGREGATE" << aggregate if aggregate
2060
2080
 
2061
2081
  synchronize do |client|
2062
- client.call([:zinterstore, destination, keys.size] + keys + args)
2082
+ client.call(args)
2063
2083
  end
2064
2084
  end
2065
2085
 
@@ -2075,40 +2095,46 @@ class Redis
2075
2095
  # - `:weights => [Float, Float, ...]`: weights to associate with source
2076
2096
  # sorted sets
2077
2097
  # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
2078
- # @return [Fixnum] number of elements in the resulting sorted set
2079
- def zunionstore(destination, keys, options = {})
2080
- args = []
2098
+ # @return [Integer] number of elements in the resulting sorted set
2099
+ def zunionstore(destination, keys, weights: nil, aggregate: nil)
2100
+ args = [:zunionstore, destination, keys.size, *keys]
2081
2101
 
2082
- weights = options[:weights]
2083
- args.concat(["WEIGHTS"] + weights) if weights
2102
+ if weights
2103
+ args << "WEIGHTS"
2104
+ args.concat(weights)
2105
+ end
2084
2106
 
2085
- aggregate = options[:aggregate]
2086
- args.concat(["AGGREGATE", aggregate]) if aggregate
2107
+ args << "AGGREGATE" << aggregate if aggregate
2087
2108
 
2088
2109
  synchronize do |client|
2089
- client.call([:zunionstore, destination, keys.size] + keys + args)
2110
+ client.call(args)
2090
2111
  end
2091
2112
  end
2092
2113
 
2093
2114
  # Get the number of fields in a hash.
2094
2115
  #
2095
2116
  # @param [String] key
2096
- # @return [Fixnum] number of fields in the hash
2117
+ # @return [Integer] number of fields in the hash
2097
2118
  def hlen(key)
2098
2119
  synchronize do |client|
2099
2120
  client.call([:hlen, key])
2100
2121
  end
2101
2122
  end
2102
2123
 
2103
- # Set the string value of a hash field.
2124
+ # Set one or more hash values.
2125
+ #
2126
+ # @example
2127
+ # redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
2128
+ # redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
2104
2129
  #
2105
2130
  # @param [String] key
2106
- # @param [String] field
2107
- # @param [String] value
2108
- # @return [Boolean] whether or not the field was **added** to the hash
2109
- def hset(key, field, value)
2131
+ # @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
2132
+ # @return [Integer] The number of fields that were added to the hash
2133
+ def hset(key, *attrs)
2134
+ attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
2135
+
2110
2136
  synchronize do |client|
2111
- client.call([:hset, key, field, value], &Boolify)
2137
+ client.call([:hset, key, *attrs])
2112
2138
  end
2113
2139
  end
2114
2140
 
@@ -2197,7 +2223,7 @@ class Redis
2197
2223
  # @see #hmget
2198
2224
  def mapped_hmget(key, *fields)
2199
2225
  hmget(key, *fields) do |reply|
2200
- if reply.kind_of?(Array)
2226
+ if reply.is_a?(Array)
2201
2227
  Hash[fields.zip(reply)]
2202
2228
  else
2203
2229
  reply
@@ -2209,7 +2235,7 @@ class Redis
2209
2235
  #
2210
2236
  # @param [String] key
2211
2237
  # @param [String, Array<String>] field
2212
- # @return [Fixnum] the number of fields that were removed from the hash
2238
+ # @return [Integer] the number of fields that were removed from the hash
2213
2239
  def hdel(key, *fields)
2214
2240
  synchronize do |client|
2215
2241
  client.call([:hdel, key, *fields])
@@ -2231,8 +2257,8 @@ class Redis
2231
2257
  #
2232
2258
  # @param [String] key
2233
2259
  # @param [String] field
2234
- # @param [Fixnum] increment
2235
- # @return [Fixnum] value of the field after incrementing it
2260
+ # @param [Integer] increment
2261
+ # @return [Integer] value of the field after incrementing it
2236
2262
  def hincrby(key, field, increment)
2237
2263
  synchronize do |client|
2238
2264
  client.call([:hincrby, key, field, increment])
@@ -2290,20 +2316,21 @@ class Redis
2290
2316
 
2291
2317
  def subscribed?
2292
2318
  synchronize do |client|
2293
- client.kind_of? SubscribedClient
2319
+ client.is_a? SubscribedClient
2294
2320
  end
2295
2321
  end
2296
2322
 
2297
2323
  # Listen for messages published to the given channels.
2298
2324
  def subscribe(*channels, &block)
2299
- synchronize do |client|
2325
+ synchronize do |_client|
2300
2326
  _subscription(:subscribe, 0, channels, block)
2301
2327
  end
2302
2328
  end
2303
2329
 
2304
- # Listen for messages published to the given channels. Throw a timeout error if there is no messages for a timeout period.
2330
+ # Listen for messages published to the given channels. Throw a timeout error
2331
+ # if there is no messages for a timeout period.
2305
2332
  def subscribe_with_timeout(timeout, *channels, &block)
2306
- synchronize do |client|
2333
+ synchronize do |_client|
2307
2334
  _subscription(:subscribe_with_timeout, timeout, channels, block)
2308
2335
  end
2309
2336
  end
@@ -2311,21 +2338,23 @@ class Redis
2311
2338
  # Stop listening for messages posted to the given channels.
2312
2339
  def unsubscribe(*channels)
2313
2340
  synchronize do |client|
2314
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2341
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
2342
+
2315
2343
  client.unsubscribe(*channels)
2316
2344
  end
2317
2345
  end
2318
2346
 
2319
2347
  # Listen for messages published to channels matching the given patterns.
2320
2348
  def psubscribe(*channels, &block)
2321
- synchronize do |client|
2349
+ synchronize do |_client|
2322
2350
  _subscription(:psubscribe, 0, channels, block)
2323
2351
  end
2324
2352
  end
2325
2353
 
2326
- # Listen for messages published to channels matching the given patterns. Throw a timeout error if there is no messages for a timeout period.
2354
+ # Listen for messages published to channels matching the given patterns.
2355
+ # Throw a timeout error if there is no messages for a timeout period.
2327
2356
  def psubscribe_with_timeout(timeout, *channels, &block)
2328
- synchronize do |client|
2357
+ synchronize do |_client|
2329
2358
  _subscription(:psubscribe_with_timeout, timeout, channels, block)
2330
2359
  end
2331
2360
  end
@@ -2333,7 +2362,8 @@ class Redis
2333
2362
  # Stop listening for messages posted to channels matching the given patterns.
2334
2363
  def punsubscribe(*channels)
2335
2364
  synchronize do |client|
2336
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2365
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
2366
+
2337
2367
  client.punsubscribe(*channels)
2338
2368
  end
2339
2369
  end
@@ -2378,7 +2408,7 @@ class Redis
2378
2408
  # @see #multi
2379
2409
  def watch(*keys)
2380
2410
  synchronize do |client|
2381
- res = client.call([:watch] + keys)
2411
+ res = client.call([:watch, *keys])
2382
2412
 
2383
2413
  if block_given?
2384
2414
  begin
@@ -2408,7 +2438,7 @@ class Redis
2408
2438
  end
2409
2439
 
2410
2440
  def pipelined
2411
- synchronize do |client|
2441
+ synchronize do |_client|
2412
2442
  begin
2413
2443
  pipeline = Pipeline.new(@client)
2414
2444
  original, @client = @client, pipeline
@@ -2608,18 +2638,12 @@ class Redis
2608
2638
  _eval(:evalsha, args)
2609
2639
  end
2610
2640
 
2611
- def _scan(command, cursor, args, options = {}, &block)
2641
+ def _scan(command, cursor, args, match: nil, count: nil, &block)
2612
2642
  # SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
2613
2643
 
2614
2644
  args << cursor
2615
-
2616
- if match = options[:match]
2617
- args.concat(["MATCH", match])
2618
- end
2619
-
2620
- if count = options[:count]
2621
- args.concat(["COUNT", count])
2622
- end
2645
+ args << "MATCH" << match if match
2646
+ args << "COUNT" << count if count
2623
2647
 
2624
2648
  synchronize do |client|
2625
2649
  client.call([command] + args, &block)
@@ -2641,8 +2665,8 @@ class Redis
2641
2665
  # - `:count => Integer`: return count keys at most per iteration
2642
2666
  #
2643
2667
  # @return [String, Array<String>] the next cursor and all found keys
2644
- def scan(cursor, options={})
2645
- _scan(:scan, cursor, [], options)
2668
+ def scan(cursor, **options)
2669
+ _scan(:scan, cursor, [], **options)
2646
2670
  end
2647
2671
 
2648
2672
  # Scan the keyspace
@@ -2660,11 +2684,12 @@ class Redis
2660
2684
  # - `:count => Integer`: return count keys at most per iteration
2661
2685
  #
2662
2686
  # @return [Enumerator] an enumerator for all found keys
2663
- def scan_each(options={}, &block)
2664
- return to_enum(:scan_each, options) unless block_given?
2687
+ def scan_each(**options, &block)
2688
+ return to_enum(:scan_each, **options) unless block_given?
2689
+
2665
2690
  cursor = 0
2666
2691
  loop do
2667
- cursor, keys = scan(cursor, options)
2692
+ cursor, keys = scan(cursor, **options)
2668
2693
  keys.each(&block)
2669
2694
  break if cursor == "0"
2670
2695
  end
@@ -2681,8 +2706,8 @@ class Redis
2681
2706
  # - `:count => Integer`: return count keys at most per iteration
2682
2707
  #
2683
2708
  # @return [String, Array<[String, String]>] the next cursor and all found keys
2684
- def hscan(key, cursor, options={})
2685
- _scan(:hscan, cursor, [key], options) do |reply|
2709
+ def hscan(key, cursor, **options)
2710
+ _scan(:hscan, cursor, [key], **options) do |reply|
2686
2711
  [reply[0], reply[1].each_slice(2).to_a]
2687
2712
  end
2688
2713
  end
@@ -2698,11 +2723,12 @@ class Redis
2698
2723
  # - `:count => Integer`: return count keys at most per iteration
2699
2724
  #
2700
2725
  # @return [Enumerator] an enumerator for all found keys
2701
- def hscan_each(key, options={}, &block)
2702
- return to_enum(:hscan_each, key, options) unless block_given?
2726
+ def hscan_each(key, **options, &block)
2727
+ return to_enum(:hscan_each, key, **options) unless block_given?
2728
+
2703
2729
  cursor = 0
2704
2730
  loop do
2705
- cursor, values = hscan(key, cursor, options)
2731
+ cursor, values = hscan(key, cursor, **options)
2706
2732
  values.each(&block)
2707
2733
  break if cursor == "0"
2708
2734
  end
@@ -2720,8 +2746,8 @@ class Redis
2720
2746
  #
2721
2747
  # @return [String, Array<[String, Float]>] the next cursor and all found
2722
2748
  # members and scores
2723
- def zscan(key, cursor, options={})
2724
- _scan(:zscan, cursor, [key], options) do |reply|
2749
+ def zscan(key, cursor, **options)
2750
+ _scan(:zscan, cursor, [key], **options) do |reply|
2725
2751
  [reply[0], FloatifyPairs.call(reply[1])]
2726
2752
  end
2727
2753
  end
@@ -2737,11 +2763,12 @@ class Redis
2737
2763
  # - `:count => Integer`: return count keys at most per iteration
2738
2764
  #
2739
2765
  # @return [Enumerator] an enumerator for all found scores and members
2740
- def zscan_each(key, options={}, &block)
2741
- return to_enum(:zscan_each, key, options) unless block_given?
2766
+ def zscan_each(key, **options, &block)
2767
+ return to_enum(:zscan_each, key, **options) unless block_given?
2768
+
2742
2769
  cursor = 0
2743
2770
  loop do
2744
- cursor, values = zscan(key, cursor, options)
2771
+ cursor, values = zscan(key, cursor, **options)
2745
2772
  values.each(&block)
2746
2773
  break if cursor == "0"
2747
2774
  end
@@ -2758,8 +2785,8 @@ class Redis
2758
2785
  # - `:count => Integer`: return count keys at most per iteration
2759
2786
  #
2760
2787
  # @return [String, Array<String>] the next cursor and all found members
2761
- def sscan(key, cursor, options={})
2762
- _scan(:sscan, cursor, [key], options)
2788
+ def sscan(key, cursor, **options)
2789
+ _scan(:sscan, cursor, [key], **options)
2763
2790
  end
2764
2791
 
2765
2792
  # Scan a set
@@ -2773,11 +2800,12 @@ class Redis
2773
2800
  # - `:count => Integer`: return count keys at most per iteration
2774
2801
  #
2775
2802
  # @return [Enumerator] an enumerator for all keys in the set
2776
- def sscan_each(key, options={}, &block)
2777
- return to_enum(:sscan_each, key, options) unless block_given?
2803
+ def sscan_each(key, **options, &block)
2804
+ return to_enum(:sscan_each, key, **options) unless block_given?
2805
+
2778
2806
  cursor = 0
2779
2807
  loop do
2780
- cursor, keys = sscan(key, cursor, options)
2808
+ cursor, keys = sscan(key, cursor, **options)
2781
2809
  keys.each(&block)
2782
2810
  break if cursor == "0"
2783
2811
  end
@@ -2800,7 +2828,7 @@ class Redis
2800
2828
  # union of the HyperLogLogs contained in the keys.
2801
2829
  #
2802
2830
  # @param [String, Array<String>] keys
2803
- # @return [Fixnum]
2831
+ # @return [Integer]
2804
2832
  def pfcount(*keys)
2805
2833
  synchronize do |client|
2806
2834
  client.call([:pfcount] + keys)
@@ -2841,12 +2869,12 @@ class Redis
2841
2869
  end
2842
2870
  end
2843
2871
 
2844
-
2845
2872
  # Query a sorted set representing a geospatial index to fetch members matching a
2846
2873
  # given maximum distance from a point
2847
2874
  #
2848
2875
  # @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
2849
- # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2876
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
2877
+ # or the farthest to the nearest relative to the center
2850
2878
  # @param [Integer] count limit the results to the first N matching items
2851
2879
  # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2852
2880
  # @return [Array<String>] may be changed with `options`
@@ -2863,7 +2891,8 @@ class Redis
2863
2891
  # given maximum distance from an already existing member
2864
2892
  #
2865
2893
  # @param [Array] args key, member, radius, unit(m|km|ft|mi)
2866
- # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2894
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
2895
+ # to the nearest relative to the center
2867
2896
  # @param [Integer] count limit the results to the first N matching items
2868
2897
  # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2869
2898
  # @return [Array<String>] may be changed with `options`
@@ -2880,7 +2909,8 @@ class Redis
2880
2909
  #
2881
2910
  # @param [String] key
2882
2911
  # @param [String, Array<String>] member one member or array of members
2883
- # @return [Array<Array<String>, nil>] returns array of elements, where each element is either array of longitude and latitude or nil
2912
+ # @return [Array<Array<String>, nil>] returns array of elements, where each
2913
+ # element is either array of longitude and latitude or nil
2884
2914
  def geopos(key, member)
2885
2915
  synchronize do |client|
2886
2916
  client.call([:geopos, key, member])
@@ -2944,10 +2974,14 @@ class Redis
2944
2974
  # @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
2945
2975
  #
2946
2976
  # @return [String] the entry id
2947
- def xadd(key, entry, opts = {})
2977
+ def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
2948
2978
  args = [:xadd, key]
2949
- args.concat(['MAXLEN', (opts[:approximate] ? '~' : nil), opts[:maxlen]].compact) if opts[:maxlen]
2950
- args << (opts[:id] || '*')
2979
+ if maxlen
2980
+ args << "MAXLEN"
2981
+ args << "~" if approximate
2982
+ args << maxlen
2983
+ end
2984
+ args << id
2951
2985
  args.concat(entry.to_a.flatten)
2952
2986
  synchronize { |client| client.call(args) }
2953
2987
  end
@@ -3002,8 +3036,8 @@ class Redis
3002
3036
  # @param count [Integer] the number of entries as limit
3003
3037
  #
3004
3038
  # @return [Array<Array<String, Hash>>] the ids and entries pairs
3005
- def xrange(key, start = '-', _end = '+', count: nil)
3006
- args = [:xrange, key, start, _end]
3039
+ def xrange(key, start = '-', range_end = '+', count: nil)
3040
+ args = [:xrange, key, start, range_end]
3007
3041
  args.concat(['COUNT', count]) if count
3008
3042
  synchronize { |client| client.call(args, &HashifyStreamEntries) }
3009
3043
  end
@@ -3025,8 +3059,8 @@ class Redis
3025
3059
  # @params count [Integer] the number of entries as limit
3026
3060
  #
3027
3061
  # @return [Array<Array<String, Hash>>] the ids and entries pairs
3028
- def xrevrange(key, _end = '+', start = '-', count: nil)
3029
- args = [:xrevrange, key, _end, start]
3062
+ def xrevrange(key, range_end = '+', start = '-', count: nil)
3063
+ args = [:xrevrange, key, range_end, start]
3030
3064
  args.concat(['COUNT', count]) if count
3031
3065
  synchronize { |client| client.call(args, &HashifyStreamEntries) }
3032
3066
  end
@@ -3118,12 +3152,12 @@ class Redis
3118
3152
  # @option opts [Boolean] :noack whether message loss is acceptable or not
3119
3153
  #
3120
3154
  # @return [Hash{String => Hash{String => Hash}}] the entries
3121
- def xreadgroup(group, consumer, keys, ids, opts = {})
3155
+ def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
3122
3156
  args = [:xreadgroup, 'GROUP', group, consumer]
3123
- args << 'COUNT' << opts[:count] if opts[:count]
3124
- args << 'BLOCK' << opts[:block].to_i if opts[:block]
3125
- args << 'NOACK' if opts[:noack]
3126
- _xread(args, keys, ids, opts[:block])
3157
+ args << 'COUNT' << count if count
3158
+ args << 'BLOCK' << block.to_i if block
3159
+ args << 'NOACK' if noack
3160
+ _xread(args, keys, ids, block)
3127
3161
  end
3128
3162
 
3129
3163
  # Removes one or multiple entries from the pending entries list of a stream consumer group.
@@ -3233,8 +3267,8 @@ class Redis
3233
3267
  when "get-master-addr-by-name"
3234
3268
  reply
3235
3269
  else
3236
- if reply.kind_of?(Array)
3237
- if reply[0].kind_of?(Array)
3270
+ if reply.is_a?(Array)
3271
+ if reply[0].is_a?(Array)
3238
3272
  reply.map(&Hashify)
3239
3273
  else
3240
3274
  Hashify.call(reply)
@@ -3258,12 +3292,17 @@ class Redis
3258
3292
  def cluster(subcommand, *args)
3259
3293
  subcommand = subcommand.to_s.downcase
3260
3294
  block = case subcommand
3261
- when 'slots' then HashifyClusterSlots
3262
- when 'nodes' then HashifyClusterNodes
3263
- when 'slaves' then HashifyClusterSlaves
3264
- when 'info' then HashifyInfo
3265
- else Noop
3266
- end
3295
+ when 'slots'
3296
+ HashifyClusterSlots
3297
+ when 'nodes'
3298
+ HashifyClusterNodes
3299
+ when 'slaves'
3300
+ HashifyClusterSlaves
3301
+ when 'info'
3302
+ HashifyInfo
3303
+ else
3304
+ Noop
3305
+ end
3267
3306
 
3268
3307
  # @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
3269
3308
  block = Noop unless @cluster_mode
@@ -3298,21 +3337,21 @@ class Redis
3298
3337
  return @original_client.connection_info if @cluster_mode
3299
3338
 
3300
3339
  {
3301
- host: @original_client.host,
3302
- port: @original_client.port,
3303
- db: @original_client.db,
3304
- id: @original_client.id,
3340
+ host: @original_client.host,
3341
+ port: @original_client.port,
3342
+ db: @original_client.db,
3343
+ id: @original_client.id,
3305
3344
  location: @original_client.location
3306
3345
  }
3307
3346
  end
3308
3347
 
3309
- def method_missing(command, *args)
3348
+ def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
3310
3349
  synchronize do |client|
3311
3350
  client.call([command] + args)
3312
3351
  end
3313
3352
  end
3314
3353
 
3315
- private
3354
+ private
3316
3355
 
3317
3356
  # Commands returning 1 for true and 0 for false may be executed in a pipeline
3318
3357
  # where the method call will return nil. Propagate the nil instead of falsely
@@ -3384,18 +3423,21 @@ private
3384
3423
  end
3385
3424
  }
3386
3425
 
3426
+ EMPTY_STREAM_RESPONSE = [nil].freeze
3427
+ private_constant :EMPTY_STREAM_RESPONSE
3428
+
3387
3429
  HashifyStreamEntries = lambda { |reply|
3388
- reply.map do |entry_id, values|
3430
+ reply.compact.map do |entry_id, values|
3389
3431
  [entry_id, values.each_slice(2).to_h]
3390
3432
  end
3391
3433
  }
3392
3434
 
3393
3435
  HashifyStreamPendings = lambda { |reply|
3394
3436
  {
3395
- 'size' => reply[0],
3437
+ 'size' => reply[0],
3396
3438
  'min_entry_id' => reply[1],
3397
3439
  'max_entry_id' => reply[2],
3398
- 'consumers' => reply[3].nil? ? {} : reply[3].to_h
3440
+ 'consumers' => reply[3].nil? ? {} : reply[3].to_h
3399
3441
  }
3400
3442
  }
3401
3443
 
@@ -3404,8 +3446,8 @@ private
3404
3446
  {
3405
3447
  'entry_id' => arr[0],
3406
3448
  'consumer' => arr[1],
3407
- 'elapsed' => arr[2],
3408
- 'count' => arr[3]
3449
+ 'elapsed' => arr[2],
3450
+ 'count' => arr[3]
3409
3451
  }
3410
3452
  end
3411
3453
  }
@@ -3413,15 +3455,15 @@ private
3413
3455
  HashifyClusterNodeInfo = lambda { |str|
3414
3456
  arr = str.split(' ')
3415
3457
  {
3416
- 'node_id' => arr[0],
3417
- 'ip_port' => arr[1],
3418
- 'flags' => arr[2].split(','),
3458
+ 'node_id' => arr[0],
3459
+ 'ip_port' => arr[1],
3460
+ 'flags' => arr[2].split(','),
3419
3461
  'master_node_id' => arr[3],
3420
- 'ping_sent' => arr[4],
3421
- 'pong_recv' => arr[5],
3422
- 'config_epoch' => arr[6],
3423
- 'link_state' => arr[7],
3424
- 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
3462
+ 'ping_sent' => arr[4],
3463
+ 'pong_recv' => arr[5],
3464
+ 'config_epoch' => arr[6],
3465
+ 'link_state' => arr[7],
3466
+ 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
3425
3467
  }
3426
3468
  }
3427
3469
 
@@ -3432,9 +3474,9 @@ private
3432
3474
  replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
3433
3475
  {
3434
3476
  'start_slot' => first_slot,
3435
- 'end_slot' => last_slot,
3436
- 'master' => master,
3437
- 'replicas' => replicas
3477
+ 'end_slot' => last_slot,
3478
+ 'master' => master,
3479
+ 'replicas' => replicas
3438
3480
  }
3439
3481
  end
3440
3482
  }