redis-objects 0.2.2 → 0.2.4

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/lib/redis/set.rb CHANGED
@@ -13,10 +13,10 @@ class Redis
13
13
  attr_reader :key, :options, :redis
14
14
 
15
15
  # Create a new Set.
16
- def initialize(key, redis=$redis, options={})
16
+ def initialize(key, *args)
17
17
  @key = key
18
- @redis = redis
19
- @options = options
18
+ @options = args.last.is_a?(Hash) ? args.pop : {}
19
+ @redis = args.first || $redis
20
20
  end
21
21
 
22
22
  # Works like add. Can chain together: list << 'a' << 'b'
@@ -0,0 +1,275 @@
1
+ class Redis
2
+ #
3
+ # Class representing a sorted set.
4
+ #
5
+ class SortedSet
6
+ # require 'enumerator'
7
+ # include Enumerable
8
+ require 'redis/helpers/core_commands'
9
+ include Redis::Helpers::CoreCommands
10
+ require 'redis/helpers/serialize'
11
+ include Redis::Helpers::Serialize
12
+
13
+ attr_reader :key, :options, :redis
14
+
15
+ # Create a new SortedSet.
16
+ def initialize(key, *args)
17
+ @key = key
18
+ @options = args.last.is_a?(Hash) ? args.pop : {}
19
+ @redis = args.first || $redis
20
+ end
21
+
22
+ # How to add values using a sorted set. The key is the member, eg,
23
+ # "Peter", and the value is the score, eg, 163. So:
24
+ # num_posts['Peter'] = 163
25
+ def []=(member, score)
26
+ add(member, score)
27
+ end
28
+
29
+ # Add a member and its corresponding value to Redis. Note that the
30
+ # arguments to this are flipped; the member comes first rather than
31
+ # the score, since the member is the unique item (not the score).
32
+ def add(member, score)
33
+ redis.zadd(key, score, to_redis(member))
34
+ end
35
+
36
+ # Same functionality as Ruby arrays. If a single number is given, return
37
+ # just the element at that index using Redis: ZRANGE. Otherwise, return
38
+ # a range of values using Redis: ZRANGE.
39
+ def [](index, length=nil)
40
+ if index.is_a? Range
41
+ range(index.first, index.last)
42
+ elsif length
43
+ range(index, length)
44
+ else
45
+ at(index)
46
+ end
47
+ end
48
+
49
+ # Return the score of the specified element of the sorted set at key. If the
50
+ # specified element does not exist in the sorted set, or the key does not exist
51
+ # at all, nil is returned. Redis: ZSCORE.
52
+ def score(member)
53
+ redis.zscore(key, to_redis(member)).to_i
54
+ end
55
+
56
+ # Return the rank of the member in the sorted set, with scores ordered from
57
+ # low to high. +revrank+ returns the rank with scores ordered from high to low.
58
+ # When the given member does not exist in the sorted set, nil is returned.
59
+ # The returned rank (or index) of the member is 0-based for both commands
60
+ def rank(member)
61
+ redis.zrank(key, to_redis(member)).to_i
62
+ end
63
+
64
+ def revrank(member)
65
+ redis.zrevrank(key, to_redis(member)).to_i
66
+ end
67
+
68
+ # Return all members of the sorted set with their scores. Extremely CPU-intensive.
69
+ # Better to use a range instead.
70
+ def members(options={})
71
+ range(0, -1, options)
72
+ end
73
+
74
+ # Return a range of values from +start_index+ to +end_index+. Can also use
75
+ # the familiar list[start,end] Ruby syntax. Redis: ZRANGE
76
+ def range(start_index, end_index, options={})
77
+ if options[:withscores]
78
+ val = from_redis redis.zrange(key, start_index, end_index, 'withscores')
79
+ ret = []
80
+ while k = val.shift and v = val.shift
81
+ ret << [k, v.to_i]
82
+ end
83
+ ret
84
+ else
85
+ from_redis redis.zrange(key, start_index, end_index)
86
+ end
87
+ end
88
+
89
+ # Return a range of values from +start_index+ to +end_index+ in reverse order. Redis: ZREVRANGE
90
+ def revrange(start_index, end_index, options={})
91
+ if options[:withscores]
92
+ val = from_redis redis.zrevrange(key, start_index, end_index, 'withscores')
93
+ ret = []
94
+ while k = val.shift and v = val.shift
95
+ ret << [k, v.to_i]
96
+ end
97
+ ret
98
+ else
99
+ from_redis redis.zrevrange(key, start_index, end_index)
100
+ end
101
+ end
102
+
103
+ # Return the all the elements in the sorted set at key with a score between min and max
104
+ # (including elements with score equal to min or max). Options:
105
+ # :count, :offset - passed to LIMIT
106
+ # :withscores - if true, scores are returned as well
107
+ # Redis: ZRANGEBYSCORE
108
+ def rangebyscore(min, max, options={})
109
+ args = []
110
+ args += ['limit', options[:offset] || 0, options[:limit] || options[:count]] if
111
+ options[:offset] || options[:limit] || options[:count]
112
+ args += ['withscores'] if options[:withscores]
113
+ from_redis redis.zrangebyscore(key, min, max, *args)
114
+ end
115
+
116
+ # Forwards compat (not yet implemented in Redis)
117
+ def revrangebyscore(min, max, options={})
118
+ args = []
119
+ args += ['limit', options[:offset] || 0, options[:limit] || options[:count]] if
120
+ options[:offset] || options[:limit] || options[:count]
121
+ args += ['withscores'] if options[:withscores]
122
+ from_redis redis.zrevrangebyscore(key, min, max, *args)
123
+ end
124
+
125
+ # Remove all elements in the sorted set at key with rank between start and end. Start and end are
126
+ # 0-based with rank 0 being the element with the lowest score. Both start and end can be negative
127
+ # numbers, where they indicate offsets starting at the element with the highest rank. For example:
128
+ # -1 is the element with the highest score, -2 the element with the second highest score and so forth.
129
+ # Redis: ZREMRANGEBYRANK
130
+ def remrangebyrank(min, max)
131
+ redis.zremrangebyrank(key, min, max)
132
+ end
133
+
134
+ # Remove all the elements in the sorted set at key with a score between min and max (including
135
+ # elements with score equal to min or max). Redis: ZREMRANGEBYSCORE
136
+ def remrangebyscore(min, max)
137
+ redis.zremrangebyscore(key, min, max)
138
+ end
139
+
140
+ # Delete the value from the set. Redis: ZREM
141
+ def delete(value)
142
+ redis.zrem(key, value)
143
+ end
144
+
145
+ # Increment the rank of that member atomically and return the new value. This
146
+ # method is aliased as incr() for brevity. Redis: ZINCRBY
147
+ def increment(member, by=1)
148
+ redis.zincrby(key, by, member).to_i
149
+ end
150
+ alias_method :incr, :increment
151
+ alias_method :incrby, :increment
152
+
153
+ # Convenience to calling increment() with a negative number.
154
+ def decrement(by=1)
155
+ redis.zincrby(key, -by).to_i
156
+ end
157
+ alias_method :decr, :decrement
158
+ alias_method :decrby, :decrement
159
+
160
+ # Return the intersection with another set. Can pass it either another set
161
+ # object or set name. Also available as & which is a bit cleaner:
162
+ #
163
+ # members_in_both = set1 & set2
164
+ #
165
+ # If you want to specify multiple sets, you must use +intersection+:
166
+ #
167
+ # members_in_all = set1.intersection(set2, set3, set4)
168
+ # members_in_all = set1.inter(set2, set3, set4) # alias
169
+ #
170
+ # Redis: SINTER
171
+ def intersection(*sets)
172
+ from_redis redis.zinter(key, *keys_from_objects(sets))
173
+ end
174
+ alias_method :intersect, :intersection
175
+ alias_method :inter, :intersection
176
+ alias_method :&, :intersection
177
+
178
+ # Calculate the intersection and store it in Redis as +name+. Returns the number
179
+ # of elements in the stored intersection. Redis: SUNIONSTORE
180
+ def interstore(name, *sets)
181
+ redis.zinterstore(name, key, *keys_from_objects(sets))
182
+ end
183
+
184
+ # Return the union with another set. Can pass it either another set
185
+ # object or set name. Also available as | and + which are a bit cleaner:
186
+ #
187
+ # members_in_either = set1 | set2
188
+ # members_in_either = set1 + set2
189
+ #
190
+ # If you want to specify multiple sets, you must use +union+:
191
+ #
192
+ # members_in_all = set1.union(set2, set3, set4)
193
+ #
194
+ # Redis: SUNION
195
+ def union(*sets)
196
+ from_redis redis.zunion(key, *keys_from_objects(sets))
197
+ end
198
+ alias_method :|, :union
199
+ alias_method :+, :union
200
+
201
+ # Calculate the union and store it in Redis as +name+. Returns the number
202
+ # of elements in the stored union. Redis: SUNIONSTORE
203
+ def unionstore(name, *sets)
204
+ redis.zunionstore(name, key, *keys_from_objects(sets))
205
+ end
206
+
207
+ # Return the difference vs another set. Can pass it either another set
208
+ # object or set name. Also available as ^ or - which is a bit cleaner:
209
+ #
210
+ # members_difference = set1 ^ set2
211
+ # members_difference = set1 - set2
212
+ #
213
+ # If you want to specify multiple sets, you must use +difference+:
214
+ #
215
+ # members_difference = set1.difference(set2, set3, set4)
216
+ # members_difference = set1.diff(set2, set3, set4)
217
+ #
218
+ # Redis: SDIFF
219
+ def difference(*sets)
220
+ from_redis redis.zdiff(key, *keys_from_objects(sets))
221
+ end
222
+ alias_method :diff, :difference
223
+ alias_method :^, :difference
224
+ alias_method :-, :difference
225
+
226
+ # Calculate the diff and store it in Redis as +name+. Returns the number
227
+ # of elements in the stored union. Redis: SDIFFSTORE
228
+ def diffstore(name, *sets)
229
+ redis.zdiffstore(name, key, *keys_from_objects(sets))
230
+ end
231
+
232
+ # Returns true if the set has no members. Redis: SCARD == 0
233
+ def empty?
234
+ length == 0
235
+ end
236
+
237
+ def ==(x)
238
+ members == x
239
+ end
240
+
241
+ def to_s
242
+ members.join(', ')
243
+ end
244
+
245
+ # Return the value at the given index. Can also use familiar list[index] syntax.
246
+ # Redis: ZRANGE
247
+ def at(index)
248
+ range(index, index).first
249
+ end
250
+
251
+ # Return the first element in the list. Redis: ZRANGE(0)
252
+ def first
253
+ at(0)
254
+ end
255
+
256
+ # Return the last element in the list. Redis: ZRANGE(-1)
257
+ def last
258
+ at(-1)
259
+ end
260
+
261
+ # The number of members in the set. Aliased as size. Redis: ZCARD
262
+ def length
263
+ redis.zcard(key)
264
+ end
265
+ alias_method :size, :length
266
+
267
+ private
268
+
269
+ def keys_from_objects(sets)
270
+ raise ArgumentError, "Must pass in one or more set names" if sets.empty?
271
+ sets.collect{|set| set.is_a?(Redis::SortedSet) ? set.key : set}
272
+ end
273
+
274
+ end
275
+ end
data/lib/redis/value.rb CHANGED
@@ -9,10 +9,10 @@ class Redis
9
9
  include Redis::Helpers::Serialize
