redis-objects 0.9.1 → 1.0.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.
@@ -25,23 +25,14 @@ class Redis
25
25
  class << self
26
26
  def expiration_filter(*names)
27
27
  names.each do |name|
28
- if ['=', '?', '!'].include? name.to_s[-1]
29
- with_name = "#{name[0..-2]}_with_expiration#{name[-1]}".to_sym
30
- without_name = "#{name[0..-2]}_without_expiration#{name[-1]}".to_sym
31
- else
32
- with_name = "#{name}_with_expiration".to_sym
33
- without_name = "#{name}_without_expiration".to_sym
34
- end
35
-
36
- alias_method without_name, name
28
+ # http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html
29
+ bind_method = instance_method(name)
37
30
 
38
- define_method(with_name) do |*args|
39
- result = send(without_name, *args)
31
+ define_method(name) do |*args, &block|
32
+ result = bind_method.bind(self).call(*args, &block)
40
33
  set_expiration
41
34
  result
42
35
  end
43
-
44
- alias_method name, with_name
45
36
  end
46
37
  end
47
38
  end
data/lib/redis/counter.rb CHANGED
@@ -113,8 +113,10 @@ class Redis
113
113
  EndOverload
114
114
  end
115
115
 
116
- expiration_filter :increment, :decrement
117
-
116
+ expiration_filter :increment, :incr, :incrby, :incrbyfloat,
117
+ :decrement, :decr, :decrby, :decrbyfloat,
118
+ :value=, :set, :reset
119
+
118
120
  private
119
121
 
120
122
  # Implements atomic increment/decrement blocks
@@ -158,7 +158,7 @@ class Redis
158
158
  def incrbyfloat(field, by=1.0)
159
159
  ret = redis.hincrbyfloat(key, field, by)
160
160
  unless ret.is_a? Array
161
- ret.to_i
161
+ ret.to_f
162
162
  else
163
163
  nil
164
164
  end
@@ -169,7 +169,9 @@ class Redis
169
169
  incrbyfloat(field, -by)
170
170
  end
171
171
 
172
- expiration_filter :[]=, :store, :bulk_set, :fill, :incrby
172
+ expiration_filter :[]=, :store, :bulk_set, :fill,
173
+ :incrby, :incr, :incrbyfloat,
174
+ :decrby, :decr, :decrbyfloat
173
175
  end
174
176
  end
175
177
 
data/lib/redis/list.rb CHANGED
@@ -70,8 +70,7 @@ class Redis
70
70
  # a range of values using Redis: LRANGE.
71
71
  def [](index, length=nil)
72
72
  if index.is_a? Range
73
- last = index.exclude_end? ? (index.last - 1) : index.last
74
- range(index.first, last)
73
+ range(index.first, index.max)
75
74
  elsif length
76
75
  case length <=> 0
77
76
  when 1 then range(index, index + length - 1)
@@ -144,6 +143,6 @@ class Redis
144
143
  values.join(', ')
145
144
  end
146
145
 
147
- expiration_filter :[]=, :push, :insert, :unshift
146
+ expiration_filter :[]=, :push, :<<, :insert, :unshift
148
147
  end
149
148
  end
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  module Objects
3
- VERSION = "0.9.1"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -41,7 +41,7 @@ class Redis
41
41
  # a range of values using Redis: ZRANGE.
42
42
  def [](index, length=nil)
43
43
  if index.is_a? Range
44
- range(index.first, index.last)
44
+ range(index.first, index.max)
45
45
  elsif length
46
46
  case length <=> 0
47
47
  when 1 then range(index, index + length - 1)
@@ -206,7 +206,8 @@ class Redis
206
206
  # Calculate the intersection and store it in Redis as +name+. Returns the number
207
207
  # of elements in the stored intersection. Redis: SUNIONSTORE
208
208
  def interstore(name, *sets)
209
- redis.zinterstore(name, keys_from_objects([self] + sets))
209
+ opts = sets.last.is_a?(Hash) ? sets.pop : {}
210
+ redis.zinterstore(key_from_object(name), keys_from_objects([self] + sets), opts)
210
211
  end
