adamwiggins-redis-rb 0.1.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.
- data/LICENSE +20 -0
 - data/README.markdown +34 -0
 - data/Rakefile +43 -0
 - data/bin/distredis +33 -0
 - data/examples/basic.rb +16 -0
 - data/examples/incr-decr.rb +18 -0
 - data/examples/list.rb +26 -0
 - data/examples/sets.rb +36 -0
 - data/examples/test_server.rb +13 -0
 - data/lib/dist_redis.rb +118 -0
 - data/lib/hash_ring.rb +127 -0
 - data/lib/pipeline.rb +22 -0
 - data/lib/redis.rb +299 -0
 - data/lib/redis/raketasks.rb +1 -0
 - data/spec/redis_spec.rb +462 -0
 - data/spec/spec_helper.rb +4 -0
 - data/tasks/redis.tasks.rb +126 -0
 - metadata +83 -0
 
    
        data/lib/pipeline.rb
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "redis"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Redis
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Pipeline < Redis
         
     | 
| 
      
 5 
     | 
    
         
            +
                BUFFER_SIZE = 50_000
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(redis)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @redis = redis
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @commands = []
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
               
         
     | 
| 
      
 12 
     | 
    
         
            +
                def call_command(command)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @commands << command
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @redis.call_command(@commands)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @commands.clear
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/redis.rb
    ADDED
    
    | 
         @@ -0,0 +1,299 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require File.join(File.dirname(__FILE__),'pipeline')
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            begin
         
     | 
| 
      
 5 
     | 
    
         
            +
              if RUBY_VERSION >= '1.9'
         
     | 
| 
      
 6 
     | 
    
         
            +
                require 'timeout'
         
     | 
| 
      
 7 
     | 
    
         
            +
                RedisTimer = Timeout
         
     | 
| 
      
 8 
     | 
    
         
            +
              else
         
     | 
| 
      
 9 
     | 
    
         
            +
                require 'system_timer'
         
     | 
| 
      
 10 
     | 
    
         
            +
                RedisTimer = SystemTimer
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 13 
     | 
    
         
            +
              RedisTimer = nil
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            class Redis
         
     | 
| 
      
 17 
     | 
    
         
            +
              OK      = "OK".freeze
         
     | 
| 
      
 18 
     | 
    
         
            +
              MINUS    = "-".freeze
         
     | 
| 
      
 19 
     | 
    
         
            +
              PLUS     = "+".freeze
         
     | 
| 
      
 20 
     | 
    
         
            +
              COLON    = ":".freeze
         
     | 
| 
      
 21 
     | 
    
         
            +
              DOLLAR   = "$".freeze
         
     | 
| 
      
 22 
     | 
    
         
            +
              ASTERISK = "*".freeze
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              BULK_COMMANDS = {
         
     | 
| 
      
 25 
     | 
    
         
            +
                "set"       => true,
         
     | 
| 
      
 26 
     | 
    
         
            +
                "setnx"     => true,
         
     | 
| 
      
 27 
     | 
    
         
            +
                "rpush"     => true,
         
     | 
| 
      
 28 
     | 
    
         
            +
                "lpush"     => true,
         
     | 
| 
      
 29 
     | 
    
         
            +
                "lset"      => true,
         
     | 
| 
      
 30 
     | 
    
         
            +
                "lrem"      => true,
         
     | 
| 
      
 31 
     | 
    
         
            +
                "sadd"      => true,
         
     | 
| 
      
 32 
     | 
    
         
            +
                "srem"      => true,
         
     | 
| 
      
 33 
     | 
    
         
            +
                "sismember" => true,
         
     | 
| 
      
 34 
     | 
    
         
            +
                "echo"      => true,
         
     | 
| 
      
 35 
     | 
    
         
            +
                "getset"    => true,
         
     | 
| 
      
 36 
     | 
    
         
            +
                "smove"     => true
         
     | 
| 
      
 37 
     | 
    
         
            +
              }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              BOOLEAN_PROCESSOR = lambda{|r| r == 0 ? false : r}
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              REPLY_PROCESSOR = {
         
     | 
| 
      
 42 
     | 
    
         
            +
                "exists"    => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 43 
     | 
    
         
            +
                "sismember" => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 44 
     | 
    
         
            +
                "sadd"      => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 45 
     | 
    
         
            +
                "srem"      => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 46 
     | 
    
         
            +
                "smove"     => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 47 
     | 
    
         
            +
                "move"      => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 48 
     | 
    
         
            +
                "setnx"     => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 49 
     | 
    
         
            +
                "del"       => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 50 
     | 
    
         
            +
                "renamenx"  => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 51 
     | 
    
         
            +
                "expire"    => BOOLEAN_PROCESSOR,
         
     | 
| 
      
 52 
     | 
    
         
            +
                "keys"      => lambda{|r| r.split(" ")},
         
     | 
| 
      
 53 
     | 
    
         
            +
                "info"      => lambda{|r|
         
     | 
| 
      
 54 
     | 
    
         
            +
                  info = {}
         
     | 
| 
      
 55 
     | 
    
         
            +
                  r.each_line {|kv|
         
     | 
| 
      
 56 
     | 
    
         
            +
                    k,v = kv.split(":",2).map{|x| x.chomp}
         
     | 
| 
      
 57 
     | 
    
         
            +
                    info[k.to_sym] = v
         
     | 
| 
      
 58 
     | 
    
         
            +
                  }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  info
         
     | 
| 
      
 60 
     | 
    
         
            +
                }
         
     | 
| 
      
 61 
     | 
    
         
            +
              }
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
              ALIASES = {
         
     | 
| 
      
 64 
     | 
    
         
            +
                "flush_db"             => "flushdb",
         
     | 
| 
      
 65 
     | 
    
         
            +
                "flush_all"            => "flushall",
         
     | 
| 
      
 66 
     | 
    
         
            +
                "last_save"            => "lastsave",
         
     | 
| 
      
 67 
     | 
    
         
            +
                "key?"                 => "exists",
         
     | 
| 
      
 68 
     | 
    
         
            +
                "delete"               => "del",
         
     | 
| 
      
 69 
     | 
    
         
            +
                "randkey"              => "randomkey",
         
     | 
| 
      
 70 
     | 
    
         
            +
                "list_length"          => "llen",
         
     | 
| 
      
 71 
     | 
    
         
            +
                "push_tail"            => "rpush",
         
     | 
| 
      
 72 
     | 
    
         
            +
                "push_head"            => "lpush",
         
     | 
| 
      
 73 
     | 
    
         
            +
                "pop_tail"             => "rpop",
         
     | 
| 
      
 74 
     | 
    
         
            +
                "pop_head"             => "lpop",
         
     | 
| 
      
 75 
     | 
    
         
            +
                "list_set"             => "lset",
         
     | 
| 
      
 76 
     | 
    
         
            +
                "list_range"           => "lrange",
         
     | 
| 
      
 77 
     | 
    
         
            +
                "list_trim"            => "ltrim",
         
     | 
| 
      
 78 
     | 
    
         
            +
                "list_index"           => "lindex",
         
     | 
| 
      
 79 
     | 
    
         
            +
                "list_rm"              => "lrem",
         
     | 
| 
      
 80 
     | 
    
         
            +
                "set_add"              => "sadd",
         
     | 
| 
      
 81 
     | 
    
         
            +
                "set_delete"           => "srem",
         
     | 
| 
      
 82 
     | 
    
         
            +
                "set_count"            => "scard",
         
     | 
| 
      
 83 
     | 
    
         
            +
                "set_member?"          => "sismember",
         
     | 
| 
      
 84 
     | 
    
         
            +
                "set_members"          => "smembers",
         
     | 
| 
      
 85 
     | 
    
         
            +
                "set_intersect"        => "sinter",
         
     | 
| 
      
 86 
     | 
    
         
            +
                "set_intersect_store"  => "sinterstore",
         
     | 
| 
      
 87 
     | 
    
         
            +
                "set_inter_store"      => "sinterstore",
         
     | 
| 
      
 88 
     | 
    
         
            +
                "set_union"            => "sunion",
         
     | 
| 
      
 89 
     | 
    
         
            +
                "set_union_store"      => "sunionstore",
         
     | 
| 
      
 90 
     | 
    
         
            +
                "set_diff"             => "sdiff",
         
     | 
| 
      
 91 
     | 
    
         
            +
                "set_diff_store"       => "sdiffstore",
         
     | 
| 
      
 92 
     | 
    
         
            +
                "set_move"             => "smove",
         
     | 
| 
      
 93 
     | 
    
         
            +
                "set_unless_exists"    => "setnx",
         
     | 
| 
      
 94 
     | 
    
         
            +
                "rename_unless_exists" => "renamenx",
         
     | 
| 
      
 95 
     | 
    
         
            +
                "type?"                => "type"
         
     | 
| 
      
 96 
     | 
    
         
            +
              }
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              DISABLED_COMMANDS = {
         
     | 
| 
      
 99 
     | 
    
         
            +
                "monitor" => true,
         
     | 
| 
      
 100 
     | 
    
         
            +
                "sync"    => true
         
     | 
| 
      
 101 
     | 
    
         
            +
              }
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
              def initialize(options = {})
         
     | 
