redis 4.1.4 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "connection/registry"
3
4
 
4
5
  # If a connection driver was required before this file, the array
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  module Connection
4
5
  module CommandHelper
5
-
6
6
  COMMAND_DELIMITER = "\r\n"
7
7
 
8
8
  def build_command(args)
@@ -29,7 +29,7 @@ class Redis
29
29
  command.join(COMMAND_DELIMITER)
30
30
  end
31
31
 
32
- protected
32
+ protected
33
33
 
34
34
  def encode(string)
35
35
  string.force_encoding(Encoding.default_external)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "registry"
3
4
  require_relative "../errors"
4
5
  require "hiredis/connection"
@@ -7,7 +8,6 @@ require "timeout"
7
8
  class Redis
8
9
  module Connection
9
10
  class Hiredis
10
-
11
11
  def self.connect(config)
12
12
  connection = ::Hiredis::Connection.new
13
13
  connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
@@ -32,7 +32,7 @@ class Redis
32
32
  end
33
33
 
34
34
  def connected?
35
- @connection && @connection.connected?
35
+ @connection&.connected?
36
36
  end
37
37
 
38
38
  def timeout=(timeout)
@@ -58,7 +58,7 @@ class Redis
58
58
  rescue Errno::EAGAIN
59
59
  raise TimeoutError
60
60
  rescue RuntimeError => err
61
- raise ProtocolError.new(err.message)
61
+ raise ProtocolError, err.message
62
62
  end
63
63
  end
64
64
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  class Redis
3
4
  module Connection
4
-
5
5
  # Store a list of loaded connection drivers in the Connection module.
6
6
  # Redis::Client uses the last required driver by default, and will be aware
7
7
  # of the loaded connection drivers if the user chooses to override the
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "registry"
3
4
  require_relative "command_helper"
4
5
  require_relative "../errors"
@@ -14,8 +15,7 @@ end
14
15
  class Redis
15
16
  module Connection
16
17
  module SocketMixin
17
-
18
- CRLF = "\r\n".freeze
18
+ CRLF = "\r\n"
19
19
 
20
20
  def initialize(*args)
21
21
  super(*args)
@@ -25,46 +25,32 @@ class Redis
25
25
  end
26
26
 
27
27
  def timeout=(timeout)
28
- if timeout && timeout > 0
29
- @timeout = timeout
30
- else
31
- @timeout = nil
32
- end
28
+ @timeout = (timeout if timeout && timeout > 0)
33
29
  end
34
30
 
35
31
  def write_timeout=(timeout)
36
- if timeout && timeout > 0
37
- @write_timeout = timeout
38
- else
39
- @write_timeout = nil
40
- end
32
+ @write_timeout = (timeout if timeout && timeout > 0)
41
33
  end
42
34
 
43
35
  def read(nbytes)
44
36
  result = @buffer.slice!(0, nbytes)
45
37
 
46
- while result.bytesize < nbytes
47
- result << _read_from_socket(nbytes - result.bytesize)
48
- end
38
+ result << _read_from_socket(nbytes - result.bytesize) while result.bytesize < nbytes
49
39
 
50
40
  result
51
41
  end
52
42
 
53
43
  def gets
54
- crlf = nil
55
-
56
- while (crlf = @buffer.index(CRLF)) == nil
57
- @buffer << _read_from_socket(16384)
44
+ while (crlf = @buffer.index(CRLF)).nil?
45
+ @buffer << _read_from_socket(16_384)
58
46
  end
59
47
 
60
48
  @buffer.slice!(0, crlf + CRLF.bytesize)
61
49
  end
62
50
 
63
51
  def _read_from_socket(nbytes)
64
-
65
52
  begin
66
53
  read_nonblock(nbytes)
67
-
68
54
  rescue IO::WaitReadable
69
55
  if IO.select([self], nil, nil, @timeout)
70
56
  retry
@@ -78,7 +64,6 @@ class Redis
78
64
  raise Redis::TimeoutError
79
65
  end
80
66
  end
81
-
82
67
  rescue EOFError
83
68
  raise Errno::ECONNRESET
