redis 3.3.5 → 4.3.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.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +132 -2
  3. data/README.md +144 -79
  4. data/lib/redis.rb +1174 -405
  5. data/lib/redis/client.rb +150 -90
  6. data/lib/redis/cluster.rb +295 -0
  7. data/lib/redis/cluster/command.rb +81 -0
  8. data/lib/redis/cluster/command_loader.rb +34 -0
  9. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  10. data/lib/redis/cluster/node.rb +107 -0
  11. data/lib/redis/cluster/node_key.rb +31 -0
  12. data/lib/redis/cluster/node_loader.rb +37 -0
  13. data/lib/redis/cluster/option.rb +93 -0
  14. data/lib/redis/cluster/slot.rb +86 -0
  15. data/lib/redis/cluster/slot_loader.rb +49 -0
  16. data/lib/redis/connection.rb +4 -2
  17. data/lib/redis/connection/command_helper.rb +5 -10
  18. data/lib/redis/connection/hiredis.rb +6 -5
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +126 -128
  21. data/lib/redis/connection/synchrony.rb +21 -8
  22. data/lib/redis/distributed.rb +147 -72
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +30 -73
  25. data/lib/redis/pipeline.rb +55 -15
  26. data/lib/redis/subscribe.rb +11 -12
  27. data/lib/redis/version.rb +3 -1
  28. metadata +49 -202
  29. data/.gitignore +0 -16
  30. data/.travis.yml +0 -89
  31. data/.travis/Gemfile +0 -11
  32. data/.yardopts +0 -3
  33. data/Gemfile +0 -4
  34. data/Rakefile +0 -87
  35. data/benchmarking/logging.rb +0 -71
  36. data/benchmarking/pipeline.rb +0 -51
  37. data/benchmarking/speed.rb +0 -21
  38. data/benchmarking/suite.rb +0 -24
  39. data/benchmarking/worker.rb +0 -71
  40. data/examples/basic.rb +0 -15
  41. data/examples/consistency.rb +0 -114
  42. data/examples/dist_redis.rb +0 -43
  43. data/examples/incr-decr.rb +0 -17
  44. data/examples/list.rb +0 -26
  45. data/examples/pubsub.rb +0 -37
  46. data/examples/sentinel.rb +0 -41
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sets.rb +0 -36
  50. data/examples/unicorn/config.ru +0 -3
  51. data/examples/unicorn/unicorn.rb +0 -20
  52. data/redis.gemspec +0 -44
  53. data/test/bitpos_test.rb +0 -69
  54. data/test/blocking_commands_test.rb +0 -42
  55. data/test/client_test.rb +0 -59
  56. data/test/command_map_test.rb +0 -30
  57. data/test/commands_on_hashes_test.rb +0 -21
  58. data/test/commands_on_hyper_log_log_test.rb +0 -21
  59. data/test/commands_on_lists_test.rb +0 -20
  60. data/test/commands_on_sets_test.rb +0 -77
  61. data/test/commands_on_sorted_sets_test.rb +0 -137
  62. data/test/commands_on_strings_test.rb +0 -101
  63. data/test/commands_on_value_types_test.rb +0 -133
  64. data/test/connection_handling_test.rb +0 -277
  65. data/test/connection_test.rb +0 -57
  66. data/test/db/.gitkeep +0 -0
  67. data/test/distributed_blocking_commands_test.rb +0 -46
  68. data/test/distributed_commands_on_hashes_test.rb +0 -10
  69. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  70. data/test/distributed_commands_on_lists_test.rb +0 -22
  71. data/test/distributed_commands_on_sets_test.rb +0 -83
  72. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  73. data/test/distributed_commands_on_strings_test.rb +0 -59
  74. data/test/distributed_commands_on_value_types_test.rb +0 -95
  75. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  76. data/test/distributed_connection_handling_test.rb +0 -23
  77. data/test/distributed_internals_test.rb +0 -79
  78. data/test/distributed_key_tags_test.rb +0 -52
  79. data/test/distributed_persistence_control_commands_test.rb +0 -26
  80. data/test/distributed_publish_subscribe_test.rb +0 -92
  81. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  82. data/test/distributed_scripting_test.rb +0 -102
  83. data/test/distributed_sorting_test.rb +0 -20
  84. data/test/distributed_test.rb +0 -58
  85. data/test/distributed_transactions_test.rb +0 -32
  86. data/test/encoding_test.rb +0 -18
  87. data/test/error_replies_test.rb +0 -59
  88. data/test/fork_safety_test.rb +0 -65
  89. data/test/helper.rb +0 -232
  90. data/test/helper_test.rb +0 -24
  91. data/test/internals_test.rb +0 -417
  92. data/test/lint/blocking_commands.rb +0 -150
  93. data/test/lint/hashes.rb +0 -162
  94. data/test/lint/hyper_log_log.rb +0 -60
  95. data/test/lint/lists.rb +0 -143
  96. data/test/lint/sets.rb +0 -140
  97. data/test/lint/sorted_sets.rb +0 -316
  98. data/test/lint/strings.rb +0 -260
  99. data/test/lint/value_types.rb +0 -122
  100. data/test/persistence_control_commands_test.rb +0 -26
  101. data/test/pipelining_commands_test.rb +0 -242
  102. data/test/publish_subscribe_test.rb +0 -282
  103. data/test/remote_server_control_commands_test.rb +0 -118
  104. data/test/scanning_test.rb +0 -413
  105. data/test/scripting_test.rb +0 -78
  106. data/test/sentinel_command_test.rb +0 -80
  107. data/test/sentinel_test.rb +0 -255
  108. data/test/sorting_test.rb +0 -59
  109. data/test/ssl_test.rb +0 -73
  110. data/test/support/connection/hiredis.rb +0 -1
  111. data/test/support/connection/ruby.rb +0 -1
  112. data/test/support/connection/synchrony.rb +0 -17
  113. data/test/support/redis_mock.rb +0 -130
  114. data/test/support/ssl/gen_certs.sh +0 -31
  115. data/test/support/ssl/trusted-ca.crt +0 -25
  116. data/test/support/ssl/trusted-ca.key +0 -27
  117. data/test/support/ssl/trusted-cert.crt +0 -81
  118. data/test/support/ssl/trusted-cert.key +0 -28
  119. data/test/support/ssl/untrusted-ca.crt +0 -26
  120. data/test/support/ssl/untrusted-ca.key +0 -27
  121. data/test/support/ssl/untrusted-cert.crt +0 -82
  122. data/test/support/ssl/untrusted-cert.key +0 -28
  123. data/test/support/wire/synchrony.rb +0 -24
  124. data/test/support/wire/thread.rb +0 -5
  125. data/test/synchrony_driver.rb +0 -88
  126. data/test/test.conf.erb +0 -9
  127. data/test/thread_safety_test.rb +0 -62
  128. data/test/transactions_test.rb +0 -264
  129. data/test/unknown_commands_test.rb +0 -14
  130. data/test/url_param_test.rb +0 -138
