redis-objects 0.8.0 → 0.9.1

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
@@ -9,8 +9,6 @@ class Redis
9
9
  include Enumerable
10
10
  require 'redis/helpers/core_commands'
11
11
  include Redis::Helpers::CoreCommands
12
- require 'redis/helpers/serialize'
13
- include Redis::Helpers::Serialize
14
12
 
15
13
  attr_reader :key, :options
16
14
 
@@ -23,49 +21,54 @@ class Redis
23
21
  # Add the specified value to the set only if it does not exist already.
24
22
  # Redis: SADD
25
23
  def add(value)
26
- redis.sadd(key, to_redis(value))
24
+ redis.sadd(key, marshal(value)) if value.nil? || !Array(value).empty?
27
25
  end
28
26
 
29
27
  # Remove and return a random member. Redis: SPOP
30
28
  def pop
31
- from_redis redis.spop(key)
29
+ unmarshal redis.spop(key)
30
+ end
31
+
32
+ # return a random member. Redis: SRANDMEMBER
33
+ def randmember
34
+ unmarshal redis.srandmember(key)
32
35
  end
33
36
 
34
37
  # Adds the specified values to the set. Only works on redis > 2.4
35
38
  # Redis: SADD
36
39
  def merge(*values)
37
- redis.sadd(key, values.flatten.map{|v| to_redis(v)})
40
+ redis.sadd(key, values.flatten.map{|v| marshal(v)})
38
41
  end
39
42
 
40
43
  # Return all members in the set. Redis: SMEMBERS
41
44
  def members
42
- v = from_redis redis.smembers(key)
43
- v.nil? ? [] : v
45
+ vals = redis.smembers(key)
46
+ vals.nil? ? [] : vals.map{|v| unmarshal(v) }
44
47
  end
45
48
  alias_method :get, :members
46
49
 
47
50
  # Returns true if the specified value is in the set. Redis: SISMEMBER
48
51
  def member?(value)
49
- redis.sismember(key, to_redis(value))
52
+ redis.sismember(key, marshal(value))
50
53
  end
51
54
  alias_method :include?, :member?
52
-
55
+
53
56
  # Delete the value from the set. Redis: SREM
54
57
  def delete(value)
55
- redis.srem(key, to_redis(value))
58
+ redis.srem(key, marshal(value))
56
59
  end
57
-
60
+
58
61
  # Delete if matches block
59
62
  def delete_if(&block)
60
63
  res = false
61
64
  redis.smembers(key).each do |m|
62
- if block.call(from_redis(m))
65
+ if block.call(unmarshal(m))
63
66
  res = redis.srem(key, m)
64
67
  end
65
68
  end
66
69
  res
67
70
  end
68
-
71
+
69
72
  # Iterate through each member of the set. Redis::Objects mixes in Enumerable,
70
73
  # so you can also use familiar methods like +collect+, +detect+, and so forth.
71
74
  def each(&block)
@@ -84,12 +87,12 @@ class Redis
84
87
  #
85
88
  # Redis: SINTER
86
89
  def intersection(*sets)
87
- from_redis redis.sinter(key, *keys_from_objects(sets))
90
+ redis.sinter(key, *keys_from_objects(sets)).map{|v| unmarshal(v)}
88
91
  end
89
92
  alias_method :intersect, :intersection
90
93
  alias_method :inter, :intersection
91
94
  alias_method :&, :intersection
92
-
95
+
93
96
  # Calculate the intersection and store it in Redis as +name+. Returns the number
94
97
  # of elements in the stored intersection. Redis: SUNIONSTORE
95
98
  def interstore(name, *sets)
@@ -108,7 +111,7 @@ class Redis
108
111
  #
109
112
  # Redis: SUNION
110
113
  def union(*sets)
111
- from_redis redis.sunion(key, *keys_from_objects(sets))
114
+ redis.sunion(key, *keys_from_objects(sets)).map{|v| unmarshal(v)}
112
115
  end