10
10
 
11
11
  attr_reader :key, :options, :redis
12
- def initialize(key, redis=$redis, options={})
12
+ def initialize(key, *args)
13
13
  @key = key
14
- @redis = redis
15
- @options = options
14
+ @options = args.last.is_a?(Hash) ? args.pop : {}
15
+ @redis = args.first || $redis
16
16
  @redis.setnx(key, @options[:default]) if @options[:default]
17
17
  end
18
18
 
@@ -3,8 +3,10 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
4
  require 'redis/counter'
5
5
  require 'redis/list'
6
- require 'redis/set'
7
6
  require 'redis/value'
7
+ require 'redis/lock'
8
+ require 'redis/set'
9
+ require 'redis/sorted_set'
8
10
 
9
11
  describe Redis::Value do
10
12
  before :all do
@@ -46,6 +48,7 @@ describe Redis::Value do
46
48
  old.should be_nil
47
49
  old.value = 'Tuff'
48
50
  @value.renamenx('spec/value').should be_false
51
+ @value.value.should == 'Peter Pan'
49
52
  end
50
53
 
51
54
  after :all do
@@ -159,9 +162,11 @@ describe Redis::List do
159
162
  old = Redis::List.new('spec/list')
160
163
  old.should be_empty
161
164
  old << 'Tuff'