211
212
 
212
213
  # Return the union with another set. Can pass it either another set
@@ -229,7 +230,8 @@ class Redis
229
230
  # Calculate the union and store it in Redis as +name+. Returns the number
230
231
  # of elements in the stored union. Redis: SUNIONSTORE
231
232
  def unionstore(name, *sets)
232
- redis.zunionstore(name, keys_from_objects([self] + sets))
233
+ opts = sets.last.is_a?(Hash) ? sets.pop : {}
234
+ redis.zunionstore(key_from_object(name), keys_from_objects([self] + sets), opts)
233
235
  end
234
236
 
235
237
  # Return the difference vs another set. Can pass it either another set
@@ -302,13 +304,18 @@ class Redis
302
304
  !redis.zscore(key, marshal(value)).nil?
303
305
  end
304
306
 
305
- expiration_filter :[]=, :add, :merge, :diffstore, :increment, :decrement, :intersection, :interstore, :unionstore
307
+ expiration_filter :[]=, :add, :merge, :delete,
308
+ :increment, :incr, :incrby, :decrement, :decr, :decrby,
309
+ :intersection, :interstore, :unionstore, :diffstore
306
310
 
307
311
  private
312
+ def key_from_object(set)
313
+ set.is_a?(Redis::SortedSet) ? set.key : set
314
+ end
308
315
 
309
316
  def keys_from_objects(sets)
310
317
  raise ArgumentError, "Must pass in one or more set names" if sets.empty?
311
- sets.collect{|set| set.is_a?(Redis::SortedSet) ? set.key : set}
318
+ sets.collect{|set| set.is_a?(Redis::SortedSet) || set.is_a?(Redis::Set) ? set.key : set}
312
319
  end
313
320
  end
314
321
  end
data/lib/redis/value.rb CHANGED
@@ -11,7 +11,7 @@ class Redis
11
11
  attr_reader :key, :options
12
12
  def initialize(key, *args)
13
13
  super(key, *args)
14
- redis.setnx(key, marshal(@options[:default])) if @options[:default]
14
+ redis.setnx(key, marshal(@options[:default])) if !@options[:default].nil?
15
15
  end
16
16
 
17
17
  def value=(val)
@@ -14,6 +14,11 @@ describe Redis::Value do
14
14
  @value.value.should == {:json => 'data'}
15
15
  end
16
16
 
17
+ it "should be able to set the default value to false" do
18
+ @value = Redis::Value.new('spec/value', :default => false, :marshal => true)
19
+ @value.value.should == false
20
+ end
21
+
17
22
  it "should handle simple values" do
18
23
  @value.should == nil
19
24
  @value.value = 'Trevor Hoffman'
@@ -157,7 +162,7 @@ describe Redis::List do
157
162
  end
158
163
  end
159
164
 
160
- describe "with basic operations" do
165
+ describe "basic operations" do
161
166
  before do
162
167
  @list = Redis::List.new('spec/list')
163
168
  @list.clear
@@ -260,23 +265,23 @@ describe Redis::List do
260
265
  list2.should == ["b"]
261
266
  end
262
267
 
263
- it "should handle insert" do
264
- @list << 'b' << 'd'
265
- @list.insert(:before,'b','a')
266
- @list.insert(:after,'b','c')
267
- @list.insert("before",'a','z')
268
- @list.insert("after",'d','e')
269
- @list.should == ['z','a','b','c','d','e']
270
- end
271
-
272
- it "should handle insert at a specific index" do
273
- @list << 'b' << 'd'
274
- @list.should == ['b','d']
275
- @list[0] = 'a'
276
- @list.should == ['a', 'd']
277
- @list[1] = 'b'
278
- @list.should == ['a', 'b']
279
- end
268
+ it "should handle insert" do
269
+ @list << 'b' << 'd'
270
+ @list.insert(:before,'b','a')
271
+ @list.insert(:after,'b','c')
272
+ @list.insert("before",'a','z')
273
+ @list.insert("after",'d','e')
274
+ @list.should == ['z','a','b','c','d','e']
275
+ end
276
+
277
+ it "should handle insert at a specific index" do
278
+ @list << 'b' << 'd'
279
+ @list.should == ['b','d']
280
+ @list[0] = 'a'
281
+ @list.should == ['a', 'd']
282
+ @list[1] = 'b'
283
+ @list.should == ['a', 'b']
284
+ end
280
285
 