113
116
  alias_method :|, :union
114
117
  alias_method :+, :union
@@ -132,7 +135,7 @@ class Redis
132
135
  #
133
136
  # Redis: SDIFF
134
137
  def difference(*sets)
135
- from_redis redis.sdiff(key, *keys_from_objects(sets))
138
+ redis.sdiff(key, *keys_from_objects(sets)).map{|v| unmarshal(v)}
136
139
  end
137
140
  alias_method :diff, :difference
138
141
  alias_method :^, :difference
@@ -172,17 +175,19 @@ class Redis
172
175
  def ==(x)
173
176
  members == x
174
177
  end
175
-
178
+
176
179
  def to_s
177
180
  members.join(', ')
178
181
  end
179
182
 
183
+ expiration_filter :add
184
+
180
185
  private
181
-
186
+
182
187
  def keys_from_objects(sets)
183
188
  raise ArgumentError, "Must pass in one or more set names" if sets.empty?
184
189
  sets.collect{|set| set.is_a?(Redis::Set) ? set.key : set}
185
190
  end
186
-
191
+
187
192
  end
188
193
  end
@@ -9,8 +9,6 @@ class Redis
9
9
  # include Enumerable
10
10
  require 'redis/helpers/core_commands'
11
11
  include Redis::Helpers::CoreCommands
12
- require 'redis/helpers/serialize'
13
- include Redis::Helpers::Serialize
14
12
 
15
13
  attr_reader :key, :options
16
14
 
@@ -25,9 +23,19 @@ class Redis
25
23
  # arguments to this are flipped; the member comes first rather than
26
24
  # the score, since the member is the unique item (not the score).
27
25
  def add(member, score)
28
- redis.zadd(key, score, to_redis(member))
26
+ redis.zadd(key, score, marshal(member))
29
27
  end
30
28
 
29
+ # Add a list of members and their corresponding value (or a hash mapping
30
+ # values to scores) to Redis. Note that the arguments to this are flipped;
31
+ # the member comes first rather than the score, since the member is the unique
32
+ # item (not the score).
33
+ def merge(values)
34
+ vals = values.map{|v,s| [s, marshal(v)] }
35
+ redis.zadd(key, vals)
36
+ end
37
+ alias_method :add_all, :merge
38
+
31
39
  # Same functionality as Ruby arrays. If a single number is given, return
32
40
  # just the element at that index using Redis: ZRANGE. Otherwise, return
33
41
  # a range of values using Redis: ZRANGE.
@@ -50,7 +58,7 @@ class Redis
50
58
  # specified element does not exist in the sorted set, or the key does not exist
51
59
  # at all, nil is returned. Redis: ZSCORE.
52
60
  def score(member)
53
- result = redis.zscore(key, to_redis(member))
61
+ result = redis.zscore(key, marshal(member))
54
62
 
55
63
  result.to_f unless result.nil?
56
64
  end
@@ -60,7 +68,7 @@ class Redis
60
68
  # When the given member does not exist in the sorted set, nil is returned.
61
69
  # The returned rank (or index) of the member is 0-based for both commands
62
70
  def rank(member)
63
- if n = redis.zrank(key, to_redis(member))
71
+ if n = redis.zrank(key, marshal(member))
64
72
  n.to_i
65
73
  else
66
74
  nil
@@ -68,7 +76,7 @@ class Redis
68
76
  end
69
77
 
70
78
  def revrank(member)
71
- if n = redis.zrevrank(key, to_redis(member))
79
+ if n = redis.zrevrank(key, marshal(member))
72
80
  n.to_i
73
81
  else
74
82
  nil
@@ -78,26 +86,25 @@ class Redis
78
86
  # Return all members of the sorted set with their scores. Extremely CPU-intensive.
79
87
  # Better to use a range instead.
80
88
  def members(options={})
81
- v = from_redis range(0, -1, options)
82
- v.nil? ? [] : v
89
+ range(0, -1, options) || []
83
90
  end