@@ -1,12 +1,13 @@
1
- require "redis/connection/registry"
2
- require "redis/errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "registry"
4
+ require_relative "../errors"
3
5
  require "hiredis/connection"
4
6
  require "timeout"
5
7
 
6
8
  class Redis
7
9
  module Connection
8
10
  class Hiredis
9
-
10
11
  def self.connect(config)
11
12
  connection = ::Hiredis::Connection.new
12
13
  connect_timeout = (config.fetch(:connect_timeout, 0) * 1_000_000).to_i
@@ -31,7 +32,7 @@ class Redis
31
32
  end
32
33
 
33
34
  def connected?
34
- @connection && @connection.connected?
35
+ @connection&.connected?
35
36
  end
36
37
 
37
38
  def timeout=(timeout)
@@ -57,7 +58,7 @@ class Redis
57
58
  rescue Errno::EAGAIN
58
59
  raise TimeoutError
59
60
  rescue RuntimeError => err
60
- raise ProtocolError.new(err.message)
61
+ raise ProtocolError, err.message
61
62
  end
62
63
  end
63
64
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Redis
2
4
  module Connection
3
-
4
5
  # Store a list of loaded connection drivers in the Connection module.
5
6
  # Redis::Client uses the last required driver by default, and will be aware
6
7
  # of the loaded connection drivers if the user chooses to override the
