redis-objects 0.3.1 → 0.3.2
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/README.rdoc +5 -0
- data/Rakefile +7 -0
- data/lib/redis/list.rb +4 -2
- data/lib/redis/sorted_set.rb +3 -3
- data/spec/redis_objects_instance_spec.rb +202 -177
- data/spec/redis_objects_model_spec.rb +50 -52
- data/spec/spec_helper.rb +4 -0
- metadata +5 -3
data/README.rdoc
CHANGED
@@ -198,6 +198,11 @@ Lists work just like Ruby arrays:
|
|
198
198
|
@list.clear
|
199
199
|
# etc
|
200
200
|
|
201
|
+
You can bound the size of the list to only hold N elements like so:
|
202
|
+
|
203
|
+
# Only holds 10 elements, throws out old ones when you reach :maxlength.
|
204
|
+
@list = Redis::List.new('list_name', redis_handle, :maxlength => 10)
|
205
|
+
|
201
206
|
Complex data types are no problem with :marshal => true:
|
202
207
|
|
203
208
|
@list = Redis::List.new('list_name', :marshal => true)
|
data/Rakefile
ADDED
data/lib/redis/list.rb
CHANGED
@@ -17,7 +17,7 @@ class Redis
|
|
17
17
|
@options = args.last.is_a?(Hash) ? args.pop : {}
|
18
18
|
@redis = args.first || $redis
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
# Works like push. Can chain together: list << 'a' << 'b'
|
22
22
|
def <<(value)
|
23
23
|
push(value)
|
@@ -27,6 +27,7 @@ class Redis
|
|
27
27
|
# Add a member to the end of the list. Redis: RPUSH
|
28
28
|
def push(value)
|
29
29
|
redis.rpush(key, to_redis(value))
|
30
|
+
redis.ltrim(key, -options[:maxlength], -1) if options[:maxlength]
|
30
31
|
end
|
31
32
|
|
32
33
|
# Remove a member from the end of the list. Redis: RPOP
|
@@ -37,6 +38,7 @@ class Redis
|
|
37
38
|
# Add a member to the start of the list. Redis: LPUSH
|
38
39
|
def unshift(value)
|
39
40
|
redis.lpush(key, to_redis(value))
|
41
|
+
redis.ltrim(key, 0, options[:maxlength] - 1) if options[:maxlength]
|
40
42
|
end
|
41
43
|
|
42
44
|
# Remove a member from the start of the list. Redis: LPOP
|
@@ -118,4 +120,4 @@ class Redis
|
|
118
120
|
values.join(', ')
|
119
121
|
end
|
120
122
|
end
|
121
|
-
end
|
123
|
+
end
|
data/lib/redis/sorted_set.rb
CHANGED
@@ -50,7 +50,7 @@ class Redis
|
|
50
50
|
# specified element does not exist in the sorted set, or the key does not exist
|
51
51
|
# at all, nil is returned. Redis: ZSCORE.
|
52
52
|
def score(member)
|
53
|
-
redis.zscore(key, to_redis(member)).
|
53
|
+
redis.zscore(key, to_redis(member)).to_f
|
54
54
|
end
|
55
55
|
|
56
56
|
# Return the rank of the member in the sorted set, with scores ordered from
|
@@ -78,7 +78,7 @@ class Redis
|
|
78
78
|
val = from_redis redis.zrange(key, start_index, end_index, 'withscores')
|
79
79
|
ret = []
|
80
80
|
while k = val.shift and v = val.shift
|
81
|
-
ret << [k, v.
|
81
|
+
ret << [k, v.to_f]
|
82
82
|
end
|
83
83
|
ret
|
84
84
|
else
|
@@ -92,7 +92,7 @@ class Redis
|
|
92
92
|
val = from_redis redis.zrevrange(key, start_index, end_index, 'withscores')
|
93
93
|
ret = []
|
94
94
|
while k = val.shift and v = val.shift
|
95
|
-
ret << [k, v.
|
95
|
+
ret << [k, v.to_f]
|
96
96
|
end
|
97
97
|
ret
|
98
98
|
else
|
@@ -9,11 +9,8 @@ require 'redis/set'
|
|
9
9
|
require 'redis/sorted_set'
|
10
10
|
|
11
11
|
describe Redis::Value do
|
12
|
-
before
|
12
|
+
before do
|
13
13
|
@value = Redis::Value.new('spec/value')
|
14
|
-
end
|
15
|
-
|
16
|
-
before :each do
|
17
14
|
@value.delete
|
18
15
|
end
|
19
16
|
|
@@ -22,8 +19,8 @@ describe Redis::Value do
|
|
22
19
|
@value.value = 'Trevor Hoffman'
|
23
20
|
@value.should == 'Trevor Hoffman'
|
24
21
|
@value.get.should == 'Trevor Hoffman'
|
25
|
-
@value.del.should
|
26
|
-
@value.should
|
22
|
+
@value.del.should.be.true
|
23
|
+
@value.should.be.nil
|
27
24
|
end
|
28
25
|
|
29
26
|
it "should handle complex marshaled values" do
|
@@ -42,161 +39,191 @@ describe Redis::Value do
|
|
42
39
|
@value.value = [[1,2], {:t3 => 4}]
|
43
40
|
@value.should == [[1,2], {:t3 => 4}]
|
44
41
|
@value.get.should == [[1,2], {:t3 => 4}]
|
45
|
-
@value.del.should
|
46
|
-
@value.should
|
42
|
+
@value.del.should.be.true
|
43
|
+
@value.should.be.nil
|
47
44
|
@value.options[:marshal] = false
|
48
45
|
end
|
49
46
|
|
50
47
|
it "should support renaming values" do
|
51
48
|
@value.value = 'Peter Pan'
|
52
49
|
@value.key.should == 'spec/value'
|
53
|
-
@value.rename('spec/value2')
|
50
|
+
@value.rename('spec/value2') # can't test result; switched from true to "OK"
|
54
51
|
@value.key.should == 'spec/value2'
|
55
52
|
@value.should == 'Peter Pan'
|
56
53
|
old = Redis::Value.new('spec/value')
|
57
|
-
old.should
|
54
|
+
old.should.be.nil
|
58
55
|
old.value = 'Tuff'
|
59
|
-
@value.renamenx('spec/value')
|
56
|
+
@value.renamenx('spec/value') # can't test result; switched from true to "OK"
|
60
57
|
@value.value.should == 'Peter Pan'
|
61
58
|
end
|
62
59
|
|
63
|
-
after
|
60
|
+
after do
|
64
61
|
@value.delete
|
65
62
|
end
|
66
63
|
end
|
67
64
|
|
68
65
|
|
69
66
|
describe Redis::List do
|
70
|
-
|
71
|
-
|
72
|
-
|
67
|
+
describe "as a bounded list" do
|
68
|
+
before do
|
69
|
+
@list = Redis::List.new('spec/bounded_list',
|
70
|
+
$redis,
|
71
|
+
:maxlength => 10)
|
72
|
+
1.upto(10) do |i|
|
73
|
+
@list << i
|
74
|
+
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
# Make sure that adding < maxlength doesn't mess up.
|
77
|
+
1.upto(10) do |i|
|
78
|
+
@list.at(i - 1).should == i.to_s
|
79
|
+
end
|
80
|
+
end
|
77
81
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
@list.unshift 'b'
|
84
|
-
@list.to_s.should == 'b, a'
|
85
|
-
@list.should == ['b','a']
|
86
|
-
@list.get.should == ['b','a']
|
87
|
-
@list.push 'c'
|
88
|
-
@list.should == ['b','a','c']
|
89
|
-
@list.get.should == ['b','a','c']
|
90
|
-
@list.first.should == 'b'
|
91
|
-
@list.last.should == 'c'
|
92
|
-
@list << 'd'
|
93
|
-
@list.should == ['b','a','c','d']
|
94
|
-
@list[1].should == 'a'
|
95
|
-
@list[0].should == 'b'
|
96
|
-
@list[2].should == 'c'
|
97
|
-
@list[3].should == 'd'
|
98
|
-
@list.include?('c').should be_true
|
99
|
-
@list.include?('no').should be_false
|
100
|
-
@list.pop.should == 'd'
|
101
|
-
@list[0].should == @list.at(0)
|
102
|
-
@list[1].should == @list.at(1)
|
103
|
-
@list[2].should == @list.at(2)
|
104
|
-
@list.should == ['b','a','c']
|
105
|
-
@list.get.should == ['b','a','c']
|
106
|
-
@list.shift.should == 'b'
|
107
|
-
@list.should == ['a','c']
|
108
|
-
@list.get.should == ['a','c']
|
109
|
-
@list << 'e' << 'f' << 'e'
|
110
|
-
@list.should == ['a','c','e','f','e']
|
111
|
-
@list.get.should == ['a','c','e','f','e']
|
112
|
-
@list.delete('e').should == 2
|
113
|
-
@list.should == ['a','c','f']
|
114
|
-
@list.get.should == ['a','c','f']
|
115
|
-
@list << 'j'
|
116
|
-
@list.should == ['a','c','f','j']
|
117
|
-
@list[0..2].should == ['a','c','f']
|
118
|
-
@list[0, 2].should == ['a','c','f'] # consistent with Redis, not Ruby
|
119
|
-
@list[1, 3].should == ['c','f','j']
|
120
|
-
@list.length.should == 4
|
121
|
-
@list.size.should == 4
|
122
|
-
@list.should == ['a','c','f','j']
|
123
|
-
@list.get.should == ['a','c','f','j']
|
124
|
-
|
125
|
-
i = -1
|
126
|
-
@list.each do |st|
|
127
|
-
st.should == @list[i += 1]
|
82
|
+
it "should push the first element out of the list" do
|
83
|
+
@list << '11'
|
84
|
+
@list.last.should == '11'
|
85
|
+
@list.first.should == '2'
|
86
|
+
@list.length.should == 10
|
128
87
|
end
|
129
|
-
@list.should == ['a','c','f','j']
|
130
|
-
@list.get.should == ['a','c','f','j']
|
131
88
|
|
132
|
-
|
133
|
-
|
89
|
+
it "should push the last element out of the list for unshift" do
|
90
|
+
@list.unshift('0')
|
91
|
+
@list.last.should == '9'
|
92
|
+
@list.first.should == '0'
|
93
|
+
@list.length.should == 10
|
134
94
|
end
|
135
|
-
@list.should == ['a','c','f','j']
|
136
|
-
@list.get.should == ['a','c','f','j']
|
137
|
-
|
138
|
-
coll = @list.collect{|st| st}
|
139
|
-
coll.should == ['a','c','f','j']
|
140
|
-
@list.should == ['a','c','f','j']
|
141
|
-
@list.get.should == ['a','c','f','j']
|
142
|
-
|
143
|
-
@list << 'a'
|
144
|
-
coll = @list.select{|st| st == 'a'}
|
145
|
-
coll.should == ['a','a']
|
146
|
-
@list.should == ['a','c','f','j','a']
|
147
|
-
@list.get.should == ['a','c','f','j','a']
|
148
|
-
end
|
149
95
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
v2 = {:json2 => 'data2'}
|
154
|
-
@list << v1
|
155
|
-
@list << v2
|
156
|
-
@list.first.should == v1
|
157
|
-
@list.last.should == v2
|
158
|
-
@list << [1,2,3,[4,5]]
|
159
|
-
@list.last.should == [1,2,3,[4,5]]
|
160
|
-
@list.shift.should == {:json => 'data'}
|
161
|
-
@list.options[:marshal] = false
|
162
|
-
end
|
163
|
-
|
164
|
-
it "should support renaming lists" do
|
165
|
-
@list.should be_empty
|
166
|
-
@list << 'a' << 'b' << 'a' << 3
|
167
|
-
@list.should == ['a','b','a','3']
|
168
|
-
@list.key.should == 'spec/list'
|
169
|
-
@list.rename('spec/list3', false).should be_true
|
170
|
-
@list.key.should == 'spec/list'
|
171
|
-
@list.redis.del('spec/list3')
|
172
|
-
@list << 'a' << 'b' << 'a' << 3
|
173
|
-
@list.rename('spec/list2').should be_true
|
174
|
-
@list.key.should == 'spec/list2'
|
175
|
-
@list.redis.lrange(@list.key, 0, 3).should == ['a','b','a','3']
|
176
|
-
old = Redis::List.new('spec/list')
|
177
|
-
old.should be_empty
|
178
|
-
old << 'Tuff'
|
179
|
-
old.values.should == ['Tuff']
|
180
|
-
@list.renamenx('spec/list').should be_false
|
181
|
-
@list.renamenx(old).should be_false
|
182
|
-
@list.renamenx('spec/foo').should be_true
|
183
|
-
old.values.should == ['Tuff']
|
184
|
-
@list.clear
|
185
|
-
@list.redis.del('spec/list2')
|
96
|
+
after do
|
97
|
+
@list.clear
|
98
|
+
end
|
186
99
|
end
|
187
100
|
|
188
|
-
|
189
|
-
|
101
|
+
describe "with basic operations" do
|
102
|
+
before do
|
103
|
+
@list = Redis::List.new('spec/list')
|
104
|
+
@list.clear
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should handle lists of simple values" do
|
108
|
+
@list.should.be.empty
|
109
|
+
@list << 'a'
|
110
|
+
@list.should == ['a']
|
111
|
+
@list.get.should == ['a']
|
112
|
+
@list.unshift 'b'
|
113
|
+
@list.to_s.should == 'b, a'
|
114
|
+
@list.should == ['b','a']
|
115
|
+
@list.get.should == ['b','a']
|
116
|
+
@list.push 'c'
|
117
|
+
@list.should == ['b','a','c']
|
118
|
+
@list.get.should == ['b','a','c']
|
119
|
+
@list.first.should == 'b'
|
120
|
+
@list.last.should == 'c'
|
121
|
+
@list << 'd'
|
122
|
+
@list.should == ['b','a','c','d']
|
123
|
+
@list[1].should == 'a'
|
124
|
+
@list[0].should == 'b'
|
125
|
+
@list[2].should == 'c'
|
126
|
+
@list[3].should == 'd'
|
127
|
+
@list.include?('c').should.be.true
|
128
|
+
@list.include?('no').should.be.false
|
129
|
+
@list.pop.should == 'd'
|
130
|
+
@list[0].should == @list.at(0)
|
131
|
+
@list[1].should == @list.at(1)
|
132
|
+
@list[2].should == @list.at(2)
|
133
|
+
@list.should == ['b','a','c']
|
134
|
+
@list.get.should == ['b','a','c']
|
135
|
+
@list.shift.should == 'b'
|
136
|
+
@list.should == ['a','c']
|
137
|
+
@list.get.should == ['a','c']
|
138
|
+
@list << 'e' << 'f' << 'e'
|
139
|
+
@list.should == ['a','c','e','f','e']
|
140
|
+
@list.get.should == ['a','c','e','f','e']
|
141
|
+
@list.delete('e').should == 2
|
142
|
+
@list.should == ['a','c','f']
|
143
|
+
@list.get.should == ['a','c','f']
|
144
|
+
@list << 'j'
|
145
|
+
@list.should == ['a','c','f','j']
|
146
|
+
@list[0..2].should == ['a','c','f']
|
147
|
+
@list[0, 2].should == ['a','c','f'] # consistent with Redis, not Ruby
|
148
|
+
@list[1, 3].should == ['c','f','j']
|
149
|
+
@list.length.should == 4
|
150
|
+
@list.size.should == 4
|
151
|
+
@list.should == ['a','c','f','j']
|
152
|
+
@list.get.should == ['a','c','f','j']
|
153
|
+
|
154
|
+
i = -1
|
155
|
+
@list.each do |st|
|
156
|
+
st.should == @list[i += 1]
|
157
|
+
end
|
158
|
+
@list.should == ['a','c','f','j']
|
159
|
+
@list.get.should == ['a','c','f','j']
|
160
|
+
|
161
|
+
@list.each_with_index do |st,i|
|
162
|
+
st.should == @list[i]
|
163
|
+
end
|
164
|
+
@list.should == ['a','c','f','j']
|
165
|
+
@list.get.should == ['a','c','f','j']
|
166
|
+
|
167
|
+
coll = @list.collect{|st| st}
|
168
|
+
coll.should == ['a','c','f','j']
|
169
|
+
@list.should == ['a','c','f','j']
|
170
|
+
@list.get.should == ['a','c','f','j']
|
171
|
+
|
172
|
+
@list << 'a'
|
173
|
+
coll = @list.select{|st| st == 'a'}
|
174
|
+
coll.should == ['a','a']
|
175
|
+
@list.should == ['a','c','f','j','a']
|
176
|
+
@list.get.should == ['a','c','f','j','a']
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should handle lists of complex data types" do
|
180
|
+
@list.options[:marshal] = true
|
181
|
+
v1 = {:json => 'data'}
|
182
|
+
v2 = {:json2 => 'data2'}
|
183
|
+
@list << v1
|
184
|
+
@list << v2
|
185
|
+
@list.first.should == v1
|
186
|
+
@list.last.should == v2
|
187
|
+
@list << [1,2,3,[4,5]]
|
188
|
+
@list.last.should == [1,2,3,[4,5]]
|
189
|
+
@list.shift.should == {:json => 'data'}
|
190
|
+
@list.options[:marshal] = false
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should support renaming lists" do
|
194
|
+
@list.should.be.empty
|
195
|
+
@list << 'a' << 'b' << 'a' << 3
|
196
|
+
@list.should == ['a','b','a','3']
|
197
|
+
@list.key.should == 'spec/list'
|
198
|
+
@list.rename('spec/list3', false) # can't test result; switched from true to "OK"
|
199
|
+
@list.key.should == 'spec/list'
|
200
|
+
@list.redis.del('spec/list3')
|
201
|
+
@list << 'a' << 'b' << 'a' << 3
|
202
|
+
@list.rename('spec/list2') # can't test result; switched from true to "OK"
|
203
|
+
@list.key.should == 'spec/list2'
|
204
|
+
@list.redis.lrange(@list.key, 0, 3).should == ['a','b','a','3']
|
205
|
+
old = Redis::List.new('spec/list')
|
206
|
+
old.should.be.empty
|
207
|
+
old << 'Tuff'
|
208
|
+
old.values.should == ['Tuff']
|
209
|
+
@list.renamenx('spec/list').should.be.false
|
210
|
+
@list.renamenx(old).should.be.false
|
211
|
+
@list.renamenx('spec/foo').should.be.true
|
212
|
+
old.values.should == ['Tuff']
|
213
|
+
@list.clear
|
214
|
+
@list.redis.del('spec/list2')
|
215
|
+
end
|
216
|
+
|
217
|
+
after do
|
218
|
+
@list.clear
|
219
|
+
end
|
190
220
|
end
|
191
221
|
end
|
192
222
|
|
193
223
|
describe Redis::Counter do
|
194
|
-
before
|
224
|
+
before do
|
195
225
|
@counter = Redis::Counter.new('spec/counter')
|
196
226
|
@counter2 = Redis::Counter.new('spec/counter')
|
197
|
-
end
|
198
|
-
|
199
|
-
before :each do
|
200
227
|
@counter.reset
|
201
228
|
end
|
202
229
|
|
@@ -206,11 +233,11 @@ describe Redis::Counter do
|
|
206
233
|
@counter.should == 10
|
207
234
|
|
208
235
|
# math proxy ops
|
209
|
-
(@counter == 10).should
|
210
|
-
(@counter <= 10).should
|
211
|
-
(@counter < 11).should
|
212
|
-
(@counter > 9).should
|
213
|
-
(@counter >= 10).should
|
236
|
+
(@counter == 10).should.be.true
|
237
|
+
(@counter <= 10).should.be.true
|
238
|
+
(@counter < 11).should.be.true
|
239
|
+
(@counter > 9).should.be.true
|
240
|
+
(@counter >= 10).should.be.true
|
214
241
|
"#{@counter}".should == "10"
|
215
242
|
|
216
243
|
@counter.increment.should == 11
|
@@ -222,19 +249,19 @@ describe Redis::Counter do
|
|
222
249
|
@counter.decrement.should == 12
|
223
250
|
@counter2.decrement(4).should == 8
|
224
251
|
@counter.should == 8
|
225
|
-
@counter.reset.should
|
252
|
+
@counter.reset.should.be.true
|
226
253
|
@counter.should == 0
|
227
|
-
@counter.reset(15).should
|
254
|
+
@counter.reset(15).should.be.true
|
228
255
|
@counter.should == 15
|
229
256
|
end
|
230
257
|
|
231
|
-
after
|
258
|
+
after do
|
232
259
|
@counter.delete
|
233
260
|
end
|
234
261
|
end
|
235
262
|
|
236
263
|
describe Redis::Lock do
|
237
|
-
before
|
264
|
+
before do
|
238
265
|
$redis.flushall
|
239
266
|
end
|
240
267
|
|
@@ -247,11 +274,11 @@ describe Redis::Lock do
|
|
247
274
|
|
248
275
|
# The expiration stored in redis should be 15 seconds from when we started
|
249
276
|
# or a little more
|
250
|
-
expiration.should
|
277
|
+
expiration.should.be.close((start + expiry).to_f, 2.0)
|
251
278
|
end
|
252
279
|
|
253
280
|
# key should have been cleaned up
|
254
|
-
$redis.get("test_lock").should
|
281
|
+
$redis.get("test_lock").should.be.nil
|
255
282
|
end
|
256
283
|
|
257
284
|
it "should set value to 1 when no expiration is set" do
|
@@ -261,7 +288,7 @@ describe Redis::Lock do
|
|
261
288
|
end
|
262
289
|
|
263
290
|
# key should have been cleaned up
|
264
|
-
$redis.get("test_lock").should
|
291
|
+
$redis.get("test_lock").should.be.nil
|
265
292
|
end
|
266
293
|
|
267
294
|
it "should let lock be gettable when lock is expired" do
|
@@ -277,8 +304,8 @@ describe Redis::Lock do
|
|
277
304
|
end
|
278
305
|
|
279
306
|
# should get the lock because it has expired
|
280
|
-
gotit.should
|
281
|
-
$redis.get("test_lock").should
|
307
|
+
gotit.should.be.true
|
308
|
+
$redis.get("test_lock").should.be.nil
|
282
309
|
end
|
283
310
|
|
284
311
|
it "should not let non-expired locks be gettable" do
|
@@ -297,13 +324,13 @@ describe Redis::Lock do
|
|
297
324
|
rescue => error
|
298
325
|
end
|
299
326
|
|
300
|
-
error.should
|
327
|
+
error.should.be.kind_of(Redis::Lock::LockTimeout)
|
301
328
|
|
302
329
|
# should not have the lock
|
303
|
-
gotit.
|
330
|
+
gotit.should.not.be.true
|
304
331
|
|
305
332
|
# lock value should still be set
|
306
|
-
$redis.get("test_lock").
|
333
|
+
$redis.get("test_lock").should.not.be.nil
|
307
334
|
end
|
308
335
|
|
309
336
|
it "should not remove the key if lock is held past expiration" do
|
@@ -314,19 +341,16 @@ describe Redis::Lock do
|
|
314
341
|
end
|
315
342
|
|
316
343
|
# lock value should still be set since the lock was held for more than the expiry
|
317
|
-
$redis.get("test_lock").
|
344
|
+
$redis.get("test_lock").should.not.be.nil
|
318
345
|
end
|
319
346
|
end
|
320
347
|
|
321
348
|
describe Redis::Set do
|
322
|
-
before
|
349
|
+
before do
|
323
350
|
@set = Redis::Set.new('spec/set')
|
324
351
|
@set_1 = Redis::Set.new('spec/set_1')
|
325
352
|
@set_2 = Redis::Set.new('spec/set_2')
|
326
353
|
@set_3 = Redis::Set.new('spec/set_3')
|
327
|
-
end
|
328
|
-
|
329
|
-
before :each do
|
330
354
|
@set.clear
|
331
355
|
@set_1.clear
|
332
356
|
@set_2.clear
|
@@ -334,7 +358,7 @@ describe Redis::Set do
|
|
334
358
|
end
|
335
359
|
|
336
360
|
it "should handle sets of simple values" do
|
337
|
-
@set.should
|
361
|
+
@set.should.be.empty
|
338
362
|
@set << 'a' << 'a' << 'a'
|
339
363
|
@set.should == ['a']
|
340
364
|
@set.get.should == ['a']
|
@@ -364,9 +388,9 @@ describe Redis::Set do
|
|
364
388
|
@set.get.should == ['a','b']
|
365
389
|
|
366
390
|
@set << 'c'
|
367
|
-
@set.member?('c').should
|
368
|
-
@set.include?('c').should
|
369
|
-
@set.member?('no').should
|
391
|
+
@set.member?('c').should.be.true
|
392
|
+
@set.include?('c').should.be.true
|
393
|
+
@set.member?('no').should.be.false
|
370
394
|
coll = @set.select{|st| st == 'c'}
|
371
395
|
coll.should == ['c']
|
372
396
|
@set.sort.should == ['a','b','c']
|
@@ -411,23 +435,23 @@ describe Redis::Set do
|
|
411
435
|
end
|
412
436
|
|
413
437
|
it "should support renaming sets" do
|
414
|
-
@set.should
|
438
|
+
@set.should.be.empty
|
415
439
|
@set << 'a' << 'b' << 'a' << 3
|
416
440
|
@set.sort.should == ['3','a','b']
|
417
441
|
@set.key.should == 'spec/set'
|
418
|
-
@set.rename('spec/set2')
|
442
|
+
@set.rename('spec/set2') # can't test result; switched from true to "OK"
|
419
443
|
@set.key.should == 'spec/set2'
|
420
444
|
old = Redis::Set.new('spec/set')
|
421
|
-
old.should
|
445
|
+
old.should.be.empty
|
422
446
|
old << 'Tuff'
|
423
|
-
@set.renamenx('spec/set').should
|
424
|
-
@set.renamenx(old).should
|
425
|
-
@set.renamenx('spec/foo').should
|
447
|
+
@set.renamenx('spec/set').should.be.false
|
448
|
+
@set.renamenx(old).should.be.false
|
449
|
+
@set.renamenx('spec/foo').should.be.true
|
426
450
|
@set.clear
|
427
451
|
@set.redis.del('spec/set2')
|
428
452
|
end
|
429
453
|
|
430
|
-
after
|
454
|
+
after do
|
431
455
|
@set.clear
|
432
456
|
@set_1.clear
|
433
457
|
@set_2.clear
|
@@ -436,14 +460,11 @@ describe Redis::Set do
|
|
436
460
|
end
|
437
461
|
|
438
462
|
describe Redis::SortedSet do
|
439
|
-
before
|
463
|
+
before do
|
440
464
|
@set = Redis::SortedSet.new('spec/zset')
|
441
465
|
@set_1 = Redis::SortedSet.new('spec/zset_1')
|
442
466
|
@set_2 = Redis::SortedSet.new('spec/zset_2')
|
443
467
|
@set_3 = Redis::SortedSet.new('spec/zset_3')
|
444
|
-
end
|
445
|
-
|
446
|
-
before :each do
|
447
468
|
@set.clear
|
448
469
|
@set_1.clear
|
449
470
|
@set_2.clear
|
@@ -451,15 +472,15 @@ describe Redis::SortedSet do
|
|
451
472
|
end
|
452
473
|
|
453
474
|
it "should handle sets of simple values" do
|
454
|
-
@set.should
|
475
|
+
@set.should.be.empty
|
455
476
|
@set['a'] = 11
|
456
477
|
@set['a'] = 21
|
457
478
|
@set.add('a', 5)
|
458
479
|
@set.score('a').should == 5
|
459
480
|
@set['a'].should == 5
|
460
481
|
@set['a'] = 3
|
461
|
-
@set['b'] = 5
|
462
|
-
@set['b'].should == 5
|
482
|
+
@set['b'] = 5.6
|
483
|
+
@set['b'].should == 5.6
|
463
484
|
@set['c'] = 4
|
464
485
|
|
465
486
|
@set[0,-1].should == ['a','c','b']
|
@@ -475,7 +496,7 @@ describe Redis::SortedSet do
|
|
475
496
|
@set.last.should == 'b'
|
476
497
|
|
477
498
|
@set.members.should == ['a','c','b']
|
478
|
-
@set.members(:withscores => true).should == [['a',3],['c',4],['b',5]]
|
499
|
+
@set.members(:withscores => true).should == [['a',3],['c',4],['b',5.6]]
|
479
500
|
|
480
501
|
@set['b'] = 5
|
481
502
|
@set['b'] = 6
|
@@ -520,8 +541,10 @@ describe Redis::SortedSet do
|
|
520
541
|
@set.size.should == 4
|
521
542
|
end
|
522
543
|
|
544
|
+
=begin
|
545
|
+
|
523
546
|
# Not until Redis 1.3.5 with hashes
|
524
|
-
|
547
|
+
it "Redis 1.3.5: should handle set intersections, unions, and diffs" do
|
525
548
|
@set_1['a'] = 5
|
526
549
|
@set_2['b'] = 18
|
527
550
|
@set_2['c'] = 12
|
@@ -569,25 +592,27 @@ describe Redis::SortedSet do
|
|
569
592
|
@set_1.redis.smembers(DIFFSTORE_KEY).sort.should == ['b']
|
570
593
|
end
|
571
594
|
|
595
|
+
=end
|
596
|
+
|
572
597
|
it "should support renaming sets" do
|
573
|
-
@set.should
|
598
|
+
@set.should.be.empty
|
574
599
|
@set['zynga'] = 151
|
575
600
|
@set['playfish'] = 202
|
576
601
|
@set.members.should == ['zynga','playfish']
|
577
602
|
@set.key.should == 'spec/zset'
|
578
|
-
@set.rename('spec/zset2')
|
603
|
+
@set.rename('spec/zset2') # can't test result; switched from true to "OK"
|
579
604
|
@set.key.should == 'spec/zset2'
|
580
605
|
old = Redis::SortedSet.new('spec/zset')
|
581
|
-
old.should
|
606
|
+
old.should.be.empty
|
582
607
|
old['tuff'] = 54
|
583
|
-
@set.renamenx('spec/zset').should
|
584
|
-
@set.renamenx(old).should
|
585
|
-
@set.renamenx('spec/zfoo').should
|
608
|
+
@set.renamenx('spec/zset').should.be.false
|
609
|
+
@set.renamenx(old).should.be.false
|
610
|
+
@set.renamenx('spec/zfoo').should.be.true
|
586
611
|
@set.clear
|
587
612
|
@set.redis.del('spec/zset2')
|
588
613
|
end
|
589
614
|
|
590
|
-
after
|
615
|
+
after do
|
591
616
|
@set.clear
|
592
617
|
@set_1.clear
|
593
618
|
@set_2.clear
|
@@ -34,16 +34,14 @@ class Roster
|
|
34
34
|
end
|
35
35
|
|
36
36
|
describe Redis::Objects do
|
37
|
-
before
|
37
|
+
before do
|
38
38
|
@roster = Roster.new
|
39
39
|
@roster2 = Roster.new
|
40
40
|
|
41
41
|
@roster_1 = Roster.new(1)
|
42
42
|
@roster_2 = Roster.new(2)
|
43
43
|
@roster_3 = Roster.new(3)
|
44
|
-
|
45
|
-
|
46
|
-
before :each do
|
44
|
+
|
47
45
|
@roster.available_slots.reset
|
48
46
|
@roster.pitchers.reset
|
49
47
|
@roster.basic.reset
|
@@ -72,13 +70,13 @@ describe Redis::Objects do
|
|
72
70
|
|
73
71
|
it "should provide a connection method" do
|
74
72
|
Roster.redis.should == Redis::Objects.redis
|
75
|
-
# Roster.redis.should
|
73
|
+
# Roster.redis.should.be.kind_of(Redis)
|
76
74
|
end
|
77
75
|
|
78
76
|
it "should support custom key names" do
|
79
77
|
@roster.player_totals.incr
|
80
78
|
@roster.redis.get('players/user1/total').should == '1'
|
81
|
-
@roster.redis.get('players/#{username}/total').should
|
79
|
+
@roster.redis.get('players/#{username}/total').should.be.nil
|
82
80
|
@roster.all_player_stats << 'a'
|
83
81
|
@roster.redis.lindex('players:all_stats', 0).should == 'a'
|
84
82
|
@roster.total_wins << 'a'
|
@@ -101,11 +99,11 @@ describe Redis::Objects do
|
|
101
99
|
@roster.available_slots.should == 10
|
102
100
|
|
103
101
|
# math proxy ops
|
104
|
-
(@roster.available_slots == 10).should
|
105
|
-
(@roster.available_slots <= 10).should
|
106
|
-
(@roster.available_slots < 11).should
|
107
|
-
(@roster.available_slots > 9).should
|
108
|
-
(@roster.available_slots >= 10).should
|
102
|
+
(@roster.available_slots == 10).should.be.true
|
103
|
+
(@roster.available_slots <= 10).should.be.true
|
104
|
+
(@roster.available_slots < 11).should.be.true
|
105
|
+
(@roster.available_slots > 9).should.be.true
|
106
|
+
(@roster.available_slots >= 10).should.be.true
|
109
107
|
"#{@roster.available_slots}".should == "10"
|
110
108
|
|
111
109
|
@roster.available_slots.increment.should == 11
|
@@ -117,9 +115,9 @@ describe Redis::Objects do
|
|
117
115
|
@roster.available_slots.decrement.should == 12
|
118
116
|
@roster2.available_slots.decrement(4).should == 8
|
119
117
|
@roster.available_slots.should == 8
|
120
|
-
@roster.available_slots.reset.should
|
118
|
+
@roster.available_slots.reset.should.be.true
|
121
119
|
@roster.available_slots.should == 10
|
122
|
-
@roster.available_slots.reset(15).should
|
120
|
+
@roster.available_slots.reset(15).should.be.true
|
123
121
|
@roster.available_slots.should == 15
|
124
122
|
@roster.pitchers.increment.should == 1
|
125
123
|
@roster.basic.increment.should == 1
|
@@ -143,7 +141,7 @@ describe Redis::Objects do
|
|
143
141
|
Roster.total_players_online.decrement.should == 0
|
144
142
|
Roster.total_players_online.increment(3).should == 3
|
145
143
|
Roster.total_players_online.decrement(2).should == 1
|
146
|
-
Roster.total_players_online.reset.should
|
144
|
+
Roster.total_players_online.reset.should.be.true
|
147
145
|
Roster.total_players_online.should == 0
|
148
146
|
|
149
147
|
Roster.get_counter(:total_players_online).should == 0
|
@@ -164,7 +162,7 @@ describe Redis::Objects do
|
|
164
162
|
end
|
165
163
|
end
|
166
164
|
@roster.available_slots.should == 9
|
167
|
-
a.should
|
165
|
+
a.should.be.true
|
168
166
|
|
169
167
|
@roster.available_slots.should == 9
|
170
168
|
@roster.available_slots.decr do |cnt|
|
@@ -224,7 +222,7 @@ describe Redis::Objects do
|
|
224
222
|
end
|
225
223
|
end
|
226
224
|
Roster.get_counter(:available_slots, @roster.id).should == 9
|
227
|
-
a.should
|
225
|
+
a.should.be.true
|
228
226
|
|
229
227
|
Roster.get_counter(:available_slots, @roster.id).should == 9
|
230
228
|
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
@@ -281,48 +279,48 @@ describe Redis::Objects do
|
|
281
279
|
Roster.increment_counter(:badness, 2)
|
282
280
|
rescue => error
|
283
281
|
end
|
284
|
-
error.should
|
282
|
+
error.should.be.kind_of(Redis::Objects::UndefinedCounter)
|
285
283
|
|
286
284
|
error = nil
|
287
285
|
begin
|
288
286
|
Roster.obtain_lock(:badness, 2){}
|
289
287
|
rescue => error
|
290
288
|
end
|
291
|
-
error.should
|
289
|
+
error.should.be.kind_of(Redis::Objects::UndefinedLock)
|
292
290
|
|
293
291
|
error = nil
|
294
292
|
begin
|
295
293
|
@roster.available_slots = 42
|
296
294
|
rescue => error
|
297
295
|
end
|
298
|
-
error.should
|
296
|
+
error.should.be.kind_of(NoMethodError)
|
299
297
|
|
300
298
|
error = nil
|
301
299
|
begin
|
302
300
|
@roster.available_slots += 69
|
303
301
|
rescue => error
|
304
302
|
end
|
305
|
-
error.should
|
303
|
+
error.should.be.kind_of(NoMethodError)
|
306
304
|
|
307
305
|
error = nil
|
308
306
|
begin
|
309
307
|
@roster.available_slots -= 15
|
310
308
|
rescue => error
|
311
309
|
end
|
312
|
-
error.should
|
310
|
+
error.should.be.kind_of(NoMethodError)
|
313
311
|
end
|
314
312
|
|
315
313
|
it "should support obtain_lock as a class method" do
|
316
314
|
error = nil
|
317
315
|
begin
|
318
316
|
Roster.obtain_lock(:resort, 2) do
|
319
|
-
Roster.redis.get("roster:2:resort_lock").
|
317
|
+
Roster.redis.get("roster:2:resort_lock").should.not.be.nil
|
320
318
|
end
|
321
319
|
rescue => error
|
322
320
|
end
|
323
321
|
|
324
|
-
error.should
|
325
|
-
Roster.redis.get("roster:2:resort_lock").should
|
322
|
+
error.should.be.nil
|
323
|
+
Roster.redis.get("roster:2:resort_lock").should.be.nil
|
326
324
|
end
|
327
325
|
|
328
326
|
it "should handle simple values" do
|
@@ -332,8 +330,8 @@ describe Redis::Objects do
|
|
332
330
|
@roster.starting_pitcher.get.should == 'Trevor Hoffman'
|
333
331
|
@roster.starting_pitcher = 'Tom Selleck'
|
334
332
|
@roster.starting_pitcher.should == 'Tom Selleck'
|
335
|
-
@roster.starting_pitcher.del.should
|
336
|
-
@roster.starting_pitcher.should
|
333
|
+
@roster.starting_pitcher.del.should.be.true
|
334
|
+
@roster.starting_pitcher.should.be.nil
|
337
335
|
end
|
338
336
|
|
339
337
|
it "should handle complex marshaled values" do
|
@@ -341,12 +339,12 @@ describe Redis::Objects do
|
|
341
339
|
@roster.starting_pitcher = {:json => 'data'}
|
342
340
|
@roster.starting_pitcher.should == {:json => 'data'}
|
343
341
|
@roster.starting_pitcher.get.should == {:json => 'data'}
|
344
|
-
@roster.starting_pitcher.del.should
|
345
|
-
@roster.starting_pitcher.should
|
342
|
+
@roster.starting_pitcher.del.should.be.true
|
343
|
+
@roster.starting_pitcher.should.be.nil
|
346
344
|
end
|
347
345
|
|
348
346
|
it "should handle lists of simple values" do
|
349
|
-
@roster.player_stats.should
|
347
|
+
@roster.player_stats.should.be.empty
|
350
348
|
@roster.player_stats << 'a'
|
351
349
|
@roster.player_stats.should == ['a']
|
352
350
|
@roster.player_stats.get.should == ['a']
|
@@ -365,8 +363,8 @@ describe Redis::Objects do
|
|
365
363
|
@roster.player_stats[0].should == 'b'
|
366
364
|
@roster.player_stats[2].should == 'c'
|
367
365
|
@roster.player_stats[3].should == 'd'
|
368
|
-
@roster.player_stats.include?('c').should
|
369
|
-
@roster.player_stats.include?('no').should
|
366
|
+
@roster.player_stats.include?('c').should.be.true
|
367
|
+
@roster.player_stats.include?('no').should.be.false
|
370
368
|
@roster.player_stats.pop.should == 'd'
|
371
369
|
@roster.player_stats[0].should == @roster.player_stats.at(0)
|
372
370
|
@roster.player_stats[1].should == @roster.player_stats.at(1)
|
@@ -417,7 +415,7 @@ describe Redis::Objects do
|
|
417
415
|
end
|
418
416
|
|
419
417
|
it "should handle sets of simple values" do
|
420
|
-
@roster.outfielders.should
|
418
|
+
@roster.outfielders.should.be.empty
|
421
419
|
@roster.outfielders << 'a' << 'a' << 'a'
|
422
420
|
@roster.outfielders.should == ['a']
|
423
421
|
@roster.outfielders.get.should == ['a']
|
@@ -447,9 +445,9 @@ describe Redis::Objects do
|
|
447
445
|
@roster.outfielders.get.should == ['a','b']
|
448
446
|
|
449
447
|
@roster.outfielders << 'c'
|
450
|
-
@roster.outfielders.member?('c').should
|
451
|
-
@roster.outfielders.include?('c').should
|
452
|
-
@roster.outfielders.member?('no').should
|
448
|
+
@roster.outfielders.member?('c').should.be.true
|
449
|
+
@roster.outfielders.include?('c').should.be.true
|
450
|
+
@roster.outfielders.member?('no').should.be.false
|
453
451
|
coll = @roster.outfielders.select{|st| st == 'c'}
|
454
452
|
coll.should == ['c']
|
455
453
|
@roster.outfielders.sort.should == ['a','b','c']
|
@@ -483,7 +481,7 @@ describe Redis::Objects do
|
|
483
481
|
end
|
484
482
|
|
485
483
|
it "should handle class-level global lists of simple values" do
|
486
|
-
Roster.all_player_stats.should
|
484
|
+
Roster.all_player_stats.should.be.empty
|
487
485
|
Roster.all_player_stats << 'a'
|
488
486
|
Roster.all_player_stats.should == ['a']
|
489
487
|
Roster.all_player_stats.get.should == ['a']
|
@@ -502,8 +500,8 @@ describe Redis::Objects do
|
|
502
500
|
Roster.all_player_stats[0].should == 'b'
|
503
501
|
Roster.all_player_stats[2].should == 'c'
|
504
502
|
Roster.all_player_stats[3].should == 'd'
|
505
|
-
Roster.all_player_stats.include?('c').should
|
506
|
-
Roster.all_player_stats.include?('no').should
|
503
|
+
Roster.all_player_stats.include?('c').should.be.true
|
504
|
+
Roster.all_player_stats.include?('no').should.be.false
|
507
505
|
Roster.all_player_stats.pop.should == 'd'
|
508
506
|
Roster.all_player_stats[0].should == Roster.all_player_stats.at(0)
|
509
507
|
Roster.all_player_stats[1].should == Roster.all_player_stats.at(1)
|
@@ -554,7 +552,7 @@ describe Redis::Objects do
|
|
554
552
|
end
|
555
553
|
|
556
554
|
it "should handle class-level global sets of simple values" do
|
557
|
-
Roster.all_players_online.should
|
555
|
+
Roster.all_players_online.should.be.empty
|
558
556
|
Roster.all_players_online << 'a' << 'a' << 'a'
|
559
557
|
Roster.all_players_online.should == ['a']
|
560
558
|
Roster.all_players_online.get.should == ['a']
|
@@ -584,9 +582,9 @@ describe Redis::Objects do
|
|
584
582
|
Roster.all_players_online.get.should == ['a','b']
|
585
583
|
|
586
584
|
Roster.all_players_online << 'c'
|
587
|
-
Roster.all_players_online.member?('c').should
|
588
|
-
Roster.all_players_online.include?('c').should
|
589
|
-
Roster.all_players_online.member?('no').should
|
585
|
+
Roster.all_players_online.member?('c').should.be.true
|
586
|
+
Roster.all_players_online.include?('c').should.be.true
|
587
|
+
Roster.all_players_online.member?('no').should.be.false
|
590
588
|
coll = Roster.all_players_online.select{|st| st == 'c'}
|
591
589
|
coll.should == ['c']
|
592
590
|
Roster.all_players_online.sort.should == ['a','b','c']
|
@@ -599,12 +597,12 @@ describe Redis::Objects do
|
|
599
597
|
Roster.last_player.get.should == 'Trevor Hoffman'
|
600
598
|
Roster.last_player = 'Tom Selleck'
|
601
599
|
Roster.last_player.should == 'Tom Selleck'
|
602
|
-
Roster.last_player.del.should
|
603
|
-
Roster.last_player.should
|
600
|
+
Roster.last_player.del.should.be.true
|
601
|
+
Roster.last_player.should.be.nil
|
604
602
|
end
|
605
603
|
|
606
604
|
it "should easily enable @object.class.global_objects" do
|
607
|
-
@roster.class.all_players_online.should
|
605
|
+
@roster.class.all_players_online.should.be.empty
|
608
606
|
@roster.class.all_players_online << 'a' << 'a' << 'a'
|
609
607
|
@roster.class.all_players_online.should == ['a']
|
610
608
|
@roster2.class.all_players_online.should == ['a']
|
@@ -612,7 +610,7 @@ describe Redis::Objects do
|
|
612
610
|
@roster.all_players_online.should == ['a']
|
613
611
|
@roster2.all_players_online.should == ['a']
|
614
612
|
|
615
|
-
@roster.class.all_player_stats.should
|
613
|
+
@roster.class.all_player_stats.should.be.empty
|
616
614
|
@roster.class.all_player_stats << 'a'
|
617
615
|
@roster.class.all_player_stats.should == ['a']
|
618
616
|
@roster.class.all_player_stats.get.should == ['a']
|
@@ -633,9 +631,9 @@ describe Redis::Objects do
|
|
633
631
|
@roster2.last_player.get.should == 'Trevor Hoffman'
|
634
632
|
@roster2.last_player = 'Tom Selleck'
|
635
633
|
@roster.last_player.should == 'Tom Selleck'
|
636
|
-
@roster.last_player.del.should
|
637
|
-
@roster.last_player.should
|
638
|
-
@roster2.last_player.should
|
634
|
+
@roster.last_player.del.should.be.true
|
635
|
+
@roster.last_player.should.be.nil
|
636
|
+
@roster2.last_player.should.be.nil
|
639
637
|
end
|
640
638
|
|
641
639
|
it "should handle lists of complex data types" do
|
@@ -664,7 +662,7 @@ describe Redis::Objects do
|
|
664
662
|
@roster.resort_lock.lock do
|
665
663
|
a = true
|
666
664
|
end
|
667
|
-
a.should
|
665
|
+
a.should.be.true
|
668
666
|
end
|
669
667
|
|
670
668
|
it "should raise an exception if the timeout is exceeded" do
|
@@ -674,7 +672,7 @@ describe Redis::Objects do
|
|
674
672
|
@roster.resort_lock.lock {}
|
675
673
|
rescue => error
|
676
674
|
end
|
677
|
-
error.
|
678
|
-
error.should
|
675
|
+
error.should.not.be.nil
|
676
|
+
error.should.be.kind_of(Redis::Lock::LockTimeout)
|
679
677
|
end
|
680
678
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
2
2
|
require 'redis'
|
3
3
|
|
4
|
+
require 'rubygems' # poor people still on 1.8
|
5
|
+
require 'bacon'
|
6
|
+
Bacon.summary_at_exit
|
7
|
+
|
4
8
|
$redis = Redis.new(:host => ENV['REDIS_HOST'], :port => ENV['REDIS_PORT'])
|
5
9
|
|
6
10
|
UNIONSTORE_KEY = 'test:unionstore'
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 2
|
9
|
+
version: 0.3.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nate Wiger
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-21 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -40,6 +40,7 @@ extensions: []
|
|
40
40
|
extra_rdoc_files:
|
41
41
|
- ATOMICITY.rdoc
|
42
42
|
- CHANGELOG.rdoc
|
43
|
+
- Rakefile
|
43
44
|
- README.rdoc
|
44
45
|
files:
|
45
46
|
- lib/redis/counter.rb
|
@@ -62,6 +63,7 @@ files:
|
|
62
63
|
- spec/spec_helper.rb
|
63
64
|
- ATOMICITY.rdoc
|
64
65
|
- CHANGELOG.rdoc
|
66
|
+
- Rakefile
|
65
67
|
- README.rdoc
|
66
68
|
has_rdoc: true
|
67
69
|
homepage: http://github.com/nateware/redis-objects
|