84
91
 
85
92
  # Return a range of values from +start_index+ to +end_index+. Can also use
86
93
  # the familiar list[start,end] Ruby syntax. Redis: ZRANGE
87
94
  def range(start_index, end_index, options={})
88
95
  if options[:withscores] || options[:with_scores]
89
- from_redis redis.zrange(key, start_index, end_index, :with_scores => true)
96
+ redis.zrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
90
97
  else
91
- from_redis redis.zrange(key, start_index, end_index)
98
+ redis.zrange(key, start_index, end_index).map{|v| unmarshal(v) }
92
99
  end
93
100
  end
94
101
 
95
102
  # Return a range of values from +start_index+ to +end_index+ in reverse order. Redis: ZREVRANGE
96
103
  def revrange(start_index, end_index, options={})
97
104
  if options[:withscores] || options[:with_scores]
98
- from_redis redis.zrevrange(key, start_index, end_index, :with_scores => true)
105
+ redis.zrevrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
99
106
  else
100
- from_redis redis.zrevrange(key, start_index, end_index)
107
+ redis.zrevrange(key, start_index, end_index).map{|v| unmarshal(v) }
101
108
  end
102
109
  end
103
110
 
@@ -112,7 +119,7 @@ class Redis
112
119
  options[:offset] || options[:limit] || options[:count]
113
120
  args[:with_scores] = true if options[:withscores] || options[:with_scores]
114
121
 
115
- from_redis redis.zrangebyscore(key, min, max, args)
122
+ redis.zrangebyscore(key, min, max, args).map{|v| unmarshal(v) }
116
123
  end
117
124
 
118
125
  # Returns all the elements in the sorted set at key with a score between max and min
@@ -128,7 +135,7 @@ class Redis
128
135
  options[:offset] || options[:limit] || options[:count]
129
136
  args[:with_scores] = true if options[:withscores] || options[:with_scores]
130
137
 
131
- from_redis redis.zrevrangebyscore(key, max, min, args)
138
+ redis.zrevrangebyscore(key, max, min, args).map{|v| unmarshal(v) }
132
139
  end
133
140
 
134
141
  # Remove all elements in the sorted set at key with rank between start and end. Start and end are
@@ -148,7 +155,7 @@ class Redis
148
155
 
149
156
  # Delete the value from the set. Redis: ZREM
150
157
  def delete(value)
151
- redis.zrem(key, to_redis(value))
158
+ redis.zrem(key, marshal(value))
152
159
  end
153
160
 
154
161
  # Delete element if it matches block
@@ -156,7 +163,7 @@ class Redis
156
163
  raise ArgumentError, "Missing block to SortedSet#delete_if" unless block_given?
157
164
  res = false
158
165
  redis.zrange(key, 0, -1).each do |m|
159
- if block.call(from_redis(m))
166
+ if block.call(unmarshal(m))
160
167
  res = redis.zrem(key, m)
161
168
  end
162
169
  end
@@ -166,14 +173,14 @@ class Redis
166
173
  # Increment the rank of that member atomically and return the new value. This
167
174
  # method is aliased as incr() for brevity. Redis: ZINCRBY
168
175
  def increment(member, by=1)
169
- redis.zincrby(key, by, to_redis(member)).to_i
176
+ redis.zincrby(key, by, marshal(member)).to_i
170
177
  end
171
178
  alias_method :incr, :increment
172
179
  alias_method :incrby, :increment
173
180
 
174
181
  # Convenience to calling increment() with a negative number.
175
182
  def decrement(member, by=1)
176
- redis.zincrby(key, -by, to_redis(member)).to_i
183
+ redis.zincrby(key, -by, marshal(member)).to_i
177
184
  end
178
185
  alias_method :decr, :decrement
179
186
  alias_method :decrby, :decrement
@@ -190,7 +197,7 @@ class Redis
190
197
  #
191
198
  # Redis: SINTER
