redis 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fb5e8fcd26f9729131009cc0c25bed4cdf1009f5
4
- data.tar.gz: 9ed7be2cc83d01dcb6c69002680105dc544e659a
2
+ SHA256:
3
+ metadata.gz: 9796f6646b7d3aaeeb5ef37629fb1a43422285724d8d2901a219ef4f2882eff5
4
+ data.tar.gz: b89f4f1d6a3c9ee93202ce08cdcd3ed184694b5693f7461be7cf7e517139a278
5
5
  SHA512:
6
- metadata.gz: b39badbb4689a4ea93cbc65ad00f0c967f24dadcc41e7750ab82977176236d6d8609d8e7b74e13a3829ce008c4a5de90930e265f6b6e03af710811419da6ccf6
7
- data.tar.gz: 3ede92146cb181328657a4713e94473f86661dffe0a66d23f48edaa2c7a6c52543a7e7036794baa9dcc2945bc3f9e5eebd9192b70510bda1ad9c0d6e67253830
6
+ metadata.gz: be709e1aad1acee8d7c3e121e946060ce9b693ac80e25af200e2a579988f3952d6522cb9855917dc76628ae2038365bb8754b49a7cc6e90395706ba30fc87a86
7
+ data.tar.gz: 00102b01b4b37daab76fc90990f980a4710bec0e797a70d65a7544ef304f01f9b9babbdcc680da71513dd8f79649bd5f529e6804e71297b26978625bea746367
@@ -1,5 +1,49 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.2.0
4
+
5
+ * Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
6
+ * Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
7
+ * Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
8
+ * Add `Redis#exists?` to get a Boolean if any of the keys exists.
9
+ * `Redis#exists` when called with a single key will warn that future versions will return an Integer.
10
+ Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
11
+ * Support `keepttl` ooption in `set`. See #913.
12
+ * Optimized initialization of Redis::Cluster. See #912.
13
+ * Accept sentinel options even with string key. See #599.
14
+ * Verify TLS connections by default. See #900.
15
+
16
+ # 4.1.4
17
+
18
+ * Alias `Redis#disconnect` as `#close`. See #901.
19
+ * Handle clusters with multiple slot ranges. See #894.
20
+ * Fix password authentication to a redis cluster. See #889.
21
+ * Handle recursive MOVED responses. See #882.
22
+ * Increase buffer size in the ruby connector. See #880.
23
+ * Fix thread safety of `Redis.queue`. See #878.
24
+ * Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
25
+ * Support `KEEPTTL` option for SET command. See #913.
26
+
27
+ # 4.1.3
28
+
29
+ * Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
30
+
31
+ # 4.1.2
32
+
33
+ * Fix several authentication problems with sentinel. See #850 and #856.
34
+ * Explicitly drop Ruby 2.2 support.
35
+
36
+
37
+ # 4.1.1
38
+
39
+ * Fix error handling in multi blocks. See #754.
40
+ * Fix geoadd to accept arrays like georadius and georadiusbymember. See #841.
41
+ * Fix georadius command failing when long == lat. See #841.
42
+ * Fix timeout error in xread block: 0. See #837.
43
+ * Fix incompatibility issue with redis-objects. See #834.
44
+ * Properly handle Errno::EADDRNOTAVAIL on connect.
45
+ * Fix password authentication to sentinel instances. See #813.
46
+
3
47
  # 4.1.0
4
48
 
5
49
  * Add Redis Cluster support. See #716.
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.
@@ -95,10 +99,60 @@ but a few so that if one is down the client will try the next one. The client
95
99
  is able to remember the last Sentinel that was able to reply correctly and will
96
100
  use it for the next requests.
97
101
 