281
286
  it "should handle lists of complex data types" do
282
287
  @list.options[:marshal] = true
@@ -329,24 +334,35 @@ describe Redis::List do
329
334
  @list.redis.del('spec/list2')
330
335
  end
331
336
 
332
- it 'should set time to live in seconds when expiration option assigned' do
333
- @list = Redis::List.new('spec/list', :expiration => 10)
334
- @list << 'val'
335
- @list.ttl.should > 0
336
- @list.ttl.should <= 10
337
+ after do
338
+ @list.clear
337
339
  end
340
+ end
338
341
 
339
- it 'should set expiration when expireat option assigned' do
340
- @list = Redis::List.new('spec/list', :expireat => Time.now + 10.seconds)
341
- @list << 'val'
342
- @list.ttl.should > 0
343
- @list.ttl.should <= 10
344
- end
342
+ describe 'with expiration' do
343
+ [:[]=, :push, :<<, :insert, :unshift].each do |meth|
344
+ describe meth do
345
+ it 'expiration: option' do
346
+ @list = Redis::List.new('spec/list_exp', :expiration => 10)
347
+ @list << 'val'
348
+ @list.ttl.should > 0
349
+ @list.ttl.should <= 10
350
+ end
351
+
352
+ it 'expireat: option' do
353
+ @list = Redis::List.new('spec/list_exp', :expireat => Time.now + 10.seconds)
354
+ @list << 'val'
355
+ @list.ttl.should > 0
356
+ @list.ttl.should <= 10
357
+ end
358
+ end
345
359
 
346
- after do
347
- @list.clear
360
+ after do
361
+ @list.clear
362
+ end
348
363
  end
349
364
  end
365
+
350
366
  end
351
367
 
352
368
  describe Redis::Counter do
@@ -399,18 +415,73 @@ describe Redis::Counter do
399
415
  @counter.clear
400
416
  end
401
417
 
402
- it 'should set time to live in seconds when expiration option assigned' do
403
- @counter = Redis::Counter.new('spec/counter', :expiration => 10)
404
- @counter.increment
405
- @counter.ttl.should > 0
406
- @counter.ttl.should <= 10
418
+ it "should support an atomic block" do
419
+ @counter = Redis::Counter.new("spec/block_counter")
420
+ @counter.should == 0
421
+ @counter.increment(1)
422
+ # The block is never executed.
423
+ @updated =
424
+ @counter.increment(1) do |updated|
425
+ if updated == 2
426
+ 'yep'
427
+ else
428
+ raise("test failed")
429
+ end
430
+ end
431
+ @updated.should == 'yep'
432
+ @counter.should == 2
407
433
  end
408
434
 