192
199
  def intersection(*sets)
193
- from_redis redis.zinter(key, *keys_from_objects(sets))
200
+ redis.zinter(key, *keys_from_objects(sets)).map{|v| unmarshal(v) }
194
201
  end
195
202
  alias_method :intersect, :intersection
196
203
  alias_method :inter, :intersection
@@ -214,7 +221,7 @@ class Redis
214
221
  #
215
222
  # Redis: SUNION
216
223
  def union(*sets)
217
- from_redis redis.zunion(key, *keys_from_objects(sets))
224
+ redis.zunion(key, *keys_from_objects(sets)).map{|v| unmarshal(v) }
218
225
  end
219
226
  alias_method :|, :union
220
227
  alias_method :+, :union
@@ -238,7 +245,7 @@ class Redis
238
245
  #
239
246
  # Redis: SDIFF
240
247
  def difference(*sets)
241
- from_redis redis.zdiff(key, *keys_from_objects(sets))
248
+ redis.zdiff(key, *keys_from_objects(sets)).map{|v| unmarshal(v) }
242
249
  end
243
250
  alias_method :diff, :difference
244
251
  alias_method :^, :difference
@@ -292,9 +299,11 @@ class Redis
292
299
 
293
300
  # Return a boolean indicating whether +value+ is a member.
294
301
  def member?(value)
295
- !redis.zscore(key, to_redis(value)).nil?
302
+ !redis.zscore(key, marshal(value)).nil?
296
303
  end
297
304
 
305
+ expiration_filter :[]=, :add, :merge, :diffstore, :increment, :decrement, :intersection, :interstore, :unionstore
306
+
298
307
  private
299
308
 
300
309
  def keys_from_objects(sets)
data/lib/redis/value.rb CHANGED
@@ -7,26 +7,24 @@ class Redis
7
7
  class Value < BaseObject
8
8
  require 'redis/helpers/core_commands'
9
9
  include Redis::Helpers::CoreCommands
10
- require 'redis/helpers/serialize'
11
- include Redis::Helpers::Serialize
12
10
 
13
11
  attr_reader :key, :options
14
12
  def initialize(key, *args)
15
13
  super(key, *args)
16
- redis.setnx(key, to_redis(@options[:default])) if @options[:default]
14
+ redis.setnx(key, marshal(@options[:default])) if @options[:default]
17
15
  end
18
16
 
19
17
  def value=(val)
20
18
  if val.nil?
21
19
  delete
22
20
  else
23
- redis.set key, to_redis(val)
21
+ redis.set key, marshal(val)
24
22
  end
25
23
  end
26
24
  alias_method :set, :value=
27
25
 
28
26
  def value
29
- from_redis redis.get(key)
27
+ unmarshal redis.get(key)
30
28
  end
31
29
  alias_method :get, :value
32
30
 
@@ -42,5 +40,7 @@ class Redis
42
40
  def method_missing(*args)
43
41
  self.value.send *args
44
42
  end
43
+
44
+ expiration_filter :value=
45
45
  end
46
46
  end
@@ -9,6 +9,38 @@ BAD_REDIS = "totally bad bogus redis handle"
9
9
 
10
10
  # Grab a global handle
11
11
  describe 'Connection tests' do
12
+ it "should support overriding object handles" do
13
+
14
+ class CustomConnectionObject
15
+ include Redis::Objects
16
+
17
+ def id
18
+ return 1
19
+ end
20
+
21
+ redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31)
22
+ value :redis_value, :redis => redis_handle, :key => 'rval'
23
+ value :default_redis_value, :key => 'rval'
24
+ end
25
+
26
+ obj = CustomConnectionObject.new
27
+
28
+ obj.default_redis_value.value.should == nil
29
+ obj.redis_value.value.should == nil
30
+
31
+ obj.default_redis_value.value = 'foo'
32
+ obj.default_redis_value.value.should == 'foo'
33
+ obj.redis_value.value.should == nil
34
+
35
+ obj.default_redis_value.clear
36
+ obj.redis_value.value = 'foo'
37
+ obj.redis_value.value.should == 'foo'
38
+ obj.default_redis_value.value.should == nil
39
+
40
+ obj.redis_value.clear
41
+ obj.default_redis_value.clear
42
+ end
43
+
12
44
  it "should support local handles" do