| 
      
 104 
     | 
    
         
            +
                @host    =  options[:host]    || '127.0.0.1'
         
     | 
| 
      
 105 
     | 
    
         
            +
                @port    = (options[:port]    || 6379).to_i
         
     | 
| 
      
 106 
     | 
    
         
            +
                @db      = (options[:db]      || 0).to_i
         
     | 
| 
      
 107 
     | 
    
         
            +
                @timeout = (options[:timeout] || 5).to_i
         
     | 
| 
      
 108 
     | 
    
         
            +
                $debug   =  options[:debug]
         
     | 
| 
      
 109 
     | 
    
         
            +
                @password = options[:password]
         
     | 
| 
      
 110 
     | 
    
         
            +
                connect_to_server
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
              def to_s
         
     | 
| 
      
 114 
     | 
    
         
            +
                "Redis Client connected to #{@host}:#{@port} against DB #{@db}"
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              def connect_to_server
         
     | 
| 
      
 118 
     | 
    
         
            +
                @sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout)
         
     | 
| 
      
 119 
     | 
    
         
            +
                call_command(["auth",@password]) if @password
         
     | 
| 
      
 120 
     | 
    
         
            +
                call_command(["select",@db]) unless @db == 0
         
     | 
| 
      
 121 
     | 
    
         
            +
              end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
              def connect_to(host, port, timeout=nil)
         
     | 
| 
      
 124 
     | 
    
         
            +
                # We support connect() timeout only if system_timer is availabe
         
     | 
| 
      
 125 
     | 
    
         
            +
                # or if we are running against Ruby >= 1.9
         
     | 
| 
      
 126 
     | 
    
         
            +
                # Timeout reading from the socket instead will be supported anyway.
         
     | 
| 
      
 127 
     | 
    
         
            +
                if @timeout != 0 and RedisTimer
         
     | 
| 
      
 128 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 129 
     | 
    
         
            +
                    sock = TCPSocket.new(host, port)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  rescue Timeout::Error
         
     | 
| 
      
 131 
     | 
    
         
            +
                    @sock = nil
         
     | 
| 
      
 132 
     | 
    
         
            +
                    raise Timeout::Error, "Timeout connecting to the server"
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
                else
         
     | 
| 
      
 135 
     | 
    
         
            +
                  sock = TCPSocket.new(host, port)
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
                sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                # If the timeout is set we set the low level socket options in order
         
     | 
| 
      
 140 
     | 
    
         
            +
                # to make sure a blocking read will return after the specified number
         
     | 
| 
      
 141 
     | 
    
         
            +
                # of seconds. This hack is from memcached ruby client.
         
     | 
| 
      
 142 
     | 
    
         
            +
                if timeout
         
     | 
| 
      
 143 
     | 
    
         
            +
                  secs   = Integer(timeout)
         
     | 
| 
      
 144 
     | 
    
         
            +
                  usecs  = Integer((timeout - secs) * 1_000_000)
         
     | 
| 
      
 145 
     | 
    
         
            +
                  optval = [secs, usecs].pack("l_2")
         
     | 
| 
      
 146 
     | 
    
         
            +
                  sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
         
     | 
| 
      
 147 
     | 
    
         
            +
                  sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
                sock
         
     | 
| 
      
 150 
     | 
    
         
            +
              end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
              def method_missing(*argv)
         
     | 
| 
      
 153 
     | 
    
         
            +
                call_command(argv)
         
     | 
| 
      
 154 
     | 
    
         
            +
              end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
              def call_command(argv)
         
     | 
| 
      
 157 
     | 
    
         
            +
                puts argv.inspect if $debug
         
     | 
| 
      
 158 
     | 
    
         
            +
                # this wrapper to raw_call_command handle reconnection on socket
         
     | 
| 
      
 159 
     | 
    
         
            +
                # error. We try to reconnect just one time, otherwise let the error
         
     | 
| 
      
 160 
     | 
    
         
            +
                # araise.
         
     | 
| 
      
 161 
     | 
    
         
            +
                connect_to_server if !@sock
         
     | 
| 
      
 162 
     | 
    
         
            +
                begin
         
     | 
| 
      
 163 
     | 
    
         
            +
                  raw_call_command(argv.dup)
         
     | 
| 
      
 164 
     | 
    
         
            +
                rescue Errno::ECONNRESET, Errno::EPIPE
         
     | 
| 
      
 165 
     | 
    
         
            +
                  @sock.close
         
     | 
| 
      
 166 
     | 
    
         
            +
                  @sock = nil
         
     | 
| 
      
 167 
     | 
    
         
            +
                  connect_to_server
         
     | 
| 
      
 168 
     | 
    
         
            +
                  raw_call_command(argv.dup)
         
     | 
| 
      
 169 
     | 
    
         
            +
                end
         
     | 
| 
      
 170 
     | 
    
         
            +
              end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
              def raw_call_command(argvp)
         
     | 
| 
      
 173 
     | 
    
         
            +
                pipeline = argvp[0].is_a?(Array)
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                unless pipeline
         
     | 
| 
      
 176 
     | 
    
         
            +
                  argvv = [argvp]
         
     | 
| 
      
 177 
     | 
    
         
            +
                else
         
     | 
| 
      
 178 
     | 
    
         
            +
                  argvv = argvp
         
     | 