409
- it 'should set expiration when expireat option assigned' do
410
- @counter = Redis::Counter.new('spec/counter', :expireat => Time.now + 10.seconds)
411
- @counter.increment
412
- @counter.ttl.should > 0
413
- @counter.ttl.should <= 10
435
+ describe 'with expiration' do
436
+ it 'should set time to live in seconds' do
437
+ @counter = Redis::Counter.new('spec/counter', :expiration => 10)
438
+ @counter.increment
439
+ @counter.ttl.should > 0
440
+ @counter.ttl.should <= 10
441
+ end
442
+
443
+ [:increment, :incr, :incrby, :incrbyfloat,
444
+ :decrement, :decr, :decrby, :decrbyfloat, :reset].each do |meth|
445
+ describe meth do
446
+ it "expiration: option" do
447
+ @counter = Redis::Counter.new('spec/counter_exp', :expiration => 10)
448
+ @counter.send(meth)
449
+ @counter.ttl.should > 0
450
+ @counter.ttl.should <= 10
451
+ end
452
+ it "expireat: option" do
453
+ @counter = Redis::Counter.new('spec/counter_exp', :expireat => Time.now + 10.seconds)
454
+ @counter.send(meth)
455
+ @counter.ttl.should > 0
456
+ @counter.ttl.should <= 10
457
+ end
458
+ after do
459
+ @counter.reset
460
+ end
461
+ end
462
+ end
463
+
464
+ [:set, :value=].each do |meth|
465
+ describe meth do
466
+ it "expiration: option" do
467
+ @counter = Redis::Counter.new('spec/counter_exp', :expireat => Time.now + 10.seconds)
468
+ @counter.send(meth, 99)
469
+ @counter.should == 99
470
+ @counter.ttl.should > 0
471
+ @counter.ttl.should <= 10
472
+ end
473
+ it "expireat: option" do
474
+ @counter = Redis::Counter.new('spec/counter_exp', :expireat => Time.now + 10.seconds)
475
+ @counter.send(meth, 99)
476
+ @counter.should == 99
477
+ @counter.ttl.should > 0
478
+ @counter.ttl.should <= 10
479
+ end
480
+ after do
481
+ @counter.reset
482
+ end
483
+ end
484
+ end
414
485
  end
415
486
 
416
487
  after do
@@ -647,7 +718,7 @@ describe Redis::HashKey do
647
718
  @hash['float'] = '5.0e3'
648
719
  @hash.incrbyfloat('float')
649
720
  @hash.incrbyfloat('float', '1.23e3')
650
- @hash.incrbyfloat('float', 45.3)
721
+ @hash.incrbyfloat('float', 45.3).should == 6276.3
651
722
  @hash.get('float').to_f.should == 6276.3
652
723
  end
653
724
 
@@ -704,10 +775,11 @@ describe Redis::HashKey do
704
775
  @hash['foo'].should == 'bar'
705
776
  @hash['abc'].should == '123'
706
777
  @hash['bang'].should == 'michael'
778
+ @hash.keys.sort.should == ['abc', 'bang', 'foo']
779
+ end
707
780
 
708
- it "raises an error if a non-Hash is passed to fill" do
709
- lambda { @hash.fill([]) }.should.raise(ArgumentError)
710
- end
781
+ it "raises an error if a non-Hash is passed to fill" do
782
+ lambda { @hash.fill([]) }.should.raise(ArgumentError)
711
783
  end
712
784
 
713
785
  it "should fetch default values" do
@@ -722,18 +794,28 @@ describe Redis::HashKey do
722
794
  block.should == "oops: missing_key"
723
795
  end
724
796
 
725
- it 'should set time to live in seconds when expiration option assigned' do
726
- @hash = Redis::HashKey.new('spec/hash_key', :expiration => 10)
727
- @hash['foo'] = 'bar'
728
- @hash.ttl.should > 0
729
- @hash.ttl.should <= 10
730
- end
731
-
732
- it 'should set expiration when expireat option assigned' do
733
- @hash = Redis::HashKey.new('spec/hash_key', :expireat => Time.now + 10.seconds)
734
- @hash['foo'] = 'bar'
735
- @hash.ttl.should > 0
736
- end
797
+ #[:[]=, :store, :bulk_set, :fill,
798
+ describe 'with expiration' do
799
+ [:incrby, :incr, :incrbyfloat, :decrby, :decr, :decrbyfloat].each do |meth|
800
+ describe meth do
801
+ it "expiration: option" do
802
+ @hash = Redis::HashKey.new('spec/hash_exp', :expiration => 10)
803
+ @hash.send(meth, 'somekey')
804
+ @hash.ttl.should > 0
805
+ @hash.ttl.should <= 10
806
+ end
807
+ it "expireat: option" do
808
+ @hash = Redis::HashKey.new('spec/hash_exp', :expireat => Time.now + 10.seconds)
809
+ @hash.send(meth, 'somekey')
810
+ @hash.ttl.should > 0
811
+ @hash.ttl.should <= 10
812
+ end
813
+ after do
814
+ @hash.clear
815
+ end
816
+ end
817
+ end
818
+ end
737
819
 