@@ -1,6 +1,8 @@
1
- require "redis/connection/registry"
2
- require "redis/connection/command_helper"
3
- require "redis/errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "registry"
4
+ require_relative "command_helper"
5
+ require_relative "../errors"
4
6
  require "socket"
5
7
  require "timeout"
6
8
 
@@ -10,130 +12,87 @@ rescue LoadError
10
12
  # Not all systems have OpenSSL support
11
13
  end
12
14
 
13
- if RUBY_VERSION < "1.9.3"
14
- class String
15
- # Ruby 1.8.7 does not have byteslice, but it handles encodings differently anyway.
16
- # We can simply slice the string, which is a byte array there.
17
- def byteslice(*args)
18
- slice(*args)
19
- end
20
- end
21
- end
22
-
23
15
  class Redis
24
16
  module Connection
25
17
  module SocketMixin
26
-
27
- CRLF = "\r\n".freeze
28
-
29
- # Exceptions raised during non-blocking I/O ops that require retrying the op
30
- if RUBY_VERSION >= "1.9.3"
31
- NBIO_READ_EXCEPTIONS = [IO::WaitReadable]
32
- NBIO_WRITE_EXCEPTIONS = [IO::WaitWritable]
33
- else
34
- NBIO_READ_EXCEPTIONS = [Errno::EWOULDBLOCK, Errno::EAGAIN]
35
- NBIO_WRITE_EXCEPTIONS = [Errno::EWOULDBLOCK, Errno::EAGAIN]
36
- end
18
+ CRLF = "\r\n"
37
19
 
38
20
  def initialize(*args)
39
21
  super(*args)
40
22
 
41
23
  @timeout = @write_timeout = nil
42
- @buffer = ""
24
+ @buffer = "".dup
43
25
  end
44
26
 
45
27
  def timeout=(timeout)
46
- if timeout && timeout > 0
47
- @timeout = timeout
48
- else
49
- @timeout = nil
50
- end
28
+ @timeout = (timeout if timeout && timeout > 0)
51
29
  end
52
30
 
53
31
  def write_timeout=(timeout)
54
- if timeout && timeout > 0
55
- @write_timeout = timeout
56
- else
57
- @write_timeout = nil
58
- end
32
+ @write_timeout = (timeout if timeout && timeout > 0)
59
33
  end
60
34
 
61
35
  def read(nbytes)
62
36
  result = @buffer.slice!(0, nbytes)
63
37
 
64
- while result.bytesize < nbytes
65
- result << _read_from_socket(nbytes - result.bytesize)
66
- end
38
+ result << _read_from_socket(nbytes - result.bytesize) while result.bytesize < nbytes
67
39
 
68
40
  result
69
41
  end
70
42
 
71
43
  def gets
72
- crlf = nil
73
-
74
- while (crlf = @buffer.index(CRLF)) == nil
75
- @buffer << _read_from_socket(1024)
44
+ while (crlf = @buffer.index(CRLF)).nil?
45
+ @buffer << _read_from_socket(16_384)
76
46
  end
77
47
 
78
48
  @buffer.slice!(0, crlf + CRLF.bytesize)
79
49
  end
80
50
 
81
51
  def _read_from_socket(nbytes)