13
45
  Redis.current = nil # reset from other tests
14
46
  Redis::Objects.redis = nil
@@ -100,5 +132,3 @@ describe 'Connection tests' do
100
132
  end
101
133
 
102
134
  end
103
-
104
-
@@ -46,6 +46,24 @@ describe Redis::Value do
46
46
  @value.options[:marshal] = false
47
47
  end
48
48
 
49
+ it "should not erroneously unmarshall a string" do
50
+ json_string = {json: 'value'}
51
+ @value = Redis::Value.new('spec/value', :marshal => true)
52
+ @value.value = json_string
53
+ @value.value.should == json_string
54
+ @value.clear
55
+
56
+ default_json_string = {json: 'default'}
57
+ @value = Redis::Value.new('spec/default', :default => default_json_string, :marshal => true)
58
+ @value.value.should == default_json_string
59
+ @value.clear
60
+
61
+ marshalled_string = Marshal.dump({json: 'marshal'})
62
+ @value = Redis::Value.new('spec/marshal', :default => marshalled_string, :marshal => true)
63
+ @value.value.should == marshalled_string
64
+ @value.clear
65
+ end
66
+
49
67
  it "should support renaming values" do
50
68
  @value.value = 'Peter Pan'
51
69
  @value.key.should == 'spec/value'
@@ -86,6 +104,19 @@ describe Redis::Value do
86
104
  @value.nil?.should == true
87
105
  end
88
106
 
107
+ it 'should set time to live in seconds when expiration option assigned' do
108
+ @value = Redis::Value.new('spec/value', :expiration => 10)
109
+ @value.value = 'monkey'
110
+ @value.ttl.should > 0
111
+ @value.ttl.should <= 10
112
+ end
113
+
114
+ it 'should set expiration when expireat option assigned' do
115
+ @value = Redis::Value.new('spec/value', :expireat => Time.now + 10.seconds)
116
+ @value.value = 'monkey'
117
+ @value.ttl.should > 0
118
+ end
119
+
89
120
  after do
90
121
  @value.delete
91
122
  end
@@ -298,6 +329,20 @@ describe Redis::List do
298
329
  @list.redis.del('spec/list2')
299
330
  end
300
331
 
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
+ end
338
+
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
345
+
301
346
  after do
302
347
  @list.clear
303
348
  end
@@ -341,6 +386,33 @@ describe Redis::Counter do
341
386
  @counter.should == 111
342
387
  end
343
388
 
389
+ it "should support increment/decrement by float" do
390
+ @counter = Redis::Counter.new('spec/floater')
391
+ @counter.set 10.5
392
+ @counter.incrbyfloat 1
393
+ @counter.incrbyfloat 0.01
394
+ @counter.to_f.should == 11.51
395
+ @counter.set '5.0e3'
396
+ @counter.decrbyfloat -14.31
397
+ @counter.incrbyfloat 2.0e2
398
+ @counter.to_f.should == 5214.31
399
+ @counter.clear
400
+ end
401
+
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
407
+ end
408
+
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
414
+ end
415
+
344
416
  after do
345
417
  @counter.delete
346
418
  end
@@ -473,8 +545,8 @@ describe Redis::HashKey do
473
545
  it "should handle complex marshaled values" do
474
546
  @hash.options[:marshal] = true
475
547
  @hash['abc'].should == nil
476
- @hash['abc'] = {:json => 'data'}
477
- @hash['abc'].should == {:json => 'data'}
548
+ @hash['abc'] = {:json => 'hash marshal'}
549
+ @hash['abc'].should == {:json => 'hash marshal'}
478
550
 