84
69
  end
@@ -86,7 +71,6 @@ class Redis
86
71
  def _write_to_socket(data)
87
72
  begin
88
73
  write_nonblock(data)
89
-
90
74
  rescue IO::WaitWritable
91
75
  if IO.select(nil, [self], nil, @write_timeout)
92
76
  retry
@@ -100,7 +84,6 @@ class Redis
100
84
  raise Redis::TimeoutError
101
85
  end
102
86
  end
103
-
104
87
  rescue EOFError
105
88
  raise Errno::ECONNRESET
106
89
  end
@@ -115,6 +98,7 @@ class Redis
115
98
 
116
99
  total_count += count
117
100
  return total_count if total_count >= length
101
+
118
102
  data = data.byteslice(count..-1)
119
103
  end
120
104
  end
@@ -125,7 +109,6 @@ class Redis
125
109
  require "timeout"
126
110
 
127
111
  class TCPSocket < ::TCPSocket
128
-
129
112
  include SocketMixin
130
113
 
131
114
  def self.connect(host, port, timeout)
@@ -141,7 +124,6 @@ class Redis
141
124
  if defined?(::UNIXSocket)
142
125
 
143
126
  class UNIXSocket < ::UNIXSocket
144
-
145
127
  include SocketMixin
146
128
 
147
129
  def self.connect(path, timeout)
@@ -159,7 +141,6 @@ class Redis
159
141
 
160
142
  def _read_from_socket(nbytes)
161
143
  readpartial(nbytes)
162
-
163
144
  rescue EOFError
164
145
  raise Errno::ECONNRESET
165
146
  end
@@ -170,19 +151,16 @@ class Redis
170
151
  else
171
152
 
172
153
  class TCPSocket < ::Socket
173
-
174
154
  include SocketMixin
175
155
 
176
- def self.connect_addrinfo(ai, port, timeout)
177
- sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
178
- sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
156
+ def self.connect_addrinfo(addrinfo, port, timeout)
157
+ sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
158
+ sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
179
159
 
180
160
  begin
181
161
  sock.connect_nonblock(sockaddr)
182
162
  rescue Errno::EINPROGRESS
183
- if IO.select(nil, [sock], nil, timeout) == nil
184
- raise TimeoutError
185
- end
163
+ raise TimeoutError if IO.select(nil, [sock], nil, timeout).nil?
186
164
 
187
165
  begin
188
166
  sock.connect_nonblock(sockaddr)
@@ -221,14 +199,13 @@ class Redis
221
199
  return connect_addrinfo(ai, port, timeout)
222
200
  rescue SystemCallError
223
201
  # Raise if this was our last attempt.
224
- raise if addrinfo.length == i+1
202
+ raise if addrinfo.length == i + 1
225
203
  end
226
204
  end
227
205
  end
228
206
  end
229
207
 
230
208
  class UNIXSocket < ::Socket
231
-
232
209
  include SocketMixin
233
210
 
234
211
  def self.connect(path, timeout)
@@ -238,9 +215,7 @@ class Redis
238
215
  begin
239
216
  sock.connect_nonblock(sockaddr)
240
217
  rescue Errno::EINPROGRESS
241
- if IO.select(nil, [sock], nil, timeout) == nil
242
- raise TimeoutError
243
- end
218
+ raise TimeoutError if IO.select(nil, [sock], nil, timeout).nil?
244
219
 
245
220
  begin
246
221
  sock.connect_nonblock(sockaddr)
@@ -263,7 +238,9 @@ class Redis
263
238
  tcp_sock = TCPSocket.connect(host, port, timeout)
264
239
 
265
240
  ctx = OpenSSL::SSL::SSLContext.new
266
- ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
241
+
242
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
243
+ ctx.set_params(ssl_params || {})
267
244
 
268
245
  ssl_sock = new(tcp_sock, ctx)
269
246
  ssl_sock.hostname = host
@@ -290,7 +267,10 @@ class Redis
290
267
  end
291
268
  end
292
269
 