82
-
83
- begin
84
- read_nonblock(nbytes)
85
-
86
- rescue *NBIO_READ_EXCEPTIONS
87
- if IO.select([self], nil, nil, @timeout)
88
- retry
89
- else
90
- raise Redis::TimeoutError
91
- end
92
- rescue *NBIO_WRITE_EXCEPTIONS
93
- if IO.select(nil, [self], nil, @timeout)
94
- retry
95
- else
96
- raise Redis::TimeoutError
97
- end
98
- end
99
-
100
- rescue EOFError
101
- raise Errno::ECONNRESET
102
- end
103
-
104
- def _write_to_socket(data)
105
- begin
106
- write_nonblock(data)
107
-
108
- rescue *NBIO_WRITE_EXCEPTIONS
109
- if IO.select(nil, [self], nil, @write_timeout)
110
- retry
111
- else
112
- raise Redis::TimeoutError
113
- end
114
- rescue *NBIO_READ_EXCEPTIONS
115
- if IO.select([self], nil, nil, @write_timeout)
116
- retry
117
- else
118
- raise Redis::TimeoutError
52
+ loop do
53
+ case chunk = read_nonblock(nbytes, exception: false)
54
+ when :wait_readable
55
+ unless wait_readable(@timeout)
56
+ raise Redis::TimeoutError
57
+ end
58
+ when :wait_writable
59
+ unless wait_writable(@timeout)
60
+ raise Redis::TimeoutError
61
+ end
62
+ when nil
63
+ raise Errno::ECONNRESET
64
+ when String
65
+ return chunk
119
66
  end
120
67
  end
121
-
122
- rescue EOFError
123
- raise Errno::ECONNRESET
124
68
  end
125
69
 
126
- def write(data)
127
- return super(data) unless @write_timeout
70
+ def write(buffer)
71
+ return super(buffer) unless @write_timeout
128
72
 
129
- length = data.bytesize
130
- total_count = 0
73
+ bytes_to_write = buffer.bytesize
74
+ total_bytes_written = 0
131
75
  loop do
132
- count = _write_to_socket(data)
76
+ case bytes_written = write_nonblock(buffer, exception: false)
77
+ when :wait_readable
78
+ unless wait_readable(@write_timeout)
79
+ raise Redis::TimeoutError
80
+ end
81
+ when :wait_writable
82
+ unless wait_writable(@write_timeout)
83
+ raise Redis::TimeoutError
84
+ end
85
+ when nil
86
+ raise Errno::ECONNRESET
87
+ when Integer
88
+ total_bytes_written += bytes_written
89
+
90
+ if total_bytes_written >= bytes_to_write
91
+ return total_bytes_written
92
+ end
133
93
 
134
- total_count += count
135
- return total_count if total_count >= length
136
- data = data.byteslice(count..-1)
94
+ buffer = buffer.byteslice(bytes_written..-1)
95
+ end
137
96
  end
138
97
  end
139
98
  end
@@ -143,7 +102,6 @@ class Redis
143
102
  require "timeout"
144
103
 
145
104
  class TCPSocket < ::TCPSocket
146
-
147
105
  include SocketMixin
148
106
 
149
107
  def self.connect(host, port, timeout)
@@ -159,7 +117,6 @@ class Redis
159
117
  if defined?(::UNIXSocket)
160
118
 
161
119
  class UNIXSocket < ::UNIXSocket
162
-
163
120
  include SocketMixin
164
121
 
165
122
  def self.connect(path, timeout)
@@ -171,13 +128,12 @@ class Redis
171
128
  raise TimeoutError
172
129
  end
173
130
 
174
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
131
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
175
132
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
176
133
  # Use the blocking #readpartial method instead.
177
134
 
178
135
  def _read_from_socket(nbytes)
179
136
  readpartial(nbytes)
180
-
181
137
  rescue EOFError
182
138
  raise Errno::ECONNRESET
183
139
  end
@@ -188,19 +144,16 @@ class Redis
188
144
  else
189
145
 
190
146
  class TCPSocket < ::Socket
191
-
192
147
  include SocketMixin
193
148
 