165
+ old.values.should == ['Tuff']
162
166
  @list.renamenx('spec/list').should be_false
163
167
  @list.renamenx(old).should be_false
164
168
  @list.renamenx('spec/foo').should be_true
169
+ old.values.should == ['Tuff']
165
170
  @list.clear
166
171
  @list.redis.del('spec/list2')
167
172
  end
@@ -171,6 +176,134 @@ describe Redis::List do
171
176
  end
172
177
  end
173
178
 
179
+ describe Redis::Counter do
180
+ before :all do
181
+ @counter = Redis::Counter.new('spec/counter')
182
+ @counter2 = Redis::Counter.new('spec/counter')
183
+ end
184
+
185
+ before :each do
186
+ @counter.reset
187
+ end
188
+
189
+ it "should support increment/decrement of counters" do
190
+ @counter.key.should == 'spec/counter'
191
+ @counter.incr(10)
192
+ @counter.should == 10
193
+
194
+ # math proxy ops
195
+ (@counter == 10).should be_true
196
+ (@counter <= 10).should be_true
197
+ (@counter < 11).should be_true
198
+ (@counter > 9).should be_true
199
+ (@counter >= 10).should be_true
200
+ "#{@counter}".should == "10"
201
+
202
+ @counter.increment.should == 11
203
+ @counter.increment.should == 12
204
+ @counter2.increment.should == 13
205
+ @counter2.increment(2).should == 15
206
+ @counter.decrement.should == 14
207
+ @counter2.decrement.should == 13
208
+ @counter.decrement.should == 12
209
+ @counter2.decrement(4).should == 8
210
+ @counter.should == 8
211
+ @counter.reset.should be_true
212
+ @counter.should == 0
213
+ @counter.reset(15).should be_true
214
+ @counter.should == 15
215
+ end
216
+
217
+ after :all do
218
+ @counter.delete
219
+ end
220
+ end
221
+
222
+ describe Redis::Lock do
223
+ before :each do
224
+ $redis.flushall
225
+ end
226
+
227
+ it "should set the value to the expiration" do
228
+ start = Time.now
229
+ expiry = 15
230
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry)
231
+ lock.lock do
232
+ expiration = $redis.get("test_lock").to_f
233
+
234
+ # The expiration stored in redis should be 15 seconds from when we started
235
+ # or a little more
236
+ expiration.should be_close((start + expiry).to_f, 2.0)
237
+ end
238
+
239
+ # key should have been cleaned up
240
+ $redis.get("test_lock").should be_nil
241
+ end
242
+
243
+ it "should set value to 1 when no expiration is set" do
244
+ lock = Redis::Lock.new(:test_lock)
245
+ lock.lock do
246
+ $redis.get('test_lock').should == '1'
247
+ end
248
+
249
+ # key should have been cleaned up
250
+ $redis.get("test_lock").should be_nil
251
+ end
252
+
253
+ it "should let lock be gettable when lock is expired" do
254
+ expiry = 15
255
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
256
+
257
+ # create a fake lock in the past
258
+ $redis.set("test_lock", Time.now-(expiry + 60))
259
+
260
+ gotit = false
261
+ lock.lock do
262
+ gotit = true
263
+ end
264
+
265
+ # should get the lock because it has expired
266
+ gotit.should be_true
267
+ $redis.get("test_lock").should be_nil
268
+ end
269
+
270
+ it "should not let non-expired locks be gettable" do
271
+ expiry = 15
272
+ lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
273
+
274
+ # create a fake lock
275
+ $redis.set("test_lock", (Time.now + expiry).to_f)
276
+
277
+ gotit = false
278
+ error = nil
279
+ begin
280
+ lock.lock do
281
+ gotit = true
282
+ end
283
+ rescue => error
284
+ end
285
+
286
+ error.should be_kind_of(Redis::Lock::LockTimeout)
287
+
288
+ # should not have the lock
289
+ gotit.should_not be_true
290
+
291
+ # lock value should still be set
292
+ $redis.get("test_lock").should_not be_nil
293
+ end
294
+
295
+ it "should not remove the key if lock is held past expiration" do
296
+ lock = Redis::Lock.new(:test_lock, :expiration => 0.0)
297
+
298
+ lock.lock do
299
+ sleep 1.1
300
+ end
301
+
302
+ # lock value should still be set since the lock was held for more than the expiry
303
+ $redis.get("test_lock").should_not be_nil
304
+ end
305
+ end
306
+
174
307
  describe Redis::Set do