293
- unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (ctx.respond_to?(:verify_hostname) && !ctx.verify_hostname)
270
+ unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
271
+ ctx.respond_to?(:verify_hostname) &&
272
+ !ctx.verify_hostname
273
+ )
294
274
  ssl_sock.post_connection_check(host)
295
275
  end
296
276
 
@@ -302,15 +282,16 @@ class Redis
302
282
  class Ruby
303
283
  include Redis::Connection::CommandHelper
304
284
 
305
- MINUS = "-".freeze
306
- PLUS = "+".freeze
307
- COLON = ":".freeze
308
- DOLLAR = "$".freeze
309
- ASTERISK = "*".freeze
285
+ MINUS = "-"
286
+ PLUS = "+"
287
+ COLON = ":"
288
+ DOLLAR = "$"
289
+ ASTERISK = "*"
310
290
 
311
291
  def self.connect(config)
312
292
  if config[:scheme] == "unix"
313
293
  raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
294
+
314
295
  sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
315
296
  elsif config[:scheme] == "rediss" || config[:ssl]
316
297
  sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
@@ -326,7 +307,7 @@ class Redis
326
307
  instance
327
308
  end
328
309
 
329
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
310
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
330
311
  def set_tcp_keepalive(keepalive)
331
312
  return unless keepalive.is_a?(Hash)
332
313
 
@@ -338,14 +319,13 @@ class Redis
338
319
 
339
320
  def get_tcp_keepalive
340
321
  {
341
- :time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
342
- :intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
343
- :probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
322
+ time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
323
+ intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
324
+ probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
344
325
  }
345
326
  end
346
327
  else
347
- def set_tcp_keepalive(keepalive)
348
- end
328
+ def set_tcp_keepalive(keepalive); end
349
329
 
350
330
  def get_tcp_keepalive