194
- def self.connect_addrinfo(ai, port, timeout)
195
- sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
196
- sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
149
+ def self.connect_addrinfo(addrinfo, port, timeout)
150
+ sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
151
+ sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
197
152
 
198
153
  begin
199
154
  sock.connect_nonblock(sockaddr)
200
155
  rescue Errno::EINPROGRESS
201
- if IO.select(nil, [sock], nil, timeout) == nil
202
- raise TimeoutError
203
- end
156
+ raise TimeoutError unless sock.wait_writable(timeout)
204
157
 
205
158
  begin
206
159
  sock.connect_nonblock(sockaddr)
@@ -239,14 +192,13 @@ class Redis
239
192
  return connect_addrinfo(ai, port, timeout)
240
193
  rescue SystemCallError
241
194
  # Raise if this was our last attempt.
242
- raise if addrinfo.length == i+1
195
+ raise if addrinfo.length == i + 1
243
196
  end
244
197
  end
245
198
  end
246
199
  end
247
200
 
248
201
  class UNIXSocket < ::Socket
249
-
250
202
  include SocketMixin
251
203
 
252
204
  def self.connect(path, timeout)
@@ -256,9 +208,7 @@ class Redis
256
208
  begin
257
209
  sock.connect_nonblock(sockaddr)
258
210
  rescue Errno::EINPROGRESS
259
- if IO.select(nil, [sock], nil, timeout) == nil
260
- raise TimeoutError
261
- end
211
+ raise TimeoutError unless sock.wait_writable(timeout)
262
212
 
263
213
  begin
264
214
  sock.connect_nonblock(sockaddr)
@@ -276,17 +226,58 @@ class Redis
276
226
  class SSLSocket < ::OpenSSL::SSL::SSLSocket
277
227
  include SocketMixin
278
228
 
229
+ unless method_defined?(:wait_readable)
230
+ def wait_readable(timeout = nil)
231
+ to_io.wait_readable(timeout)
232
+ end
233
+ end
234
+
235
+ unless method_defined?(:wait_writable)
236
+ def wait_writable(timeout = nil)
237
+ to_io.wait_writable(timeout)
238
+ end
239
+ end
240
+
279
241
  def self.connect(host, port, timeout, ssl_params)
280
242
  # Note: this is using Redis::Connection::TCPSocket
281
243
  tcp_sock = TCPSocket.connect(host, port, timeout)
282
244
 
283
245
  ctx = OpenSSL::SSL::SSLContext.new
284
- ctx.set_params(ssl_params) if ssl_params && !ssl_params.empty?
246
+
247
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
248
+ ctx.set_params(ssl_params || {})
285
249
 
286
250
  ssl_sock = new(tcp_sock, ctx)
287
251
  ssl_sock.hostname = host
288
- ssl_sock.connect
289
- ssl_sock.post_connection_check(host)
252
+
253
+ begin
254
+ # Initiate the socket connection in the background. If it doesn't fail
255
+ # immediately it will raise an IO::WaitWritable (Errno::EINPROGRESS)
256
+ # indicating the connection is in progress.
257
+ # Unlike waiting for a tcp socket to connect, you can't time out ssl socket
258
+ # connections during the connect phase properly, because IO.select only partially works.
259
+ # Instead, you have to retry.
260
+ ssl_sock.connect_nonblock
261
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
262
+ if ssl_sock.wait_readable(timeout)
263
+ retry
264
+ else
265
+ raise TimeoutError
266
+ end
267
+ rescue IO::WaitWritable
268
+ if ssl_sock.wait_writable(timeout)
269
+ retry
270
+ else
271
+ raise TimeoutError
272
+ end
273
+ end
274
+
275
+ unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
276
+ ctx.respond_to?(:verify_hostname) &&
277
+ !ctx.verify_hostname
278
+ )
279
+ ssl_sock.post_connection_check(host)
280
+ end
290
281
 
291
282
  ssl_sock
292
283
  end
@@ -296,31 +287,32 @@ class Redis
296
287
  class Ruby