175
308
  before :all do
176
309
  @set = Redis::Set.new('spec/set')
@@ -288,45 +421,157 @@ describe Redis::Set do
288
421
  end
289
422
  end
290
423
 
291
- describe Redis::Counter do
424
+ describe Redis::SortedSet do
292
425
  before :all do
293
- @counter = Redis::Counter.new('spec/counter')
294
- @counter2 = Redis::Counter.new('spec/counter')
426
+ @set = Redis::SortedSet.new('spec/zset')
427
+ @set_1 = Redis::SortedSet.new('spec/zset_1')
428
+ @set_2 = Redis::SortedSet.new('spec/zset_2')
429
+ @set_3 = Redis::SortedSet.new('spec/zset_3')
295
430
  end
296
431
 
297
432
  before :each do
298
- @counter.reset
433
+ @set.clear
434
+ @set_1.clear
435
+ @set_2.clear
436
+ @set_3.clear
299
437
  end
300
438
 
301
- it "should support increment/decrement of counters" do
302
- @counter.key.should == 'spec/counter'
303
- @counter.incr(10)
304
- @counter.should == 10
439
+ it "should handle sets of simple values" do
440
+ @set.should be_empty
441
+ @set['a'] = 11
442
+ @set['a'] = 21
443
+ @set.add('a', 5)
444
+ @set.score('a').should == 5
445
+ @set['a'] = 3
446
+ @set['b'] = 5
447
+ @set['c'] = 4
448
+
449
+ @set[0,-1].should == ['a','c','b']
450
+ @set.range(0,-1).should == ['a','c','b']
451
+ @set.revrange(0,-1).should == ['b','c','a']
452
+ @set[0..1].should == ['a','c']
453
+ @set[1].should == 'c'
454
+ @set.at(1).should == 'c'
455
+ @set.first.should == 'a'
456
+ @set.last.should == 'b'
457
+
458
+ @set.members.should == ['a','c','b']
459
+ @set.members(:withscores => true).should == [['a',3],['c',4],['b',5]]
460
+
461
+ @set['b'] = 5
462
+ @set['b'] = 6
463
+ @set.score('b').should == 6
464
+ @set.delete('c')
465
+ @set.to_s.should == 'a, b'
466
+ @set.should == ['a','b']
467
+ @set.members.should == ['a','b']
468
+ @set['d'] = 0
305
469
 