479
551
  # no marshaling
480
552
  @hash.options[:marshal] = false
@@ -508,6 +580,18 @@ describe Redis::HashKey do
508
580
  @hash.options[:marshal] = false
509
581
  end
510
582
 
583
+ it "should marshal nil correctly" do
584
+ @hash.options[:marshal] = true
585
+
586
+ @hash['test'].should.be.nil
587
+ @hash['test'] = nil
588
+ @hash['test'].should.be.nil
589
+ @hash.delete('test').should == 1
590
+ @hash['test'].should.be.nil
591
+
592
+ @hash.options[:marshal] = false
593
+ end
594
+
511
595
  it "should get and set values" do
512
596
  @hash['foo'] = 'bar'
513
597
  @hash['foo'].should == 'bar'
@@ -544,6 +628,29 @@ describe Redis::HashKey do
544
628
  end
545
629
  end
546
630
 
631
+ it "should handle increment/decrement" do
632
+ @hash['integer'] = 1
633
+ @hash.incrby('integer')
634
+ @hash.incrby('integer', 2)
635
+ @hash.get('integer').to_i.should == 4
636
+
637
+ @hash['integer'] = 9
638
+ @hash.decrby('integer')
639
+ @hash.decrby('integer', 6)
640
+ @hash.get('integer').to_i.should == 2
641
+
642
+ @hash['float'] = 12.34
643
+ @hash.decrbyfloat('float')
644
+ @hash.decrbyfloat('float', 6.3)
645
+ @hash.get('float').to_f.should == 5.04
646
+
647
+ @hash['float'] = '5.0e3'
648
+ @hash.incrbyfloat('float')
649
+ @hash.incrbyfloat('float', '1.23e3')
650
+ @hash.incrbyfloat('float', 45.3)
651
+ @hash.get('float').to_f.should == 6276.3
652
+ end
653
+
547
654
  it "should respond to each_value" do
548
655
  @hash['foo'] = 'bar'
549
656
  @hash.each_value do |val|
@@ -603,6 +710,31 @@ describe Redis::HashKey do
603
710
  end
604
711
  end
605
712
 
713
+ it "should fetch default values" do
714
+ @hash['abc'] = "123"
715
+
716
+ value = @hash.fetch('missing_key','default_value')
717
+ block = @hash.fetch("missing_key") {|key| "oops: #{key}" }
718
+ no_error = @hash.fetch("abc") rescue "error"
719
+
720
+ no_error.should == "123"
721
+ value.should == "default_value"
722
+ block.should == "oops: missing_key"
723
+ end
724
+
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
737
+
606
738
  after do
607
739
  @hash.clear
608
740
  end
@@ -665,6 +797,17 @@ describe Redis::Set do
665
797
  @set.sort.should == ['a','b','c']
666
798
  @set.delete_if{|m| m == 'c'}
667
799
  @set.sort.should == ['a','b']
800
+
801
+ @set << nil
802
+ @set.include?("").should.be.true
803
+ end
804
+
805
+ it "should handle empty array adds" do
806
+ should.not.raise(Redis::CommandError) { @set.add([]) }
807
+ @set.should.be.empty
808
+
809
+ should.not.raise(Redis::CommandError) { @set << [] }
810
+ @set.should.be.empty
668
811
  end
669
812
 
670
813
  it "should handle set intersections, unions, and diffs" do
@@ -764,7 +907,20 @@ describe Redis::Set do
764
907
  @set_1.redis.del val1.key
765
908
  @set_1.redis.del val2.key
766
909
  @set_1.redis.del SORT_STORE[:store]
910
+ end
767
911
 