297
288
  include Redis::Connection::CommandHelper
298
289
 
299
- MINUS = "-".freeze
300
- PLUS = "+".freeze
301
- COLON = ":".freeze
302
- DOLLAR = "$".freeze
303
- ASTERISK = "*".freeze
290
+ MINUS = "-"
291
+ PLUS = "+"
292
+ COLON = ":"
293
+ DOLLAR = "$"
294
+ ASTERISK = "*"
304
295
 
305
296
  def self.connect(config)
306
297
  if config[:scheme] == "unix"
307
298
  raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
299
+
308
300
  sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
309
301
  elsif config[:scheme] == "rediss" || config[:ssl]
310
- raise ArgumentError, "This library does not support SSL on Ruby < 1.9" if RUBY_VERSION < "1.9.3"
311
302
  sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
312
303
  else
313
304
  sock = TCPSocket.connect(config[:host], config[:port], config[:connect_timeout])
314
305
  end
315
306
 
316
307
  instance = new(sock)
317
- instance.timeout = config[:timeout]
308
+ instance.timeout = config[:read_timeout]
318
309
  instance.write_timeout = config[:write_timeout]
319
310
  instance.set_tcp_keepalive config[:tcp_keepalive]
311
+ instance.set_tcp_nodelay if sock.is_a? TCPSocket
320
312
  instance
321
313
  end
322
314
 
323
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
315
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
324
316
  def set_tcp_keepalive(keepalive)
325
317
  return unless keepalive.is_a?(Hash)
326
318
 
@@ -332,14 +324,13 @@ class Redis
332
324
 
333
325
  def get_tcp_keepalive
334
326
  {
335
- :time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
336
- :intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
337
- :probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
327
+ time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
328
+ intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
329
+ probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
338
330
  }
339
331
  end
340
332
  else
341
- def set_tcp_keepalive(keepalive)
342
- end
333
+ def set_tcp_keepalive(keepalive); end
343
334
 
344
335
  def get_tcp_keepalive
345
336
  {
@@ -347,12 +338,21 @@ class Redis
347
338
  end
348
339
  end
349
340
 
341
+ # disables Nagle's Algorithm, prevents multiple round trips with MULTI
342
+ if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
343
+ def set_tcp_nodelay
344
+ @sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
345
+ end
346
+ else
347
+ def set_tcp_nodelay; end
348
+ end
349
+
350
350
  def initialize(sock)
351
351
  @sock = sock
352
352
  end
353
353
 
354
354
  def connected?
355
- !! @sock
355
+ !!@sock
356
356
  end
357
357
 
358
358
  def disconnect
@@ -363,9 +363,7 @@ class Redis
363
363
  end
364
364
 
365
365
  def timeout=(timeout)
366
- if @sock.respond_to?(:timeout=)
367
- @sock.timeout = timeout
368
- end
366
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
369
367
  end
370
368
 
371
369
  def write_timeout=(timeout)
@@ -380,7 +378,6 @@ class Redis
380
378
  line = @sock.gets
381
379
  reply_type = line.slice!(0, 1)
382
380
  format_reply(reply_type, line)
383
-
384
381
  rescue Errno::EAGAIN
385
382
  raise TimeoutError
386
383
  end
@@ -392,7 +389,7 @@ class Redis
392
389
  when COLON then format_integer_reply(line)
393
390
  when DOLLAR then format_bulk_reply(line)
394
391
  when ASTERISK then format_multi_bulk_reply(line)
395
- else raise ProtocolError.new(reply_type)
392
+ else raise ProtocolError, reply_type
396
393
  end
397
394
  end
398
395
 
@@ -411,6 +408,7 @@ class Redis
411
408
  def format_bulk_reply(line)
412
409
  bulklen = line.to_i
413
410
  return if bulklen == -1
411
+
414
412
  reply = encode(@sock.read(bulklen))
415
413
  @sock.read(2) # Discard CRLF.
416
414
  reply