| 
      
 179 
     | 
    
         
            +
                end
         
     | 
| 
      
 180 
     | 
    
         
            +
             
     | 
| 
      
 181 
     | 
    
         
            +
                command = ''
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                argvv.each do |argv|
         
     | 
| 
      
 184 
     | 
    
         
            +
                  bulk = nil
         
     | 
| 
      
 185 
     | 
    
         
            +
                  argv[0] = argv[0].to_s.downcase
         
     | 
| 
      
 186 
     | 
    
         
            +
                  argv[0] = ALIASES[argv[0]] if ALIASES[argv[0]]
         
     | 
| 
      
 187 
     | 
    
         
            +
                  raise "#{argv[0]} command is disabled" if DISABLED_COMMANDS[argv[0]]
         
     | 
| 
      
 188 
     | 
    
         
            +
                  if BULK_COMMANDS[argv[0]] and argv.length > 1
         
     | 
| 
      
 189 
     | 
    
         
            +
                    bulk = argv[-1].to_s
         
     | 
| 
      
 190 
     | 
    
         
            +
                    argv[-1] = bulk.length
         
     | 
| 
      
 191 
     | 
    
         
            +
                  end
         
     | 
| 
      
 192 
     | 
    
         
            +
                  command << argv.join(' ') + "\r\n"
         
     | 
| 
      
 193 
     | 
    
         
            +
                  command << bulk + "\r\n" if bulk
         
     | 
| 
      
 194 
     | 
    
         
            +
                end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                @sock.write(command)
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                results = argvv.map do |argv|
         
     | 
| 
      
 199 
     | 
    
         
            +
                  processor = REPLY_PROCESSOR[argv[0]]
         
     | 
| 
      
 200 
     | 
    
         
            +
                  processor ? processor.call(read_reply) : read_reply
         
     | 
| 
      
 201 
     | 
    
         
            +
                end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                return pipeline ? results : results[0]
         
     | 
| 
      
 204 
     | 
    
         
            +
              end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
              def select(*args)
         
     | 
| 
      
 207 
     | 
    
         
            +
                raise "SELECT not allowed, use the :db option when creating the object"
         
     | 
| 
      
 208 
     | 
    
         
            +
              end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
              def [](key)
         
     | 
| 
      
 211 
     | 
    
         
            +
                self.get(key)
         
     | 
| 
      
 212 
     | 
    
         
            +
              end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
              def []=(key,value)
         
     | 
| 
      
 215 
     | 
    
         
            +
                set(key,value)
         
     | 
| 
      
 216 
     | 
    
         
            +
              end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
              def set(key, value, expiry=nil)
         
     | 
| 
      
 219 
     | 
    
         
            +
                s = call_command([:set, key, value]) == OK
         
     | 
| 
      
 220 
     | 
    
         
            +
                expire(key, expiry) if s && expiry
         
     | 
| 
      
 221 
     | 
    
         
            +
                s
         
     | 
| 
      
 222 
     | 
    
         
            +
              end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
              def sort(key, options = {})
         
     | 
| 
      
 225 
     | 
    
         
            +
                cmd = []
         
     | 
| 
      
 226 
     | 
    
         
            +
                cmd << "SORT #{key}"
         
     | 
| 
      
 227 
     | 
    
         
            +
                cmd << "BY #{options[:by]}" if options[:by]
         
     | 
| 
      
 228 
     | 
    
         
            +
                cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get]
         
     | 
| 
      
 229 
     | 
    
         
            +
                cmd << "#{options[:order]}" if options[:order]
         
     | 
| 
      
 230 
     | 
    
         
            +
                cmd << "LIMIT #{options[:limit].join(' ')}" if options[:limit]
         
     | 
| 
      
 231 
     | 
    
         
            +
                call_command(cmd)
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
              def incr(key, increment = nil)
         
     | 
| 
      
 235 
     | 
    
         
            +
                call_command(increment ? ["incrby",key,increment] : ["incr",key])
         
     | 
| 
      
 236 
     | 
    
         
            +
              end
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
              def decr(key,decrement = nil)
         
     | 
| 
      
 239 
     | 
    
         
            +
                call_command(decrement ? ["decrby",key,decrement] : ["decr",key])
         
     | 
| 
      
 240 
     | 
    
         
            +
              end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
              # Ruby defines a now deprecated type method so we need to override it here
         
     | 
| 
      
 243 
     | 
    
         
            +
              # since it will never hit method_missing
         
     | 
| 
      
 244 
     | 
    
         
            +
              def type(key)
         
     | 
| 
      
 245 
     | 
    
         
            +
                call_command(['type', key])
         
     | 
| 
      
 246 
     | 
    
         
            +
              end
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
              def quit
         
     | 
| 
      
 249 
     | 
    
         
            +
                call_command(['quit'])
         
     | 
| 
      
 250 
     | 
    
         
            +
              rescue Errno::ECONNRESET
         
     | 
| 
      
 251 
     | 
    
         
            +
              end
         
     | 
| 
      
 252 
     | 
    
         
            +
             
     | 
| 
      
 253 
     | 
    
         
            +
              def pipelined(&block)
         
     | 
| 
      
 254 
     | 
    
         
            +
                pipeline = Pipeline.new self
         
     | 
| 
      
 255 
     | 
    
         
            +
                yield pipeline
         
     | 
| 
      
 256 
     | 
    
         
            +
                pipeline.execute
         
     | 
| 
      
 257 
     | 
    
         
            +
              end
         
     | 
| 
      
 258 
     | 
    
         
            +
             
     | 
| 
      
 259 
     | 
    
         
            +
              def read_reply
         
     | 
| 
      
 260 
     | 
    
         
            +
                # We read the first byte using read() mainly because gets() is
         
     | 
| 
      
 261 
     | 
    
         
            +
                # immune to raw socket timeouts.
         
     | 
| 
      
 262 
     | 
    
         
            +
                begin
         
     | 
| 
      
 263 
     | 
    
         
            +
                  rtype = @sock.read(1)
         
     | 
| 
      
 264 
     | 
    
         
            +
                rescue Errno::EAGAIN
         
     | 
| 
      
 265 
     | 
    
         
            +
                  # We want to make sure it reconnects on the next command after the
         
     | 
| 
      
 266 
     | 
    
         
            +
                  # timeout. Otherwise the server may reply in the meantime leaving
         
     | 
| 
      
 267 
     | 
    
         
            +
                  # the protocol in a desync status.
         
     | 
| 
      
 268 
     | 
    
         
            +
                  @sock = nil
         
     | 
| 
      
 269 
     | 
    
         
            +
                  raise Errno::EAGAIN, "Timeout reading from the socket"
         
     | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                raise Errno::ECONNRESET,"Connection lost" if !rtype
         
     | 
| 
      
 273 
     | 
    
         
            +
                line = @sock.gets
         
     | 
| 
      
 274 
     | 
    
         
            +
                case rtype
         
     | 
| 
      
 275 
     | 
    
         
            +
                when MINUS
         
     | 
| 
      
 276 
     | 
    
         
            +
                  raise MINUS + line.strip
         
     | 
| 
      
 277 
     | 
    
         
            +
                when PLUS
         
     | 
| 
      
 278 
     | 
    
         
            +
                  line.strip
         
     | 
| 
      
 279 
     | 
    
         
            +
                when COLON
         
     | 