306
- # math proxy ops
307
- (@counter == 10).should be_true
308
- (@counter <= 10).should be_true
309
- (@counter < 11).should be_true
310
- (@counter > 9).should be_true
311
- (@counter >= 10).should be_true
312
- "#{@counter}".should == "10"
470
+ @set.rangebyscore(0, 4).should == ['d','a']
471
+ @set.rangebyscore(0, 4, :count => 1).should == ['d']
472
+ @set.rangebyscore(0, 4, :count => 2).should == ['d','a']
473
+ @set.rangebyscore(0, 4, :limit => 2).should == ['d','a']
474
+
475
+ # Redis 1.3.5
476
+ # @set.rangebyscore(0,4, :withscores => true).should == [['d',4],['a',3]]
477
+ # @set.revrangebyscore(0,4).should == ['d','a']
478
+ # @set.revrangebyscore(0,4, :count => 2).should == ['a','d']
479
+ # @set.rank('b').should == 2
480
+ # @set.revrank('b').should == 3
481
+
482
+ @set['f'] = 100
483
+ @set['g'] = 110
484
+ @set['h'] = 120
485
+ @set['j'] = 130
486
+ @set.incr('h', 20)
487
+ @set.remrangebyscore(100, 120)
488
+ @set.members.should == ['d','a','b','j','h']
489
+
490
+ # Redis 1.3.5
491
+ # @set['h'] = 12
492
+ # @set['j'] = 13
493
+ # @set.remrangebyrank(4,-1)
494
+ # @set.members.should == ['d','a','b']
495
+
496
+ @set.delete('d')
497
+ @set['c'] = 200
498
+ @set.members.should == ['a','b','j','h','c']
499
+ @set.delete('c')
500
+ @set.length.should == 4
501
+ @set.size.should == 4
502
+ end
313
503
 