912
+ it 'should set time to live in seconds when expiration option assigned' do
913
+ @set = Redis::Set.new('spec/set', :expiration => 10)
914
+ @set << 'val'
915
+ @set.ttl.should > 0
916
+ @set.ttl.should <= 10
917
+ end
918
+
919
+ it 'should set expiration when expireat option assigned' do
920
+ @set = Redis::Set.new('spec/set', :expireat => Time.now + 10.seconds)
921
+ @set << 'val'
922
+ @set.ttl.should > 0
923
+ @set.ttl.should <= 10
768
924
  end
769
925
 
770
926
  after do
@@ -810,6 +966,7 @@ describe Redis::SortedSet do
810
966
  @set.range(0, 2).should == a[0..2]
811
967
  @set[0, 0].should == []
812
968
  @set.range(0,1,:withscores => true).should == [['a',3],['c',4]]
969
+ @set.revrange(0,1,:withscores => true).should == [['b',5.6],['c',4]]
813
970
  @set.range(0,-1).should == a[0..-1]
814
971
  @set.revrange(0,-1).should == a[0..-1].reverse
815
972
  @set[0..1].should == a[0..1]
@@ -823,6 +980,8 @@ describe Redis::SortedSet do
823
980
  @set.members(:withscores => true).should == [['a',3],['c',4],['b',5.6]]
824
981
  @set.members(:with_scores => true).should == [['a',3],['c',4],['b',5.6]]
825
982
  @set.members(:withscores => true).reverse.should == [['b',5.6],['c',4],['a',3]]
983
+ @set.members(:withscores => true).should == @set.range(0,-1,:withscores => true)
984
+ @set.members(:withscores => true).reverse.should == @set.revrange(0,-1,:withscores => true)
826
985
 
827
986
  @set['b'] = 5
828
987
  @set['b'] = 6
@@ -882,13 +1041,33 @@ describe Redis::SortedSet do
882
1041
  @set.size.should == 3
883
1042
  end
884
1043
 
1044
+ it "should handle inserting multiple values at once" do
1045
+ @set.merge({ 'a' => 1, 'b' => 2 })
1046
+ @set.merge([['a', 4], ['c', 5]])
1047
+ @set.merge({d: 0, e: 9 })
1048
+
1049
+ @set.members.should == ["d", "b", "a", "c", "e"]
1050
+
1051
+ @set[:f] = 3
1052
+ @set.members.should == ["d", "b", "f", "a", "c", "e"]
1053
+ end
1054
+
885
1055
  it "should support marshaling key names" do
1056
+ @set_4.members.should == []
1057
+
886
1058
  @set_4[Object] = 1.20
887
1059
  @set_4[Module] = 2.30
1060
+ @set_4[nil] = 3.40
1061
+
888
1062
  @set_4.incr(Object, 0.5)
889
1063
  @set_4.decr(Module, 0.5)
1064
+ @set_4.incr(nil, 0.5)
1065
+
890
1066
  @set_4[Object].round(1).should == 1.7
891
1067
  @set_4[Module].round(1).should == 1.8
1068
+ @set_4[nil].round(1).should == 3.9
1069
+
1070
+ @set_4.members.should == [Object, Module, nil]
892
1071
  end
893
1072
 
894
1073
  it "should support renaming sorted sets" do
@@ -909,6 +1088,20 @@ describe Redis::SortedSet do
909
1088
  @set.redis.del('spec/zset2')
910
1089
  end
911
1090
 
1091
+ it 'should set time to live in seconds when expiration option assigned' do
1092
+ @set = Redis::SortedSet.new('spec/zset', :expiration => 10)
1093
+ @set['val'] = 1
1094
+ @set.ttl.should > 0
1095
+ @set.ttl.should <= 10
1096
+ end
1097
+
1098
+ it 'should set expiration when expireat option assigned' do
1099
+ @set = Redis::SortedSet.new('spec/zset', :expireat => Time.now + 10.seconds)
1100
+ @set['val'] = 1
1101
+ @set.ttl.should > 0
1102
+ @set.ttl.should <= 10
1103
+ end
1104
+
912
1105
  after do
913
1106
  @set.clear
914
1107
  @set_1.clear