| 
      
 280 
     | 
    
         
            +
                  line.to_i
         
     | 
| 
      
 281 
     | 
    
         
            +
                when DOLLAR
         
     | 
| 
      
 282 
     | 
    
         
            +
                  bulklen = line.to_i
         
     | 
| 
      
 283 
     | 
    
         
            +
                  return nil if bulklen == -1
         
     | 
| 
      
 284 
     | 
    
         
            +
                  data = @sock.read(bulklen)
         
     | 
| 
      
 285 
     | 
    
         
            +
                  @sock.read(2) # CRLF
         
     | 
| 
      
 286 
     | 
    
         
            +
                  data
         
     | 
| 
      
 287 
     | 
    
         
            +
                when ASTERISK
         
     | 
| 
      
 288 
     | 
    
         
            +
                  objects = line.to_i
         
     | 
| 
      
 289 
     | 
    
         
            +
                  return nil if bulklen == -1
         
     | 
| 
      
 290 
     | 
    
         
            +
                  res = []
         
     | 
| 
      
 291 
     | 
    
         
            +
                  objects.times {
         
     | 
| 
      
 292 
     | 
    
         
            +
                    res << read_reply
         
     | 
| 
      
 293 
     | 
    
         
            +
                  }
         
     | 
| 
      
 294 
     | 
    
         
            +
                  res
         
     | 
| 
      
 295 
     | 
    
         
            +
                else
         
     | 
| 
      
 296 
     | 
    
         
            +
                  raise "Protocol error, got '#{rtype}' as initial reply byte"
         
     | 
| 
      
 297 
     | 
    
         
            +
                end
         
     | 
| 
      
 298 
     | 
    
         
            +
              end
         
     | 
| 
      
 299 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + "/../../tasks/redis.tasks"
         
     | 
    
        data/spec/redis_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,462 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.dirname(__FILE__) + '/spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Foo
         
     | 
| 
      
 4 
     | 
    
         
            +
              attr_accessor :bar
         
     | 
| 
      
 5 
     | 
    
         
            +
              def initialize(bar)
         
     | 
| 
      
 6 
     | 
    
         
            +
                @bar = bar
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def ==(other)
         
     | 
| 
      
 10 
     | 
    
         
            +
                @bar == other.bar
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end  
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            describe "redis" do
         
     | 
| 
      
 15 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 16 
     | 
    
         
            +
                # use database 15 for testing so we dont accidentally step on you real data
         
     | 
| 
      
 17 
     | 
    
         
            +
                @r = Redis.new :db => 15
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              before(:each) do
         
     | 
| 
      
 21 
     | 
    
         
            +
                @r['foo'] = 'bar'
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              after(:each) do
         
     | 
| 
      
 25 
     | 
    
         
            +
                @r.keys('*').each {|k| @r.del k}
         
     | 
| 
      
 26 
     | 
    
         
            +
              end  
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              after(:all) do
         
     | 
| 
      
 29 
     | 
    
         
            +
                @r.quit
         
     | 
| 
      
 30 
     | 
    
         
            +
              end  
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              it "should be able connect without a timeout" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                lambda { Redis.new :timeout => 0 }.should_not raise_error
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              it "should be able to PING" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                @r.ping.should == 'PONG' 
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              it "should be able to GET a key" do
         
     | 
| 
      
 41 
     | 
    
         
            +
                @r['foo'].should == 'bar'
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
              
         
     | 
| 
      
 44 
     | 
    
         
            +
              it "should be able to SET a key" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                @r['foo'] = 'nik'
         
     | 
| 
      
 46 
     | 
    
         
            +
                @r['foo'].should == 'nik'
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
              
         
     | 
| 
      
 49 
     | 
    
         
            +
              it "should properly handle trailing newline characters" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                @r['foo'] = "bar\n"
         
     | 
| 
      
 51 
     | 
    
         
            +
                @r['foo'].should == "bar\n"
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
              it "should store and retrieve all possible characters at the beginning and the end of a string" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                (0..255).each do |char_idx|
         
     | 
| 
      
 56 
     | 
    
         
            +
                  string = "#{char_idx.chr}---#{char_idx.chr}"
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @r['foo'] = string
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @r['foo'].should == string
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
              
         
     | 
| 
      
 62 
     | 
    
         
            +
              it "should be able to SET a key with an expiry" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                @r.set('foo', 'bar', 1)
         
     | 
| 
      
 64 
     | 
    
         
            +
                @r['foo'].should == 'bar'
         
     | 
| 
      
 65 
     | 
    
         
            +
                sleep 2
         
     | 
| 
      
 66 
     | 
    
         
            +
                @r['foo'].should == nil
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              it "should be able to return a TTL for a key" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                @r.set('foo', 'bar', 1)
         
     | 
| 
      
 71 
     | 
    
         
            +
                @r.ttl('foo').should == 1
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              it "should be able to SETNX" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                @r['foo'] = 'nik'
         
     | 
| 
      
 76 
     | 
    
         
            +
                @r['foo'].should == 'nik'
         
     | 
| 
      
 77 
     | 
    
         
            +
                @r.setnx 'foo', 'bar'
         
     | 
| 
      
 78 
     | 
    
         
            +
                @r['foo'].should == 'nik'
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
              #
         
     | 
| 
      
 81 
     | 
    
         
            +
              it "should be able to GETSET" do
         
     | 
| 
      
 82 
     | 
    
         
            +
               @r.getset('foo', 'baz').should == 'bar'
         
     | 
| 
      
 83 
     | 
    
         
            +
               @r['foo'].should == 'baz'
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
              # 
         
     | 
| 
      
 86 
     | 
    
         
            +
              it "should be able to INCR a key" do
         
     | 
| 
      
 87 
     | 
    
         
            +
                @r.del('counter')
         
     | 
| 
      
 88 
     | 
    
         
            +
                @r.incr('counter').should == 1
         
     | 
| 
      
 89 
     | 
    
         
            +
                @r.incr('counter').should == 2
         
     | 
| 
      
 90 
     | 
    
         
            +
                @r.incr('counter').should == 3
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
              #
         
     | 
| 
      
 93 
     | 
    
         
            +
              it "should be able to INCRBY a key" do
         
     | 
| 
      
 94 
     | 
    
         
            +
                @r.del('counter')
         
     | 
| 
      
 95 
     | 
    
         
            +
                @r.incrby('counter', 1).should == 1
         
     | 
| 
      
 96 
     | 
    
         
            +
                @r.incrby('counter', 2).should == 3
         
     | 
| 
      
 97 
     | 
    
         
            +
                @r.incrby('counter', 3).should == 6
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
              #
         
     | 
| 
      
 100 
     | 
    
         
            +
              it "should be able to DECR a key" do
         
     | 
| 
      
 101 
     | 
    
         
            +
                @r.del('counter')
         
     | 
| 
      
 102 
     | 
    
         
            +
                @r.incr('counter').should == 1
         
     | 
| 
      
 103 
     | 
    
         
            +
                @r.incr('counter').should == 2
         
     | 
| 
      
 104 
     | 
    
         
            +
                @r.incr('counter').should == 3
         
     | 
| 
      
 105 
     | 
    
         
            +
                @r.decr('counter').should == 2
         
     | 