314
- @counter.increment.should == 11
315
- @counter.increment.should == 12
316
- @counter2.increment.should == 13
317
- @counter2.increment(2).should == 15
318
- @counter.decrement.should == 14
319
- @counter2.decrement.should == 13
320
- @counter.decrement.should == 12
321
- @counter2.decrement(4).should == 8
322
- @counter.should == 8
323
- @counter.reset.should be_true
324
- @counter.should == 0
325
- @counter.reset(15).should be_true
326
- @counter.should == 15
504
+ # Not until Redis 1.3.5 with hashes
505
+ xit "Redis 1.3.5: should handle set intersections, unions, and diffs" do
506
+ @set_1['a'] = 5
507
+ @set_2['b'] = 18
508
+ @set_2['c'] = 12
509
+
510
+ @set_2['a'] = 10
511
+ @set_2['b'] = 15
512
+ @set_2['c'] = 15
513
+
514
+ (@set_1 & @set_2).sort.should == ['c','d','e']
515
+
516
+ @set_1 << 'a' << 'b' << 'c' << 'd' << 'e'
517
+ @set_2 << 'c' << 'd' << 'e' << 'f' << 'g'
518
+ @set_3 << 'a' << 'd' << 'g' << 'l' << 'm'
519
+ @set_1.sort.should == %w(a b c d e)
520
+ @set_2.sort.should == %w(c d e f g)
521
+ @set_3.sort.should == %w(a d g l m)
522
+ (@set_1 & @set_2).sort.should == ['c','d','e']
523
+ @set_1.intersection(@set_2).sort.should == ['c','d','e']
524
+ @set_1.intersection(@set_2, @set_3).sort.should == ['d']
525
+ @set_1.intersect(@set_2).sort.should == ['c','d','e']
526
+ @set_1.inter(@set_2, @set_3).sort.should == ['d']
527
+ @set_1.interstore(INTERSTORE_KEY, @set_2).should == 3
528
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['c','d','e']
529
+ @set_1.interstore(INTERSTORE_KEY, @set_2, @set_3).should == 1
530
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['d']
531
+
532
+ (@set_1 | @set_2).sort.should == ['a','b','c','d','e','f','g']
533
+ (@set_1 + @set_2).sort.should == ['a','b','c','d','e','f','g']
534
+ @set_1.union(@set_2).sort.should == ['a','b','c','d','e','f','g']
535
+ @set_1.union(@set_2, @set_3).sort.should == ['a','b','c','d','e','f','g','l','m']
536
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2).should == 7
537
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g']
538
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2, @set_3).should == 9
539
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g','l','m']
540
+
541
+ (@set_1 ^ @set_2).sort.should == ["a", "b"]
542
+ (@set_1 - @set_2).sort.should == ["a", "b"]
543
+ (@set_2 - @set_1).sort.should == ["f", "g"]
544
+ @set_1.difference(@set_2).sort.should == ["a", "b"]
545
+ @set_1.diff(@set_2).sort.should == ["a", "b"]
546
+ @set_1.difference(@set_2, @set_3).sort.should == ['b']
547
+ @set_1.diffstore(DIFFSTORE_KEY, @set_2).should == 2
548
+ @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['a','b']
549
+ @set_1.diffstore(DIFFSTORE_KEY, @set_2, @set_3).should == 1
550
+ @set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['b']
551
+ end
552
+
553
+ it "should support renaming sets" do
554
+ @set.should be_empty
555
+ @set['zynga'] = 151
556
+ @set['playfish'] = 202
557
+ @set.members.should == ['zynga','playfish']
558
+ @set.key.should == 'spec/zset'
559
+ @set.rename('spec/zset2').should be_true
560
+ @set.key.should == 'spec/zset2'
561
+ old = Redis::SortedSet.new('spec/zset')
562
+ old.should be_empty
563
+ old['tuff'] = 54
564
+ @set.renamenx('spec/zset').should be_false
565
+ @set.renamenx(old).should be_false
566
+ @set.renamenx('spec/zfoo').should be_true
567
+ @set.clear
568
+ @set.redis.del('spec/zset2')
327
569
  end