738
820
  after do
739
821
  @hash.clear
@@ -884,14 +966,14 @@ describe Redis::Set do
884
966
  @set_2.sort(SORT_LIMIT).should == %w(3 4)
885
967
 
886
968
  @set_3 << 'm_4' << 'm_5' << 'm_1' << 'm_3' << 'm_2'
887
- ### incorrect interpretation of what the :by parameter means
888
- ### :by will look up values of keys so it would try to find a value in
889
- ### redis of "m_m_1" which doesn't exist at this point, it is not a way to
890
- ### alter the value to sort by but rather use a different value for this value
891
- ### in the set (Kris Fox)
969
+ ### incorrect interpretation of what the :by parameter means
970
+ ### :by will look up values of keys so it would try to find a value in
971
+ ### redis of "m_m_1" which doesn't exist at this point, it is not a way to
972
+ ### alter the value to sort by but rather use a different value for this value
973
+ ### in the set (Kris Fox)
892
974
  # @set_3.sort(:by => 'm_*').should == %w(m_1 m_2 m_3 m_4 m_5)
893
- # below passes just fine
894
- @set_3.sort.should == %w(m_1 m_2 m_3 m_4 m_5)
975
+ # below passes just fine
976
+ @set_3.sort.should == %w(m_1 m_2 m_3 m_4 m_5)
895
977
 
896
978
  val1 = Redis::Value.new('spec/3/sorted')
897
979
  val2 = Redis::Value.new('spec/4/sorted')
@@ -938,11 +1020,13 @@ describe Redis::SortedSet do
938
1020
  @set_2 = Redis::SortedSet.new('spec/zset_2')
939
1021
  @set_3 = Redis::SortedSet.new('spec/zset_3')
940
1022
  @set_4 = Redis::SortedSet.new('spec/zset_3', :marshal => true)
1023
+ @set_5 = Redis::Set.new('spec/zset_4')
941
1024
  @set.clear
942
1025
  @set_1.clear
943
1026
  @set_2.clear
944
1027
  @set_3.clear
945
1028
  @set_4.clear
1029
+ @set_5.clear
946
1030
  end
947
1031
 
948
1032
  it "should handle sorted sets of simple values" do
@@ -960,6 +1044,7 @@ describe Redis::SortedSet do
960
1044
  a = @set.members
961
1045
  @set[0,-1].should == a[0,-1]
962
1046
  @set[0..2].should == a[0..2]
1047
+ @set[0...2].should == a[0...2]
963
1048
  @set.slice(0..2).should == a.slice(0..2)
964
1049
  @set[0, 2].should == a[0,2]
965
1050
  @set.slice(0, 2).should == a.slice(0, 2)
@@ -1088,6 +1173,74 @@ describe Redis::SortedSet do
1088
1173
  @set.redis.del('spec/zset2')
1089
1174
  end
1090
1175
 