| 
      
 106 
     | 
    
         
            +
                @r.decr('counter', 2).should == 0
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
              # 
         
     | 
| 
      
 109 
     | 
    
         
            +
              it "should be able to RANDKEY" do
         
     | 
| 
      
 110 
     | 
    
         
            +
                @r.randkey.should_not be_nil
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
              # 
         
     | 
| 
      
 113 
     | 
    
         
            +
              it "should be able to RENAME a key" do
         
     | 
| 
      
 114 
     | 
    
         
            +
                @r.del 'foo'
         
     | 
| 
      
 115 
     | 
    
         
            +
                @r.del'bar'
         
     | 
| 
      
 116 
     | 
    
         
            +
                @r['foo'] = 'hi'
         
     | 
| 
      
 117 
     | 
    
         
            +
                @r.rename 'foo', 'bar'
         
     | 
| 
      
 118 
     | 
    
         
            +
                @r['bar'].should == 'hi'
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
              # 
         
     | 
| 
      
 121 
     | 
    
         
            +
              it "should be able to RENAMENX a key" do
         
     | 
| 
      
 122 
     | 
    
         
            +
                @r.del 'foo'
         
     | 
| 
      
 123 
     | 
    
         
            +
                @r.del 'bar'
         
     | 
| 
      
 124 
     | 
    
         
            +
                @r['foo'] = 'hi'
         
     | 
| 
      
 125 
     | 
    
         
            +
                @r['bar'] = 'ohai'
         
     | 
| 
      
 126 
     | 
    
         
            +
                @r.renamenx 'foo', 'bar'
         
     | 
| 
      
 127 
     | 
    
         
            +
                @r['bar'].should == 'ohai'
         
     | 
| 
      
 128 
     | 
    
         
            +
              end
         
     | 
| 
      
 129 
     | 
    
         
            +
              #
         
     | 
| 
      
 130 
     | 
    
         
            +
              it "should be able to get DBSIZE of the database" do
         
     | 
| 
      
 131 
     | 
    
         
            +
                @r.delete 'foo'
         
     | 
| 
      
 132 
     | 
    
         
            +
                dbsize_without_foo = @r.dbsize
         
     | 
| 
      
 133 
     | 
    
         
            +
                @r['foo'] = 0
         
     | 
| 
      
 134 
     | 
    
         
            +
                dbsize_with_foo = @r.dbsize
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                dbsize_with_foo.should == dbsize_without_foo + 1
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
              #
         
     | 
| 
      
 139 
     | 
    
         
            +
              it "should be able to EXPIRE a key" do
         
     | 
| 
      
 140 
     | 
    
         
            +
                @r['foo'] = 'bar'
         
     | 
| 
      
 141 
     | 
    
         
            +
                @r.expire 'foo', 1
         
     | 
| 
      
 142 
     | 
    
         
            +
                @r['foo'].should == "bar"
         
     | 
| 
      
 143 
     | 
    
         
            +
                sleep 2
         
     | 
| 
      
 144 
     | 
    
         
            +
                @r['foo'].should == nil
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
              #
         
     | 
| 
      
 147 
     | 
    
         
            +
              it "should be able to EXISTS" do
         
     | 
| 
      
 148 
     | 
    
         
            +
                @r['foo'] = 'nik'
         
     | 
| 
      
 149 
     | 
    
         
            +
                @r.exists('foo').should be_true
         
     | 
| 
      
 150 
     | 
    
         
            +
                @r.del 'foo'
         
     | 
| 
      
 151 
     | 
    
         
            +
                @r.exists('foo').should be_false
         
     | 
| 
      
 152 
     | 
    
         
            +
              end
         
     | 
| 
      
 153 
     | 
    
         
            +
              # 
         
     | 
| 
      
 154 
     | 
    
         
            +
              it "should be able to KEYS" do
         
     | 
| 
      
 155 
     | 
    
         
            +
                @r.keys("f*").each { |key| @r.del key }
         
     | 
| 
      
 156 
     | 
    
         
            +
                @r['f'] = 'nik'
         
     | 
| 
      
 157 
     | 
    
         
            +
                @r['fo'] = 'nak'
         
     | 
| 
      
 158 
     | 
    
         
            +
                @r['foo'] = 'qux'
         
     | 
| 
      
 159 
     | 
    
         
            +
                @r.keys("f*").sort.should == ['f','fo', 'foo'].sort
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
              #
         
     | 
| 
      
 162 
     | 
    
         
            +
              it "should be able to return a random key (RANDOMKEY)" do
         
     | 
| 
      
 163 
     | 
    
         
            +
                3.times { @r.exists(@r.randomkey).should be_true }
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
              #BTM - TODO 
         
     | 
| 
      
 166 
     | 
    
         
            +
              it "should be able to check the TYPE of a key" do
         
     | 
| 
      
 167 
     | 
    
         
            +
                @r['foo'] = 'nik'
         
     | 
| 
      
 168 
     | 
    
         
            +
                @r.type('foo').should == "string"
         
     | 
| 
      
 169 
     | 
    
         
            +
                @r.del 'foo'
         
     | 
| 
      
 170 
     | 
    
         
            +
                @r.type('foo').should == "none"
         
     | 
| 
      
 171 
     | 
    
         
            +
              end
         
     | 
| 
      
 172 
     | 
    
         
            +
              # 
         
     | 
| 
      
 173 
     | 
    
         
            +
              it "should be able to push to the head of a list (LPUSH)" do
         
     | 
| 
      
 174 
     | 
    
         
            +
                @r.lpush "list", 'hello'
         
     | 
| 
      
 175 
     | 
    
         
            +
                @r.lpush "list", 42
         
     | 
| 
      
 176 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 177 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 178 
     | 
    
         
            +
                @r.lpop('list').should == '42'
         
     | 
| 
      
 179 
     | 
    
         
            +
              end
         
     | 
| 
      
 180 
     | 
    
         
            +
              # 
         
     | 
| 
      
 181 
     | 
    
         
            +
              it "should be able to push to the tail of a list (RPUSH)" do
         
     | 
| 
      
 182 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 183 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 184 
     | 
    
         
            +
                @r.llen('list').should == 1
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
              # 
         
     | 
| 
      
 187 
     | 
    
         
            +
              it "should be able to pop the tail of a list (RPOP)" do
         
     | 
| 
      
 188 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 189 
     | 
    
         
            +
                @r.rpush"list", 'goodbye'
         
     | 
| 
      
 190 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 191 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 192 
     | 
    
         
            +
                @r.rpop('list').should == 'goodbye'
         
     | 
| 
      
 193 
     | 
    
         
            +
              end
         
     | 
| 
      
 194 
     | 
    
         
            +
              # 
         
     | 
| 
      
 195 
     | 
    
         
            +
              it "should be able to pop the head of a list (LPOP)" do
         
     | 
| 
      
 196 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 197 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 198 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 199 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 200 
     | 
    
         
            +
                @r.lpop('list').should == 'hello'
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
              # 
         
     | 
| 
      
 203 
     | 
    
         
            +
              it "should be able to get the length of a list (LLEN)" do
         
     | 
| 
      
 204 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 205 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 206 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 207 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 208 
     | 
    
         
            +
              end
         
     | 
| 
      
 209 
     | 
    
         
            +
              # 
         
     | 
