em-hiredis 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  .DS_Store
6
+ *.swp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in em-hiredis.gemspec
4
- gemspec
3
+ gem "em-spec", :git => "git://github.com/bcg/em-spec.git"
4
+ gem "eventmachine"
5
+ gem "hiredis"
6
+ gem "rspec"
data/README.md CHANGED
@@ -1,13 +1,18 @@
1
1
  Getting started
2
2
  ===============
3
3
 
4
- Connect to redis
4
+ Connect to redis:
5
5
 
6
- redis_client = EM::Hiredis.connect
6
+ require 'em-hiredis'
7
+ redis = EM::Hiredis.connect
8
+
9
+ Or, connect to redis with a redis URL (for a different host, port, password, DB)
10
+
11
+ redis = EM::Hiredis.connect("redis://:secretpassword@example.com:9000/4")
7
12
 
8
13
  The client is a deferrable which succeeds when the underlying connection is established so you can bind to this. This isn't necessary however - any commands sent before the connection is established (or while reconnecting) will be sent to redis on connect.
9
14
 
10
- redis_client.callback { puts "Redis now connected" }
15
+ redis.callback { puts "Redis now connected" }
11
16
 
12
17
  All redis commands are available without any remapping of names
13
18
 
@@ -40,8 +45,8 @@ Pubsub
40
45
 
41
46
  This example should explain things. Once a redis connection is in a pubsub state, you must make sure you only send pubsub commands.
42
47
 
43
- redis = EM::Hiredis::Client.connect
44
- subscriber = EM::Hiredis::Client.connect
48
+ redis = EM::Hiredis.connect
49
+ subscriber = EM::Hiredis.connect
45
50
 
46
51
  subscriber.subscribe('bar.0')
47
52
  subscriber.psubscribe('bar.*')
@@ -59,3 +64,21 @@ This example should explain things. Once a redis connection is in a pubsub state
59
64
  p [:publisherror, e]
60
65
  }
61
66
  }
67
+
68
+ Hacking
69
+ -------
70
+
71
+ Hacking on em-hiredis is pretty simple, make sure you have Bundler installed:
72
+
73
+ gem install bundler
74
+ bundle
75
+
76
+ To run all the tests:
77
+
78
+ rake
79
+
80
+ To run an individual test:
81
+
82
+ bundle exec rspec spec/redis_commands_spec.rb
83
+
84
+ Much thanks to the em-redis gem for getting this gem bootstrapped with some tests.
data/Rakefile CHANGED
@@ -1,2 +1,11 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Default: run specs.'
7
+ task :default => :spec
8
+
9
+ desc "Run specs"
10
+ RSpec::Core::RakeTask.new do |t|
11
+ end
@@ -4,7 +4,7 @@ require "em-hiredis/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "em-hiredis"
7
- s.version = EM::Hiredis::VERSION
7
+ s.version = EventMachine::Hiredis::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Martyn Loughran"]
10
10
  s.email = ["me@mloughran.com"]
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{Eventmachine redis client}
13
13
  s.description = %q{Eventmachine redis client using hiredis native parser}
14
14
 
15
- s.add_dependency 'hiredis', '~> 0.2.0'
15
+ s.add_dependency 'hiredis', '~> 0.3.0'
16
16
 
17
17
  s.rubyforge_project = "em-hiredis"
18
18
 
@@ -1,17 +1,29 @@
1
1
  require 'eventmachine'
2
+ require 'uri'
2
3
 
3
- module EM
4
+ module EventMachine
4
5
  module Hiredis
5
- class << self
6
- attr_writer :logger
6
+ def self.setup(uri = nil)
7
+ url = URI(uri || ENV["REDIS_URL"] || "redis://127.0.0.1:6379/0")
8
+ Client.new(url.host, url.port, url.password, url.path[1..-1])
9
+ end
10
+
11
+ def self.connect(uri = nil)
12
+ client = setup(uri)
13
+ client.connect
14
+ client
15
+ end
16
+
17
+ def self.logger=(logger)
18
+ @@logger = logger
19
+ end
7
20
 
8
- def logger
9
- @logger ||= begin
10
- require 'logger'
11
- log = Logger.new(STDOUT)
12
- log.level = Logger::WARN
13
- log
14
- end
21
+ def self.logger
22
+ @@logger ||= begin
23
+ require 'logger'
24
+ log = Logger.new(STDOUT)
25
+ log.level = Logger::WARN
26
+ log
15
27
  end