102
+ If you want to [authenticate](https://redis.io/topics/sentinel#configuring-sentinel-instances-with-authentication) Sentinel itself, you must specify the `password` option per instance.
103
+
104
+ ```ruby
105
+ SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
106
+ { host: '127.0.0.1', port: 26381, password: 'mysecret' }]
107
+
108
+ redis = Redis.new(host: 'mymaster', sentinels: SENTINELS, role: :master)
109
+ ```
110
+
111
+ ## Cluster support
112
+
113
+ `redis-rb` supports [clustering](https://redis.io/topics/cluster-spec).
114
+
115
+ ```ruby
116
+ # Nodes can be passed to the client as an array of connection URLs.
117
+ nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
118
+ redis = Redis.new(cluster: nodes)
119
+
120
+ # You can also specify the options as a Hash. The options are the same as for a single server connection.
121
+ (7000..7005).map { |port| { host: '127.0.0.1', port: port } }
122
+ ```
123
+
124
+ You can also specify only a subset of the nodes, and the client will discover the missing ones using the [CLUSTER NODES](https://redis.io/commands/cluster-nodes) command.
125
+
126
+ ```ruby
127
+ Redis.new(cluster: %w[redis://127.0.0.1:7000])
128
+ ```
129
+
130
+ If you want [the connection to be able to read from any replica](https://redis.io/commands/readonly), you must pass the `replica: true`. Note that this connection won't be usable to write keys.
131
+
132
+ ```ruby
133
+ Redis.new(cluster: nodes, replica: true)
134
+ ```
135
+
136
+ The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
137
+
138
+ ```ruby
139
+ redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
140
+
141
+ redis.mget('key1', 'key2')
142
+ #=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
143
+
144
+ redis.mget('{key}1', '{key}2')
145
+ #=> [nil, nil]
146
+ ```
147
+
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.
150
+ * The client supports `MOVED` and `ASK` redirections transparently.
151
+
98
152
  ## Storing objects
99
153
 
100
- Redis only stores strings as values. If you want to store an object, you
101
- 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:
102
156
 
103
157
  ```ruby
104
158
  require "json"
@@ -272,7 +326,7 @@ This library supports natively terminating client side SSL/TLS connections
272
326
  when talking to Redis via a server-side proxy such as [stunnel], [hitch],
273
327
  or [ghostunnel].
274
328
 
275
- 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
276
330
  Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
277
331
  You will also need to pass in an `:ssl_params => { ... }` hash used to
278
332
  configure the `OpenSSL::SSL::SSLContext` object used for the connection:
@@ -387,6 +441,10 @@ redis = Redis.new(:driver => :synchrony)
387
441
  This library is tested against recent Ruby and Redis versions.
388
442
  Check [Travis][travis-link] for the exact versions supported.
389
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
+
390
448
  ## Contributors
391
449
 
392
450
  Several people contributed to redis-rb, but we would like to especially
@@ -397,7 +455,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
397
455
  ## Contributing
398
456
 
399
457
  [Fork the project](https://github.com/redis/redis-rb) and send pull
400
- requests. You can also ask for help at `#redis-rb` on Freenode.
458
+ requests.
401
459
 
402
460
 
403
461
  [inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
@@ -1,33 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "monitor"
2
4
  require_relative "redis/errors"
3
5
 
4
6
  class Redis
7
+ class << self
8
+ attr_accessor :exists_returns_integer
9
+ attr_writer :current
10
+ end
5
11
 
6
12
  def self.current
7
13
  @current ||= Redis.new
8
14
  end
9
15
 
10
- def self.current=(redis)
11
- @current = redis
12
- end
13
-
14
16
  include MonitorMixin
15
17
 
16
18
  # Create a new client instance
17
19
  #
18
20
  # @param [Hash] options
19
- # @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.
21
+ # @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
22
+ # `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
23
+ # connection: `unix://[path to Redis socket]`. This overrides all other options.
20
24
  # @option options [String] :host ("127.0.0.1") server hostname
21
- # @option options [Fixnum] :port (6379) server port
25
+ # @option options [Integer] :port (6379) server port
22
26
  # @option options [String] :path path to server socket (overrides host and port)
23
27
  # @option options [Float] :timeout (5.0) timeout in seconds
24
28
  # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
25
29
  # @option options [String] :password Password to authenticate against server
26
- # @option options [Fixnum] :db (0) Database to select after initial connect
30
+ # @option options [Integer] :db (0) Database to select after initial connect
27
31
  # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
28
- # @option options [String] :id ID for the client connection, assigns name to current connection by sending `CLIENT SETNAME`
29
- # @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
30
- # @option options [Fixnum] :reconnect_attempts Number of attempts trying to connect
32
+ # @option options [String] :id ID for the client connection, assigns name to current connection by sending
33
+ # `CLIENT SETNAME`
34
+ # @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
35
+ # based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
36
+ # @option options [Integer] :reconnect_attempts Number of attempts trying to connect
31
37
  # @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
32
38
  # @option options [Array] :sentinels List of sentinels to contact
33
39
  # @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
@@ -51,7 +57,7 @@ class Redis
51
57
  end
52
58
 
53
59
  # Run code with the client reconnecting
54
- def with_reconnect(val=true, &blk)
60
+ def with_reconnect(val = true, &blk)
55
61
  synchronize do |client|
56
62
  client.with_reconnect(val, &blk)
57
63
  end
@@ -94,7 +100,9 @@ class Redis
94
100
  # See http://redis.io/topics/pipelining for more details.
95
101
  #
96
102
  def queue(*command)
97
- @queue[Thread.current.object_id] << command
103
+ synchronize do
104
+ @queue[Thread.current.object_id] << command
105
+ end
98
106
  end
99
107
 
100
108
  # Sends all commands in the queue.
@@ -104,7 +112,12 @@ class Redis
104
112
  def commit
105
113
  synchronize do |client|
106
114
  begin
107
- client.call_pipelined(@queue[Thread.current.object_id])
115
+ pipeline = Pipeline.new(client)
116
+ @queue[Thread.current.object_id].each do |command|
117
+ pipeline.call(command)
118
+ end
119
+
120
+ client.call_pipelined(pipeline)
108
121
  ensure
109
122
  @queue.delete(Thread.current.object_id)
110
123
  end
@@ -128,7 +141,7 @@ class Redis
128
141
 
129
142
  # Change the selected database for the current connection.
130
143
  #
131
- # @param [Fixnum] db zero-based index of the DB to use (0 to 15)
144
+ # @param [Integer] db zero-based index of the DB to use (0 to 15)
132
145
  # @return [String] `OK`
133
146
  def select(db)
134
147
  synchronize do |client|
@@ -197,7 +210,7 @@ class Redis
197
210
  def config(action, *args)
198
211
  synchronize do |client|
199
212
  client.call([:config, action] + args) do |reply|
200
- if reply.kind_of?(Array) && action == :get
213
+ if reply.is_a?(Array) && action == :get
201
214
  Hashify.call(reply)
202
215
  else
203
216
  reply
@@ -227,7 +240,7 @@ class Redis
227
240
 
228
241
  # Return the number of keys in the selected database.
229
242
  #
230
- # @return [Fixnum]
243
+ # @return [Integer]
231
244
  def dbsize
232
245
  synchronize do |client|
233
246
  client.call([:dbsize])
@@ -248,7 +261,7 @@ class Redis
248
261
  def flushall(options = nil)
249
262
  synchronize do |client|
250
263
  if options && options[:async]
251
- client.call([:flushall, :async])
264
+ client.call(%i[flushall async])
252
265
  else
253
266
  client.call([:flushall])
254
267
  end
@@ -263,7 +276,7 @@ class Redis
263
276
  def flushdb(options = nil)
264
277
  synchronize do |client|
265
278
  if options && options[:async]
266
- client.call([:flushdb, :async])
279
+ client.call(%i[flushdb async])
267
280
  else
268
281
  client.call([:flushdb])
269
282
  end
@@ -277,7 +290,7 @@ class Redis
277
290
  def info(cmd = nil)
278
291
  synchronize do |client|
279
292
  client.call([:info, cmd].compact) do |reply|
280
- if reply.kind_of?(String)
293
+ if reply.is_a?(String)
281
294
  reply = HashifyInfo.call(reply)
282
295
 
283
296
  if cmd && cmd.to_s == "commandstats"
@@ -296,7 +309,7 @@ class Redis
296
309
 
297
310
  # Get the UNIX time stamp of the last successful save to disk.
298
311
  #
299
- # @return [Fixnum]
312
+ # @return [Integer]
300
313
  def lastsave
301
314
  synchronize do |client|
302
315
  client.call([:lastsave])
@@ -348,9 +361,9 @@ class Redis
348
361
  # Interact with the slowlog (get, len, reset)
349
362
  #
350
363
  # @param [String] subcommand e.g. `get`, `len`, `reset`
351
- # @param [Fixnum] length maximum number of entries to return
352
- # @return [Array<String>, Fixnum, String] depends on subcommand
353
- def slowlog(subcommand, length=nil)
364
+ # @param [Integer] length maximum number of entries to return
365
+ # @return [Array<String>, Integer, String] depends on subcommand
366
+ def slowlog(subcommand, length = nil)
354
367
  synchronize do |client|
355
368
  args = [:slowlog, subcommand]
356
369
  args << length if length
@@ -370,12 +383,12 @@ class Redis
370
383
  # @example
371
384
  # r.time # => [ 1333093196, 606806 ]
372
385
  #
373
- # @return [Array<Fixnum>] tuple of seconds since UNIX epoch and
386
+ # @return [Array<Integer>] tuple of seconds since UNIX epoch and
374
387
  # microseconds in the current second
375
388
  def time
376
389
  synchronize do |client|
377
390
  client.call([:time]) do |reply|
378
- reply.map(&:to_i) if reply
391
+ reply&.map(&:to_i)
379
392
  end
380
393
  end
381
394
  end
@@ -393,7 +406,7 @@ class Redis
393
406
  # Set a key's time to live in seconds.
394
407
  #
395
408
  # @param [String] key
396
- # @param [Fixnum] seconds time to live
409
+ # @param [Integer] seconds time to live
397
410
  # @return [Boolean] whether the timeout was set or not
398
411
  def expire(key, seconds)
399
412
  synchronize do |client|
@@ -404,7 +417,7 @@ class Redis
404
417
  # Set the expiration for a key as a UNIX timestamp.
405
418
  #
406
419
  # @param [String] key
407
- # @param [Fixnum] unix_time expiry time specified as a UNIX timestamp
420
+ # @param [Integer] unix_time expiry time specified as a UNIX timestamp
408
421
  # @return [Boolean] whether the timeout was set or not
409
422
  def expireat(key, unix_time)
410
423
  synchronize do |client|
@@ -415,7 +428,7 @@ class Redis
415
428
  # Get the time to live (in seconds) for a key.
416
429
  #
417
430
  # @param [String] key
418
- # @return [Fixnum] remaining time to live in seconds.
431
+ # @return [Integer] remaining time to live in seconds.
419
432
  #
420
433
  # In Redis 2.6 or older the command returns -1 if the key does not exist or if
421
434
  # the key exist but has no associated expire.
@@ -433,7 +446,7 @@ class Redis
433
446
  # Set a key's time to live in milliseconds.
434
447
  #
435
448
  # @param [String] key
436
- # @param [Fixnum] milliseconds time to live
449
+ # @param [Integer] milliseconds time to live
437
450
  # @return [Boolean] whether the timeout was set or not
438
451
  def pexpire(key, milliseconds)
439
452
  synchronize do |client|
@@ -444,7 +457,7 @@ class Redis
444
457
  # Set the expiration for a key as number of milliseconds from UNIX Epoch.
445
458
  #
446
459
  # @param [String] key
447
- # @param [Fixnum] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
460
+ # @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
448
461
  # @return [Boolean] whether the timeout was set or not
449
462
  def pexpireat(key, ms_unix_time)
450
463
  synchronize do |client|
@@ -455,7 +468,7 @@ class Redis
455
468
  # Get the time to live (in milliseconds) for a key.
456
469
  #
457
470
  # @param [String] key
458
- # @return [Fixnum] remaining time to live in milliseconds
471
+ # @return [Integer] remaining time to live in milliseconds
459
472
  # In Redis 2.6 or older the command returns -1 if the key does not exist or if
460
473
  # the key exist but has no associated expire.
461
474
  #
@@ -488,9 +501,9 @@ class Redis
488
501
  # - `:replace => Boolean`: if false, raises an error if key already exists
489
502
  # @raise [Redis::CommandError]
490
503
  # @return [String] `"OK"`
491
- def restore(key, ttl, serialized_value, options = {})
504
+ def restore(key, ttl, serialized_value, replace: nil)
492
505
  args = [:restore, key, ttl, serialized_value]
493
- args << 'REPLACE' if options[:replace]
506
+ args << 'REPLACE' if replace
494
507
 
495
508
  synchronize do |client|
496
509
  client.call(args)
@@ -525,7 +538,7 @@ class Redis
525
538
  # Delete one or more keys.
526
539
  #
527
540
  # @param [String, Array<String>] keys
528
- # @return [Fixnum] number of keys that were deleted
541
+ # @return [Integer] number of keys that were deleted
529
542
  def del(*keys)
530
543
  synchronize do |client|
531
544
  client.call([:del] + keys)
@@ -535,20 +548,43 @@ class Redis
535
548
  # Unlink one or more keys.
536
549
  #
537
550
  # @param [String, Array<String>] keys
538
- # @return [Fixnum] number of keys that were unlinked
551
+ # @return [Integer] number of keys that were unlinked
539
552
  def unlink(*keys)
540
553
  synchronize do |client|
541
554
  client.call([:unlink] + keys)
542
555
  end
543
556
  end
544
557
 
545
- # Determine if a key exists.
558
+ # Determine how many of the keys exists.
546
559
  #
547
- # @param [String] key
560
+ # @param [String, Array<String>] keys
561
+ # @return [Integer]
562
+ def exists(*keys)
563
+ if !Redis.exists_returns_integer && keys.size == 1
564
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
565
+ "use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
566
+ "(#{::Kernel.caller(1, 1).first})\n"
567
+
568
+ ::Kernel.warn(message)
569
+ exists?(*keys)
570
+ else
571
+ _exists(*keys)
572
+ end
573
+ end
574
+
575
+ def _exists(*keys)
576
+ synchronize do |client|
577
+ client.call([:exists, *keys])
578
+ end
579
+ end
580
+
581
+ # Determine if any of the keys exists.
582
+ #
583
+ # @param [String, Array<String>] keys
548
584
  # @return [Boolean]
549
- def exists(key)
585
+ def exists?(*keys)
550
586
  synchronize do |client|
551
- client.call([:exists, key], &Boolify)
587
+ client.call([:exists, *keys], &Boolify)
552
588
  end
553
589
  end
554
590
 
@@ -559,7 +595,7 @@ class Redis
559
595
  def keys(pattern = "*")
560
596
  synchronize do |client|
561
597
  client.call([:keys, pattern]) do |reply|
562
- if reply.kind_of?(String)
598
+ if reply.is_a?(String)
563
599
  reply.split(" ")
564
600
  else
565
601
  reply
@@ -585,7 +621,7 @@ class Redis
585
621
  # # => "bar"
586
622
  #
587
623
  # @param [String] key
588
- # @param [Fixnum] db
624
+ # @param [Integer] db
589
625
  # @return [Boolean] whether the key was moved or not
590
626
  def move(key, db)
591
627
  synchronize do |client|
@@ -649,36 +685,33 @@ class Redis
649
685
  # - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
650
686
  # - `:store => String`: key to store the result at
651
687
  #
652
- # @return [Array<String>, Array<Array<String>>, Fixnum]
688
+ # @return [Array<String>, Array<Array<String>>, Integer]
653
689
  # - when `:get` is not specified, or holds a single element, an array of elements
654
690
  # - when `:get` is specified, and holds more than one element, an array of
655
691
  # elements where every element is an array with the result for every
656
692
  # element specified in `:get`
657
693
  # - when `:store` is specified, the number of elements in the stored result
658
- def sort(key, options = {})
659
- args = []
660
-
661
- by = options[:by]
662
- args.concat(["BY", by]) if by
694
+ def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
695
+ args = [:sort, key]
696
+ args << "BY" << by if by
663
697
 
664
- limit = options[:limit]
665
- args.concat(["LIMIT"] + limit) if limit
698
+ if limit
699
+ args << "LIMIT"
700
+ args.concat(limit)
701
+ end
666
702
 
667
- get = Array(options[:get])
668
- args.concat(["GET"].product(get).flatten) unless get.empty?
703
+ get = Array(get)
704
+ get.each do |item|
705
+ args << "GET" << item
706
+ end
669
707
 
670
- order = options[:order]
671
708
  args.concat(order.split(" ")) if order
672
-
673
- store = options[:store]
674
- args.concat(["STORE", store]) if store
709
+ args << "STORE" << store if store
675
710
 
676
711
  synchronize do |client|
677
- client.call([:sort, key] + args) do |reply|
712
+ client.call(args) do |reply|
678
713
  if get.size > 1 && !store
679
- if reply
680
- reply.each_slice(get.size).to_a
681
- end
714
+ reply.each_slice(get.size).to_a if reply
682
715
  else
683
716
  reply
684
717
  end
@@ -703,7 +736,7 @@ class Redis
703
736
  # # => 4
704
737
  #
705
738
  # @param [String] key
706
- # @return [Fixnum] value after decrementing it
739
+ # @return [Integer] value after decrementing it
707
740
  def decr(key)
708
741
  synchronize do |client|
709
742
  client.call([:decr, key])
@@ -717,8 +750,8 @@ class Redis
717
750
  # # => 0
718
751
  #
719
752
  # @param [String] key
720
- # @param [Fixnum] decrement
721
- # @return [Fixnum] value after decrementing it
753
+ # @param [Integer] decrement
754
+ # @return [Integer] value after decrementing it
722
755
  def decrby(key, decrement)
723
756
  synchronize do |client|
724
757
  client.call([:decrby, key, decrement])
@@ -732,7 +765,7 @@ class Redis
732
765
  # # => 6
733
766
  #
734
767
  # @param [String] key
735
- # @return [Fixnum] value after incrementing it
768
+ # @return [Integer] value after incrementing it
736
769
  def incr(key)
737
770
  synchronize do |client|
738
771
  client.call([:incr, key])
@@ -746,8 +779,8 @@ class Redis
746
779
  # # => 10
747
780
  #
748
781
  # @param [String] key
749
- # @param [Fixnum] increment
750
- # @return [Fixnum] value after incrementing it
782
+ # @param [Integer] increment
783
+ # @return [Integer] value after incrementing it
751
784
  def incrby(key, increment)
752
785
  synchronize do |client|
753
786
  client.call([:incrby, key, increment])
@@ -774,31 +807,25 @@ class Redis
774
807
  # @param [String] key
775
808
  # @param [String] value
776
809
  # @param [Hash] options
777
- # - `:ex => Fixnum`: Set the specified expire time, in seconds.
778
- # - `:px => Fixnum`: Set the specified expire time, in milliseconds.
810
+ # - `:ex => Integer`: Set the specified expire time, in seconds.
811
+ # - `:px => Integer`: Set the specified expire time, in milliseconds.
779
812
  # - `:nx => true`: Only set the key if it does not already exist.
780
813
  # - `:xx => true`: Only set the key if it already exist.
814
+ # - `:keepttl => true`: Retain the time to live associated with the key.
781
815
  # @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
782
- def set(key, value, options = {})
783
- args = []
784
-
785
- ex = options[:ex]
786
- args.concat(["EX", ex]) if ex
787
-
788
- px = options[:px]
789
- args.concat(["PX", px]) if px
790
-
791
- nx = options[:nx]
792
- args.concat(["NX"]) if nx
793
-
794
- xx = options[:xx]
795
- args.concat(["XX"]) if xx
816
+ def set(key, value, ex: nil, px: nil, nx: nil, xx: nil, keepttl: nil)
817
+ args = [:set, key, value.to_s]
818
+ args << "EX" << ex if ex
819
+ args << "PX" << px if px
820
+ args << "NX" if nx
821
+ args << "XX" if xx
822
+ args << "KEEPTTL" if keepttl
796
823
 
797
824
  synchronize do |client|
798
825
  if nx || xx
799
- client.call([:set, key, value.to_s] + args, &BoolifySet)
826
+ client.call(args, &BoolifySet)
800
827
  else
801
- client.call([:set, key, value.to_s] + args)
828
+ client.call(args)
802
829
  end
803
830
  end
804
831
  end
@@ -806,7 +833,7 @@ class Redis
806
833
  # Set the time to live in seconds of a key.
807
834
  #
808
835
  # @param [String] key
809
- # @param [Fixnum] ttl
836
+ # @param [Integer] ttl
810
837
  # @param [String] value
811
838
  # @return [String] `"OK"`
812
839
  def setex(key, ttl, value)
@@ -818,7 +845,7 @@ class Redis
818
845
  # Set the time to live in milliseconds of a key.
819
846
  #
820
847
  # @param [String] key
821
- # @param [Fixnum] ttl
848
+ # @param [Integer] ttl
822
849
  # @param [String] value
823
850
  # @return [String] `"OK"`
824
851
  def psetex(key, ttl, value)
@@ -880,7 +907,7 @@ class Redis
880
907
  # @see #mapped_msetnx
881
908
  def msetnx(*args)
882
909
  synchronize do |client|
883
- client.call([:msetnx] + args, &Boolify)
910
+ client.call([:msetnx, *args], &Boolify)
884
911
  end
885
912
  end
886
913
 
@@ -911,7 +938,7 @@ class Redis
911
938
  # Get the values of all the given keys.
912
939
  #
913
940
  # @example
914
- # redis.mget("key1", "key1")
941
+ # redis.mget("key1", "key2")
915
942
  # # => ["v1", "v2"]
916
943
  #
917
944
  # @param [Array<String>] keys
@@ -920,7 +947,7 @@ class Redis
920
947
  # @see #mapped_mget
921
948
  def mget(*keys, &blk)
922
949
  synchronize do |client|
923
- client.call([:mget] + keys, &blk)
950
+ client.call([:mget, *keys], &blk)
924
951
  end
925
952
  end
926
953
 
@@ -936,7 +963,7 @@ class Redis
936
963
  # @see #mget
937
964
  def mapped_mget(*keys)
938
965
  mget(*keys) do |reply|
939
- if reply.kind_of?(Array)
966
+ if reply.is_a?(Array)
940
967
  Hash[keys.zip(reply)]
941
968
  else
942
969
  reply
@@ -947,9 +974,9 @@ class Redis
947
974
  # Overwrite part of a string at key starting at the specified offset.
948
975
  #
949
976
  # @param [String] key
950
- # @param [Fixnum] offset byte offset
977
+ # @param [Integer] offset byte offset
951
978
  # @param [String] value
952
- # @return [Fixnum] length of the string after it was modified
979
+ # @return [Integer] length of the string after it was modified
953
980
  def setrange(key, offset, value)
954
981
  synchronize do |client|
955
982
  client.call([:setrange, key, offset, value.to_s])
@@ -959,10 +986,10 @@ class Redis
959
986
  # Get a substring of the string stored at a key.
960
987
  #
961
988
  # @param [String] key
962
- # @param [Fixnum] start zero-based start offset
963
- # @param [Fixnum] stop zero-based end offset. Use -1 for representing
989
+ # @param [Integer] start zero-based start offset
990
+ # @param [Integer] stop zero-based end offset. Use -1 for representing
964
991
  # the end of the string
965
- # @return [Fixnum] `0` or `1`
992
+ # @return [Integer] `0` or `1`
966
993
  def getrange(key, start, stop)
967
994
  synchronize do |client|
968
995
  client.call([:getrange, key, start, stop])
@@ -972,9 +999,9 @@ class Redis
972
999
  # Sets or clears the bit at offset in the string value stored at key.
973
1000
  #
974
1001
  # @param [String] key
975
- # @param [Fixnum] offset bit offset
976
- # @param [Fixnum] value bit value `0` or `1`
977
- # @return [Fixnum] the original bit value stored at `offset`
1002
+ # @param [Integer] offset bit offset
1003
+ # @param [Integer] value bit value `0` or `1`
1004
+ # @return [Integer] the original bit value stored at `offset`
978
1005
  def setbit(key, offset, value)
979
1006
  synchronize do |client|
980
1007
  client.call([:setbit, key, offset, value])
@@ -984,8 +1011,8 @@ class Redis
984
1011
  # Returns the bit value at offset in the string value stored at key.
985
1012
  #
986
1013
  # @param [String] key
987
- # @param [Fixnum] offset bit offset
988
- # @return [Fixnum] `0` or `1`
1014
+ # @param [Integer] offset bit offset
1015
+ # @return [Integer] `0` or `1`
989
1016
  def getbit(key, offset)
990
1017
  synchronize do |client|
991
1018
  client.call([:getbit, key, offset])
@@ -996,7 +1023,7 @@ class Redis
996
1023
  #
997
1024
  # @param [String] key
998
1025
  # @param [String] value value to append
999
- # @return [Fixnum] length of the string after appending
1026
+ # @return [Integer] length of the string after appending
1000
1027
  def append(key, value)
1001
1028
  synchronize do |client|
1002
1029
  client.call([:append, key, value])
@@ -1006,9 +1033,9 @@ class Redis
1006
1033
  # Count the number of set bits in a range of the string value stored at key.
1007
1034
  #
1008
1035
  # @param [String] key
1009
- # @param [Fixnum] start start index
1010
- # @param [Fixnum] stop stop index
1011
- # @return [Fixnum] the number of bits set to 1
1036
+ # @param [Integer] start start index
1037
+ # @param [Integer] stop stop index
1038
+ # @return [Integer] the number of bits set to 1
1012
1039
  def bitcount(key, start = 0, stop = -1)
1013
1040
  synchronize do |client|
1014
1041
  client.call([:bitcount, key, start, stop])
@@ -1020,25 +1047,23 @@ class Redis
1020
1047
  # @param [String] operation e.g. `and`, `or`, `xor`, `not`
1021
1048
  # @param [String] destkey destination key
1022
1049
  # @param [String, Array<String>] keys one or more source keys to perform `operation`
1023
- # @return [Fixnum] the length of the string stored in `destkey`
1050
+ # @return [Integer] the length of the string stored in `destkey`
1024
1051
  def bitop(operation, destkey, *keys)
1025
1052
  synchronize do |client|
1026
- client.call([:bitop, operation, destkey] + keys)
1053
+ client.call([:bitop, operation, destkey, *keys])
1027
1054
  end
1028
1055
  end
1029
1056
 
1030
1057
  # Return the position of the first bit set to 1 or 0 in a string.
1031
1058
  #
1032
1059
  # @param [String] key
1033
- # @param [Fixnum] bit whether to look for the first 1 or 0 bit
1034
- # @param [Fixnum] start start index
1035
- # @param [Fixnum] stop stop index
1036
- # @return [Fixnum] the position of the first 1/0 bit.
1060
+ # @param [Integer] bit whether to look for the first 1 or 0 bit
1061
+ # @param [Integer] start start index
1062
+ # @param [Integer] stop stop index
1063
+ # @return [Integer] the position of the first 1/0 bit.
1037
1064
  # -1 if looking for 1 and it is not found or start and stop are given.
1038
- def bitpos(key, bit, start=nil, stop=nil)
1039
- if stop and not start
1040
- raise(ArgumentError, 'stop parameter specified without start parameter')
1041
- end
1065
+ def bitpos(key, bit, start = nil, stop = nil)
1066
+ raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
1042
1067
 
1043
1068
  synchronize do |client|
1044
1069
  command = [:bitpos, key, bit]
@@ -1063,7 +1088,7 @@ class Redis
1063
1088
  # Get the length of the value stored in a key.
1064
1089
  #
1065
1090
  # @param [String] key
1066
- # @return [Fixnum] the length of the value stored in the key, or 0
1091
+ # @return [Integer] the length of the value stored in the key, or 0
1067
1092
  # if the key does not exist
1068
1093
  def strlen(key)
1069
1094
  synchronize do |client|
@@ -1074,7 +1099,7 @@ class Redis
1074
1099
  # Get the length of a list.
1075
1100
  #
1076
1101
  # @param [String] key
1077
- # @return [Fixnum]
1102
+ # @return [Integer]
1078
1103
  def llen(key)
1079
1104
  synchronize do |client|
1080
1105
  client.call([:llen, key])
@@ -1085,7 +1110,7 @@ class Redis
1085
1110
  #
1086
1111
  # @param [String] key
1087
1112
  # @param [String, Array<String>] value string value, or array of string values to push
1088
- # @return [Fixnum] the length of the list after the push operation
1113
+ # @return [Integer] the length of the list after the push operation
1089
1114
  def lpush(key, value)
1090
1115
  synchronize do |client|
1091
1116
  client.call([:lpush, key, value])
@@ -1096,7 +1121,7 @@ class Redis
1096
1121
  #
1097
1122
  # @param [String] key
1098
1123
  # @param [String] value
1099
- # @return [Fixnum] the length of the list after the push operation
1124
+ # @return [Integer] the length of the list after the push operation
1100
1125
  def lpushx(key, value)
1101
1126
  synchronize do |client|
1102
1127
  client.call([:lpushx, key, value])
@@ -1107,7 +1132,7 @@ class Redis
1107
1132
  #
1108
1133
  # @param [String] key
1109
1134
  # @param [String, Array<String>] value string value, or array of string values to push
1110
- # @return [Fixnum] the length of the list after the push operation
1135
+ # @return [Integer] the length of the list after the push operation
1111
1136
  def rpush(key, value)
1112
1137
  synchronize do |client|
1113
1138
  client.call([:rpush, key, value])
@@ -1118,7 +1143,7 @@ class Redis
1118
1143
  #
1119
1144
  # @param [String] key
1120
1145
  # @param [String] value
1121
- # @return [Fixnum] the length of the list after the push operation
1146
+ # @return [Integer] the length of the list after the push operation
1122
1147
  def rpushx(key, value)
1123
1148
  synchronize do |client|
1124
1149
  client.call([:rpushx, key, value])
@@ -1157,21 +1182,21 @@ class Redis
1157
1182
  end
1158
1183
 
1159
1184
  def _bpop(cmd, args, &blk)
1160
- options = {}
1161
-
1162
- if args.last.is_a?(Hash)
1185
+ timeout = if args.last.is_a?(Hash)
1163
1186
  options = args.pop
1187
+ options[:timeout]
1164
1188
  elsif args.last.respond_to?(:to_int)
1165
1189
  # Issue deprecation notice in obnoxious mode...
1166
- options[:timeout] = args.pop.to_int
1190
+ args.pop.to_int
1167
1191
  end
1168
1192
 
1193
+ timeout ||= 0
1194
+
1169
1195
  if args.size > 1
1170
1196
  # Issue deprecation notice in obnoxious mode...
1171
1197
  end
1172
1198
 
1173
1199
  keys = args.flatten
1174
- timeout = options[:timeout] || 0
1175
1200
 
1176
1201
  synchronize do |client|
1177
1202
  command = [cmd, keys, timeout]
@@ -1196,7 +1221,7 @@ class Redis
1196
1221
  # @param [String, Array<String>] keys one or more keys to perform the
1197
1222
  # blocking pop on
1198
1223
  # @param [Hash] options
1199
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1224
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1200
1225
  #
1201
1226
  # @return [nil, [String, String]]
1202
1227
  # - `nil` when the operation timed out
@@ -1210,7 +1235,7 @@ class Redis
1210
1235
  # @param [String, Array<String>] keys one or more keys to perform the
1211
1236
  # blocking pop on
1212
1237
  # @param [Hash] options
1213
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1238
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1214
1239
  #
1215
1240
  # @return [nil, [String, String]]
1216
1241
  # - `nil` when the operation timed out
@@ -1227,20 +1252,12 @@ class Redis
1227
1252
  # @param [String] source source key
1228
1253
  # @param [String] destination destination key
1229
1254
  # @param [Hash] options
1230
- # - `:timeout => Fixnum`: timeout in seconds, defaults to no timeout
1255
+ # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
1231
1256
  #
1232
1257
  # @return [nil, String]
1233
1258
  # - `nil` when the operation timed out
1234
1259
  # - the element was popped and pushed otherwise
1235
- def brpoplpush(source, destination, options = {})
1236
- case options
1237
- when Integer
1238
- # Issue deprecation notice in obnoxious mode...
1239
- options = { :timeout => options }
1240
- end
1241
-
1242
- timeout = options[:timeout] || 0
1243
-
1260
+ def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
1244
1261
  synchronize do |client|
1245
1262
  command = [:brpoplpush, source, destination, timeout]
1246
1263
  timeout += client.timeout if timeout > 0
@@ -1251,7 +1268,7 @@ class Redis
1251
1268
  # Get an element from a list by its index.
1252
1269
  #
1253
1270
  # @param [String] key
1254
- # @param [Fixnum] index
1271
+ # @param [Integer] index
1255
1272
  # @return [String]
1256
1273
  def lindex(key, index)
1257
1274
  synchronize do |client|
@@ -1265,7 +1282,7 @@ class Redis
1265
1282
  # @param [String, Symbol] where `BEFORE` or `AFTER`
1266
1283
  # @param [String] pivot reference element
1267
1284
  # @param [String] value
1268
- # @return [Fixnum] length of the list after the insert operation, or `-1`
1285
+ # @return [Integer] length of the list after the insert operation, or `-1`
1269
1286
  # when the element `pivot` was not found
1270
1287
  def linsert(key, where, pivot, value)
1271
1288
  synchronize do |client|
@@ -1276,8 +1293,8 @@ class Redis
1276
1293
  # Get a range of elements from a list.
1277
1294
  #
1278
1295
  # @param [String] key
1279
- # @param [Fixnum] start start index
1280
- # @param [Fixnum] stop stop index
1296
+ # @param [Integer] start start index
1297
+ # @param [Integer] stop stop index
1281
1298
  # @return [Array<String>]
1282
1299
  def lrange(key, start, stop)
1283
1300
  synchronize do |client|
@@ -1288,12 +1305,12 @@ class Redis
1288
1305
  # Remove elements from a list.
1289
1306
  #
1290
1307
  # @param [String] key
1291
- # @param [Fixnum] count number of elements to remove. Use a positive
1308
+ # @param [Integer] count number of elements to remove. Use a positive
1292
1309
  # value to remove the first `count` occurrences of `value`. A negative
1293
1310
  # value to remove the last `count` occurrences of `value`. Or zero, to
1294
1311
  # remove all occurrences of `value` from the list.
1295
1312
  # @param [String] value
1296
- # @return [Fixnum] the number of removed elements
1313
+ # @return [Integer] the number of removed elements
1297
1314
  def lrem(key, count, value)
1298
1315
  synchronize do |client|
1299
1316
  client.call([:lrem, key, count, value])
@@ -1303,7 +1320,7 @@ class Redis
1303
1320
  # Set the value of an element in a list by its index.
1304
1321
  #
1305
1322
  # @param [String] key
1306
- # @param [Fixnum] index
1323
+ # @param [Integer] index
1307
1324
  # @param [String] value
1308
1325
  # @return [String] `OK`
1309
1326
  def lset(key, index, value)
@@ -1315,8 +1332,8 @@ class Redis
1315
1332
  # Trim a list to the specified range.
1316
1333
  #
1317
1334
  # @param [String] key
1318
- # @param [Fixnum] start start index
1319
- # @param [Fixnum] stop stop index
1335
+ # @param [Integer] start start index
1336
+ # @param [Integer] stop stop index
1320
1337
  # @return [String] `OK`
1321
1338
  def ltrim(key, start, stop)
1322
1339
  synchronize do |client|
@@ -1327,7 +1344,7 @@ class Redis
1327
1344
  # Get the number of members in a set.
1328
1345
  #
1329
1346
  # @param [String] key
1330
- # @return [Fixnum]
1347
+ # @return [Integer]
1331
1348
  def scard(key)
1332
1349
  synchronize do |client|
1333
1350
  client.call([:scard, key])
@@ -1338,8 +1355,8 @@ class Redis
1338
1355
  #
1339
1356
  # @param [String] key
1340
1357
  # @param [String, Array<String>] member one member, or array of members
1341
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1342
- # holding whether or not adding the member succeeded, or `Fixnum` when an
1358
+ # @return [Boolean, Integer] `Boolean` when a single member is specified,
1359
+ # holding whether or not adding the member succeeded, or `Integer` when an
1343
1360
  # array of members is specified, holding the number of members that were
1344
1361
  # successfully added
1345
1362
  def sadd(key, member)
@@ -1360,8 +1377,8 @@ class Redis
1360
1377
  #
1361
1378
  # @param [String] key
1362
1379
  # @param [String, Array<String>] member one member, or array of members
1363
- # @return [Boolean, Fixnum] `Boolean` when a single member is specified,
1364
- # holding whether or not removing the member succeeded, or `Fixnum` when an
1380
+ # @return [Boolean, Integer] `Boolean` when a single member is specified,
1381
+ # holding whether or not removing the member succeeded, or `Integer` when an
1365
1382
  # array of members is specified, holding the number of members that were
1366
1383
  # successfully removed
1367
1384
  def srem(key, member)
@@ -1382,7 +1399,7 @@ class Redis
1382
1399
  #
1383
1400
  # @param [String] key
1384
1401
  # @return [String]
1385
- # @param [Fixnum] count
1402
+ # @param [Integer] count
1386
1403
  def spop(key, count = nil)
1387
1404
  synchronize do |client|
1388
1405
  if count.nil?
@@ -1396,7 +1413,7 @@ class Redis
1396
1413
  # Get one or more random members from a set.
1397
1414
  #
1398
1415
  # @param [String] key
1399
- # @param [Fixnum] count
1416
+ # @param [Integer] count
1400
1417
  # @return [String]
1401
1418
  def srandmember(key, count = nil)
1402
1419
  synchronize do |client|
@@ -1447,7 +1464,7 @@ class Redis
1447
1464
  # @return [Array<String>] members in the difference
1448
1465
  def sdiff(*keys)
1449
1466
  synchronize do |client|
1450
- client.call([:sdiff] + keys)
1467
+ client.call([:sdiff, *keys])
1451
1468
  end
1452
1469
  end
1453
1470
 
@@ -1455,10 +1472,10 @@ class Redis
1455
1472
  #
1456
1473
  # @param [String] destination destination key
1457
1474
  # @param [String, Array<String>] keys keys pointing to sets to subtract
1458
- # @return [Fixnum] number of elements in the resulting set
1475
+ # @return [Integer] number of elements in the resulting set
1459
1476
  def sdiffstore(destination, *keys)
1460
1477
  synchronize do |client|
1461
- client.call([:sdiffstore, destination] + keys)
1478
+ client.call([:sdiffstore, destination, *keys])
1462
1479
  end
1463
1480
  end
1464
1481
 
@@ -1468,7 +1485,7 @@ class Redis
1468
1485
  # @return [Array<String>] members in the intersection
1469
1486
  def sinter(*keys)
1470
1487
  synchronize do |client|
1471
- client.call([:sinter] + keys)
1488
+ client.call([:sinter, *keys])
1472
1489
  end
1473
1490
  end
1474
1491
 
@@ -1476,10 +1493,10 @@ class Redis
1476
1493
  #
1477
1494
  # @param [String] destination destination key
1478
1495
  # @param [String, Array<String>] keys keys pointing to sets to intersect
1479
- # @return [Fixnum] number of elements in the resulting set
1496
+ # @return [Integer] number of elements in the resulting set
1480
1497
  def sinterstore(destination, *keys)
1481
1498
  synchronize do |client|
1482
- client.call([:sinterstore, destination] + keys)
1499
+ client.call([:sinterstore, destination, *keys])
1483
1500
  end
1484
1501
  end
1485
1502
 
@@ -1489,7 +1506,7 @@ class Redis
1489
1506
  # @return [Array<String>] members in the union
1490
1507
  def sunion(*keys)
1491
1508
  synchronize do |client|
1492
- client.call([:sunion] + keys)
1509
+ client.call([:sunion, *keys])
1493
1510
  end
1494
1511
  end
1495
1512
 
@@ -1497,10 +1514,10 @@ class Redis
1497
1514
  #
1498
1515
  # @param [String] destination destination key
1499
1516
  # @param [String, Array<String>] keys keys pointing to sets to unify
1500
- # @return [Fixnum] number of elements in the resulting set
1517
+ # @return [Integer] number of elements in the resulting set
1501
1518
  def sunionstore(destination, *keys)
1502
1519
  synchronize do |client|
1503
- client.call([:sunionstore, destination] + keys)
1520
+ client.call([:sunionstore, destination, *keys])
1504
1521
  end
1505
1522
  end
1506
1523
 
@@ -1511,7 +1528,7 @@ class Redis
1511
1528
  # # => 4
1512
1529
  #
1513
1530
  # @param [String] key
1514
- # @return [Fixnum]
1531
+ # @return [Integer]
1515
1532
  def zcard(key)
1516
1533
  synchronize do |client|
1517
1534
  client.call([:zcard, key])
@@ -1542,38 +1559,27 @@ class Redis
1542
1559
  # - `:incr => true`: When this option is specified ZADD acts like
1543
1560
  # ZINCRBY; only one score-element pair can be specified in this mode
1544
1561
  #
1545
- # @return [Boolean, Fixnum, Float]
1562
+ # @return [Boolean, Integer, Float]
1546
1563
  # - `Boolean` when a single pair is specified, holding whether or not it was
1547
1564
  # **added** to the sorted set.
1548
- # - `Fixnum` when an array of pairs is specified, holding the number of
1565
+ # - `Integer` when an array of pairs is specified, holding the number of
1549
1566
  # pairs that were **added** to the sorted set.
1550
1567
  # - `Float` when option :incr is specified, holding the score of the member
1551
1568
  # after incrementing it.
1552
- def zadd(key, *args) #, options
1553
- zadd_options = []
1554
- if args.last.is_a?(Hash)
1555
- options = args.pop
1556
-
1557
- nx = options[:nx]
1558
- zadd_options << "NX" if nx
1559
-
1560
- xx = options[:xx]
1561
- zadd_options << "XX" if xx
1562
-
1563
- ch = options[:ch]
1564
- zadd_options << "CH" if ch
1565
-
1566
- incr = options[:incr]
1567
- zadd_options << "INCR" if incr
1568
- end
1569
+ def zadd(key, *args, nx: nil, xx: nil, ch: nil, incr: nil)
1570
+ command = [:zadd, key]
1571
+ command << "NX" if nx
1572
+ command << "XX" if xx
1573
+ command << "CH" if ch
1574
+ command << "INCR" if incr
1569
1575
 
1570
1576
  synchronize do |client|
1571
1577
  if args.size == 1 && args[0].is_a?(Array)
1572
1578
  # Variadic: return float if INCR, integer if !INCR
1573
- client.call([:zadd, key] + zadd_options + args[0], &(incr ? Floatify : nil))
1579
+ client.call(command + args[0], &(incr ? Floatify : nil))
1574
1580
  elsif args.size == 2
1575
1581
  # Single pair: return float if INCR, boolean if !INCR
1576
- client.call([:zadd, key] + zadd_options + args, &(incr ? Floatify : Boolify))
1582
+ client.call(command + args, &(incr ? Floatify : Boolify))
1577
1583
  else
1578
1584
  raise ArgumentError, "wrong number of arguments"
1579
1585
  end
@@ -1608,10 +1614,10 @@ class Redis
1608
1614
  # - a single member
1609
1615
  # - an array of members
1610
1616
  #
1611
- # @return [Boolean, Fixnum]
1617
+ # @return [Boolean, Integer]
1612
1618
  # - `Boolean` when a single member is specified, holding whether or not it
1613
1619
  # was removed from the sorted set
1614
- # - `Fixnum` when an array of pairs is specified, holding the number of
1620
+ # - `Integer` when an array of pairs is specified, holding the number of
1615
1621
  # members that were removed to the sorted set
1616
1622
  def zrem(key, member)
1617
1623
  synchronize do |client|
@@ -1736,18 +1742,16 @@ class Redis
1736
1742
  # # => [["a", 32.0], ["b", 64.0]]
1737
1743
  #
1738
1744
  # @param [String] key
1739
- # @param [Fixnum] start start index
1740
- # @param [Fixnum] stop stop index
1745
+ # @param [Integer] start start index
1746
+ # @param [Integer] stop stop index
1741
1747
  # @param [Hash] options
1742
1748
  # - `:with_scores => true`: include scores in output
1743
1749
  #
1744
1750
  # @return [Array<String>, Array<[String, Float]>]
1745
1751
  # - when `:with_scores` is not specified, an array of members
1746
1752
  # - when `:with_scores` is specified, an array with `[member, score]` pairs
1747
- def zrange(key, start, stop, options = {})
1748
- args = []
1749
-
1750
- with_scores = options[:with_scores] || options[:withscores]
1753
+ def zrange(key, start, stop, withscores: false, with_scores: withscores)
1754
+ args = [:zrange, key, start, stop]
1751
1755
 
1752
1756
  if with_scores
1753
1757
  args << "WITHSCORES"
@@ -1755,7 +1759,7 @@ class Redis
1755
1759
  end
1756
1760
 
1757
1761
  synchronize do |client|
1758
- client.call([:zrange, key, start, stop] + args, &block)
1762
+ client.call(args, &block)
1759
1763
  end
1760
1764
  end
1761
1765
 
@@ -1770,10 +1774,8 @@ class Redis
1770
1774
  # # => [["b", 64.0], ["a", 32.0]]
1771
1775
  #
1772
1776
  # @see #zrange
1773
- def zrevrange(key, start, stop, options = {})
1774
- args = []
1775
-
1776
- with_scores = options[:with_scores] || options[:withscores]
1777
+ def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
1778
+ args = [:zrevrange, key, start, stop]
1777
1779
 
1778
1780
  if with_scores
1779
1781
  args << "WITHSCORES"
@@ -1781,7 +1783,7 @@ class Redis
1781
1783
  end
1782
1784
 
1783
1785
  synchronize do |client|
1784
- client.call([:zrevrange, key, start, stop] + args, &block)
1786
+ client.call(args, &block)
1785
1787
  end
1786
1788
  end
1787
1789
 
@@ -1789,7 +1791,7 @@ class Redis
1789
1791
  #
1790
1792
  # @param [String] key
1791
1793
  # @param [String] member
1792
- # @return [Fixnum]
1794
+ # @return [Integer]
1793
1795
  def zrank(key, member)
1794
1796
  synchronize do |client|
1795
1797
  client.call([:zrank, key, member])
@@ -1801,7 +1803,7 @@ class Redis
1801
1803
  #
1802
1804
  # @param [String] key
1803
1805
  # @param [String] member
1804
- # @return [Fixnum]
1806
+ # @return [Integer]
1805
1807
  def zrevrank(key, member)
1806
1808
  synchronize do |client|
1807
1809
  client.call([:zrevrank, key, member])
@@ -1818,9 +1820,9 @@ class Redis
1818
1820
  # # => 5
1819
1821
  #
1820
1822
  # @param [String] key
1821
- # @param [Fixnum] start start index
1822
- # @param [Fixnum] stop stop index
1823
- # @return [Fixnum] number of members that were removed
1823
+ # @param [Integer] start start index
1824
+ # @param [Integer] stop stop index
1825
+ # @return [Integer] number of members that were removed
1824
1826
  def zremrangebyrank(key, start, stop)
1825
1827
  synchronize do |client|
1826
1828
  client.call([:zremrangebyrank, key, start, stop])
@@ -1844,7 +1846,7 @@ class Redis
1844
1846
  # - inclusive maximum is specified by prefixing `(`
1845
1847
  # - exclusive maximum is specified by prefixing `[`
1846
1848
  #
1847
- # @return [Fixnum] number of members within the specified lexicographical range
1849
+ # @return [Integer] number of members within the specified lexicographical range
1848
1850
  def zlexcount(key, min, max)
1849
1851
  synchronize do |client|
1850
1852
  client.call([:zlexcount, key, min, max])
@@ -1872,14 +1874,16 @@ class Redis
1872
1874
  # `count` members
1873
1875
  #
1874
1876
  # @return [Array<String>, Array<[String, Float]>]
1875
- def zrangebylex(key, min, max, options = {})
1876
- args = []
1877
+ def zrangebylex(key, min, max, limit: nil)
1878
+ args = [:zrangebylex, key, min, max]
1877
1879
 
1878
- limit = options[:limit]
1879
- args.concat(["LIMIT"] + limit) if limit
1880
+ if limit
1881
+ args << "LIMIT"
1882
+ args.concat(limit)
1883
+ end
1880
1884
 
1881
1885
  synchronize do |client|
1882
- client.call([:zrangebylex, key, min, max] + args)
1886
+ client.call(args)
1883
1887
  end
1884
1888
  end
1885
1889
 
@@ -1894,14 +1898,16 @@ class Redis
1894
1898
  # # => ["abbygail", "abby"]
1895
1899
  #
1896
1900
  # @see #zrangebylex
1897
- def zrevrangebylex(key, max, min, options = {})
1898
- args = []
1901
+ def zrevrangebylex(key, max, min, limit: nil)
1902
+ args = [:zrevrangebylex, key, max, min]
1899
1903
 
1900
- limit = options[:limit]
1901
- args.concat(["LIMIT"] + limit) if limit
1904
+ if limit
1905
+ args << "LIMIT"
1906
+ args.concat(limit)
1907
+ end
1902
1908
 
1903
1909
  synchronize do |client|
1904
- client.call([:zrevrangebylex, key, max, min] + args)
1910
+ client.call(args)
1905
1911
  end
1906
1912
  end
1907
1913
 
@@ -1932,21 +1938,21 @@ class Redis
1932
1938
  # @return [Array<String>, Array<[String, Float]>]
1933
1939
  # - when `:with_scores` is not specified, an array of members
1934
1940
  # - when `:with_scores` is specified, an array with `[member, score]` pairs
1935
- def zrangebyscore(key, min, max, options = {})
1936
- args = []
1937
-
1938
- with_scores = options[:with_scores] || options[:withscores]
1941
+ def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
1942
+ args = [:zrangebyscore, key, min, max]
1939
1943
 
1940
1944
  if with_scores
1941
1945
  args << "WITHSCORES"
1942
1946
  block = FloatifyPairs
1943
1947
  end
1944
1948
 
1945
- limit = options[:limit]
1946
- args.concat(["LIMIT"] + limit) if limit
1949
+ if limit
1950
+ args << "LIMIT"
1951
+ args.concat(limit)
1952
+ end
1947
1953
 
1948
1954
  synchronize do |client|
1949
- client.call([:zrangebyscore, key, min, max] + args, &block)
1955
+ client.call(args, &block)
1950
1956
  end
1951
1957
  end
1952
1958
 
@@ -1964,21 +1970,21 @@ class Redis
1964
1970
  # # => [["b", 64.0], ["a", 32.0]]
1965
1971
  #
1966
1972
  # @see #zrangebyscore
1967
- def zrevrangebyscore(key, max, min, options = {})
1968
- args = []
1969
-
1970
- with_scores = options[:with_scores] || options[:withscores]
1973
+ def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
1974
+ args = [:zrevrangebyscore, key, max, min]
1971
1975
 
1972
1976
  if with_scores
1973
- args << ["WITHSCORES"]
1977
+ args << "WITHSCORES"
1974
1978
  block = FloatifyPairs
1975
1979
  end
1976
1980
 
1977
- limit = options[:limit]
1978
- args.concat(["LIMIT"] + limit) if limit
1981
+ if limit
1982
+ args << "LIMIT"
1983
+ args.concat(limit)
1984
+ end
1979
1985
 
1980
1986
  synchronize do |client|
1981
- client.call([:zrevrangebyscore, key, max, min] + args, &block)
1987
+ client.call(args, &block)
1982
1988
  end
1983
1989
  end
1984
1990
 
@@ -1998,7 +2004,7 @@ class Redis
1998
2004
  # @param [String] max
1999
2005
  # - inclusive maximum score is specified verbatim
2000
2006
  # - exclusive maximum score is specified by prefixing `(`
2001
- # @return [Fixnum] number of members that were removed
2007
+ # @return [Integer] number of members that were removed
2002
2008
  def zremrangebyscore(key, min, max)
2003
2009
  synchronize do |client|
2004
2010
  client.call([:zremrangebyscore, key, min, max])
@@ -2021,7 +2027,7 @@ class Redis
2021
2027
  # @param [String] max
2022
2028
  # - inclusive maximum score is specified verbatim
2023
2029
  # - exclusive maximum score is specified by prefixing `(`
2024
- # @return [Fixnum] number of members in within the specified range
2030
+ # @return [Integer] number of members in within the specified range
2025
2031
  def zcount(key, min, max)
2026
2032
  synchronize do |client|
2027
2033
  client.call([:zcount, key, min, max])
@@ -2041,18 +2047,19 @@ class Redis
2041
2047
  # - `:weights => [Float, Float, ...]`: weights to associate with source
2042
2048
  # sorted sets
2043
2049
  # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
2044
- # @return [Fixnum] number of elements in the resulting sorted set
2045
- def zinterstore(destination, keys, options = {})
2046
- args = []
2050
+ # @return [Integer] number of elements in the resulting sorted set
2051
+ def zinterstore(destination, keys, weights: nil, aggregate: nil)
2052
+ args = [:zinterstore, destination, keys.size, *keys]
2047
2053
 
2048
- weights = options[:weights]
2049
- args.concat(["WEIGHTS"] + weights) if weights
2054
+ if weights
2055
+ args << "WEIGHTS"
2056
+ args.concat(weights)
2057
+ end
2050
2058
 
2051
- aggregate = options[:aggregate]
2052
- args.concat(["AGGREGATE", aggregate]) if aggregate
2059
+ args << "AGGREGATE" << aggregate if aggregate
2053
2060
 
2054
2061
  synchronize do |client|
2055
- client.call([:zinterstore, destination, keys.size] + keys + args)
2062
+ client.call(args)
2056
2063
  end
2057
2064
  end
2058
2065
 
@@ -2068,40 +2075,46 @@ class Redis
2068
2075
  # - `:weights => [Float, Float, ...]`: weights to associate with source
2069
2076
  # sorted sets
2070
2077
  # - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
2071
- # @return [Fixnum] number of elements in the resulting sorted set
2072
- def zunionstore(destination, keys, options = {})
2073
- args = []
2078
+ # @return [Integer] number of elements in the resulting sorted set
2079
+ def zunionstore(destination, keys, weights: nil, aggregate: nil)
2080
+ args = [:zunionstore, destination, keys.size, *keys]
2074
2081
 
2075
- weights = options[:weights]
2076
- args.concat(["WEIGHTS"] + weights) if weights
2082
+ if weights
2083
+ args << "WEIGHTS"
2084
+ args.concat(weights)
2085
+ end
2077
2086
 
2078
- aggregate = options[:aggregate]
2079
- args.concat(["AGGREGATE", aggregate]) if aggregate
2087
+ args << "AGGREGATE" << aggregate if aggregate
2080
2088
 
2081
2089
  synchronize do |client|
2082
- client.call([:zunionstore, destination, keys.size] + keys + args)
2090
+ client.call(args)
2083
2091
  end
2084
2092
  end
2085
2093
 
2086
2094
  # Get the number of fields in a hash.
2087
2095
  #
2088
2096
  # @param [String] key
2089
- # @return [Fixnum] number of fields in the hash
2097
+ # @return [Integer] number of fields in the hash
2090
2098
  def hlen(key)
2091
2099
  synchronize do |client|
2092
2100
  client.call([:hlen, key])
2093
2101
  end
2094
2102
  end
2095
2103
 
2096
- # Set the string value of a hash field.
2104
+ # Set one or more hash values.
2105
+ #
2106
+ # @example
2107
+ # redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
2108
+ # redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
2097
2109
  #
2098
2110
  # @param [String] key
2099
- # @param [String] field
2100
- # @param [String] value
2101
- # @return [Boolean] whether or not the field was **added** to the hash
2102
- def hset(key, field, value)
2111
+ # @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
2112
+ # @return [Integer] The number of fields that were added to the hash
2113
+ def hset(key, *attrs)
2114
+ attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
2115
+
2103
2116
  synchronize do |client|
2104
- client.call([:hset, key, field, value], &Boolify)
2117
+ client.call([:hset, key, *attrs])
2105
2118
  end
2106
2119
  end
2107
2120
 
@@ -2190,7 +2203,7 @@ class Redis
2190
2203
  # @see #hmget
2191
2204
  def mapped_hmget(key, *fields)
2192
2205
  hmget(key, *fields) do |reply|
2193
- if reply.kind_of?(Array)
2206
+ if reply.is_a?(Array)
2194
2207
  Hash[fields.zip(reply)]
2195
2208
  else
2196
2209
  reply
@@ -2202,7 +2215,7 @@ class Redis
2202
2215
  #
2203
2216
  # @param [String] key
2204
2217
  # @param [String, Array<String>] field
2205
- # @return [Fixnum] the number of fields that were removed from the hash
2218
+ # @return [Integer] the number of fields that were removed from the hash
2206
2219
  def hdel(key, *fields)
2207
2220
  synchronize do |client|
2208
2221
  client.call([:hdel, key, *fields])
@@ -2224,8 +2237,8 @@ class Redis
2224
2237
  #
2225
2238
  # @param [String] key
2226
2239
  # @param [String] field
2227
- # @param [Fixnum] increment
2228
- # @return [Fixnum] value of the field after incrementing it
2240
+ # @param [Integer] increment
2241
+ # @return [Integer] value of the field after incrementing it
2229
2242
  def hincrby(key, field, increment)
2230
2243
  synchronize do |client|
2231
2244
  client.call([:hincrby, key, field, increment])
@@ -2283,20 +2296,21 @@ class Redis
2283
2296
 
2284
2297
  def subscribed?
2285
2298
  synchronize do |client|
2286
- client.kind_of? SubscribedClient
2299
+ client.is_a? SubscribedClient
2287
2300
  end
2288
2301
  end
2289
2302
 
2290
2303
  # Listen for messages published to the given channels.
2291
2304
  def subscribe(*channels, &block)
2292
- synchronize do |client|
2305
+ synchronize do |_client|
2293
2306
  _subscription(:subscribe, 0, channels, block)
2294
2307
  end
2295
2308
  end
2296
2309
 
2297
- # Listen for messages published to the given channels. Throw a timeout error if there is no messages for a timeout period.
2310
+ # Listen for messages published to the given channels. Throw a timeout error
2311
+ # if there is no messages for a timeout period.
2298
2312
  def subscribe_with_timeout(timeout, *channels, &block)
2299
- synchronize do |client|
2313
+ synchronize do |_client|
2300
2314
  _subscription(:subscribe_with_timeout, timeout, channels, block)
2301
2315
  end
2302
2316
  end
@@ -2304,21 +2318,23 @@ class Redis
2304
2318
  # Stop listening for messages posted to the given channels.
2305
2319
  def unsubscribe(*channels)
2306
2320
  synchronize do |client|
2307
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2321
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
2322
+
2308
2323
  client.unsubscribe(*channels)
2309
2324
  end
2310
2325
  end
2311
2326
 
2312
2327
  # Listen for messages published to channels matching the given patterns.
2313
2328
  def psubscribe(*channels, &block)
2314
- synchronize do |client|
2329
+ synchronize do |_client|
2315
2330
  _subscription(:psubscribe, 0, channels, block)
2316
2331
  end
2317
2332
  end
2318
2333
 
2319
- # Listen for messages published to channels matching the given patterns. Throw a timeout error if there is no messages for a timeout period.
2334
+ # Listen for messages published to channels matching the given patterns.
2335
+ # Throw a timeout error if there is no messages for a timeout period.
2320
2336
  def psubscribe_with_timeout(timeout, *channels, &block)
2321
- synchronize do |client|
2337
+ synchronize do |_client|
2322
2338
  _subscription(:psubscribe_with_timeout, timeout, channels, block)
2323
2339
  end
2324
2340
  end
@@ -2326,7 +2342,8 @@ class Redis
2326
2342
  # Stop listening for messages posted to channels matching the given patterns.
2327
2343
  def punsubscribe(*channels)
2328
2344
  synchronize do |client|
2329
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
2345
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
2346
+
2330
2347
  client.punsubscribe(*channels)
2331
2348
  end
2332
2349
  end
@@ -2371,7 +2388,7 @@ class Redis
2371
2388
  # @see #multi
2372
2389
  def watch(*keys)
2373
2390
  synchronize do |client|
2374
- res = client.call([:watch] + keys)
2391
+ res = client.call([:watch, *keys])
2375
2392
 
2376
2393
  if block_given?
2377
2394
  begin
@@ -2401,9 +2418,10 @@ class Redis
2401
2418
  end
2402
2419
 
2403
2420
  def pipelined
2404
- synchronize do |client|
2421
+ synchronize do |_client|
2405
2422
  begin
2406
- original, @client = @client, Pipeline.new
2423
+ pipeline = Pipeline.new(@client)
2424
+ original, @client = @client, pipeline
2407
2425
  yield(self)
2408
2426
  original.call_pipeline(@client)
2409
2427
  ensure
@@ -2448,7 +2466,7 @@ class Redis
2448
2466
  client.call([:multi])
2449
2467
  else
2450
2468
  begin
2451
- pipeline = Pipeline::Multi.new
2469
+ pipeline = Pipeline::Multi.new(@client)
2452
2470
  original, @client = @client, pipeline
2453
2471
  yield(self)
2454
2472
  original.call_pipeline(pipeline)
@@ -2600,18 +2618,12 @@ class Redis
2600
2618
  _eval(:evalsha, args)
2601
2619
  end
2602
2620
 
2603
- def _scan(command, cursor, args, options = {}, &block)
2621
+ def _scan(command, cursor, args, match: nil, count: nil, &block)
2604
2622
  # SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
2605
2623
 
2606
2624
  args << cursor
2607
-
2608
- if match = options[:match]
2609
- args.concat(["MATCH", match])
2610
- end
2611
-
2612
- if count = options[:count]
2613
- args.concat(["COUNT", count])
2614
- end
2625
+ args << "MATCH" << match if match
2626
+ args << "COUNT" << count if count
2615
2627
 
2616
2628
  synchronize do |client|
2617
2629
  client.call([command] + args, &block)
@@ -2633,8 +2645,8 @@ class Redis
2633
2645
  # - `:count => Integer`: return count keys at most per iteration
2634
2646
  #
2635
2647
  # @return [String, Array<String>] the next cursor and all found keys
2636
- def scan(cursor, options={})
2637
- _scan(:scan, cursor, [], options)
2648
+ def scan(cursor, **options)
2649
+ _scan(:scan, cursor, [], **options)
2638
2650
  end
2639
2651
 
2640
2652
  # Scan the keyspace
@@ -2652,11 +2664,12 @@ class Redis
2652
2664
  # - `:count => Integer`: return count keys at most per iteration
2653
2665
  #
2654
2666
  # @return [Enumerator] an enumerator for all found keys
2655
- def scan_each(options={}, &block)
2656
- return to_enum(:scan_each, options) unless block_given?
2667
+ def scan_each(**options, &block)
2668
+ return to_enum(:scan_each, **options) unless block_given?
2669
+
2657
2670
  cursor = 0
2658
2671
  loop do
2659
- cursor, keys = scan(cursor, options)
2672
+ cursor, keys = scan(cursor, **options)
2660
2673
  keys.each(&block)
2661
2674
  break if cursor == "0"
2662
2675
  end
@@ -2673,8 +2686,8 @@ class Redis
2673
2686
  # - `:count => Integer`: return count keys at most per iteration
2674
2687
  #
2675
2688
  # @return [String, Array<[String, String]>] the next cursor and all found keys
2676
- def hscan(key, cursor, options={})
2677
- _scan(:hscan, cursor, [key], options) do |reply|
2689
+ def hscan(key, cursor, **options)
2690
+ _scan(:hscan, cursor, [key], **options) do |reply|
2678
2691
  [reply[0], reply[1].each_slice(2).to_a]
2679
2692
  end
2680
2693
  end
@@ -2690,11 +2703,12 @@ class Redis
2690
2703
  # - `:count => Integer`: return count keys at most per iteration
2691
2704
  #
2692
2705
  # @return [Enumerator] an enumerator for all found keys
2693
- def hscan_each(key, options={}, &block)
2694
- return to_enum(:hscan_each, key, options) unless block_given?
2706
+ def hscan_each(key, **options, &block)
2707
+ return to_enum(:hscan_each, key, **options) unless block_given?
2708
+
2695
2709
  cursor = 0
2696
2710
  loop do
2697
- cursor, values = hscan(key, cursor, options)
2711
+ cursor, values = hscan(key, cursor, **options)
2698
2712
  values.each(&block)
2699
2713
  break if cursor == "0"
2700
2714
  end
@@ -2712,8 +2726,8 @@ class Redis
2712
2726
  #
2713
2727
  # @return [String, Array<[String, Float]>] the next cursor and all found
2714
2728
  # members and scores
2715
- def zscan(key, cursor, options={})
2716
- _scan(:zscan, cursor, [key], options) do |reply|
2729
+ def zscan(key, cursor, **options)
2730
+ _scan(:zscan, cursor, [key], **options) do |reply|
2717
2731
  [reply[0], FloatifyPairs.call(reply[1])]
2718
2732
  end
2719
2733
  end
@@ -2729,11 +2743,12 @@ class Redis
2729
2743
  # - `:count => Integer`: return count keys at most per iteration
2730
2744
  #
2731
2745
  # @return [Enumerator] an enumerator for all found scores and members
2732
- def zscan_each(key, options={}, &block)
2733
- return to_enum(:zscan_each, key, options) unless block_given?
2746
+ def zscan_each(key, **options, &block)
2747
+ return to_enum(:zscan_each, key, **options) unless block_given?
2748
+
2734
2749
  cursor = 0
2735
2750
  loop do
2736
- cursor, values = zscan(key, cursor, options)
2751
+ cursor, values = zscan(key, cursor, **options)
2737
2752
  values.each(&block)
2738
2753
  break if cursor == "0"
2739
2754
  end
@@ -2750,8 +2765,8 @@ class Redis
2750
2765
  # - `:count => Integer`: return count keys at most per iteration
2751
2766
  #
2752
2767
  # @return [String, Array<String>] the next cursor and all found members
2753
- def sscan(key, cursor, options={})
2754
- _scan(:sscan, cursor, [key], options)
2768
+ def sscan(key, cursor, **options)
2769
+ _scan(:sscan, cursor, [key], **options)
2755
2770
  end
2756
2771
 
2757
2772
  # Scan a set
@@ -2765,11 +2780,12 @@ class Redis
2765
2780
  # - `:count => Integer`: return count keys at most per iteration
2766
2781
  #
2767
2782
  # @return [Enumerator] an enumerator for all keys in the set
2768
- def sscan_each(key, options={}, &block)
2769
- return to_enum(:sscan_each, key, options) unless block_given?
2783
+ def sscan_each(key, **options, &block)
2784
+ return to_enum(:sscan_each, key, **options) unless block_given?
2785
+
2770
2786
  cursor = 0
2771
2787
  loop do
2772
- cursor, keys = sscan(key, cursor, options)
2788
+ cursor, keys = sscan(key, cursor, **options)
2773
2789
  keys.each(&block)
2774
2790
  break if cursor == "0"
2775
2791
  end
@@ -2792,7 +2808,7 @@ class Redis
2792
2808
  # union of the HyperLogLogs contained in the keys.
2793
2809
  #
2794
2810
  # @param [String, Array<String>] keys
2795
- # @return [Fixnum]
2811
+ # @return [Integer]
2796
2812
  def pfcount(*keys)
2797
2813
  synchronize do |client|
2798
2814
  client.call([:pfcount] + keys)
@@ -2815,10 +2831,10 @@ class Redis
2815
2831
  #
2816
2832
  # @param [String] key
2817
2833
  # @param [Array] member arguemnts for member or members: longitude, latitude, name
2818
- # @return [Intger] number of elements added to the sorted set
2834
+ # @return [Integer] number of elements added to the sorted set
2819
2835
  def geoadd(key, *member)
2820
2836
  synchronize do |client|
2821
- client.call([:geoadd, key, member])
2837
+ client.call([:geoadd, key, *member])
2822
2838
  end
2823
2839
  end
2824
2840
 
@@ -2833,12 +2849,12 @@ class Redis
2833
2849
  end
2834
2850
  end
2835
2851
 
2836
-
2837
2852
  # Query a sorted set representing a geospatial index to fetch members matching a
2838
2853
  # given maximum distance from a point
2839
2854
  #
2840
2855
  # @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
2841
- # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2856
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
2857
+ # or the farthest to the nearest relative to the center
2842
2858
  # @param [Integer] count limit the results to the first N matching items
2843
2859
  # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2844
2860
  # @return [Array<String>] may be changed with `options`
@@ -2855,7 +2871,8 @@ class Redis
2855
2871
  # given maximum distance from an already existing member
2856
2872
  #
2857
2873
  # @param [Array] args key, member, radius, unit(m|km|ft|mi)
2858
- # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest to the nearest relative to the center
2874
+ # @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
2875
+ # to the nearest relative to the center
2859
2876
  # @param [Integer] count limit the results to the first N matching items
2860
2877
  # @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
2861
2878
  # @return [Array<String>] may be changed with `options`
@@ -2872,7 +2889,8 @@ class Redis
2872
2889
  #
2873
2890
  # @param [String] key
2874
2891
  # @param [String, Array<String>] member one member or array of members
2875
- # @return [Array<Array<String>, nil>] returns array of elements, where each element is either array of longitude and latitude or nil
2892
+ # @return [Array<Array<String>, nil>] returns array of elements, where each
2893
+ # element is either array of longitude and latitude or nil
2876
2894
  def geopos(key, member)
2877
2895
  synchronize do |client|
2878
2896
  client.call([:geopos, key, member])
@@ -2936,10 +2954,14 @@ class Redis
2936
2954
  # @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
2937
2955
  #
2938
2956
  # @return [String] the entry id
2939
- def xadd(key, entry, opts = {})
2957
+ def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
2940
2958
  args = [:xadd, key]
2941
- args.concat(['MAXLEN', (opts[:approximate] ? '~' : nil), opts[:maxlen]].compact) if opts[:maxlen]
2942
- args << (opts[:id] || '*')
2959
+ if maxlen
2960
+ args << "MAXLEN"
2961
+ args << "~" if approximate
2962
+ args << maxlen
2963
+ end
2964
+ args << id
2943
2965
  args.concat(entry.to_a.flatten)
2944
2966
  synchronize { |client| client.call(args) }
2945
2967
  end
@@ -2977,24 +2999,6 @@ class Redis
2977
2999
  synchronize { |client| client.call(args) }
2978
3000
  end
2979
3001
 
2980
- # Fetches entries of the stream.
2981
- #
2982
- # @example Without options
2983
- # redis.xrange('mystream')
2984
- # @example With first entry id option
2985
- # redis.xrange('mystream', first: '0-1')
2986
- # @example With first and last entry id options
2987
- # redis.xrange('mystream', first: '0-1', last: '0-3')
2988
- # @example With count options
2989
- # redis.xrange('mystream', count: 10)
2990
- #
2991
- # @param key [String] the stream key
2992
- # @param start [String] first entry id of range, default value is `+`
2993
- # @param end [String] last entry id of range, default value is `-`
2994
- # @param count [Integer] the number of entries as limit
2995
- #
2996
- # @return [Hash{String => Hash}] the entries
2997
-
2998
3002
  # Fetches entries of the stream in ascending order.
2999
3003
  #
3000
3004
  # @example Without options
@@ -3012,8 +3016,8 @@ class Redis
3012
3016
  # @param count [Integer] the number of entries as limit
3013
3017
  #
3014
3018
  # @return [Array<Array<String, Hash>>] the ids and entries pairs
3015
- def xrange(key, start = '-', _end = '+', count: nil)
3016
- args = [:xrange, key, start, _end]
3019
+ def xrange(key, start = '-', range_end = '+', count: nil)
3020
+ args = [:xrange, key, start, range_end]
3017
3021
  args.concat(['COUNT', count]) if count
3018
3022
  synchronize { |client| client.call(args, &HashifyStreamEntries) }
3019
3023
  end
@@ -3035,8 +3039,8 @@ class Redis
3035
3039
  # @params count [Integer] the number of entries as limit
3036
3040
  #
3037
3041
  # @return [Array<Array<String, Hash>>] the ids and entries pairs
3038
- def xrevrange(key, _end = '+', start = '-', count: nil)
3039
- args = [:xrevrange, key, _end, start]
3042
+ def xrevrange(key, range_end = '+', start = '-', count: nil)
3043
+ args = [:xrevrange, key, range_end, start]
3040
3044
  args.concat(['COUNT', count]) if count
3041
3045
  synchronize { |client| client.call(args, &HashifyStreamEntries) }
3042
3046
  end
@@ -3128,12 +3132,12 @@ class Redis
3128
3132
  # @option opts [Boolean] :noack whether message loss is acceptable or not
3129
3133
  #
3130
3134
  # @return [Hash{String => Hash{String => Hash}}] the entries
3131
- def xreadgroup(group, consumer, keys, ids, opts = {})
3135
+ def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
3132
3136
  args = [:xreadgroup, 'GROUP', group, consumer]
3133
- args << 'COUNT' << opts[:count] if opts[:count]
3134
- args << 'BLOCK' << opts[:block].to_i if opts[:block]
3135
- args << 'NOACK' if opts[:noack]
3136
- _xread(args, keys, ids, opts[:block])
3137
+ args << 'COUNT' << count if count
3138
+ args << 'BLOCK' << block.to_i if block
3139
+ args << 'NOACK' if noack
3140
+ _xread(args, keys, ids, block)
3137
3141
  end
3138
3142
 
3139
3143
  # Removes one or multiple entries from the pending entries list of a stream consumer group.
@@ -3243,8 +3247,8 @@ class Redis
3243
3247
  when "get-master-addr-by-name"
3244
3248
  reply
3245
3249
  else
3246
- if reply.kind_of?(Array)
3247
- if reply[0].kind_of?(Array)
3250
+ if reply.is_a?(Array)
3251
+ if reply[0].is_a?(Array)
3248
3252
  reply.map(&Hashify)
3249
3253
  else
3250
3254
  Hashify.call(reply)
@@ -3268,12 +3272,17 @@ class Redis
3268
3272
  def cluster(subcommand, *args)
3269
3273
  subcommand = subcommand.to_s.downcase
3270
3274
  block = case subcommand
3271
- when 'slots' then HashifyClusterSlots
3272
- when 'nodes' then HashifyClusterNodes
3273
- when 'slaves' then HashifyClusterSlaves
3274
- when 'info' then HashifyInfo
3275
- else Noop
3276
- end
3275
+ when 'slots'
3276
+ HashifyClusterSlots
3277
+ when 'nodes'
3278
+ HashifyClusterNodes
3279
+ when 'slaves'
3280
+ HashifyClusterSlaves
3281
+ when 'info'
3282
+ HashifyInfo
3283
+ else
3284
+ Noop
3285
+ end
3277
3286
 
3278
3287
  # @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
3279
3288
  block = Noop unless @cluster_mode
@@ -3308,150 +3317,154 @@ class Redis
3308
3317
  return @original_client.connection_info if @cluster_mode
3309
3318
 
3310
3319
  {
3311
- host: @original_client.host,
3312
- port: @original_client.port,
3313
- db: @original_client.db,
3314
- id: @original_client.id,
3320
+ host: @original_client.host,
3321
+ port: @original_client.port,
3322
+ db: @original_client.db,
3323
+ id: @original_client.id,
3315
3324
  location: @original_client.location
3316
3325
  }
3317
3326
  end
3318
3327
 
3319
- def method_missing(command, *args)
3328
+ def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
3320
3329
  synchronize do |client|
3321
3330
  client.call([command] + args)
3322
3331
  end
3323
3332
  end
3324
3333
 
3325
- private
3334
+ private
3326
3335
 
3327
3336
  # Commands returning 1 for true and 0 for false may be executed in a pipeline
3328
3337
  # where the method call will return nil. Propagate the nil instead of falsely
3329
3338
  # returning false.
3330
- Boolify =
3331
- lambda { |value|
3332
- value == 1 if value
3333
- }
3339
+ Boolify = lambda { |value|
3340
+ case value
3341
+ when 1
3342
+ true
3343
+ when 0
3344
+ false
3345
+ else
3346
+ value
3347
+ end
3348
+ }
3334
3349
 
3335
- BoolifySet =
3336
- lambda { |value|
3337
- if value && "OK" == value
3338
- true
3339
- else
3340
- false
3341
- end
3342
- }
3350
+ BoolifySet = lambda { |value|
3351
+ case value
3352
+ when "OK"
3353
+ true
3354
+ when nil
3355
+ false
3356
+ else
3357
+ value
3358
+ end
3359
+ }
3343
3360
 
3344
- Hashify =
3345
- lambda { |array|
3346
- hash = Hash.new
3347
- array.each_slice(2) do |field, value|
3348
- hash[field] = value
3349
- end
3350
- hash
3351
- }
3361
+ Hashify = lambda { |value|
3362
+ if value.respond_to?(:each_slice)
3363
+ value.each_slice(2).to_h
3364
+ else
3365
+ value
3366
+ end
3367
+ }
3368
+
3369
+ Floatify = lambda { |value|
3370
+ case value
3371
+ when "inf"
3372
+ Float::INFINITY
3373
+ when "-inf"
3374
+ -Float::INFINITY
3375
+ when String
3376
+ Float(value)
3377
+ else
3378
+ value
3379
+ end
3380
+ }
3352
3381
 
3353
- Floatify =
3354
- lambda { |str|
3355
- if str
3356
- if (inf = str.match(/^(-)?inf/i))
3357
- (inf[1] ? -1.0 : 1.0) / 0.0
3358
- else
3359
- Float(str)
3360
- end
3361
- end
3362
- }
3382
+ FloatifyPairs = lambda { |value|
3383
+ return value unless value.respond_to?(:each_slice)
3363
3384
 
3364
- FloatifyPairs =
3365
- lambda { |result|
3366
- result.each_slice(2).map do |member, score|
3367
- [member, Floatify.call(score)]
3368
- end
3369
- }
3385
+ value.each_slice(2).map do |member, score|
3386
+ [member, Floatify.call(score)]
3387
+ end
3388
+ }
3370
3389
 
3371
- HashifyInfo =
3372
- lambda { |reply|
3373
- Hash[reply.split("\r\n").map do |line|
3374
- line.split(':', 2) unless line =~ /^(#|$)/
3375
- end.compact]
3376
- }
3390
+ HashifyInfo = lambda { |reply|
3391
+ lines = reply.split("\r\n").grep_v(/^(#|$)/)
3392
+ lines.map! { |line| line.split(':', 2) }
3393
+ lines.compact!
3394
+ lines.to_h
3395
+ }
3377
3396
 
3378
- HashifyStreams =
3379
- lambda { |reply|
3380
- return {} if reply.nil?
3381
- reply.map do |stream_key, entries|
3382
- [stream_key, HashifyStreamEntries.call(entries)]
3383
- end.to_h
3384
- }
3397
+ HashifyStreams = lambda { |reply|
3398
+ case reply
3399
+ when nil
3400
+ {}
3401
+ else
3402
+ reply.map { |key, entries| [key, HashifyStreamEntries.call(entries)] }.to_h
3403
+ end
3404
+ }
3385
3405
 
3386
- HashifyStreamEntries =
3387
- lambda { |reply|
3388
- reply.map do |entry_id, values|
3389
- [entry_id, values.each_slice(2).to_h]
3390
- end
3406
+ HashifyStreamEntries = lambda { |reply|
3407
+ reply.map do |entry_id, values|
3408
+ [entry_id, values.each_slice(2).to_h]
3409
+ end
3410
+ }
3411
+
3412
+ HashifyStreamPendings = lambda { |reply|
3413
+ {
3414
+ 'size' => reply[0],
3415
+ 'min_entry_id' => reply[1],
3416
+ 'max_entry_id' => reply[2],
3417
+ 'consumers' => reply[3].nil? ? {} : reply[3].to_h
3391
3418
  }
3419
+ }
3392
3420
 
3393
- HashifyStreamPendings =
3394
- lambda { |reply|
3421
+ HashifyStreamPendingDetails = lambda { |reply|
3422
+ reply.map do |arr|
3395
3423
  {
3396
- 'size' => reply[0],
3397
- 'min_entry_id' => reply[1],
3398
- 'max_entry_id' => reply[2],
3399
- 'consumers' => reply[3].nil? ? {} : Hash[reply[3]]
3424
+ 'entry_id' => arr[0],
3425
+ 'consumer' => arr[1],
3426
+ 'elapsed' => arr[2],
3427
+ 'count' => arr[3]
3400
3428
  }
3401
- }
3429
+ end
3430
+ }
3402
3431
 
3403
- HashifyStreamPendingDetails =
3404
- lambda { |reply|
3405
- reply.map do |arr|
3406
- {
3407
- 'entry_id' => arr[0],
3408
- 'consumer' => arr[1],
3409
- 'elapsed' => arr[2],
3410
- 'count' => arr[3]
3411
- }
3412
- end
3432
+ HashifyClusterNodeInfo = lambda { |str|
3433
+ arr = str.split(' ')
3434
+ {
3435
+ 'node_id' => arr[0],
3436
+ 'ip_port' => arr[1],
3437
+ 'flags' => arr[2].split(','),
3438
+ 'master_node_id' => arr[3],
3439
+ 'ping_sent' => arr[4],
3440
+ 'pong_recv' => arr[5],
3441
+ 'config_epoch' => arr[6],
3442
+ 'link_state' => arr[7],
3443
+ 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
3413
3444
  }
3445
+ }
3414
3446
 
3415
- HashifyClusterNodeInfo =
3416
- lambda { |str|
3417
- arr = str.split(' ')
3447
+ HashifyClusterSlots = lambda { |reply|
3448
+ reply.map do |arr|
3449
+ first_slot, last_slot = arr[0..1]
3450
+ master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
3451
+ replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
3418
3452
  {
3419
- 'node_id' => arr[0],
3420
- 'ip_port' => arr[1],
3421
- 'flags' => arr[2].split(','),
3422
- 'master_node_id' => arr[3],
3423
- 'ping_sent' => arr[4],
3424
- 'pong_recv' => arr[5],
3425
- 'config_epoch' => arr[6],
3426
- 'link_state' => arr[7],
3427
- 'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
3453
+ 'start_slot' => first_slot,
3454
+ 'end_slot' => last_slot,
3455
+ 'master' => master,
3456
+ 'replicas' => replicas
3428
3457
  }
3429
- }
3430
-
3431
- HashifyClusterSlots =
3432
- lambda { |reply|
3433
- reply.map do |arr|
3434
- first_slot, last_slot = arr[0..1]
3435
- master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
3436
- replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
3437
- {
3438
- 'start_slot' => first_slot,
3439
- 'end_slot' => last_slot,
3440
- 'master' => master,
3441
- 'replicas' => replicas
3442
- }
3443
- end
3444
- }
3458
+ end
3459
+ }
3445
3460
 
3446
- HashifyClusterNodes =
3447
- lambda { |reply|
3448
- reply.split(/[\r\n]+/).map { |str| HashifyClusterNodeInfo.call(str) }
3449
- }
3461
+ HashifyClusterNodes = lambda { |reply|
3462
+ reply.split(/[\r\n]+/).map { |str| HashifyClusterNodeInfo.call(str) }
3463
+ }
3450
3464
 
3451
- HashifyClusterSlaves =
3452
- lambda { |reply|
3453
- reply.map { |str| HashifyClusterNodeInfo.call(str) }
3454
- }
3465
+ HashifyClusterSlaves = lambda { |reply|
3466
+ reply.map { |str| HashifyClusterNodeInfo.call(str) }
3467
+ }
3455
3468
 
3456
3469
  Noop = ->(reply) { reply }
3457
3470
 
@@ -3459,8 +3472,7 @@ private
3459
3472
  args.push sort if sort
3460
3473
  args.push 'count', count if count
3461
3474
  args.push options if options
3462
-
3463
- args.uniq
3475
+ args
3464
3476
  end
3465
3477
 
3466
3478
  def _subscription(method, timeout, channels, block)
@@ -3488,6 +3500,8 @@ private
3488
3500
  synchronize do |client|
3489
3501
  if blocking_timeout_msec.nil?
3490
3502
  client.call(args, &HashifyStreams)
3503
+ elsif blocking_timeout_msec.to_f.zero?
3504
+ client.call_without_timeout(args, &HashifyStreams)
3491
3505
  else
3492
3506
  timeout = client.timeout.to_f + blocking_timeout_msec.to_f / 1000.0
3493
3507
  client.call_with_timeout(args, timeout, &HashifyStreams)