| 
      
 210 
     | 
    
         
            +
              it "should be able to get a range of values from a list (LRANGE)" do
         
     | 
| 
      
 211 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 212 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 213 
     | 
    
         
            +
                @r.rpush "list", '1'
         
     | 
| 
      
 214 
     | 
    
         
            +
                @r.rpush "list", '2'
         
     | 
| 
      
 215 
     | 
    
         
            +
                @r.rpush "list", '3'
         
     | 
| 
      
 216 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 217 
     | 
    
         
            +
                @r.llen('list').should == 5
         
     | 
| 
      
 218 
     | 
    
         
            +
                @r.lrange('list', 2, -1).should == ['1', '2', '3']
         
     | 
| 
      
 219 
     | 
    
         
            +
              end
         
     | 
| 
      
 220 
     | 
    
         
            +
              # 
         
     | 
| 
      
 221 
     | 
    
         
            +
              it "should be able to trim a list (LTRIM)" do
         
     | 
| 
      
 222 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 223 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 224 
     | 
    
         
            +
                @r.rpush "list", '1'
         
     | 
| 
      
 225 
     | 
    
         
            +
                @r.rpush "list", '2'
         
     | 
| 
      
 226 
     | 
    
         
            +
                @r.rpush "list", '3'
         
     | 
| 
      
 227 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 228 
     | 
    
         
            +
                @r.llen('list').should == 5
         
     | 
| 
      
 229 
     | 
    
         
            +
                @r.ltrim 'list', 0, 1
         
     | 
| 
      
 230 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 231 
     | 
    
         
            +
                @r.lrange('list', 0, -1).should == ['hello', 'goodbye']
         
     | 
| 
      
 232 
     | 
    
         
            +
              end
         
     | 
| 
      
 233 
     | 
    
         
            +
              # 
         
     | 
| 
      
 234 
     | 
    
         
            +
              it "should be able to get a value by indexing into a list (LINDEX)" do
         
     | 
| 
      
 235 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 236 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 237 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 238 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 239 
     | 
    
         
            +
                @r.lindex('list', 1).should == 'goodbye'
         
     | 
| 
      
 240 
     | 
    
         
            +
              end
         
     | 
| 
      
 241 
     | 
    
         
            +
              # 
         
     | 
| 
      
 242 
     | 
    
         
            +
              it "should be able to set a value by indexing into a list (LSET)" do
         
     | 
| 
      
 243 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 244 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 245 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 246 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 247 
     | 
    
         
            +
                @r.lset('list', 1, 'goodbye').should == 'OK'
         
     | 
| 
      
 248 
     | 
    
         
            +
                @r.lindex('list', 1).should == 'goodbye'
         
     | 
| 
      
 249 
     | 
    
         
            +
              end
         
     | 
| 
      
 250 
     | 
    
         
            +
              # 
         
     | 
| 
      
 251 
     | 
    
         
            +
              it "should be able to remove values from a list (LREM)" do
         
     | 
| 
      
 252 
     | 
    
         
            +
                @r.rpush "list", 'hello'
         
     | 
| 
      
 253 
     | 
    
         
            +
                @r.rpush "list", 'goodbye'
         
     | 
| 
      
 254 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 255 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 256 
     | 
    
         
            +
                @r.lrem('list', 1, 'hello').should == 1
         
     | 
| 
      
 257 
     | 
    
         
            +
                @r.lrange('list', 0, -1).should == ['goodbye']
         
     | 
| 
      
 258 
     | 
    
         
            +
              end
         
     | 
| 
      
 259 
     | 
    
         
            +
              # 
         
     | 
| 
      
 260 
     | 
    
         
            +
              it "should be able add members to a set (SADD)" do
         
     | 
| 
      
 261 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 262 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 263 
     | 
    
         
            +
                @r.type('set').should == "set"
         
     | 
| 
      
 264 
     | 
    
         
            +
                @r.scard('set').should == 2
         
     | 
| 
      
 265 
     | 
    
         
            +
                @r.smembers('set').sort.should == ['key1', 'key2'].sort
         
     | 
| 
      
 266 
     | 
    
         
            +
              end
         
     | 
| 
      
 267 
     | 
    
         
            +
              # 
         
     | 
| 
      
 268 
     | 
    
         
            +
              it "should be able delete members to a set (SREM)" do
         
     | 
| 
      
 269 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 270 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 271 
     | 
    
         
            +
                @r.type('set').should == "set"
         
     | 
| 
      
 272 
     | 
    
         
            +
                @r.scard('set').should == 2
         
     | 
| 
      
 273 
     | 
    
         
            +
                @r.smembers('set').sort.should == ['key1', 'key2'].sort
         
     | 
| 
      
 274 
     | 
    
         
            +
                @r.srem('set', 'key1')
         
     | 
| 
      
 275 
     | 
    
         
            +
                @r.scard('set').should == 1
         
     | 
| 
      
 276 
     | 
    
         
            +
                @r.smembers('set').should == ['key2']
         
     | 
| 
      
 277 
     | 
    
         
            +
              end
         
     | 
| 
      
 278 
     | 
    
         
            +
              # 
         
     | 
| 
      
 279 
     | 
    
         
            +
              it "should be able count the members of a set (SCARD)" do
         
     | 
| 
      
 280 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 281 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 282 
     | 
    
         
            +
                @r.type('set').should == "set"
         
     | 
| 
      
 283 
     | 
    
         
            +
                @r.scard('set').should == 2
         
     | 
| 
      
 284 
     | 
    
         
            +
              end
         
     | 
| 
      
 285 
     | 
    
         
            +
              # 
         
     | 
| 
      
 286 
     | 
    
         
            +
              it "should be able test for set membership (SISMEMBER)" do
         
     | 
| 
      
 287 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 288 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 289 
     | 
    
         
            +
                @r.type('set').should == "set"
         
     | 
| 
      
 290 
     | 
    
         
            +
                @r.scard('set').should == 2
         
     | 
| 
      
 291 
     | 
    
         
            +
                @r.sismember('set', 'key1').should be_true
         
     | 
| 
      
 292 
     | 
    
         
            +
                @r.sismember('set', 'key2').should be_true
         
     | 
| 
      
 293 
     | 
    
         
            +
                @r.sismember('set', 'notthere').should be_false
         
     | 
| 
      
 294 
     | 
    
         
            +
              end
         
     | 
| 
      
 295 
     | 
    
         
            +
              # 
         
     | 
| 
      
 296 
     | 
    
         
            +
              it "should be able to do set intersection (SINTER)" do
         
     | 
| 
      
 297 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 298 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 299 
     | 
    
         
            +
                @r.sadd "set2", 'key2'
         
     | 
| 
      
 300 
     | 
    
         
            +
                @r.sinter('set', 'set2').should == ['key2']
         
     | 
| 
      
 301 
     | 
    
         
            +
              end
         
     | 
| 
      
 302 
     | 
    
         
            +
              # 
         
     | 
| 
      
 303 
     | 
    
         
            +
              it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do
         
     | 
| 
      
 304 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 305 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 306 
     | 
    
         
            +
                @r.sadd "set2", 'key2'
         
     | 
| 
      
 307 
     | 
    
         
            +
                @r.sinterstore('newone', 'set', 'set2').should == 1
         
     | 