328
570
 
329
571
  after :all do
330
- @counter.delete
572
+ @set.clear
573
+ @set_1.clear
574
+ @set_2.clear
575
+ @set_3.clear
331
576
  end
332
- end
577
+ end
@@ -58,7 +58,7 @@ describe Redis::Objects do
58
58
 
59
59
  it "should provide a connection method" do
60
60
  Roster.redis.should == Redis::Objects.redis
61
- Roster.redis.should be_kind_of(Redis)
61
+ # Roster.redis.should be_kind_of(Redis)
62
62
  end
63
63
 
64
64
  it "should create counter accessors" do
@@ -282,6 +282,19 @@ describe Redis::Objects do
282
282
  end
283
283
  error.should be_kind_of(NoMethodError)
284
284
  end
285
+
286
+ it "should support obtain_lock as a class method" do
287
+ error = nil
288
+ begin
289
+ Roster.obtain_lock(:resort, 2) do
290
+ Roster.redis.get("roster:2:resort_lock").should_not be_nil
291
+ end
292
+ rescue => error
293
+ end
294
+
295
+ error.should be_nil
296
+ Roster.redis.get("roster:2:resort_lock").should be_nil
297
+ end
285
298
 
286
299
  it "should handle simple values" do
287
300
  @roster.starting_pitcher.should == nil
@@ -635,4 +648,5 @@ describe Redis::Objects do
635
648
  error.should_not be_nil
636
649
  error.should be_kind_of(Redis::Lock::LockTimeout)
637
650
  end
651
+
638
652
  end