em-hiredis 0.0.1 → 0.1.0

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/.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