redis 1.0.2 → 1.0.3

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.
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ GEM_VERSION = Redis::VERSION
12
12
  AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi']
13
13
  EMAIL = "ez@engineyard.com"
14
14
  HOMEPAGE = "http://github.com/ezmobius/redis-rb"
15
- SUMMARY = "Ruby client library for redis key value storage server"
15
+ SUMMARY = "Ruby client library for Redis, the key value storage server"
16
16
 
17
17
  spec = Gem::Specification.new do |s|
18
18
  s.name = GEM
@@ -25,7 +25,6 @@ spec = Gem::Specification.new do |s|
25
25
  s.authors = AUTHORS
26
26
  s.email = EMAIL
27
27
  s.homepage = HOMEPAGE
28
- s.add_development_dependency "rspec"
29
28
  s.require_path = 'lib'
30
29
  s.autorequire = GEM
31
30
  s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  class Redis
4
- VERSION = "1.0.2"
4
+ VERSION = "1.0.3"
5
5
 
6
6
  def self.new(*attrs)
7
7
  Client.new(*attrs)
@@ -1,5 +1,11 @@
1
1
  class Redis
2
2
  class Client
3
+ class ProtocolError < RuntimeError
4
+ def initialize(reply_type)
5
+ super("Protocol error, got '#{reply_type}' as initial reply byte")
6
+ end
7
+ end
8
+
3
9
  OK = "OK".freeze
4
10
  MINUS = "-".freeze
5
11
  PLUS = "+".freeze
@@ -215,8 +221,8 @@ class Redis
215
221
  end
216
222
 
217
223
  def sort(key, options = {})
218
- cmd = ["SORT"]
219
- cmd << key
224
+ cmd = []
225
+ cmd << "SORT #{key}"
220
226
  cmd << "BY #{options[:by]}" if options[:by]
221
227
  cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get]
222
228
  cmd << "#{options[:order]}" if options[:order]
@@ -226,11 +232,21 @@ class Redis
226
232
  end
227
233
 
228
234
  def incr(key, increment = nil)
229
- call_command(increment ? ["incrby",key,increment] : ["incr",key])
235
+ if increment
236
+ deprecated("incr with an increment", :incrby, caller[0])
237
+ incrby(key, increment)
238
+ else
239
+ call_command([:incr, key])
240
+ end
230
241
  end
231
242
 
232
- def decr(key,decrement = nil)
233
- call_command(decrement ? ["decrby",key,decrement] : ["decr",key])
243
+ def decr(key, decrement = nil)
244
+ if decrement
245
+ deprecated("decr with a decrement", :decrby, caller[0])
246
+ decrby(key, decrement)
247
+ else
248
+ call_command([:decr, key])
249
+ end
234
250
  end
235
251
 
236
252
  # Ruby defines a now deprecated type method so we need to override it here
@@ -270,13 +286,13 @@ class Redis
270
286
  end
271
287
 
272
288
  def subscribe(*classes)
273
- # Top-level `subscribe` MUST be called with a block,
274
- # nested `subscribe` MUST NOT be called with a block
275
- if !@pubsub && !block_given?
289
+ # Top-level `subscribe` MUST be called with a block,
290
+ # nested `subscribe` MUST NOT be called with a block
291
+ if !@pubsub && !block_given?
276
292
  raise "Top-level subscribe requires a block"
277
- elsif @pubsub == true && block_given?
293
+ elsif @pubsub == true && block_given?
278
294
  raise "Nested subscribe does not take a block"
279
- elsif @pubsub
295
+ elsif @pubsub
280
296
  # If we're already pubsub'ing, just subscribe us to some more classes
281
297
  call_command [:subscribe,*classes]
282
298
  return true
@@ -305,26 +321,21 @@ class Redis
305
321
  end
306
322
  end
307
323
 
308
- def unsubscribe(*classes)
309
- call_command [:unsubscribe,*classes]
310
- return true
311
- end
312
-
324
+ # Wrap raw_call_command to handle reconnection on socket error. We
325
+ # try to reconnect just one time, otherwise let the error araise.
313
326
  def call_command(argv)
314
327
  log(argv.inspect, :debug)
315
328
 
316
- # this wrapper to raw_call_command handle reconnection on socket
317
- # error. We try to reconnect just one time, otherwise let the error
318
- # araise.
319
- connect_to_server if !@sock
329
+ connect_to_server unless connected?
320
330
 
321
331
  begin
322
332
  raw_call_command(argv.dup)
323
333
  rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED
324
- @sock.close rescue nil
325
- @sock = nil
326
- connect_to_server
327
- raw_call_command(argv.dup)
334
+ if reconnect
335
+ raw_call_command(argv.dup)
336
+ else
337
+ raise Errno::ECONNRESET
338
+ end
328
339
  end
329
340
  end
330
341
 
@@ -332,35 +343,38 @@ class Redis
332
343
  "#{@host}:#{@port}"
333
344
  end
334
345
 
335
- def connect_to(host, port, timeout=nil)
336
- # We support connect() timeout only if system_timer is availabe
346
+ def connect_to(host, port)
347
+
348
+ # We support connect_to() timeout only if system_timer is availabe
337
349
  # or if we are running against Ruby >= 1.9
338
350
  # Timeout reading from the socket instead will be supported anyway.
339
351
  if @timeout != 0 and Timer
340
352
  begin
341
- sock = TCPSocket.new(host, port)
353
+ @sock = TCPSocket.new(host, port)
342
354
  rescue Timeout::Error
343
355
  @sock = nil
344
356
  raise Timeout::Error, "Timeout connecting to the server"
345
357
  end
346
358
  else
347
- sock = TCPSocket.new(host, port)
359
+ @sock = TCPSocket.new(host, port)
348
360
  end
349
- sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
361
+
362
+ @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
350
363
 
351
364
  # If the timeout is set we set the low level socket options in order
352
365
  # to make sure a blocking read will return after the specified number
353
366
  # of seconds. This hack is from memcached ruby client.
354
- if timeout
355
- set_socket_timeout(sock, timeout)
356
- end
357
- sock
367
+ set_socket_timeout!(@timeout) if @timeout
368
+
369
+ rescue Errno::ECONNREFUSED
370
+ raise Errno::ECONNREFUSED, "Unable to connect to Redis on #{host}:#{port}"
358
371
  end
359
372
 
360
373
  def connect_to_server
361
- @sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout)
362
- call_command(["auth",@password]) if @password
363
- call_command(["select",@db]) unless @db == 0
374
+ connect_to(@host, @port)
375
+ call_command([:auth, @password]) if @password
376
+ call_command([:select, @db]) if @db != 0
377
+ @sock
364
378
  end
365
379
 
366
380
  def method_missing(*argv)
@@ -412,10 +426,10 @@ class Redis
412
426
  # The normal command execution is reading and processing the reply.
413
427
  results = maybe_lock do
414
428
  begin
415
- set_socket_timeout(@sock, 0) if requires_timeout_reset?(argvv[0][0].to_s)
429
+ set_socket_timeout!(0) if requires_timeout_reset?(argvv[0][0].to_s)
416
430
  process_command(command, argvv)
417
431
  ensure
418
- set_socket_timeout(@sock, @timeout) if requires_timeout_reset?(argvv[0][0].to_s)
432
+ set_socket_timeout!(@timeout) if requires_timeout_reset?(argvv[0][0].to_s)
419
433
  end
420
434
  end
421
435
 
@@ -439,50 +453,33 @@ class Redis
439
453
  end
440
454
 
441
455
  def read_reply
456
+
442
457
  # We read the first byte using read() mainly because gets() is
443
458
  # immune to raw socket timeouts.
444
459
  begin
445
- rtype = @sock.read(1)
460
+ reply_type = @sock.read(1)
446
461
  rescue Errno::EAGAIN
462
+
447
463
  # We want to make sure it reconnects on the next command after the
448
464
  # timeout. Otherwise the server may reply in the meantime leaving
449
465
  # the protocol in a desync status.
450
- @sock = nil
466
+ disconnect
467
+
451
468
  raise Errno::EAGAIN, "Timeout reading from the socket"
452
469
  end
453
470
 
454
- raise Errno::ECONNRESET,"Connection lost" if !rtype
455
- line = @sock.gets
456
- case rtype
457
- when MINUS
458
- raise MINUS + line.strip
459
- when PLUS
460
- line.strip
461
- when COLON
462
- line.to_i
463
- when DOLLAR
464
- bulklen = line.to_i
465
- return nil if bulklen == -1
466
- data = @sock.read(bulklen)
467
- @sock.read(2) # CRLF
468
- data
469
- when ASTERISK
470
- objects = line.to_i
471
- return nil if bulklen == -1
472
- res = []
473
- objects.times {
474
- res << read_reply
475
- }
476
- res
477
- else
478
- raise "Protocol error, got '#{rtype}' as initial reply byte"
479
- end
471
+ raise Errno::ECONNRESET, "Connection lost" unless reply_type
472
+
473
+ format_reply(reply_type, @sock.gets)
480
474
  end
481
475
 
476
+
482
477
  def get_size(string)
483
478
  string.respond_to?(:bytesize) ? string.bytesize : string.size
