redis 3.2.2 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 183e90b7d3961182b8b5b20b1295b6dd9d30df12
4
- data.tar.gz: 60023071a61af0e34d85b0a999db0bc5877070ad
3
+ metadata.gz: 4744291b8bc26230044fc12c456951a60c5802c7
4
+ data.tar.gz: 6eabe9bb60b74aa2408007a72f9a44e831b71a5e
5
5
  SHA512:
6
- metadata.gz: a1d93f8ee26f3dfecb10d223d178e4f78aa399d3bc8a78a4db479f0e6d89bd77c97d9e113b0138d102fbecf3d0a4452ce5f0da9412e069726c3b1fd7bb7bf7a4
7
- data.tar.gz: 1a2077544497d0f2a1cd9035677dc1d514a9395b070b10f380e8fcc35cbbbbbae898e1b4ad3e7ff44e2fb96930330cb66b021ccaa726451c2c15276ff26b0011
6
+ metadata.gz: 7fb460a3595ed430dbf4dab6f516dcbef029cf1c72350e4e50b7e425e8d94b8d47760d33f58db21bad95852ec97fa7fdba55cfb0858292c221c947516a291f97
7
+ data.tar.gz: 7cdf461c39d5eede9b295bf987391cd70461cd5adcee945ae243d509f67457ea14aa0ad08ca47efdab8bb8ca315d6bdff94460d6cecc6b981f459081cd93dfbd
data/.travis.yml CHANGED
@@ -6,8 +6,10 @@ rvm:
6
6
  - 2.0
7
7
  - 2.1
8
8
  - 2.2
9
+ - 2.3.0
9
10
  - jruby-18mode
10
11
  - jruby-19mode
12
+ - jruby-9.0.5.0
11
13
  - rbx-2
12
14
 
13
15
  gemfile: ".travis/Gemfile"
@@ -19,9 +21,12 @@ env:
19
21
  - VERBOSE=true
20
22
  - TIMEOUT=1
21
23
  matrix:
22
- - conn=ruby REDIS_BRANCH=2.8
23
- - conn=hiredis REDIS_BRANCH=2.8
24
- - conn=synchrony REDIS_BRANCH=2.8
24
+ - conn=ruby REDIS_BRANCH=3.0
25
+ - conn=ruby REDIS_BRANCH=3.2
26
+ - conn=hiredis REDIS_BRANCH=3.0
27
+ - conn=hiredis REDIS_BRANCH=3.2
28
+ - conn=synchrony REDIS_BRANCH=3.0
29
+ - conn=synchrony REDIS_BRANCH=3.2
25
30
  - conn=ruby REDIS_BRANCH=unstable
26
31
 
27
32
  branches:
@@ -33,27 +38,52 @@ matrix:
33
38
  # hiredis
34
39
  - rvm: jruby-18mode
35
40
  gemfile: .travis/Gemfile
36
- env: conn=hiredis REDIS_BRANCH=2.8
41
+ env: conn=hiredis REDIS_BRANCH=3.0
42
+ - rvm: jruby-18mode
43
+ gemfile: .travis/Gemfile
44
+ env: conn=hiredis REDIS_BRANCH=3.2
45
+ - rvm: jruby-19mode
46
+ gemfile: .travis/Gemfile
47
+ env: conn=hiredis REDIS_BRANCH=3.0
37
48
  - rvm: jruby-19mode
38
49
  gemfile: .travis/Gemfile
39
- env: conn=hiredis REDIS_BRANCH=2.8
50
+ env: conn=hiredis REDIS_BRANCH=3.2
51
+ - rvm: jruby-9.0.5.0
52
+ gemfile: .travis/Gemfile
53
+ env: conn=hiredis REDIS_BRANCH=3.0
54
+ - rvm: jruby-9.0.5.0
55
+ gemfile: .travis/Gemfile
56
+ env: conn=hiredis REDIS_BRANCH=3.2
40
57
 
41
58
  # synchrony
42
59
  - rvm: 1.8.7
43
60
  gemfile: .travis/Gemfile