| 
      
 308 
     | 
    
         
            +
                @r.smembers('newone').should == ['key2']
         
     | 
| 
      
 309 
     | 
    
         
            +
              end
         
     | 
| 
      
 310 
     | 
    
         
            +
              #
         
     | 
| 
      
 311 
     | 
    
         
            +
              it "should be able to do set union (SUNION)" do
         
     | 
| 
      
 312 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 313 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 314 
     | 
    
         
            +
                @r.sadd "set2", 'key2'
         
     | 
| 
      
 315 
     | 
    
         
            +
                @r.sadd "set2", 'key3'
         
     | 
| 
      
 316 
     | 
    
         
            +
                @r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort
         
     | 
| 
      
 317 
     | 
    
         
            +
              end
         
     | 
| 
      
 318 
     | 
    
         
            +
              # 
         
     | 
| 
      
 319 
     | 
    
         
            +
              it "should be able to do set union and store the results in a key (SUNIONSTORE)" do
         
     | 
| 
      
 320 
     | 
    
         
            +
                @r.sadd "set", 'key1'
         
     | 
| 
      
 321 
     | 
    
         
            +
                @r.sadd "set", 'key2'
         
     | 
| 
      
 322 
     | 
    
         
            +
                @r.sadd "set2", 'key2'
         
     | 
| 
      
 323 
     | 
    
         
            +
                @r.sadd "set2", 'key3'
         
     | 
| 
      
 324 
     | 
    
         
            +
                @r.sunionstore('newone', 'set', 'set2').should == 3
         
     | 
| 
      
 325 
     | 
    
         
            +
                @r.smembers('newone').sort.should == ['key1','key2','key3'].sort
         
     | 
| 
      
 326 
     | 
    
         
            +
              end
         
     | 
| 
      
 327 
     | 
    
         
            +
              # 
         
     | 
| 
      
 328 
     | 
    
         
            +
              it "should be able to do set difference (SDIFF)" do
         
     | 
| 
      
 329 
     | 
    
         
            +
                 @r.sadd "set", 'a'
         
     | 
| 
      
 330 
     | 
    
         
            +
                 @r.sadd "set", 'b'
         
     | 
| 
      
 331 
     | 
    
         
            +
                 @r.sadd "set2", 'b'
         
     | 
| 
      
 332 
     | 
    
         
            +
                 @r.sadd "set2", 'c'
         
     | 
| 
      
 333 
     | 
    
         
            +
                 @r.sdiff('set', 'set2').should == ['a']
         
     | 
| 
      
 334 
     | 
    
         
            +
               end
         
     | 
| 
      
 335 
     | 
    
         
            +
              # 
         
     | 
| 
      
 336 
     | 
    
         
            +
              it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do
         
     | 
| 
      
 337 
     | 
    
         
            +
                 @r.sadd "set", 'a'
         
     | 
| 
      
 338 
     | 
    
         
            +
                 @r.sadd "set", 'b'
         
     | 
| 
      
 339 
     | 
    
         
            +
                 @r.sadd "set2", 'b'
         
     | 
| 
      
 340 
     | 
    
         
            +
                 @r.sadd "set2", 'c'
         
     | 
| 
      
 341 
     | 
    
         
            +
                 @r.sdiffstore('newone', 'set', 'set2')
         
     | 
| 
      
 342 
     | 
    
         
            +
                 @r.smembers('newone').should == ['a']
         
     | 
| 
      
 343 
     | 
    
         
            +
               end
         
     | 
| 
      
 344 
     | 
    
         
            +
              # 
         
     | 
| 
      
 345 
     | 
    
         
            +
              it "should be able move elements from one set to another (SMOVE)" do
         
     | 
| 
      
 346 
     | 
    
         
            +
                @r.sadd 'set1', 'a'
         
     | 
| 
      
 347 
     | 
    
         
            +
                @r.sadd 'set1', 'b'
         
     | 
| 
      
 348 
     | 
    
         
            +
                @r.sadd 'set2', 'x'
         
     | 
| 
      
 349 
     | 
    
         
            +
                @r.smove('set1', 'set2', 'a').should be_true 
         
     | 
| 
      
 350 
     | 
    
         
            +
                @r.sismember('set2', 'a').should be_true
         
     | 
| 
      
 351 
     | 
    
         
            +
                @r.delete('set1')
         
     | 
| 
      
 352 
     | 
    
         
            +
              end
         
     | 
| 
      
 353 
     | 
    
         
            +
              #
         
     | 
| 
      
 354 
     | 
    
         
            +
              it "should be able to do crazy SORT queries" do
         
     | 
| 
      
 355 
     | 
    
         
            +
                @r['dog_1'] = 'louie'
         
     | 
| 
      
 356 
     | 
    
         
            +
                @r.rpush 'dogs', 1
         
     | 
| 
      
 357 
     | 
    
         
            +
                @r['dog_2'] = 'lucy'
         
     | 
| 
      
 358 
     | 
    
         
            +
                @r.rpush 'dogs', 2
         
     | 
| 
      
 359 
     | 
    
         
            +
                @r['dog_3'] = 'max'
         
     | 
| 
      
 360 
     | 
    
         
            +
                @r.rpush 'dogs', 3
         
     | 
| 
      
 361 
     | 
    
         
            +
                @r['dog_4'] = 'taj'
         
     | 
| 
      
 362 
     | 
    
         
            +
                @r.rpush 'dogs', 4
         
     | 
| 
      
 363 
     | 
    
         
            +
                @r.sort('dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie']
         
     | 
| 
      
 364 
     | 
    
         
            +
                @r.sort('dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj']
         
     | 
| 
      
 365 
     | 
    
         
            +
              end
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
              it "should be able to handle array of :get using SORT" do
         
     | 
| 
      
 368 
     | 
    
         
            +
                @r['dog:1:name'] = 'louie'
         
     | 
| 
      
 369 
     | 
    
         
            +
                @r['dog:1:breed'] = 'mutt'
         
     | 
| 
      
 370 
     | 
    
         
            +
                @r.rpush 'dogs', 1
         
     | 
| 
      
 371 
     | 
    
         
            +
                @r['dog:2:name'] = 'lucy'
         
     | 
| 
      
 372 
     | 
    
         
            +
                @r['dog:2:breed'] = 'poodle'
         
     | 
| 
      
 373 
     | 
    
         
            +
                @r.rpush 'dogs', 2
         
     | 
| 
      
 374 
     | 
    
         
            +
                @r['dog:3:name'] = 'max'
         
     | 
| 
      
 375 
     | 
    
         
            +
                @r['dog:3:breed'] = 'hound'
         
     | 
| 
      
 376 
     | 
    
         
            +
                @r.rpush 'dogs', 3
         
     | 
| 
      
 377 
     | 
    
         
            +
                @r['dog:4:name'] = 'taj'
         
     | 
| 
      
 378 
     | 
    
         
            +
                @r['dog:4:breed'] = 'terrier'
         
     | 
| 
      
 379 
     | 
    
         
            +
                @r.rpush 'dogs', 4
         
     | 
| 
      
 380 
     | 
    
         
            +
                @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt']
         
     | 
| 
      
 381 
     | 
    
         
            +
                @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
         
     | 
| 
      
 382 
     | 
    
         
            +
              end
         
     | 