484
479
  end
485
480
 
481
+ private
482
+
486
483
  def log(str, level = :info)
487
484
  @logger.send(level, str.to_s) if @logger
488
485
  end
@@ -494,19 +491,73 @@ class Redis
494
491
  def requires_timeout_reset?(command)
495
492
  BLOCKING_COMMANDS[command] && @timeout
496
493
  end
497
-
498
- def set_socket_timeout(sock, timeout)
494
+
495
+ def set_socket_timeout!(timeout)
499
496
  secs = Integer(timeout)
500
497
  usecs = Integer((timeout - secs) * 1_000_000)
501
498
  optval = [secs, usecs].pack("l_2")
502
499
  begin
503
- sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
504
- sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
505
- rescue Exception => ex
500
+ @sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
501
+ @sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
502
+ rescue Exception => e
506
503
  # Solaris, for one, does not like/support socket timeouts.
507
- log("Unable to use raw socket timeouts: #{ex.class.name}: #{ex.message}")
504
+ log("Unable to use raw socket timeouts: #{e.class.name}: #{e.message}")
508
505
  end
509
506
  end
510
507
 
508
+ def connected?
509
+ !! @sock
510
+ end
511
+
512
+ def disconnect
513
+ begin
514
+ @sock.close
515
+ rescue
516
+ ensure
517
+ @sock = nil
518
+ end
519
+ true
520
+ end
521
+
522
+ def reconnect
523
+ disconnect && connect_to_server
524
+ end
525
+
526
+ def format_reply(reply_type, line)
527
+ case reply_type
528
+ when MINUS then format_error_reply(line)
529
+ when PLUS then format_status_reply(line)
530
+ when COLON then format_integer_reply(line)
531
+ when DOLLAR then format_bulk_reply(line)
532
+ when ASTERISK then format_multi_bulk_reply(line)
533
+ else raise ProtocolError.new(reply_type)
534
+ end
535
+ end
536
+
537
+ def format_error_reply(line)
538
+ raise "-" + line.strip
539
+ end
540
+
541
+ def format_status_reply(line)
542
+ line.strip
543
+ end
544
+
545
+ def format_integer_reply(line)
546
+ line.to_i
547
+ end
548
+
549
+ def format_bulk_reply(line)
550
+ bulklen = line.to_i
551
+ return if bulklen == -1
552
+ reply = @sock.read(bulklen)
553
+ @sock.read(2) # Discard CRLF.
554
+ reply
555
+ end
556
+
557
+ def format_multi_bulk_reply(line)
558
+ reply = []
559
+ line.to_i.times { reply << read_reply }
560
+ reply
561
+ end
511
562
  end
512
563
  end
@@ -1,14 +1,16 @@
1
- class Subscription
2
- def subscribe(&block)
3
- if block_given? then @subscribe = block else @subscribe end
1
+ class Redis
2
+ class Subscription
3
+ def subscribe(&block)
4
+ if block_given? then @subscribe = block else @subscribe end
5
+ end
6
+
7
+ def unsubscribe(&block)
8
+ if block_given? then @unsubscribe = block else @unsubscribe end
9
+ end
10
+
11
+ def message(&block)
12
+ if block_given? then @message = block else @message end
13
+ end
14
+
4
15
  end
5
-
6
- def unsubscribe(&block)
7
- if block_given? then @unsubscribe = block else @unsubscribe end
8
- end
9
-
10
- def message(&block)
11
- if block_given? then @message = block else @message end
12
- end
13
-
14
16
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 2
9
- version: 1.0.2
8
+ - 3
9
+ version: 1.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ezra Zygmuntowicz
@@ -19,22 +19,11 @@ autorequire: redis
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-04-02 00:00:00 -07:00
22
+ date: 2010-04-03 00:00:00 -07:00
23
23
  default_executable:
24
- dependencies:
25
- - !ruby/object:Gem::Dependency
26
- name: rspec
27
- prerelease: false
28
- requirement: &id001 !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- segments:
33
- - 0
34
- version: "0"
35
- type: :development
36
- version_requirements: *id001
37
- description: Ruby client library for redis key value storage server
24
+ dependencies: []
25
+
26
+ description: Ruby client library for Redis, the key value storage server
38
27
  email: ez@engineyard.com
39
28
  executables: []
40
29
 
@@ -84,6 +73,6 @@ rubyforge_project:
84
73
  rubygems_version: 1.3.6
85
74
  signing_key:
86
75
  specification_version: 3
87
- summary: Ruby client library for redis key value storage server
76
+ summary: Ruby client library for Redis, the key value storage server
88
77
  test_files: []
89
78