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/ChangeLog +8 -0
- data/README.rdoc +181 -105
- data/lib/redis/counter.rb +6 -5
- data/lib/redis/helpers/core_commands.rb +9 -1
- data/lib/redis/list.rb +3 -3
- data/lib/redis/lock.rb +42 -5
- data/lib/redis/objects/counters.rb +4 -3
- data/lib/redis/objects/locks.rb +1 -4
- data/lib/redis/objects/sorted_sets.rb +45 -0
- data/lib/redis/objects.rb +8 -6
- data/lib/redis/set.rb +3 -3
- data/lib/redis/sorted_set.rb +275 -0
- data/lib/redis/value.rb +3 -3
- data/spec/redis_objects_instance_spec.rb +276 -31
- data/spec/redis_objects_model_spec.rb +15 -1
- metadata +24 -11
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,
|
|
16
|
+
def initialize(key, *args)
|
|
17
17
|
@key = key
|
|
18
|
-
@
|
|
19
|
-
@
|
|
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,
|
|
12
|
+
def initialize(key, *args)
|
|
13
13
|
@key = key
|
|
14
|
-
@
|
|
15
|
-
@
|
|
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::
|
|
424
|
+
describe Redis::SortedSet do
|
|
292
425
|
before :all do
|
|
293
|
-
@
|
|
294
|
-
@
|
|
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
|
-
@
|
|
433
|
+
@set.clear
|
|
434
|
+
@set_1.clear
|
|
435
|
+
@set_2.clear
|
|
436
|
+
@set_3.clear
|
|
299
437
|
end
|
|
300
438
|
|
|
301
|
-
it "should
|
|
302
|
-
@
|
|
303
|
-
@
|
|
304
|
-
@
|
|
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
|
-
|
|
307
|
-
(
|
|
308
|
-
(
|
|
309
|
-
(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
@
|
|
317
|
-
@
|
|
318
|
-
@
|
|
319
|
-
|
|
320
|
-
@
|
|
321
|
-
@
|
|
322
|
-
@
|
|
323
|
-
|
|
324
|
-
@
|
|
325
|
-
|
|
326
|
-
@
|
|
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
|
-
@
|
|
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
|