351
331
  {
@@ -354,13 +334,12 @@ class Redis
354
334
  end
355
335
 
356
336
  # disables Nagle's Algorithm, prevents multiple round trips with MULTI
357
- if [:IPPROTO_TCP, :TCP_NODELAY].all?{|c| Socket.const_defined? c}
337
+ if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
358
338
  def set_tcp_nodelay
359
339
  @sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
360
340
  end
361
341
  else
362
- def set_tcp_nodelay
363
- end
342
+ def set_tcp_nodelay; end
364
343
  end
365
344
 
366
345
  def initialize(sock)
@@ -368,7 +347,7 @@ class Redis
368
347
  end
369
348
 
370
349
  def connected?
371
- !! @sock
350
+ !!@sock
372
351
  end
373
352
 
374
353
  def disconnect
@@ -379,9 +358,7 @@ class Redis
379
358
  end
380
359
 
381
360
  def timeout=(timeout)
382
- if @sock.respond_to?(:timeout=)
383
- @sock.timeout = timeout
384
- end
361
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
385
362
  end
386
363
 
387
364
  def write_timeout=(timeout)
@@ -396,7 +373,6 @@ class Redis
396
373
  line = @sock.gets
397
374
  reply_type = line.slice!(0, 1)
398
375
  format_reply(reply_type, line)
399
-
400
376
  rescue Errno::EAGAIN
401
377
  raise TimeoutError
402
378
  end
@@ -408,7 +384,7 @@ class Redis
408
384
  when COLON then format_integer_reply(line)
409
385
  when DOLLAR then format_bulk_reply(line)
410
386
  when ASTERISK then format_multi_bulk_reply(line)
411
- else raise ProtocolError.new(reply_type)
387
+ else raise ProtocolError, reply_type
412
388
  end
413
389
  end
414
390
 
@@ -427,6 +403,7 @@ class Redis
427
403
  def format_bulk_reply(line)
428
404
  bulklen = line.to_i
429
405
  return if bulklen == -1
406
+
430
407
  reply = encode(@sock.read(bulklen))
431
408
  @sock.read(2) # Discard CRLF.
432
409
  reply
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "command_helper"
3
4
  require_relative "registry"
4
5
  require_relative "../errors"
5
6
  require "em-synchrony"
6
7
  require "hiredis/reader"
7
8
 
9
+ Kernel.warn(
10
+ "The redis synchrony driver is deprecated and will be removed in redis-rb 5.0. " \
11
+ "We're looking for people to maintain it as a separate gem, see https://github.com/redis/redis-rb/issues/915"
12
+ )
13
+
8
14
  class Redis
9
15
  module Connection
10
16
  class RedisClient < EventMachine::Connection
@@ -47,9 +53,7 @@ class Redis
47
53
 
48
54
  def read
49
55
  @req = EventMachine::DefaultDeferrable.new
50
- if @timeout > 0
51
- @req.timeout(@timeout, :timeout)
52
- end
56
+ @req.timeout(@timeout, :timeout) if @timeout > 0
53
57
  EventMachine::Synchrony.sync @req
54
58
  end
55
59
 
@@ -106,7 +110,7 @@ class Redis
106
110
  end
107
111
 
108
112
  def connected?
109
- @connection && @connection.connected?
113
+ @connection&.connected?
110
114
  end
111
115
 
112
116
  def timeout=(timeout)
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "hash_ring"
3
4
 
4
5
  class Redis
5
6
  class Distributed
6
-
7
7
  class CannotDistribute < RuntimeError
8
8
  def initialize(command)
9
9
  @command = command
10
10
  end
11
11
 
12
12
  def message
13
- "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need to be on the same server or because we cannot guarantee that the operation will be atomic."
13
+ "#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
14
+ "to be on the same server or because we cannot guarantee that the operation will be atomic."
14
15
  end
15
16
  end
16
17
 
@@ -34,9 +35,9 @@ class Redis
34
35
  end
35
36
 
36
37
  def add_node(options)
37
- options = { :url => options } if options.is_a?(String)
38
+ options = { url: options } if options.is_a?(String)
38
39
  options = @default_options.merge(options)
39
- @ring.add_node Redis.new( options )
40
+ @ring.add_node Redis.new(options)
40
41
  end
41
42
 
42
43
  # Change the selected database for the current connection.
@@ -145,12 +146,12 @@ class Redis
145
146
  end
146
147
 
147
148
  # Create a key using the serialized value, previously obtained using DUMP.
148
- def restore(key, ttl, serialized_value, options = {})
149
- node_for(key).restore(key, ttl, serialized_value, options)
149
+ def restore(key, ttl, serialized_value, **options)
150
+ node_for(key).restore(key, ttl, serialized_value, **options)
150
151
  end
151
152
 
152
153
  # Transfer a key from the connected instance to another instance.
153
- def migrate(key, options)
154
+ def migrate(_key, _options)
154
155
  raise CannotDistribute, :migrate
155
156
  end
156
157
 
@@ -171,8 +172,33 @@ class Redis
171
172
  end
172
173
 
173
174
  # Determine if a key exists.
174
- def exists(key)
175
- node_for(key).exists(key)
175
+ def exists(*args)
176
+ if !Redis.exists_returns_integer && args.size == 1
177
+ message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
178
+ "use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
179
+ "(#{::Kernel.caller(1, 1).first})\n"
180
+
181
+ if defined?(::Warning)
182
+ ::Warning.warn(message)
183
+ else
184
+ warn(message)
185
+ end
186
+ exists?(*args)
187
+ else
188
+ keys_per_node = args.group_by { |key| node_for(key) }
189
+ keys_per_node.inject(0) do |sum, (node, keys)|
190
+ sum + node._exists(*keys)
191
+ end
192
+ end
193
+ end
194
+
195
+ # Determine if any of the keys exists.
196
+ def exists?(*args)
197
+ keys_per_node = args.group_by { |key| node_for(key) }
198
+ keys_per_node.each do |node, keys|
199
+ return true if node.exists?(*keys)
200
+ end
201
+ false
176
202
  end
177
203
 
178
204
  # Find all keys matching the given pattern.
@@ -205,11 +231,11 @@ class Redis
205
231
  end
206
232
 
207
233
  # Sort the elements in a list, set or sorted set.
208
- def sort(key, options = {})
234
+ def sort(key, **options)
209
235
  keys = [key, options[:by], options[:store], *Array(options[:get])].compact
210
236
 
211
237
  ensure_same_node(:sort, keys) do |node|
212
- node.sort(key, options)
238
+ node.sort(key, **options)
213
239
  end
214
240
  end
215
241
 
@@ -244,8 +270,8 @@ class Redis
244
270
  end
245
271
 
246
272
  # Set the string value of a key.
247
- def set(key, value, options = {})
248
- node_for(key).set(key, value, options)
273
+ def set(key, value, **options)
274
+ node_for(key).set(key, value, **options)
249
275
  end
250
276
 
251
277
  # Set the time to live in seconds of a key.
@@ -264,20 +290,20 @@ class Redis
264
290
  end
265
291
 
266
292
  # Set multiple keys to multiple values.
267
- def mset(*args)
293
+ def mset(*_args)
268
294
  raise CannotDistribute, :mset
269
295
  end
270
296
 
271
- def mapped_mset(hash)
297
+ def mapped_mset(_hash)
272
298
  raise CannotDistribute, :mapped_mset
273
299
  end
274
300
 
275
301
  # Set multiple keys to multiple values, only if none of the keys exist.
276
- def msetnx(*args)
302
+ def msetnx(*_args)
277
303
  raise CannotDistribute, :msetnx
278
304
  end
279
305
 
280
- def mapped_msetnx(hash)
306
+ def mapped_msetnx(_hash)
281
307
  raise CannotDistribute, :mapped_msetnx
282
308
  end
283
309
 
@@ -336,7 +362,7 @@ class Redis
336
362
  end
337
363
 
338
364
  # Return the position of the first bit set to 1 or 0 in a string.
339
- def bitpos(key, bit, start=nil, stop=nil)
365
+ def bitpos(key, bit, start = nil, stop = nil)
340
366
  node_for(key).bitpos(key, bit, start, stop)
341
367
  end
342
368
 
@@ -354,7 +380,7 @@ class Redis
354
380
  get(key)
355
381
  end
356
382
 
357
- def []=(key,value)
383
+ def []=(key, value)
358
384
  set(key, value)
359
385
  end
360
386
 
@@ -439,15 +465,9 @@ class Redis
439
465
 
440
466
  # Pop a value from a list, push it to another list and return it; or block
441
467
  # until one is available.
442
- def brpoplpush(source, destination, options = {})
443
- case options
444
- when Integer
445
- # Issue deprecation notice in obnoxious mode...
446
- options = { :timeout => options }
447
- end
448
-
468
+ def brpoplpush(source, destination, deprecated_timeout = 0, **options)
449
469
  ensure_same_node(:brpoplpush, [source, destination]) do |node|
450
- node.brpoplpush(source, destination, options)
470
+ node.brpoplpush(source, destination, deprecated_timeout, **options)
451
471
  end
452
472
  end
453
473
 
@@ -524,13 +544,13 @@ class Redis
524
544
  end
525
545
 
526
546
  # Scan a set
527
- def sscan(key, cursor, options={})
528
- node_for(key).sscan(key, cursor, options)
547
+ def sscan(key, cursor, **options)
548
+ node_for(key).sscan(key, cursor, **options)
529
549
  end
530
550
 
531
551
  # Scan a set and return an enumerator
532
- def sscan_each(key, options={}, &block)
533
- node_for(key).sscan_each(key, options, &block)
552
+ def sscan_each(key, **options, &block)
553
+ node_for(key).sscan_each(key, **options, &block)
534
554
  end
535
555
 
536
556
  # Subtract multiple sets.
@@ -585,6 +605,7 @@ class Redis
585
605
  def zadd(key, *args)
586
606
  node_for(key).zadd(key, *args)
587
607
  end
608
+ ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
588
609
 
589
610
  # Increment the score of a member in a sorted set.
590
611
  def zincrby(key, increment, member)
@@ -602,14 +623,14 @@ class Redis
602
623
  end
603
624
 
604
625
  # Return a range of members in a sorted set, by index.
605
- def zrange(key, start, stop, options = {})
606
- node_for(key).zrange(key, start, stop, options)
626
+ def zrange(key, start, stop, **options)
627
+ node_for(key).zrange(key, start, stop, **options)
607
628
  end
608
629
 
609
630
  # Return a range of members in a sorted set, by index, with scores ordered
610
631
  # from high to low.
611
- def zrevrange(key, start, stop, options = {})
612
- node_for(key).zrevrange(key, start, stop, options)
632
+ def zrevrange(key, start, stop, **options)
633
+ node_for(key).zrevrange(key, start, stop, **options)
613
634
  end
614
635
 
615
636
  # Determine the index of a member in a sorted set.
@@ -629,14 +650,14 @@ class Redis
629
650
  end
630
651
 
631
652
  # Return a range of members in a sorted set, by score.
632
- def zrangebyscore(key, min, max, options = {})
633
- node_for(key).zrangebyscore(key, min, max, options)
653
+ def zrangebyscore(key, min, max, **options)
654
+ node_for(key).zrangebyscore(key, min, max, **options)
634
655
  end
635
656
 
636
657
  # Return a range of members in a sorted set, by score, with scores ordered
637
658
  # from high to low.
638
- def zrevrangebyscore(key, max, min, options = {})
639
- node_for(key).zrevrangebyscore(key, max, min, options)
659
+ def zrevrangebyscore(key, max, min, **options)
660
+ node_for(key).zrevrangebyscore(key, max, min, **options)
640
661
  end
641
662
 
642
663
  # Remove all members in a sorted set within the given scores.
@@ -651,16 +672,16 @@ class Redis
651
672
 
652
673
  # Intersect multiple sorted sets and store the resulting sorted set in a new
653
674
  # key.
654
- def zinterstore(destination, keys, options = {})
675
+ def zinterstore(destination, keys, **options)
655
676
  ensure_same_node(:zinterstore, [destination] + keys) do |node|
656
- node.zinterstore(destination, keys, options)
677
+ node.zinterstore(destination, keys, **options)
657
678
  end
658
679
  end
659
680
 
660
681
  # Add multiple sorted sets and store the resulting sorted set in a new key.
661
- def zunionstore(destination, keys, options = {})
682
+ def zunionstore(destination, keys, **options)
662
683
  ensure_same_node(:zunionstore, [destination] + keys) do |node|
663
- node.zunionstore(destination, keys, options)
684
+ node.zunionstore(destination, keys, **options)
664
685
  end
665
686
  end
666
687
 
@@ -669,9 +690,9 @@ class Redis
669
690
  node_for(key).hlen(key)
670
691
  end
671
692
 
672
- # Set the string value of a hash field.
673
- def hset(key, field, value)
674
- node_for(key).hset(key, field, value)
693
+ # Set multiple hash fields to multiple values.
694
+ def hset(key, *attrs)
695
+ node_for(key).hset(key, *attrs)
675
696
  end
676
697
 
677
698
  # Set the value of a hash field, only if the field does not exist.
@@ -743,7 +764,7 @@ class Redis
743
764
  end
744
765
 
745
766
  def subscribed?
746
- !! @subscribed_node
767
+ !!@subscribed_node
747
768
  end
748
769
 
749
770
  # Listen for messages published to the given channels.
@@ -761,7 +782,8 @@ class Redis
761
782
 
762
783
  # Stop listening for messages posted to the given channels.
763
784
  def unsubscribe(*channels)
764
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
785
+ raise "Can't unsubscribe if not subscribed." unless subscribed?
786
+
765
787
  @subscribed_node.unsubscribe(*channels)
766
788
  end
767
789
 
@@ -777,7 +799,7 @@ class Redis
777
799
  end
778
800
 
779
801
  # Watch the given keys to determine execution of the MULTI/EXEC block.
780
- def watch(*keys)
802
+ def watch(*_keys)
781
803
  raise CannotDistribute, :watch
782
804
  end
783
805
 
@@ -861,7 +883,7 @@ class Redis
861
883
  self.class.new(@node_configs, @default_options)
862
884
  end
863
885
 
864
- protected
886
+ protected
865
887
 
866
888
  def on_each_node(command, *args)
867
889
  nodes.map do |node|