44
- env: conn=synchrony REDIS_BRANCH=2.8
61
+ env: conn=synchrony REDIS_BRANCH=3.0
62
+ - rvm: 1.8.7
63
+ gemfile: .travis/Gemfile
64
+ env: conn=synchrony REDIS_BRANCH=3.2
65
+ - rvm: jruby-18mode
66
+ gemfile: .travis/Gemfile
67
+ env: conn=synchrony REDIS_BRANCH=3.0
45
68
  - rvm: jruby-18mode
46
69
  gemfile: .travis/Gemfile
47
- env: conn=synchrony REDIS_BRANCH=2.8
70
+ env: conn=synchrony REDIS_BRANCH=3.2
48
71
  - rvm: jruby-19mode
49
72
  gemfile: .travis/Gemfile
50
- env: conn=synchrony REDIS_BRANCH=2.8
73
+ env: conn=synchrony REDIS_BRANCH=3.0
74
+ - rvm: jruby-19mode
75
+ gemfile: .travis/Gemfile
76
+ env: conn=synchrony REDIS_BRANCH=3.2
77
+ - rvm: jruby-9.0.5.0
78
+ gemfile: .travis/Gemfile
79
+ env: conn=synchrony REDIS_BRANCH=3.0
80
+ - rvm: jruby-9.0.5.0
81
+ gemfile: .travis/Gemfile
82
+ env: conn=synchrony REDIS_BRANCH=3.2
51
83
  allow_failures:
52
84
  - rvm: rbx-2
53
85
 
54
86
  notifications:
55
87
  irc:
56
88
  - irc.freenode.net#redis-rb
57
- email:
58
- - damian.janowski@gmail.com
59
- - pcnoordhuis@gmail.com
89
+ email: false
data/CHANGELOG.md CHANGED
@@ -12,6 +12,25 @@
12
12
  security updates in June of 2013; continuing to support it would prevent
13
13
  the use of newer features of Ruby.
14
14
 
15
+ # 3.3.1
16
+
17
+ * Remove usage of Timeout::timeout, refactor into using low level non-blocking writes.
18
+ This fixes a memory leak due to Timeout creating threads on each invocation.
19
+
20
+ # 3.3.0
21
+
22
+ * Added support for SSL/TLS. Redis doesn't support SSL natively, so you still
23
+ need to run a terminating proxy on Redis' side. See #496.
24
+
25
+ * Added `read_timeout` and `write_timeout` options. See #437, #482.
26
+
27
+ * Added support for pub/sub with timeouts. See #329.
28
+
29
+ * Added `Redis#call`, `Redis#queue` and `Redis#commit` as a more minimal API to
30
+ the client.
31
+
32
+ * Deprecated `Redis#disconnect!` in favor of `Redis#close`.
33
+
15
34
  # 3.2.2
16
35
 
17
36
  * Added support for `ZADD` options `NX`, `XX`, `CH`, `INCR`. See #547.
data/README.md CHANGED
@@ -29,7 +29,7 @@ To install **redis-rb**, run the following command:
29
29
  gem install redis
30
30
  ```
31
31
 
32
- Or if you are using **bundler**, add
32
+ Or if you are using **bundler**, add
33
33
 
34
34
  ```
35
35
  gem 'redis', '~>3.2'
@@ -222,6 +222,86 @@ end
222
222
 
223
223
  See lib/redis/errors.rb for information about what exceptions are possible.
224
224
 
