提交 3113921a 编写于 作者: A antirez

Ruby client lib updated to the latest git version

上级 123d7c93
...@@ -9,7 +9,7 @@ require 'tasks/redis.tasks' ...@@ -9,7 +9,7 @@ require 'tasks/redis.tasks'
GEM = 'redis' GEM = 'redis'
GEM_NAME = 'redis' GEM_NAME = 'redis'
GEM_VERSION = '0.1' GEM_VERSION = '0.1'
AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark'] AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi']
EMAIL = "ez@engineyard.com" EMAIL = "ez@engineyard.com"
HOMEPAGE = "http://github.com/ezmobius/redis-rb" HOMEPAGE = "http://github.com/ezmobius/redis-rb"
SUMMARY = "Ruby client library for redis key value storage server" SUMMARY = "Ruby client library for redis key value storage server"
...@@ -28,7 +28,7 @@ spec = Gem::Specification.new do |s| ...@@ -28,7 +28,7 @@ spec = Gem::Specification.new do |s|
s.add_dependency "rspec" s.add_dependency "rspec"
s.require_path = 'lib' s.require_path = 'lib'
s.autorequire = GEM s.autorequire = GEM
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,spec}/**/*") s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
end end
task :default => :spec task :default => :spec
......
require 'socket'
require 'pp'
require File.join(File.dirname(__FILE__), '../lib/redis')
#require File.join(File.dirname(__FILE__), '../lib/server')
#r = Redis.new
#loop do
# puts "--------------------------------------"
# sleep 12
#end
\ No newline at end of file
...@@ -4,32 +4,30 @@ class DistRedis ...@@ -4,32 +4,30 @@ class DistRedis
attr_reader :ring attr_reader :ring
def initialize(opts={}) def initialize(opts={})
hosts = [] hosts = []
db = opts[:db] || nil db = opts[:db] || nil
timeout = opts[:timeout] || nil timeout = opts[:timeout] || nil
raise Error, "No hosts given" unless opts[:hosts] raise Error, "No hosts given" unless opts[:hosts]
opts[:hosts].each do |h| opts[:hosts].each do |h|
host, port = h.split(':') host, port = h.split(':')
hosts << Redis.new(:host => host, :port => port, :db => db, :timeout => timeout, :db => db) hosts << Redis.new(:host => host, :port => port, :db => db, :timeout => timeout)
end end
@ring = HashRing.new hosts @ring = HashRing.new hosts
end end
def node_for_key(key) def node_for_key(key)
if key =~ /\{(.*)?\}/ key = $1 if key =~ /\{(.*)?\}/
key = $1
end
@ring.get_node(key) @ring.get_node(key)
end end
def add_server(server) def add_server(server)
server, port = server.split(':') server, port = server.split(':')
@ring.add_node Redis.new(:host => server, :port => port) @ring.add_node Redis.new(:host => server, :port => port)
end end
def method_missing(sym, *args, &blk) def method_missing(sym, *args, &blk)
if redis = node_for_key(args.first.to_s) if redis = node_for_key(args.first.to_s)
redis.send sym, *args, &blk redis.send sym, *args, &blk
...@@ -37,41 +35,49 @@ class DistRedis ...@@ -37,41 +35,49 @@ class DistRedis
super super
end end
end end
def keys(glob) def keys(glob)
keyz = [] @ring.nodes.map do |red|
@ring.nodes.each do |red| red.keys(glob)
keyz.concat red.keys(glob)
end end
keyz
end end
def save def save
@ring.nodes.each do |red| on_each_node :save
red.save
end
end end
def bgsave def bgsave
@ring.nodes.each do |red| on_each_node :bgsave
red.bgsave
end
end end
def quit def quit
@ring.nodes.each do |red| on_each_node :quit
red.quit end
end
def flush_all
on_each_node :flush_all
end
alias_method :flushall, :flush_all
def flush_db
on_each_node :flush_db
end end
alias_method :flushdb, :flush_db
def delete_cloud! def delete_cloud!
@ring.nodes.each do |red| @ring.nodes.each do |red|
red.keys("*").each do |key| red.keys("*").each do |key|
red.delete key red.delete key
end end
end end
end end
def on_each_node(command, *args)
@ring.nodes.each do |red|
red.send(command, *args)
end
end
end end
...@@ -94,21 +100,21 @@ r = DistRedis.new 'localhost:6379', 'localhost:6380', 'localhost:6381', 'localho ...@@ -94,21 +100,21 @@ r = DistRedis.new 'localhost:6379', 'localhost:6380', 'localhost:6381', 'localho
p r['urdad2'] p r['urdad2']
p r['urmom3'] p r['urmom3']
p r['urdad3'] p r['urdad3']
r.push_tail 'listor', 'foo1' r.push_tail 'listor', 'foo1'
r.push_tail 'listor', 'foo2' r.push_tail 'listor', 'foo2'
r.push_tail 'listor', 'foo3' r.push_tail 'listor', 'foo3'
r.push_tail 'listor', 'foo4' r.push_tail 'listor', 'foo4'
r.push_tail 'listor', 'foo5' r.push_tail 'listor', 'foo5'
p r.pop_tail('listor') p r.pop_tail('listor')
p r.pop_tail('listor') p r.pop_tail('listor')
p r.pop_tail('listor') p r.pop_tail('listor')
p r.pop_tail('listor') p r.pop_tail('listor')
p r.pop_tail('listor') p r.pop_tail('listor')
puts "key distribution:" puts "key distribution:"
r.ring.nodes.each do |red| r.ring.nodes.each do |red|
p [red.port, red.keys("*")] p [red.port, red.keys("*")]
end end
......
...@@ -31,8 +31,9 @@ class HashRing ...@@ -31,8 +31,9 @@ class HashRing
end end
def remove_node(node) def remove_node(node)
@nodes.reject!{|n| n.to_s == node.to_s}
@replicas.times do |i| @replicas.times do |i|
key = Zlib.crc32("#{node}:#{count}") key = Zlib.crc32("#{node}:#{i}")
@ring.delete(key) @ring.delete(key)
@sorted_keys.reject! {|k| k == key} @sorted_keys.reject! {|k| k == key}
end end
......
...@@ -36,7 +36,7 @@ class Redis ...@@ -36,7 +36,7 @@ class Redis
"smove" => true "smove" => true
} }
BOOLEAN_PROCESSOR = lambda{|r| r == 0 ? false : r} BOOLEAN_PROCESSOR = lambda{|r| r == 1 }
REPLY_PROCESSOR = { REPLY_PROCESSOR = {
"exists" => BOOLEAN_PROCESSOR, "exists" => BOOLEAN_PROCESSOR,
...@@ -95,21 +95,34 @@ class Redis ...@@ -95,21 +95,34 @@ class Redis
"type?" => "type" "type?" => "type"
} }
DISABLED_COMMANDS = {
"monitor" => true,
"sync" => true
}
def initialize(options = {}) def initialize(options = {})
@host = options[:host] || '127.0.0.1' @host = options[:host] || '127.0.0.1'
@port = (options[:port] || 6379).to_i @port = (options[:port] || 6379).to_i
@db = (options[:db] || 0).to_i @db = (options[:db] || 0).to_i
@timeout = (options[:timeout] || 5).to_i @timeout = (options[:timeout] || 5).to_i
$debug = options[:debug] @password = options[:password]
@logger = options[:logger]
@logger.info { self.to_s } if @logger
connect_to_server connect_to_server
end end
def to_s def to_s
"Redis Client connected to #{@host}:#{@port} against DB #{@db}" "Redis Client connected to #{server} against DB #{@db}"
end
def server
"#{@host}:#{@port}"
end end
def connect_to_server def connect_to_server
@sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout) @sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout)
call_command(["auth",@password]) if @password
call_command(["select",@db]) unless @db == 0 call_command(["select",@db]) unless @db == 0
end end
...@@ -147,15 +160,18 @@ class Redis ...@@ -147,15 +160,18 @@ class Redis
end end
def call_command(argv) def call_command(argv)
puts argv.inspect if $debug @logger.debug { argv.inspect } if @logger
# this wrapper to raw_call_command handle reconnection on socket # this wrapper to raw_call_command handle reconnection on socket
# error. We try to reconnect just one time, otherwise let the error # error. We try to reconnect just one time, otherwise let the error
# araise. # araise.
connect_to_server if !@sock connect_to_server if !@sock
begin begin
raw_call_command(argv.dup) raw_call_command(argv.dup)
rescue Errno::ECONNRESET, Errno::EPIPE rescue Errno::ECONNRESET, Errno::EPIPE
@sock.close @sock.close
@sock = nil
connect_to_server connect_to_server
raw_call_command(argv.dup) raw_call_command(argv.dup)
end end
...@@ -176,12 +192,13 @@ class Redis ...@@ -176,12 +192,13 @@ class Redis
bulk = nil bulk = nil
argv[0] = argv[0].to_s.downcase argv[0] = argv[0].to_s.downcase
argv[0] = ALIASES[argv[0]] if ALIASES[argv[0]] argv[0] = ALIASES[argv[0]] if ALIASES[argv[0]]
raise "#{argv[0]} command is disabled" if DISABLED_COMMANDS[argv[0]]
if BULK_COMMANDS[argv[0]] and argv.length > 1 if BULK_COMMANDS[argv[0]] and argv.length > 1
bulk = argv[-1].to_s bulk = argv[-1].to_s
argv[-1] = bulk.length argv[-1] = bulk.respond_to?(:bytesize) ? bulk.bytesize : bulk.size
end end
command << argv.join(' ') + "\r\n" command << "#{argv.join(' ')}\r\n"
command << bulk + "\r\n" if bulk command << "#{bulk}\r\n" if bulk
end end
@sock.write(command) @sock.write(command)
...@@ -199,7 +216,7 @@ class Redis ...@@ -199,7 +216,7 @@ class Redis
end end
def [](key) def [](key)
get(key) self.get(key)
end end
def []=(key,value) def []=(key,value)
...@@ -213,8 +230,8 @@ class Redis ...@@ -213,8 +230,8 @@ class Redis
end end
def sort(key, options = {}) def sort(key, options = {})
cmd = [] cmd = ["SORT"]
cmd << "SORT #{key}" cmd << key
cmd << "BY #{options[:by]}" if options[:by] cmd << "BY #{options[:by]}" if options[:by]
cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get] cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get]
cmd << "#{options[:order]}" if options[:order] cmd << "#{options[:order]}" if options[:order]
...@@ -230,6 +247,15 @@ class Redis ...@@ -230,6 +247,15 @@ class Redis
call_command(decrement ? ["decrby",key,decrement] : ["decr",key]) call_command(decrement ? ["decrby",key,decrement] : ["decr",key])
end end
# Similar to memcache.rb's #get_multi, returns a hash mapping
# keys to values.
def mapped_mget(*keys)
mget(*keys).inject({}) do |hash, value|
key = keys.shift
value.nil? ? hash : hash.merge(key => value)
end
end
# Ruby defines a now deprecated type method so we need to override it here # Ruby defines a now deprecated type method so we need to override it here
# since it will never hit method_missing # since it will never hit method_missing
def type(key) def type(key)
......
...@@ -2,18 +2,18 @@ ...@@ -2,18 +2,18 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = %q{redis} s.name = %q{redis}
s.version = "0.0.5" s.version = "0.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Ezra Zygmuntowicz", "Taylor Weibley", "Matthew Clark"] s.authors = ["Ezra Zygmuntowicz", "Taylor Weibley", "Matthew Clark", "Brian McKinney", "Salvatore Sanfilippo", "Luca Guidi"]
#s.autorequire = %q{redis} # s.autorequire = %q{redis-rb}
s.date = %q{2009-03-31} s.date = %q{2009-06-23}
s.description = %q{Ruby client library for redis key value storage server} s.description = %q{Ruby client library for redis key value storage server}
s.email = %q{ez@engineyard.com} s.email = %q{ez@engineyard.com}
s.extra_rdoc_files = ["LICENSE"] s.extra_rdoc_files = ["LICENSE"]
s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/redis.rb", "lib/dist_redis.rb", "lib/hash_ring.rb", "lib/pipeline.rb", "lib/server.rb", "spec/redis_spec.rb", "spec/spec_helper.rb"] s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/dist_redis.rb", "lib/hash_ring.rb", "lib/pipeline.rb", "lib/redis.rb", "spec/redis_spec.rb", "spec/spec_helper.rb"]
s.has_rdoc = true s.has_rdoc = true
s.homepage = %q{http://github.com/winescout/redis-rb} s.homepage = %q{http://github.com/ezmobius/redis-rb}
s.require_paths = ["lib"] s.require_paths = ["lib"]
s.rubygems_version = %q{1.3.1} s.rubygems_version = %q{1.3.1}
s.summary = %q{Ruby client library for redis key value storage server} s.summary = %q{Ruby client library for redis key value storage server}
......
require File.dirname(__FILE__) + '/spec_helper' require File.dirname(__FILE__) + '/spec_helper'
require 'logger'
class Foo class Foo
attr_accessor :bar attr_accessor :bar
def initialize(bar) def initialize(bar)
@bar = bar @bar = bar
end end
def ==(other) def ==(other)
@bar == other.bar @bar == other.bar
end end
end end
describe "redis" do describe "redis" do
before(:all) do before(:all) do
...@@ -23,34 +24,41 @@ describe "redis" do ...@@ -23,34 +24,41 @@ describe "redis" do
after(:each) do after(:each) do
@r.keys('*').each {|k| @r.del k} @r.keys('*').each {|k| @r.del k}
end end
after(:all) do after(:all) do
@r.quit @r.quit
end end
it "should be able connect without a timeout" do it "should be able connect without a timeout" do
lambda { Redis.new :timeout => 0 }.should_not raise_error lambda { Redis.new :timeout => 0 }.should_not raise_error
end end
it "should be able to provide a logger" do
log = StringIO.new
r = Redis.new :db => 15, :logger => Logger.new(log)
r.ping
log.string.should include("ping")
end
it "should be able to PING" do it "should be able to PING" do
@r.ping.should == 'PONG' @r.ping.should == 'PONG'
end end
it "should be able to GET a key" do it "should be able to GET a key" do
@r['foo'].should == 'bar' @r['foo'].should == 'bar'
end end
it "should be able to SET a key" do it "should be able to SET a key" do
@r['foo'] = 'nik' @r['foo'] = 'nik'
@r['foo'].should == 'nik' @r['foo'].should == 'nik'
end end
it "should properly handle trailing newline characters" do it "should properly handle trailing newline characters" do
@r['foo'] = "bar\n" @r['foo'] = "bar\n"
@r['foo'].should == "bar\n" @r['foo'].should == "bar\n"
end end
it "should store and retrieve all possible characters at the beginning and the end of a string" do it "should store and retrieve all possible characters at the beginning and the end of a string" do
(0..255).each do |char_idx| (0..255).each do |char_idx|
string = "#{char_idx.chr}---#{char_idx.chr}" string = "#{char_idx.chr}---#{char_idx.chr}"
...@@ -58,7 +66,7 @@ describe "redis" do ...@@ -58,7 +66,7 @@ describe "redis" do
@r['foo'].should == string @r['foo'].should == string
end end
end end
it "should be able to SET a key with an expiry" do it "should be able to SET a key with an expiry" do
@r.set('foo', 'bar', 1) @r.set('foo', 'bar', 1)
@r['foo'].should == 'bar' @r['foo'].should == 'bar'
...@@ -82,7 +90,7 @@ describe "redis" do ...@@ -82,7 +90,7 @@ describe "redis" do
@r.getset('foo', 'baz').should == 'bar' @r.getset('foo', 'baz').should == 'bar'
@r['foo'].should == 'baz' @r['foo'].should == 'baz'
end end
# #
it "should be able to INCR a key" do it "should be able to INCR a key" do
@r.del('counter') @r.del('counter')
@r.incr('counter').should == 1 @r.incr('counter').should == 1
...@@ -105,11 +113,11 @@ describe "redis" do ...@@ -105,11 +113,11 @@ describe "redis" do
@r.decr('counter').should == 2 @r.decr('counter').should == 2
@r.decr('counter', 2).should == 0 @r.decr('counter', 2).should == 0
end end
# #
it "should be able to RANDKEY" do it "should be able to RANDKEY" do
@r.randkey.should_not be_nil @r.randkey.should_not be_nil
end end
# #
it "should be able to RENAME a key" do it "should be able to RENAME a key" do
@r.del 'foo' @r.del 'foo'
@r.del'bar' @r.del'bar'
...@@ -117,7 +125,7 @@ describe "redis" do ...@@ -117,7 +125,7 @@ describe "redis" do
@r.rename 'foo', 'bar' @r.rename 'foo', 'bar'
@r['bar'].should == 'hi' @r['bar'].should == 'hi'
end end
# #
it "should be able to RENAMENX a key" do it "should be able to RENAMENX a key" do
@r.del 'foo' @r.del 'foo'
@r.del 'bar' @r.del 'bar'
...@@ -150,7 +158,7 @@ describe "redis" do ...@@ -150,7 +158,7 @@ describe "redis" do
@r.del 'foo' @r.del 'foo'
@r.exists('foo').should be_false @r.exists('foo').should be_false
end end
# #
it "should be able to KEYS" do it "should be able to KEYS" do
@r.keys("f*").each { |key| @r.del key } @r.keys("f*").each { |key| @r.del key }
@r['f'] = 'nik' @r['f'] = 'nik'
...@@ -162,14 +170,14 @@ describe "redis" do ...@@ -162,14 +170,14 @@ describe "redis" do
it "should be able to return a random key (RANDOMKEY)" do it "should be able to return a random key (RANDOMKEY)" do
3.times { @r.exists(@r.randomkey).should be_true } 3.times { @r.exists(@r.randomkey).should be_true }
end end
#BTM - TODO #
it "should be able to check the TYPE of a key" do it "should be able to check the TYPE of a key" do
@r['foo'] = 'nik' @r['foo'] = 'nik'
@r.type('foo').should == "string" @r.type('foo').should == "string"
@r.del 'foo' @r.del 'foo'
@r.type('foo').should == "none" @r.type('foo').should == "none"
end end
# #
it "should be able to push to the head of a list (LPUSH)" do it "should be able to push to the head of a list (LPUSH)" do
@r.lpush "list", 'hello' @r.lpush "list", 'hello'
@r.lpush "list", 42 @r.lpush "list", 42
...@@ -177,13 +185,13 @@ describe "redis" do ...@@ -177,13 +185,13 @@ describe "redis" do
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.lpop('list').should == '42' @r.lpop('list').should == '42'
end end
# #
it "should be able to push to the tail of a list (RPUSH)" do it "should be able to push to the tail of a list (RPUSH)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.type('list').should == "list" @r.type('list').should == "list"
@r.llen('list').should == 1 @r.llen('list').should == 1
end end
# #
it "should be able to pop the tail of a list (RPOP)" do it "should be able to pop the tail of a list (RPOP)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush"list", 'goodbye' @r.rpush"list", 'goodbye'
...@@ -191,7 +199,7 @@ describe "redis" do ...@@ -191,7 +199,7 @@ describe "redis" do
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.rpop('list').should == 'goodbye' @r.rpop('list').should == 'goodbye'
end end
# #
it "should be able to pop the head of a list (LPOP)" do it "should be able to pop the head of a list (LPOP)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
...@@ -199,14 +207,14 @@ describe "redis" do ...@@ -199,14 +207,14 @@ describe "redis" do
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.lpop('list').should == 'hello' @r.lpop('list').should == 'hello'
end end
# #
it "should be able to get the length of a list (LLEN)" do it "should be able to get the length of a list (LLEN)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
@r.type('list').should == "list" @r.type('list').should == "list"
@r.llen('list').should == 2 @r.llen('list').should == 2
end end
# #
it "should be able to get a range of values from a list (LRANGE)" do it "should be able to get a range of values from a list (LRANGE)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
...@@ -217,7 +225,7 @@ describe "redis" do ...@@ -217,7 +225,7 @@ describe "redis" do
@r.llen('list').should == 5 @r.llen('list').should == 5
@r.lrange('list', 2, -1).should == ['1', '2', '3'] @r.lrange('list', 2, -1).should == ['1', '2', '3']
end end
# #
it "should be able to trim a list (LTRIM)" do it "should be able to trim a list (LTRIM)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
...@@ -230,7 +238,7 @@ describe "redis" do ...@@ -230,7 +238,7 @@ describe "redis" do
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.lrange('list', 0, -1).should == ['hello', 'goodbye'] @r.lrange('list', 0, -1).should == ['hello', 'goodbye']
end end
# #
it "should be able to get a value by indexing into a list (LINDEX)" do it "should be able to get a value by indexing into a list (LINDEX)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
...@@ -238,7 +246,7 @@ describe "redis" do ...@@ -238,7 +246,7 @@ describe "redis" do
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.lindex('list', 1).should == 'goodbye' @r.lindex('list', 1).should == 'goodbye'
end end
# #
it "should be able to set a value by indexing into a list (LSET)" do it "should be able to set a value by indexing into a list (LSET)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
...@@ -247,7 +255,7 @@ describe "redis" do ...@@ -247,7 +255,7 @@ describe "redis" do
@r.lset('list', 1, 'goodbye').should == 'OK' @r.lset('list', 1, 'goodbye').should == 'OK'
@r.lindex('list', 1).should == 'goodbye' @r.lindex('list', 1).should == 'goodbye'
end end
# #
it "should be able to remove values from a list (LREM)" do it "should be able to remove values from a list (LREM)" do
@r.rpush "list", 'hello' @r.rpush "list", 'hello'
@r.rpush "list", 'goodbye' @r.rpush "list", 'goodbye'
...@@ -256,7 +264,7 @@ describe "redis" do ...@@ -256,7 +264,7 @@ describe "redis" do
@r.lrem('list', 1, 'hello').should == 1 @r.lrem('list', 1, 'hello').should == 1
@r.lrange('list', 0, -1).should == ['goodbye'] @r.lrange('list', 0, -1).should == ['goodbye']
end end
# #
it "should be able add members to a set (SADD)" do it "should be able add members to a set (SADD)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
...@@ -264,7 +272,7 @@ describe "redis" do ...@@ -264,7 +272,7 @@ describe "redis" do
@r.scard('set').should == 2 @r.scard('set').should == 2
@r.smembers('set').sort.should == ['key1', 'key2'].sort @r.smembers('set').sort.should == ['key1', 'key2'].sort
end end
# #
it "should be able delete members to a set (SREM)" do it "should be able delete members to a set (SREM)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
...@@ -275,14 +283,14 @@ describe "redis" do ...@@ -275,14 +283,14 @@ describe "redis" do
@r.scard('set').should == 1 @r.scard('set').should == 1
@r.smembers('set').should == ['key2'] @r.smembers('set').should == ['key2']
end end
# #
it "should be able count the members of a set (SCARD)" do it "should be able count the members of a set (SCARD)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
@r.type('set').should == "set" @r.type('set').should == "set"
@r.scard('set').should == 2 @r.scard('set').should == 2
end end
# #
it "should be able test for set membership (SISMEMBER)" do it "should be able test for set membership (SISMEMBER)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
...@@ -292,14 +300,14 @@ describe "redis" do ...@@ -292,14 +300,14 @@ describe "redis" do
@r.sismember('set', 'key2').should be_true @r.sismember('set', 'key2').should be_true
@r.sismember('set', 'notthere').should be_false @r.sismember('set', 'notthere').should be_false
end end
# #
it "should be able to do set intersection (SINTER)" do it "should be able to do set intersection (SINTER)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
@r.sadd "set2", 'key2' @r.sadd "set2", 'key2'
@r.sinter('set', 'set2').should == ['key2'] @r.sinter('set', 'set2').should == ['key2']
end end
# #
it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
...@@ -315,7 +323,7 @@ describe "redis" do ...@@ -315,7 +323,7 @@ describe "redis" do
@r.sadd "set2", 'key3' @r.sadd "set2", 'key3'
@r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort @r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort
end end
# #
it "should be able to do set union and store the results in a key (SUNIONSTORE)" do it "should be able to do set union and store the results in a key (SUNIONSTORE)" do
@r.sadd "set", 'key1' @r.sadd "set", 'key1'
@r.sadd "set", 'key2' @r.sadd "set", 'key2'
...@@ -324,7 +332,7 @@ describe "redis" do ...@@ -324,7 +332,7 @@ describe "redis" do
@r.sunionstore('newone', 'set', 'set2').should == 3 @r.sunionstore('newone', 'set', 'set2').should == 3
@r.smembers('newone').sort.should == ['key1','key2','key3'].sort @r.smembers('newone').sort.should == ['key1','key2','key3'].sort
end end
# #
it "should be able to do set difference (SDIFF)" do it "should be able to do set difference (SDIFF)" do
@r.sadd "set", 'a' @r.sadd "set", 'a'
@r.sadd "set", 'b' @r.sadd "set", 'b'
...@@ -332,7 +340,7 @@ describe "redis" do ...@@ -332,7 +340,7 @@ describe "redis" do
@r.sadd "set2", 'c' @r.sadd "set2", 'c'
@r.sdiff('set', 'set2').should == ['a'] @r.sdiff('set', 'set2').should == ['a']
end end
# #
it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do
@r.sadd "set", 'a' @r.sadd "set", 'a'
@r.sadd "set", 'b' @r.sadd "set", 'b'
...@@ -341,27 +349,28 @@ describe "redis" do ...@@ -341,27 +349,28 @@ describe "redis" do
@r.sdiffstore('newone', 'set', 'set2') @r.sdiffstore('newone', 'set', 'set2')
@r.smembers('newone').should == ['a'] @r.smembers('newone').should == ['a']
end end
# #
it "should be able move elements from one set to another (SMOVE)" do it "should be able move elements from one set to another (SMOVE)" do
@r.sadd 'set1', 'a' @r.sadd 'set1', 'a'
@r.sadd 'set1', 'b' @r.sadd 'set1', 'b'
@r.sadd 'set2', 'x' @r.sadd 'set2', 'x'
@r.smove('set1', 'set2', 'a').should be_true @r.smove('set1', 'set2', 'a').should be_true
@r.sismember('set2', 'a').should be_true @r.sismember('set2', 'a').should be_true
@r.delete('set1') @r.delete('set1')
end end
# #
it "should be able to do crazy SORT queries" do it "should be able to do crazy SORT queries" do
# The 'Dogs' is capitialized on purpose
@r['dog_1'] = 'louie' @r['dog_1'] = 'louie'
@r.rpush 'dogs', 1 @r.rpush 'Dogs', 1
@r['dog_2'] = 'lucy' @r['dog_2'] = 'lucy'
@r.rpush 'dogs', 2 @r.rpush 'Dogs', 2
@r['dog_3'] = 'max' @r['dog_3'] = 'max'
@r.rpush 'dogs', 3 @r.rpush 'Dogs', 3
@r['dog_4'] = 'taj' @r['dog_4'] = 'taj'
@r.rpush 'dogs', 4 @r.rpush 'Dogs', 4
@r.sort('dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie'] @r.sort('Dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie']
@r.sort('dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj'] @r.sort('Dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj']
end end
it "should be able to handle array of :get using SORT" do it "should be able to handle array of :get using SORT" do
...@@ -380,13 +389,13 @@ describe "redis" do ...@@ -380,13 +389,13 @@ describe "redis" do
@r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt'] @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt']
@r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier'] @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier']
end end
# #
it "should provide info (INFO)" do it "should provide info (INFO)" do
[: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| [: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|
@r.info.keys.should include(x) @r.info.keys.should include(x)
end end
end end
# #
it "should be able to flush the database (FLUSHDB)" do it "should be able to flush the database (FLUSHDB)" do
@r['key1'] = 'keyone' @r['key1'] = 'keyone'
@r['key2'] = 'keytwo' @r['key2'] = 'keytwo'
...@@ -404,22 +413,37 @@ describe "redis" do ...@@ -404,22 +413,37 @@ describe "redis" do
Time.at(savetime).class.should == Time Time.at(savetime).class.should == Time
Time.at(savetime).should <= Time.now Time.at(savetime).should <= Time.now
end end
it "should be able to MGET keys" do it "should be able to MGET keys" do
@r['foo'] = 1000 @r['foo'] = 1000
@r['bar'] = 2000 @r['bar'] = 2000
@r.mget('foo', 'bar').should == ['1000', '2000'] @r.mget('foo', 'bar').should == ['1000', '2000']
@r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil] @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil]
end end
it "should be able to mapped MGET keys" do
@r['foo'] = 1000
@r['bar'] = 2000
@r.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000'}
@r.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000'}
end
it "should bgsave" do it "should bgsave" do
@r.bgsave.should == 'OK' @r.bgsave.should == 'OK'
end end
it "should should be able to ECHO" do it "should be able to ECHO" do
@r.echo("message in a bottle\n").should == "message in a bottle\n" @r.echo("message in a bottle\n").should == "message in a bottle\n"
end end
it "should raise error when invoke MONITOR" do
lambda { @r.monitor }.should raise_error
end
it "should raise error when invoke SYNC" do
lambda { @r.sync }.should raise_error
end
it "should handle multiple servers" do it "should handle multiple servers" do
require 'dist_redis' require 'dist_redis'
@r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15) @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15)
...@@ -438,10 +462,17 @@ describe "redis" do ...@@ -438,10 +462,17 @@ describe "redis" do
pipeline.lpush 'list', "hello" pipeline.lpush 'list', "hello"
pipeline.lpush 'list', 42 pipeline.lpush 'list', 42
end end
@r.type('list').should == "list" @r.type('list').should == "list"
@r.llen('list').should == 2 @r.llen('list').should == 2
@r.lpop('list').should == '42' @r.lpop('list').should == '42'
end end
it "should AUTH when connecting with a password" do
r = Redis.new(:password => 'secret')
r.stub!(:connect_to)
r.should_receive(:call_command).with(['auth', 'secret'])
r.connect_to_server
end
end end
require 'rubygems' require 'rubygems'
$TESTING=true $TESTING=true
$:.push File.join(File.dirname(__FILE__), '..', 'lib') $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
require 'redis' require 'redis'
# Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master # Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master
require 'fileutils' require 'fileutils'
require 'open-uri'
class RedisRunner class RedisRunner
...@@ -106,10 +107,8 @@ namespace :dtach do ...@@ -106,10 +107,8 @@ namespace :dtach do
unless File.exists?('/tmp/dtach-0.8.tar.gz') unless File.exists?('/tmp/dtach-0.8.tar.gz')
require 'net/http' require 'net/http'
Net::HTTP.start('superb-west.dl.sourceforge.net') do |http| url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
resp = http.get('/sourceforge/dtach/dtach-0.8.tar.gz') open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(open(url).read) end
open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(resp.body) end
end
end end
unless File.directory?('/tmp/dtach-0.8') unless File.directory?('/tmp/dtach-0.8')
...@@ -123,4 +122,4 @@ namespace :dtach do ...@@ -123,4 +122,4 @@ namespace :dtach do
puts 'Dtach successfully installed to /usr/bin.' puts 'Dtach successfully installed to /usr/bin.'
end end
end end
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册