16
28
  end
17
29
  end
@@ -1,21 +1,25 @@
1
- module EM::Hiredis
1
+ module EventMachine::Hiredis
2
2
  class Client
3
3
  PUBSUB_MESSAGES = %w{message pmessage}.freeze
4
4
 
5
- include EM::Hiredis::EventEmitter
5
+ include EventMachine::Hiredis::EventEmitter
6
6
  include EM::Deferrable
7
7
 
8
+ attr_reader :host, :port, :password, :db
9
+
8
10
  def self.connect(host = 'localhost', port = 6379)
9
- new(host, port)
11
+ new(host, port).connect
12
+ end
13
+
14
+ def initialize(host, port, password = nil, db = nil)
15
+ @host, @port, @password, @db = host, port, password, db
16
+ @subs, @psubs, @defs = [], [], []
10
17
  end
11
18
 
12
- def initialize(host, port)
13
- @host, @port = host, port
14
- @subs, @psubs = [], []
15
- @defs = []
16
- @connection = EM.connect(host, port, Connection, host, port)
19
+ def connect
20
+ @connection = EM.connect(@host, @port, Connection, @host, @port)
17
21
 
18
- @connection.on(:closed) {
22
+ @connection.on(:closed) do
19
23
  if @connected
20
24
  @defs.each { |d| d.fail("Redis disconnected") }
21
25
  @defs = []
@@ -26,11 +30,14 @@ module EM::Hiredis
26
30
  else
27
31
  EM.add_timer(1) { reconnect }
28
32
  end
29
- }
33
+ end
30
34
 
31
- @connection.on(:connected) {
35
+ @connection.on(:connected) do
32
36
  @connected = true
37
+
33
38
  select(@db) if @db
39
+ auth(@password) if @password
40
+
34
41
  @subs.each { |s| method_missing(:subscribe, s) }
35
42
  @psubs.each { |s| method_missing(:psubscribe, s) }
36
43
  succeed
@@ -39,9 +46,9 @@ module EM::Hiredis
39
46
  @reconnecting = false
40
47
  emit(:reconnected)
41
48
  end
42
- }
49
+ end
43
50
 
44
- @connection.on(:message) { |reply|
51
+ @connection.on(:message) do |reply|
45
52
  if RuntimeError === reply
46
53
  raise "Replies out of sync: #{reply.inspect}" if @defs.empty?
47
54
  deferred = @defs.shift
@@ -57,23 +64,32 @@ module EM::Hiredis
57
64
  emit(:pmessage, subscription, d1, d2)
58
65
  end
59
66
  else
60
- raise "Replies out of sync: #{reply.inspect}" if @defs.empty?
61
- deferred = @defs.shift
62
- deferred.succeed(reply) if deferred
67
+ if @defs.empty?
68
+ if @monitoring
69
+ emit(:monitor, reply)
70
+ else
71
+ raise "Replies out of sync: #{reply.inspect}"
72
+ end
73
+ else
74
+ deferred = @defs.shift
75
+ deferred.succeed(reply) if deferred
76
+ end
63
77
  end
64
78
  end
65
- }
79
+ end
66
80
 
67
81
  @connected = false
68
82
  @reconnecting = false
83
+
84
+ return self
69
85
  end
70
86
 
71
- # Indicates that commands have been sent to redis but a reply has not yet
72
- # been received.
73
- #
74
- # This can be useful for example to avoid stopping the
87
+ # Indicates that commands have been sent to redis but a reply has not yet
88
+ # been received
89
+ #
90
+ # This can be useful for example to avoid stopping the
75
91
  # eventmachine reactor while there are outstanding commands
76
- #
92
+ #
77
93
  def pending_commands?
78
94
  @connected && @defs.size > 0
79
95
  end
@@ -98,11 +114,35 @@ module EM::Hiredis
98
114
  method_missing(:punsubscribe, channel)
99
115
  end
100
116
 
101
- def select(db)
117
+ def select(db, &blk)
102
118
  @db = db
103
- method_missing(:select, db)
119
+ method_missing(:select, db, &blk)
120
+ end
121
+
122
+ def auth(password, &blk)
123
+ @password = password
124
+ method_missing(:auth, password, &blk)
104
125
  end