225
+ ## Timeouts
226
+
227
+ The client allows you to configure connect, read, and write timeouts.
228
+ Passing a single `timeout` option will set all three values:
229
+
230
+ ```ruby
231
+ Redis.new(:timeout => 1)
232
+ ```
233
+
234
+ But you can use specific values for each of them:
235
+
236
+ ```ruby
237
+ Redis.new(
238
+ :connect_timeout => 0.2,
239
+ :read_timeout => 1.0,
240
+ :write_timeout => 0.5
241
+ )
242
+ ```
243
+
244
+ All timeout values are specified in seconds.
245
+
246
+ When using pub/sub, you can subscribe to a channel using a timeout as well:
247
+
248
+ ```ruby
249
+ redis.subscribe_with_timeout(5, "news") do |on|
250
+ on.message do |channel, message|
251
+ # ...
252
+ end
253
+ end
254
+ ```
255
+
256
+ If no message is received after 5 seconds, the client will unsubscribe.
257
+
258
+
259
+ ## SSL/TLS Support
260
+
261
+ This library supports natively terminating client side SSL/TLS connections
262
+ when talking to Redis via a server-side proxy such as [stunnel], [hitch],
263
+ or [ghostunnel].
264
+
265
+ To enable SSL support, pass the `:ssl => :true` option when configuring the
266
+ Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
267
+ You will also need to pass in an `:ssl_params => { ... }` hash used to
268
+ configure the `OpenSSL::SSL::SSLContext` object used for the connection:
269
+
270
+ ```ruby
271
+ redis = Redis.new(
272
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
273
+ :ssl_params => {
274
+ :ca_file => "/path/to/ca.crt"
275
+ }
276
+ )
277
+ ```
278
+
279
+ The options given to `:ssl_params` are passed directly to the
280
+ `OpenSSL::SSL::SSLContext#set_params` method and can be any valid attribute
281
+ of the SSL context. Please see the [OpenSSL::SSL::SSLContext documentation]
282
+ for all of the available attributes.
283
+
284
+ Here is an example of passing in params that can be used for SSL client
285
+ certificate authentication (a.k.a. mutual TLS):
286
+
287
+ ```ruby
288
+ redis = Redis.new(
289
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
290
+ :ssl_params => {
291
+ :ca_file => "/path/to/ca.crt",
292
+ :cert => OpenSSL::X509::Certificate.new(File.read("client.crt")),
293
+ :key => OpenSSL::PKey::RSA.new(File.read("client.key"))
294
+ }
295
+ )
296
+ ```
297
+
298
+ [stunnel]: https://www.stunnel.org/
299
+ [hitch]: https://hitch-tls.org/
300
+ [ghostunnel]: https://github.com/square/ghostunnel
301
+ [OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.3.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
302
+
303
+ *NOTE:* SSL is only supported by the default "Ruby" driver
304
+
225
305
 
226
306
  ## Expert-Mode Options
227
307
 
@@ -298,9 +378,11 @@ This library is tested using [Travis][travis-home], where it is tested
298
378
  against the following interpreters and drivers:
299
379
 
300
380
  * MRI 1.8.7 (drivers: ruby, hiredis)
301
- * MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
302
381
  * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
303
- * MRI 2.0.0 (drivers: ruby, hiredis, synchrony)
382
+ * MRI 2.0 (drivers: ruby, hiredis, synchrony)
383
+ * MRI 2.1 (drivers: ruby, hiredis, synchrony)
384
+ * MRI 2.2 (drivers: ruby, hiredis, synchrony)
385
+ * MRI 2.3 (drivers: ruby, hiredis, synchrony)
304
386
  * JRuby 1.7 (1.8 mode) (drivers: ruby)
305
387
  * JRuby 1.7 (1.9 mode) (drivers: ruby)
306
388
 
data/lib/redis.rb CHANGED
@@ -49,6 +49,7 @@ class Redis
49
49
  def initialize(options = {})
50
50
  @options = options.dup
51
51
  @original_client = @client = Client.new(options)
52
+ @queue = Hash.new { |h, k| h[k] = [] }
52
53
 
53
54
  super() # Monitor#initialize
54
55
  end
@@ -75,9 +76,48 @@ class Redis
75
76
  end
76
77
 
77
78
  # Disconnect the client as quickly and silently as possible.
78
- def disconnect!
79
+ def close
79
80
  @original_client.disconnect
80
81
  end
82
+ alias disconnect! close
83
+
84
+ # Sends a command to Redis and returns its reply.
85
+ #
86
+ # Replies are converted to Ruby objects according to the RESP protocol, so
87
+ # you can expect a Ruby array, integer or nil when Redis sends one. Higher
88
+ # level transformations, such as converting an array of pairs into a Ruby
89
+ # hash, are up to consumers.
90
+ #
91
+ # Redis error replies are raised as Ruby exceptions.
92
+ def call(*command)
93
+ synchronize do |client|
94
+ client.call(command)
95
+ end
96
+ end
97
+
98
+ # Queues a command for pipelining.
99
+ #
100
+ # Commands in the queue are executed with the Redis#commit method.
101
+ #
102
+ # See http://redis.io/topics/pipelining for more details.
103
+ #
104
+ def queue(*command)
105
+ @queue[Thread.current.object_id] << command
106
+ end
107
+
108
+ # Sends all commands in the queue.
109
+ #
110
+ # See http://redis.io/topics/pipelining for more details.
111
+ #
112
+ def commit
113
+ synchronize do |client|
114
+ begin
115
+ client.call_pipelined(@queue[Thread.current.object_id])
116
+ ensure
117
+ @queue.delete(Thread.current.object_id)
118
+ end
119
+ end
120
+ end
81
121
 
82
122
  # Authenticate to the server.
83
123
  #
@@ -161,7 +201,7 @@ class Redis
161
201
  synchronize do |client|
162
202
  client.call([:config, action] + args) do |reply|
163
203
  if reply.kind_of?(Array) && action == :get
164
- Hash[_pairify(reply)]
204
+ Hashify.call(reply)
165
205
  else
166
206
  reply
167
207
  end
@@ -320,7 +360,7 @@ class Redis
320
360
  # @return [Boolean] whether the timeout was removed or not
321
361
  def persist(key)
322
362
  synchronize do |client|
323
- client.call([:persist, key], &_boolify)
363
+ client.call([:persist, key], &Boolify)
324
364
  end
325
365
  end
326
366
 
@@ -331,7 +371,7 @@ class Redis
331
371
  # @return [Boolean] whether the timeout was set or not
332
372
  def expire(key, seconds)
333
373
  synchronize do |client|
334
- client.call([:expire, key, seconds], &_boolify)
374
+ client.call([:expire, key, seconds], &Boolify)
335
375
  end
336
376
  end
337
377
 
@@ -342,7 +382,7 @@ class Redis
342
382
  # @return [Boolean] whether the timeout was set or not
343
383
  def expireat(key, unix_time)
344
384
  synchronize do |client|
345
- client.call([:expireat, key, unix_time], &_boolify)
385
+ client.call([:expireat, key, unix_time], &Boolify)
346
386
  end
347
387
  end
348
388
 
@@ -371,7 +411,7 @@ class Redis
371
411
  # @return [Boolean] whether the timeout was set or not
372
412
  def pexpire(key, milliseconds)
373
413
  synchronize do |client|
374
- client.call([:pexpire, key, milliseconds], &_boolify)
414
+ client.call([:pexpire, key, milliseconds], &Boolify)
375
415
  end
376
416
  end
377
417
 
@@ -382,7 +422,7 @@ class Redis
382
422
  # @return [Boolean] whether the timeout was set or not
383
423
  def pexpireat(key, ms_unix_time)
384
424
  synchronize do |client|
385
- client.call([:pexpireat, key, ms_unix_time], &_boolify)
425
+ client.call([:pexpireat, key, ms_unix_time], &Boolify)
386
426
  end
387
427
  end
388
428
 
@@ -461,7 +501,7 @@ class Redis
461
501
  # @return [Boolean]
462
502
  def exists(key)
463
503
  synchronize do |client|
464
- client.call([:exists, key], &_boolify)
504
+ client.call([:exists, key], &Boolify)
465
505
  end
466
506
  end
467
507
 
@@ -502,7 +542,7 @@ class Redis
502
542
  # @return [Boolean] whether the key was moved or not
503
543
  def move(key, db)
504
544
  synchronize do |client|
505
- client.call([:move, key, db], &_boolify)
545
+ client.call([:move, key, db], &Boolify)
506
546
  end
507
547
  end
508
548
 
@@ -539,7 +579,7 @@ class Redis
539
579
  # @return [Boolean] whether the key was renamed or not
540
580
  def renamenx(old_name, new_name)
541
581
  synchronize do |client|
542
- client.call([:renamenx, old_name, new_name], &_boolify)
582
+ client.call([:renamenx, old_name, new_name], &Boolify)
543
583
  end
544
584
  end
545
585
 
@@ -678,7 +718,7 @@ class Redis
678
718
  # @return [Float] value after incrementing it
679
719
  def incrbyfloat(key, increment)
680
720
  synchronize do |client|
681
- client.call([:incrbyfloat, key, increment], &_floatify)
721
+ client.call([:incrbyfloat, key, increment], &Floatify)
682
722
  end
683
723
  end
684
724
 
@@ -709,7 +749,7 @@ class Redis
709
749
 
710
750
  synchronize do |client|
711
751
  if nx || xx
712
- client.call([:set, key, value.to_s] + args, &_boolify_set)
752
+ client.call([:set, key, value.to_s] + args, &BoolifySet)
713
753
  else
714
754
  client.call([:set, key, value.to_s] + args)
715
755
  end
@@ -749,7 +789,7 @@ class Redis
749
789
  # @return [Boolean] whether the key was set or not
750
790
  def setnx(key, value)
751
791
  synchronize do |client|
752
- client.call([:setnx, key, value.to_s], &_boolify)
792
+ client.call([:setnx, key, value.to_s], &Boolify)
753
793
  end
754
794
  end
755
795
 
@@ -795,7 +835,7 @@ class Redis
795
835
  # @see #mapped_msetnx
796
836
  def msetnx(*args)
797
837
  synchronize do |client|
798
- client.call([:msetnx] + args, &_boolify)
838
+ client.call([:msetnx] + args, &Boolify)
799
839
  end
800
840
  end
801
841
 
@@ -844,7 +884,7 @@ class Redis
844
884
  # Get the values of all the given keys.
845
885
  #
846
886
  # @example
847
- # redis.mapped_mget("key1", "key1")
887
+ # redis.mapped_mget("key1", "key2")
848
888
  # # => { "key1" => "v1", "key2" => "v2" }
849
889
  #
850
890
  # @param [Array<String>] keys array of keys
@@ -1268,7 +1308,7 @@ class Redis
1268
1308
  reply
1269
1309
  else
1270
1310
  # Single argument: return boolean
1271
- _boolify.call(reply)
1311
+ Boolify.call(reply)
1272
1312
  end
1273
1313
  end
1274
1314
  end
@@ -1290,7 +1330,7 @@ class Redis
1290
1330
  reply
1291
1331
  else
1292
1332
  # Single argument: return boolean
1293
- _boolify.call(reply)
1333
+ Boolify.call(reply)
1294
1334
  end
1295
1335
  end
1296
1336
  end
@@ -1329,7 +1369,7 @@ class Redis
1329
1369
  # @return [Boolean]
1330
1370
  def smove(source, destination, member)
1331
1371
  synchronize do |client|
1332
- client.call([:smove, source, destination, member], &_boolify)
1372
+ client.call([:smove, source, destination, member], &Boolify)
1333
1373
  end
1334
1374
  end
1335
1375
 
@@ -1340,7 +1380,7 @@ class Redis
1340
1380
  # @return [Boolean]
1341
1381
  def sismember(key, member)
1342
1382
  synchronize do |client|
1343
- client.call([:sismember, key, member], &_boolify)
1383
+ client.call([:sismember, key, member], &Boolify)
1344
1384
  end
1345
1385
  end
1346
1386
 
@@ -1483,10 +1523,10 @@ class Redis
1483
1523
  synchronize do |client|
1484
1524
  if args.size == 1 && args[0].is_a?(Array)
1485
1525
  # Variadic: return float if INCR, integer if !INCR
1486
- client.call([:zadd, key] + zadd_options + args[0], &(incr ? _floatify : _identity))
1526
+ client.call([:zadd, key] + zadd_options + args[0], &(incr ? Floatify : nil))
1487
1527
  elsif args.size == 2
1488
1528
  # Single pair: return float if INCR, boolean if !INCR
1489
- client.call([:zadd, key] + zadd_options + args, &(incr ? _floatify : _boolify))
1529
+ client.call([:zadd, key] + zadd_options + args, &(incr ? Floatify : Boolify))
1490
1530
  else
1491
1531
  raise ArgumentError, "wrong number of arguments"
1492
1532
  end
@@ -1505,7 +1545,7 @@ class Redis
1505
1545
  # @return [Float] score of the member after incrementing it
1506
1546
  def zincrby(key, increment, member)
1507
1547
  synchronize do |client|
1508
- client.call([:zincrby, key, increment, member], &_floatify)
1548
+ client.call([:zincrby, key, increment, member], &Floatify)
1509
1549
  end
1510
1550
  end
1511
1551
 
@@ -1534,7 +1574,7 @@ class Redis
1534
1574
  reply
1535
1575
  else
1536
1576
  # Single argument: return boolean
1537
- _boolify.call(reply)
1577
+ Boolify.call(reply)
1538
1578
  end
1539
1579
  end
1540
1580
  end
@@ -1551,7 +1591,7 @@ class Redis
1551
1591
  # @return [Float] score of the member
1552
1592
  def zscore(key, member)
1553
1593
  synchronize do |client|
1554
- client.call([:zscore, key, member], &_floatify)
1594
+ client.call([:zscore, key, member], &Floatify)
1555
1595
  end
1556
1596
  end
1557
1597
 
@@ -1580,7 +1620,7 @@ class Redis
1580
1620
 
1581
1621
  if with_scores
1582
1622
  args << "WITHSCORES"
1583
- block = _floatify_pairs
1623
+ block = FloatifyPairs
1584
1624
  end
1585
1625
 
1586
1626
  synchronize do |client|
@@ -1606,7 +1646,7 @@ class Redis
1606
1646
 
1607
1647
  if with_scores
1608
1648
  args << "WITHSCORES"
1609
- block = _floatify_pairs
1649
+ block = FloatifyPairs
1610
1650
  end
1611
1651
 
1612
1652
  synchronize do |client|
@@ -1744,7 +1784,7 @@ class Redis
1744
1784
 
1745
1785
  if with_scores
1746
1786
  args << "WITHSCORES"
1747
- block = _floatify_pairs
1787
+ block = FloatifyPairs
1748
1788
  end
1749
1789
 
1750
1790
  limit = options[:limit]
@@ -1776,7 +1816,7 @@ class Redis
1776
1816
 
1777
1817
  if with_scores
1778
1818
  args << ["WITHSCORES"]
1779
- block = _floatify_pairs
1819
+ block = FloatifyPairs
1780
1820
  end
1781
1821
 
1782
1822
  limit = options[:limit]
@@ -1906,7 +1946,7 @@ class Redis
1906
1946
  # @return [Boolean] whether or not the field was **added** to the hash
1907
1947
  def hset(key, field, value)
1908
1948
  synchronize do |client|
1909
- client.call([:hset, key, field, value], &_boolify)
1949
+ client.call([:hset, key, field, value], &Boolify)
1910
1950
  end
1911
1951
  end
1912
1952
 
@@ -1918,7 +1958,7 @@ class Redis
1918
1958
  # @return [Boolean] whether or not the field was **added** to the hash
1919
1959
  def hsetnx(key, field, value)
1920
1960
  synchronize do |client|
1921
- client.call([:hsetnx, key, field, value], &_boolify)
1961
+ client.call([:hsetnx, key, field, value], &Boolify)
1922
1962
  end
1923
1963
  end
1924
1964
 
@@ -2021,7 +2061,7 @@ class Redis
2021
2061
  # @return [Boolean] whether or not the field exists in the hash
2022
2062
  def hexists(key, field)
2023
2063
  synchronize do |client|
2024
- client.call([:hexists, key, field], &_boolify)
2064
+ client.call([:hexists, key, field], &Boolify)
2025
2065
  end
2026
2066
  end
2027
2067
 
@@ -2045,7 +2085,7 @@ class Redis
2045
2085
  # @return [Float] value of the field after incrementing it
2046
2086
  def hincrbyfloat(key, field, increment)
2047
2087
  synchronize do |client|
2048
- client.call([:hincrbyfloat, key, field, increment], &_floatify)
2088
+ client.call([:hincrbyfloat, key, field, increment], &Floatify)
2049
2089
  end
2050
2090
  end
2051
2091
 
@@ -2075,7 +2115,7 @@ class Redis
2075
2115
  # @return [Hash<String, String>]
2076
2116
  def hgetall(key)
2077
2117
  synchronize do |client|
2078
- client.call([:hgetall, key], &_hashify)
2118
+ client.call([:hgetall, key], &Hashify)
2079
2119
  end
2080
2120
  end
2081
2121
 
@@ -2095,7 +2135,14 @@ class Redis
2095
2135
  # Listen for messages published to the given channels.
2096
2136
  def subscribe(*channels, &block)
2097
2137
  synchronize do |client|
2098
- _subscription(:subscribe, channels, block)
2138
+ _subscription(:subscribe, 0, channels, block)
2139
+ end
2140
+ end
2141
+
2142
+ # Listen for messages published to the given channels. Throw a timeout error if there is no messages for a timeout period.
2143
+ def subscribe_with_timeout(timeout, *channels, &block)
2144
+ synchronize do |client|
2145
+ _subscription(:subscribe_with_timeout, timeout, channels, block)
2099
2146
  end
2100
2147
  end
2101
2148
 
@@ -2110,7 +2157,14 @@ class Redis
2110
2157
  # Listen for messages published to channels matching the given patterns.
2111
2158
  def psubscribe(*channels, &block)
2112
2159
  synchronize do |client|
2113
- _subscription(:psubscribe, channels, block)
2160
+ _subscription(:psubscribe, 0, channels, block)
2161
+ end
2162
+ end
2163
+
2164
+ # Listen for messages published to channels matching the given patterns. Throw a timeout error if there is no messages for a timeout period.
2165
+ def psubscribe_with_timeout(timeout, *channels, &block)
2166
+ synchronize do |client|
2167
+ _subscription(:psubscribe_with_timeout, timeout, channels, block)
2114
2168
  end
2115
2169
  end
2116
2170
 
@@ -2312,7 +2366,7 @@ class Redis
2312
2366
  arg = args.first
2313
2367
 
2314
2368
  client.call([:script, :exists, arg]) do |reply|
2315
- reply = reply.map { |r| _boolify.call(r) }
2369
+ reply = reply.map { |r| Boolify.call(r) }
2316
2370
 
2317
2371
  if arg.is_a?(Array)
2318
2372
  reply
@@ -2466,7 +2520,7 @@ class Redis
2466
2520
  # @return [String, Array<[String, String]>] the next cursor and all found keys
2467
2521
  def hscan(key, cursor, options={})
2468
2522
  _scan(:hscan, cursor, [key], options) do |reply|
2469
- [reply[0], _pairify(reply[1])]
2523
+ [reply[0], reply[1].each_slice(2).to_a]
2470
2524
  end
2471
2525
  end
2472
2526
 
@@ -2505,7 +2559,7 @@ class Redis
2505
2559
  # members and scores
2506
2560
  def zscan(key, cursor, options={})
2507
2561
  _scan(:zscan, cursor, [key], options) do |reply|
2508
- [reply[0], _floatify_pairs.call(reply[1])]
2562
+ [reply[0], FloatifyPairs.call(reply[1])]
2509
2563
  end
2510
2564
  end
2511
2565
 
@@ -2573,7 +2627,7 @@ class Redis
2573
2627
  # @return [Boolean] true if at least 1 HyperLogLog internal register was altered. false otherwise.
2574
2628
  def pfadd(key, member)
2575
2629
  synchronize do |client|
2576
- client.call([:pfadd, key, member], &_boolify)
2630
+ client.call([:pfadd, key, member], &Boolify)
2577
2631
  end
2578
2632
  end
2579
2633
 
@@ -2598,7 +2652,7 @@ class Redis
2598
2652
  # @return [Boolean]
2599
2653
  def pfmerge(dest_key, *source_key)
2600
2654
  synchronize do |client|
2601
- client.call([:pfmerge, dest_key, *source_key], &_boolify_set)
2655
+ client.call([:pfmerge, dest_key, *source_key], &BoolifySet)
2602
2656
  end
2603
2657
  end
2604
2658
 
@@ -2617,9 +2671,9 @@ class Redis
2617
2671
  else
2618
2672
  if reply.kind_of?(Array)
2619
2673
  if reply[0].kind_of?(Array)
2620
- reply.map(&_hashify)
2674
+ reply.map(&Hashify)
2621
2675
  else
2622
- _hashify.call(reply)
2676
+ Hashify.call(reply)
2623
2677
  end
2624
2678
  else
2625
2679
  reply
@@ -2652,13 +2706,12 @@ private
2652
2706
  # Commands returning 1 for true and 0 for false may be executed in a pipeline
2653
2707
  # where the method call will return nil. Propagate the nil instead of falsely
2654
2708
  # returning false.
2655
- def _boolify
2709
+ Boolify =
2656
2710
  lambda { |value|
2657
2711
  value == 1 if value
2658
2712
  }
2659
- end
2660
2713
 
2661
- def _boolify_set
2714
+ BoolifySet =
2662
2715
  lambda { |value|
2663
2716
  if value && "OK" == value
2664
2717
  true
@@ -2666,9 +2719,8 @@ private
2666
2719
  false
2667
2720
  end
2668
2721
  }
2669
- end
2670
2722
 
2671
- def _hashify
2723
+ Hashify =
2672
2724
  lambda { |array|
2673
2725
  hash = Hash.new
2674
2726
  array.each_slice(2) do |field, value|
@@ -2676,46 +2728,37 @@ private
2676
2728
  end
2677
2729
  hash
2678
2730
  }
2679
- end
2680
2731
 
2681
- def _floatify
2732
+ Floatify =
2682
2733
  lambda { |str|
2683
- return unless str
2684
-
2685
- if (inf = str.match(/^(-)?inf/i))
2686
- (inf[1] ? -1.0 : 1.0) / 0.0
2687
- else
2688
- Float(str)
2734
+ if str
2735
+ if (inf = str.match(/^(-)?inf/i))
2736
+ (inf[1] ? -1.0 : 1.0) / 0.0
2737
+ else
2738
+ Float(str)
2739
+ end
2689
2740
  end
2690
2741
  }
2691
- end
2692
2742
 
2693
- def _floatify_pairs
2743
+ FloatifyPairs =
2694
2744
  lambda { |array|
2695
- return unless array
2696
-
2697
- array.each_slice(2).map do |member, score|
2698
- [member, _floatify.call(score)]
2745
+ if array
2746
+ array.each_slice(2).map do |member, score|
2747
+ [member, Floatify.call(score)]
2748
+ end
2699
2749
  end
2700
2750
  }
2701
- end
2702
-
2703
- def _pairify(array)
2704
- array.each_slice(2).to_a
2705
- end
2706
-
2707
- def _identity
2708
- lambda { |value|
2709
- value
2710
- }
2711
- end
2712
2751
 
2713
- def _subscription(method, channels, block)
2752
+ def _subscription(method, timeout, channels, block)
2714
2753
  return @client.call([method] + channels) if subscribed?
2715
2754
 
2716
2755
  begin
2717
2756
  original, @client = @client, SubscribedClient.new(@client)
2718
- @client.send(method, *channels, &block)
2757
+ if timeout > 0
2758
+ @client.send(method, timeout, *channels, &block)
2759
+ else
2760
+ @client.send(method, *channels, &block)
2761
+ end
2719
2762
  ensure
2720
2763
  @client = original
2721
2764
  end