1176
+ it "should handle unions" do
1177
+ @set_1.add('a', 1)
1178
+ @set_1.add('b', 4)
1179
+ @set_1.add('c', 3)
1180
+
1181
+ @set_2.add('b', 2)
1182
+ @set_2.add('c', 1)
1183
+ @set_2.add('d', 0)
1184
+
1185
+ @set_1.unionstore(@set.key, @set_2)
1186
+ # @set is now: [[d, 0], [a, 1], [c, 4], [b, 6]]
1187
+ @set.members.should == ['d', 'a', 'c', 'b']
1188
+
1189
+ @set_2.unionstore(@set, @set_1, :aggregate => :sum)
1190
+ # @set is now: [[d, 0], [a, 1], [c, 4], [b, 6]]
1191
+ @set.members.should == ['d', 'a', 'c', 'b']
1192
+
1193
+ @set_1.unionstore(@set, @set_2, :aggregate => :min)
1194
+ # @set is now: [[d, 0], [a, 1], [c, 1], [b, 2]]
1195
+ @set.members.should == ['d', 'a', 'c', 'b']
1196
+ @set['b'].should == 2
1197
+
1198
+ @set_1.unionstore(@set, @set_2, :aggregate => :max)
1199
+ # @set is now: [[d, 0], [a, 1], [c, 3], [b, 4]]
1200
+ @set.members.should == ['d', 'a', 'c', 'b']
1201
+ @set['b'].should == 4
1202
+
1203
+ @set_1.unionstore(@set, @set_2, :aggregate => :sum, :weights => [0, 1])
1204
+ # @set is now: [[a, 0], [d, 0], [c, 1], [b, 2]]
1205
+ @set.members.should == ['a', 'd', 'c', 'b']
1206
+ @set['b'].should == 2
1207
+
1208
+ @set_5 << ['a', 'e', 'f']
1209
+ @set_1.unionstore(@set, @set_5, :aggregate => :sum)
1210
+ # #set is now: [[e, 1], [f, 1], [a, 1], [c, 3], [b, 4]]
1211
+ @set.members.should == ['e', 'f', 'a', 'c', 'b']
1212
+ @set['e'].should == 1
1213
+ end
1214
+
1215
+ it "should handle intersections" do
1216
+ @set_1.add('a', 1)
1217
+ @set_1.add('b', 4)
1218
+ @set_1.add('c', 3)
1219
+
1220
+ @set_2.add('b', 2)
1221
+ @set_2.add('c', 1)
1222
+ @set_2.add('d', 0)
1223
+
1224
+ @set_1.interstore(@set.key, @set_2)
1225
+ # @set is now: [[c, 4], [b, 6]]
1226
+ @set.members.should == ['c', 'b']
1227
+
1228
+ @set_2.interstore(@set, @set_1, :aggregate => :sum)
1229
+ # @set is now: [[c, 4], [b, 6]]
1230
+ @set.members.should == ['c', 'b']
1231
+
1232
+ @set_1.interstore(@set, @set_2, :aggregate => :min)
1233
+ # @set is now: [[c, 1], [b, 2]]
1234
+ @set.members.should == ['c', 'b']
1235
+ @set['b'].should == 2
1236
+
1237
+ @set_5 << ['a', 'e', 'b']
1238
+ @set_1.interstore(@set, @set_5, :aggregate => :max)
1239
+ # @set is now: [[a, 1], [b, 4]]
1240
+ @set.members.should == ['a', 'b']
1241
+ @set['b'].should == 4
1242
+ end
1243
+
1091
1244
  it 'should set time to live in seconds when expiration option assigned' do
1092
1245
  @set = Redis::SortedSet.new('spec/zset', :expiration => 10)
1093
1246
  @set['val'] = 1
@@ -1102,11 +1255,34 @@ describe Redis::SortedSet do
1102
1255
  @set.ttl.should <= 10
1103
1256
  end
1104
1257
 
1258
+ describe "with expiration" do
1259
+ [:[]=, :add, :increment, :incr, :incrby, :decrement, :decr, :decrby].each do |meth|
1260
+ describe meth do
1261
+ it "expiration: option" do
1262
+ @hash = Redis::SortedSet.new('spec/zset_exp', :expiration => 10)
1263
+ @hash.send(meth, 'somekey', 12)
1264
+ @hash.ttl.should > 0
1265
+ @hash.ttl.should <= 10
1266
+ end
1267
+ it "expireat: option" do
1268
+ @hash = Redis::SortedSet.new('spec/zset_exp', :expireat => Time.now + 10.seconds)
1269
+ @hash.send(meth, 'somekey', 12)
1270
+ @hash.ttl.should > 0
1271
+ @hash.ttl.should <= 10
1272
+ end
1273
+ after do
1274
+ @hash.clear
1275
+ end
1276
+ end
1277
+ end
1278
+ end
1279
+
1105
1280
  after do
1106
1281
  @set.clear
1107
1282
  @set_1.clear
1108
1283
  @set_2.clear
1109
1284
  @set_3.clear
1110
1285
  @set_4.clear
1286
+ @set_5.clear
1111
1287
  end
1112
1288
  end