| 
      
 383 
     | 
    
         
            +
              # 
         
     | 
| 
      
 384 
     | 
    
         
            +
              it "should provide info (INFO)" do
         
     | 
| 
      
 385 
     | 
    
         
            +
                [:last_save_time, :redis_version, :total_connections_received, :connected_clients, :total_commands_processed, :connected_slaves, :uptime_in_seconds, :used_memory, :uptime_in_days, :changes_since_last_save].each do |x|
         
     | 
| 
      
 386 
     | 
    
         
            +
                @r.info.keys.should include(x)
         
     | 
| 
      
 387 
     | 
    
         
            +
                end
         
     | 
| 
      
 388 
     | 
    
         
            +
              end
         
     | 
| 
      
 389 
     | 
    
         
            +
              # 
         
     | 
| 
      
 390 
     | 
    
         
            +
              it "should be able to flush the database (FLUSHDB)" do
         
     | 
| 
      
 391 
     | 
    
         
            +
                @r['key1'] = 'keyone'
         
     | 
| 
      
 392 
     | 
    
         
            +
                @r['key2'] = 'keytwo'
         
     | 
| 
      
 393 
     | 
    
         
            +
                @r.keys('*').sort.should == ['foo', 'key1', 'key2'].sort #foo from before
         
     | 
| 
      
 394 
     | 
    
         
            +
                @r.flushdb
         
     | 
| 
      
 395 
     | 
    
         
            +
                @r.keys('*').should == []
         
     | 
| 
      
 396 
     | 
    
         
            +
              end
         
     | 
| 
      
 397 
     | 
    
         
            +
              #
         
     | 
| 
      
 398 
     | 
    
         
            +
              it "should raise exception when manually try to change the database" do
         
     | 
| 
      
 399 
     | 
    
         
            +
                lambda { @r.select(0) }.should raise_error
         
     | 
| 
      
 400 
     | 
    
         
            +
              end
         
     | 
| 
      
 401 
     | 
    
         
            +
              #
         
     | 
| 
      
 402 
     | 
    
         
            +
              it "should be able to provide the last save time (LASTSAVE)" do
         
     | 
| 
      
 403 
     | 
    
         
            +
                savetime = @r.lastsave
         
     | 
| 
      
 404 
     | 
    
         
            +
                Time.at(savetime).class.should == Time
         
     | 
| 
      
 405 
     | 
    
         
            +
                Time.at(savetime).should <= Time.now
         
     | 
| 
      
 406 
     | 
    
         
            +
              end
         
     | 
| 
      
 407 
     | 
    
         
            +
              
         
     | 
| 
      
 408 
     | 
    
         
            +
              it "should be able to MGET keys" do
         
     | 
| 
      
 409 
     | 
    
         
            +
                @r['foo'] = 1000
         
     | 
| 
      
 410 
     | 
    
         
            +
                @r['bar'] = 2000
         
     | 
| 
      
 411 
     | 
    
         
            +
                @r.mget('foo', 'bar').should == ['1000', '2000']
         
     | 
| 
      
 412 
     | 
    
         
            +
                @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil]
         
     | 
| 
      
 413 
     | 
    
         
            +
              end
         
     | 
| 
      
 414 
     | 
    
         
            +
              
         
     | 
| 
      
 415 
     | 
    
         
            +
              it "should bgsave" do
         
     | 
| 
      
 416 
     | 
    
         
            +
                @r.bgsave.should == 'OK'
         
     | 
| 
      
 417 
     | 
    
         
            +
              end
         
     | 
| 
      
 418 
     | 
    
         
            +
              
         
     | 
| 
      
 419 
     | 
    
         
            +
              it "should be able to ECHO" do
         
     | 
| 
      
 420 
     | 
    
         
            +
                @r.echo("message in a bottle\n").should == "message in a bottle\n"
         
     | 
| 
      
 421 
     | 
    
         
            +
              end
         
     | 
| 
      
 422 
     | 
    
         
            +
             
     | 
| 
      
 423 
     | 
    
         
            +
              it "should raise error when invoke MONITOR" do
         
     | 
| 
      
 424 
     | 
    
         
            +
                lambda { @r.monitor }.should raise_error
         
     | 
| 
      
 425 
     | 
    
         
            +
              end
         
     | 
| 
      
 426 
     | 
    
         
            +
             
     | 
| 
      
 427 
     | 
    
         
            +
              it "should raise error when invoke SYNC" do
         
     | 
| 
      
 428 
     | 
    
         
            +
                lambda { @r.sync }.should raise_error
         
     | 
| 
      
 429 
     | 
    
         
            +
              end
         
     | 
| 
      
 430 
     | 
    
         
            +
             
     | 
| 
      
 431 
     | 
    
         
            +
              it "should handle multiple servers" do
         
     | 
| 
      
 432 
     | 
    
         
            +
                require 'dist_redis'
         
     | 
| 
      
 433 
     | 
    
         
            +
                @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15)
         
     | 
| 
      
 434 
     | 
    
         
            +
             
     | 
| 
      
 435 
     | 
    
         
            +
                100.times do |idx|
         
     | 
| 
      
 436 
     | 
    
         
            +
                  @r[idx] = "foo#{idx}"
         
     | 
| 
      
 437 
     | 
    
         
            +
                end
         
     | 
| 
      
 438 
     | 
    
         
            +
             
     | 
| 
      
 439 
     | 
    
         
            +
                100.times do |idx|
         
     | 
| 
      
 440 
     | 
    
         
            +
                  @r[idx].should == "foo#{idx}"
         
     | 
| 
      
 441 
     | 
    
         
            +
                end
         
     | 
| 
      
 442 
     | 
    
         
            +
              end
         
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
      
 444 
     | 
    
         
            +
              it "should be able to pipeline writes" do
         
     | 
| 
      
 445 
     | 
    
         
            +
                @r.pipelined do |pipeline|
         
     | 
| 
      
 446 
     | 
    
         
            +
                  pipeline.lpush 'list', "hello"
         
     | 
| 
      
 447 
     | 
    
         
            +
                  pipeline.lpush 'list', 42
         
     | 
| 
      
 448 
     | 
    
         
            +
                end
         
     | 
| 
      
 449 
     | 
    
         
            +
                
         
     | 
| 
      
 450 
     | 
    
         
            +
                @r.type('list').should == "list"
         
     | 
| 
      
 451 
     | 
    
         
            +
                @r.llen('list').should == 2
         
     | 
| 
      
 452 
     | 
    
         
            +
                @r.lpop('list').should == '42'
         
     | 
| 
      
 453 
     | 
    
         
            +
              end
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
              it "should AUTH when connecting with a password" do
         
     | 
| 
      
 456 
     | 
    
         
            +
                r = Redis.new(:password => 'secret')
         
     | 
| 
      
 457 
     | 
    
         
            +
                r.stub!(:connect_to)
         
     | 
| 
      
 458 
     | 
    
         
            +
                r.should_receive(:call_command).with(['auth', 'secret'])
         
     | 
| 
      
 459 
     | 
    
         
            +
                r.connect_to_server
         
     | 
| 
      
 460 
     | 
    
         
            +
              end
         
     | 
| 
      
 461 
     | 
    
         
            +
              
         
     | 
| 
      
 462 
     | 
    
         
            +
            end
         
     |