105
126
 
127
+ def monitor(&blk)
128
+ @monitoring = true
129
+ method_missing(:monitor, &blk)
130
+ end
131
+
132
+ def info(&blk)
133
+ hash_processor = lambda do |response|
134
+ info = {}
135
+ response.each_line do |line|
136
+ key, value = line.split(":", 2)
137
+ info[key.to_sym] = value.chomp
138
+ end
139
+ blk.call(info)
140
+ end
141
+ method_missing(:info, &hash_processor)
142
+ end
143
+
144
+ private
145
+
106
146
  def method_missing(sym, *args)
107
147
  deferred = EM::DefaultDeferrable.new
108
148
  # Shortcut for defining the callback case with just a block
@@ -112,19 +152,17 @@ module EM::Hiredis
112
152
  @connection.send_command(sym, *args)
113
153
  @defs.push(deferred)
114
154
  else
115
- callback {
155
+ callback do
116
156
  @connection.send_command(sym, *args)
117
157
  @defs.push(deferred)
118
- }
158
+ end
119
159
  end
120
160
 
121
- return deferred
161
+ deferred
122
162
  end
123
163
 
124
- private
125
-
126
164
  def reconnect
127
- EM::Hiredis.logger.debug("Trying to reconnect to Redis")
165
+ EventMachine::Hiredis.logger.debug("Trying to reconnect to Redis")
128
166
  @connection.reconnect @host, @port
129
167
  end
130
168
  end
@@ -1,8 +1,8 @@
1
1
  require 'hiredis/reader'
2
2
 
3
- module EM::Hiredis
3
+ module EventMachine::Hiredis
4
4
  class Connection < EM::Connection
5
- include EM::Hiredis::EventEmitter
5
+ include EventMachine::Hiredis::EventEmitter
6
6
 
7
7
  def initialize(host, port)
8
8
  super
@@ -10,7 +10,7 @@ module EM::Hiredis
10
10
  end
11
11
 
12
12
  def connection_completed
13
- EM::Hiredis.logger.info("Connected to Redis")
13
+ EventMachine::Hiredis.logger.info("Connected to Redis")
14
14
  @reader = ::Hiredis::Reader.new
15
15
  emit(:connected)
16
16
  end
@@ -23,7 +23,7 @@ module EM::Hiredis
23
23
  end
24
24
 
25
25
  def unbind
26
- EM::Hiredis.logger.info("Disconnected from Redis")
26
+ EventMachine::Hiredis.logger.info("Disconnected from Redis")
27
27
  emit(:closed)
28
28
  end
29
29
 
@@ -1,4 +1,4 @@
1
- module EM::Hiredis
1
+ module EventMachine::Hiredis
2
2
  module EventEmitter
3
3
  def on(event, &listener)
4
4
  _listeners[event] << listener
@@ -1,5 +1,5 @@
1
- module EM
1
+ module EventMachine
2
2
  module Hiredis
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventMachine::Hiredis, "connecting" do
4
+ let(:replies) do
5
+ # shove db number into PING reply since redis has no way
6
+ # of exposing the currently selected DB
7
+ replies = {
8
+ :select => lambda { |db| $db = db; "+OK" },
9
+ :ping => lambda { "+PONG #{$db}" },
10
+ :auth => lambda { |password| $auth = password; "+OK" },
11
+ :get => lambda { |key| $auth == "secret" ? "$3\r\nbar" : "$-1" },
12
+ }
13
+ end
14
+
15
+ def connect_to_mock(url, &blk)
16
+ redis_mock(replies) do
17
+ connect(url, &blk)
18
+ end
19
+ end
20
+
21
+ it "doesn't call select by default" do
22
+ connect_to_mock("redis://localhost:6380/") do |redis|
23
+ redis.ping do |response|
24
+ response.should == "PONG "
25
+ done
26
+ end
27
+ end
28
+ end
29
+
30
+ it "selects the right db" do
31
+ connect_to_mock("redis://localhost:6380/9") do |redis|
32
+ redis.ping do |response|
33
+ response.should == "PONG 9"
34
+ done
35
+ end
36
+ end
37
+ end
38
+
39
+ it "authenticates with a password" do
40
+ connect_to_mock("redis://:secret@localhost:6380/9") do |redis|
41
+ redis.get("foo") do |response|
42
+ response.should == "bar"
43
+ done
44
+ end
45
+ end
46
+ end
47
+
48
+ it "rejects a bad password" do
49
+ connect_to_mock("redis://:failboat@localhost:6380/9") do |redis|
50
+ redis.get("foo") do |response|
51
+ response.should be_nil
52
+ done
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,512 @@
1
+ require 'spec_helper'
2
+
3
+ describe EventMachine::Hiredis, "connected to an empty db" do
4
+ it "sets a string value" do
5
+ connect do |redis|
6
+ redis.set("foo", "bar") do |r|
7
+ r.should == "OK"
8
+ done
9
+ end
10
+ end
11
+ end
12
+
13
+ it "increments the value of a string" do
14
+ connect do |redis|
15
+ redis.incr "foo" do |r|
16
+ r.should == 1
17
+ redis.incr "foo" do |r|
18
+ r.should == 2
19
+ done
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ it "increments the value of a string by an amount" do
26
+ connect do |redis|
27
+ redis.incrby "foo", 10 do |r|
28
+ r.should == 10
29
+ done
30
+ end
31
+ end
32
+ end
33
+
34
+ it "decrements the value of a string" do
35
+ connect do |redis|
36
+ redis.incr "foo" do |r|
37
+ r.should == 1
38
+ redis.decr "foo" do |r|
39
+ r.should == 0
40
+ done
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ it "decrement the value of a string by an amount" do
47
+ connect do |redis|
48
+ redis.incrby "foo", 20 do |r|
49
+ r.should == 20
50
+ redis.decrby "foo", 10 do |r|
51
+ r.should == 10
52
+ done
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ it "can 'lpush' to a nonexistent list" do
59
+ connect do |redis|
60
+ redis.lpush("foo", "bar") do |r|
61
+ r.should == 1
62
+ done
63
+ end
64
+ end
65
+ end
66
+
67
+ it "can 'rpush' to a nonexistent list" do
68
+ connect do |redis|
69
+ redis.rpush("foo", "bar") do |r|
70
+ r.should == 1
71
+ done
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+ it "gets the size of the database" do
78
+ connect do |redis|
79
+ redis.dbsize do |r|
80
+ r.should == 0
81
+ done
82
+ end
83
+ end
84
+ end
85
+
86
+ it "adds a member to a nonexistent set" do
87
+ connect do |redis|
88
+ redis.sadd("set_foo", "bar") do |r|
89
+ r.should == 1
90
+ done
91
+ end
92
+ end
93
+ end
94
+
95
+ it "reads info about the db" do
96
+ connect do |redis|
97
+ redis.info do |info|
98
+ info[:redis_version].should_not be_nil
99
+ done
100
+ end
101
+ end
102
+ end
103
+
104
+ it "can save the db" do
105
+ connect do |redis|
106
+ redis.save do |r|
107
+ r.should == "OK"
108
+ done
109
+ end
110
+ end
111
+ end
112
+
113
+ it "can save the db in the background" do
114
+ connect do |redis|
115
+ redis.bgsave do |r|
116
+ r.should == "Background saving started"
117
+ done
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ describe EventMachine::Hiredis, "connected to a db containing some simple string-valued keys" do
124
+ def set(&blk)
125
+ connect do |redis|
126
+ redis.flushdb
127
+ redis.set "a", "b"
128
+ redis.set "x", "y"
129
+ blk.call(redis)
130
+ end
131
+ end
132
+
133
+ it "fetches the values of multiple keys" do
134
+ set do |redis|
135
+ redis.mget "a", "x" do |r|
136
+ r.should == ["b", "y"]
137
+ done
138
+ end
139
+ end
140
+ end
141
+
142
+ it "fetches all the keys" do
143
+ set do |redis|
144
+ redis.keys "*" do |r|
145
+ r.sort.should == ["a", "x"]
146
+ done
147
+ end
148
+ end
149
+ end
150
+
151
+ it "sets a value if a key doesn't exist" do
152
+ set do |redis|
153
+ redis.setnx "a", "foo" do |r|
154
+ r.should == 0
155
+ redis.setnx "zzz", "foo" do |r|
156
+ r.should == 1
157
+ done
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ it "tests for the existence of a key" do
164
+ set do |redis|
165
+ redis.exists "a" do |r|
166
+ r.should == 1
167
+ redis.exists "zzz" do |r|
168
+ r.should == 0
169
+ done
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ it "deletes a key" do
176
+ set do |redis|
177
+ redis.del "a" do |r|
178
+ r.should == 1
179
+ redis.exists "a" do |r|
180
+ r.should == 0
181
+ redis.del "a" do |r|
182
+ r.should == 0
183
+ done
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ it "detects the type of a key, existing or not" do
191
+ set do |redis|
192
+ redis.type "a" do |r|
193
+ r.should == "string"
194
+ redis.type "zzz" do |r|
195
+ r.should == "none"
196
+ done
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ it "renames a key" do
203
+ set do |redis|
204
+ redis.rename "a", "x" do |r|
205
+ redis.get "x" do |r|
206
+ r.should == "b"
207
+ done
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ it "renames a key unless it exists" do
214
+ set do |redis|
215
+ redis.renamenx "a", "x" do |r|
216
+ r.should == 0
217
+ redis.renamenx "a", "zzz" do |r|
218
+ r.should == 1
219
+ redis.get "zzz" do |r|
220
+ r.should == "b"
221
+ done
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ describe EventMachine::Hiredis, "connected to a db containing a list" do
230
+ def set(&blk)
231
+ connect do |redis|
232
+ redis.flushdb
233
+ redis.lpush "foo", "c"
234
+ redis.lpush "foo", "b"
235
+ redis.lpush "foo", "a"
236
+ blk.call(redis)
237
+ end
238
+ end
239
+
240
+ it "sets a list member and 'lindex' to retrieve it" do
241
+ set do |redis|
242
+ redis.lset("foo", 1, "bar") do |r|
243
+ redis.lindex("foo", 1) do |r|
244
+ r.should == "bar"
245
+ done
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ it "pushes onto tail of the list" do
252
+ set do |redis|
253
+ redis.rpush "foo", "d" do |r|
254
+ r.should == 4
255
+ redis.rpop "foo" do |r|
256
+ r.should == "d"
257
+ done
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ it "pushes onto the head of the list" do
264
+ set do |redis|
265
+ redis.lpush "foo", "d" do |r|
266
+ r.should == 4
267
+ redis.lpop "foo" do |r|
268
+ r.should == "d"
269
+ done
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ it "pops off the tail of the list" do
276
+ set do |redis|
277
+ redis.rpop("foo") do |r|
278
+ r.should == "c"
279
+ done
280
+ end
281
+ end
282
+ end
283
+
284
+ it "pops off the tail of the list" do
285
+ set do |redis|
286
+ redis.lpop("foo") do |r|
287
+ r.should == "a"
288
+ done
289
+ end
290
+ end
291
+ end
292
+
293
+ it "gets a range of values from a list" do
294
+ set do |redis|
295
+ redis.lrange("foo", 0, 1) do |r|
296
+ r.should == ["a", "b"]
297
+ done
298
+ end
299
+ end
300
+ end
301
+
302
+ it "trims a list" do
303
+ set do |redis|
304
+ redis.ltrim("foo", 0, 1) do |r|
305
+ r.should == "OK"
306
+ redis.llen("foo") do |r|
307
+ r.should == 2
308
+ done
309
+ end
310
+ end
311
+ end
312
+ end
313
+
314
+ it "removes a list element" do
315
+ set do |redis|
316
+ redis.lrem("foo", 0, "a") do |r|
317
+ r.should == 1
318
+ redis.llen("foo") do |r|
319
+ r.should == 2
320
+ done
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ it "detects the type of a list" do
327
+ set do |redis|
328
+ redis.type "foo" do |r|
329
+ r.should == "list"
330
+ done
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ describe EventMachine::Hiredis, "connected to a db containing two sets" do
337
+ def set(&blk)
338
+ connect do |redis|
339
+ redis.flushdb
340
+ redis.sadd "foo", "a"
341
+ redis.sadd "foo", "b"
342
+ redis.sadd "foo", "c"
343
+ redis.sadd "bar", "c"
344
+ redis.sadd "bar", "d"
345
+ redis.sadd "bar", "e"
346
+ blk.call(redis)
347
+ end
348
+ end
349
+
350
+ it "finds a set's cardinality" do
351
+ set do |redis|
352
+ redis.scard("foo") do |r|
353
+ r.should == 3
354
+ done
355
+ end
356
+ end
357
+ end
358
+
359
+ it "adds a new member to a set unless it is a duplicate" do
360
+ set do |redis|
361
+ redis.sadd("foo", "d") do |r|
362
+ r.should == 1 # success
363
+ redis.sadd("foo", "a") do |r|
364
+ r.should == 0 # failure
365
+ redis.scard("foo") do |r|
366
+ r.should == 4
367
+ done
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ it "removes a set member if it exists" do
375
+ set do |redis|
376
+ redis.srem("foo", "a") do |r|
377
+ r.should == 1
378
+ redis.srem("foo", "z") do |r|
379
+ r.should == 0
380
+ redis.scard("foo") do |r|
381
+ r.should == 2
382
+ done
383
+ end
384
+ end
385
+ end
386
+ end
387
+ end
388
+
389
+ it "retrieves a set's members" do
390
+ set do |redis|
391
+ redis.smembers("foo") do |r|
392
+ r.sort.should == ["a", "b", "c"]
393
+ done
394
+ end
395
+ end
396
+ end
397
+
398
+ it "detects set membership" do
399
+ set do |redis|
400
+ redis.sismember("foo", "a") do |r|
401
+ r.should == 1
402
+ redis.sismember("foo", "z") do |r|
403
+ r.should == 0
404
+ done
405
+ end
406
+ end
407
+ end
408
+ end
409
+
410
+ it "finds the sets' intersection" do
411
+ set do |redis|
412
+ redis.sinter("foo", "bar") do |r|
413
+ r.should == ["c"]
414
+ done
415
+ end
416
+ end
417
+ end
418
+
419
+ it "finds and stores the sets' intersection" do
420
+ set do |redis|
421
+ redis.sinterstore("baz", "foo", "bar") do |r|
422
+ r.should == 1
423
+ redis.smembers("baz") do |r|
424
+ r.should == ["c"]
425
+ done
426
+ end
427
+ end
428
+ end
429
+ end
430
+
431
+ it "finds the sets' union" do
432
+ set do |redis|
433
+ redis.sunion("foo", "bar") do |r|
434
+ r.sort.should == ["a","b","c","d","e"]
435
+ done
436
+ end
437
+ end
438
+ end
439
+
440
+ it "finds and stores the sets' union" do
441
+ set do |redis|
442
+ redis.sunionstore("baz", "foo", "bar") do |r|
443
+ r.should == 5
444
+ redis.smembers("baz") do |r|
445
+ r.sort.should == ["a","b","c","d","e"]
446
+ done
447
+ end
448
+ end
449
+ end
450
+ end
451
+
452
+ it "detects the type of a set" do
453
+ set do |redis|
454
+ redis.type "foo" do |r|
455
+ r.should == "set"
456
+ done
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ describe EventMachine::Hiredis, "connected to a db containing three linked lists" do
463
+ def set(&blk)
464
+ connect do |redis|
465
+ redis.flushdb
466
+ redis.rpush "foo", "a"
467
+ redis.rpush "foo", "b"
468
+ redis.set "a_sort", "2"
469
+ redis.set "b_sort", "1"
470
+ redis.set "a_data", "foo"
471
+ redis.set "b_data", "bar"
472
+ blk.call(redis)
473
+ end
474
+ end
475
+
476
+ it "collates a sorted set of data" do
477
+ set do |redis|
478
+ redis.sort("foo", "BY", "*_sort", "GET", "*_data") do |r|
479
+ r.should == ["bar", "foo"]
480
+ done
481
+ end
482
+ end
483
+ end
484
+
485
+ it "gets keys selectively" do
486
+ set do |redis|
487
+ redis.keys "a_*" do |r|
488
+ r.sort.should == ["a_sort", "a_data"].sort
489
+ done
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ describe EventMachine::Hiredis, "when reconnecting" do
496
+ it "select previously selected dataset" do
497
+ connect do |redis|
498
+ #simulate disconnect
499
+ redis.set('foo', 'a') { redis.close_connection_after_writing }
500
+
501
+ EventMachine.add_timer(2) do
502
+ redis.get('foo') do |r|
503
+ r.should == 'a'
504
+ redis.get('non_existing') do |r|
505
+ r.should == nil
506
+ done
507
+ end
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end