redis-objects 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -47,6 +47,9 @@ Create a new counter. The +counter_name+ is the key stored in Redis.
47
47
  @counter.increment
48
48
  @counter.decrement
49
49
  puts @counter.value
50
+
51
+ This gem provides a clean way to do atomic blocks as well:
52
+
50
53
  @counter.increment do |val|
51
54
  raise "Full" if val > MAX_VAL # rewind counter
52
55
  end
@@ -72,6 +75,14 @@ Lists work just like Ruby arrays:
72
75
  @list.clear
73
76
  # etc
74
77
 
78
+ Complex data types are no problem:
79
+
80
+ @list << {:name => "Nate", :city => "San Diego"}
81
+ @list << {:name => "Peter", :city => "Oceanside"}
82
+ @list.each do |el|
83
+ puts "#{el[:name]} lives in #{el[:city]}"
84
+ end
85
+
75
86
  === Sets
76
87
 
77
88
  Sets work like the Ruby {Set}[http://ruby-doc.org/core/classes/Set.html] class:
@@ -106,6 +117,16 @@ Or store them in Redis:
106
117
  @set1.unionstore('unionname', @set2, @set3)
107
118
  members = @set1.redis.get('unionname')
108
119
 
120
+ And use complex data types too:
121
+
122
+ @set1 << {:name => "Nate", :city => "San Diego"}
123
+ @set1 << {:name => "Peter", :city => "Oceanside"}
124
+ @set2 << {:name => "Nate", :city => "San Diego"}
125
+ @set2 << {:name => "Jeff", :city => "Del Mar"}
126
+
127
+ @set1 & @set2 # Nate
128
+ @set1 | @set2 # all 3 people
129
+
109
130
  === Values
110
131
 
111
132
  Simple values are easy as well:
@@ -114,10 +135,16 @@ Simple values are easy as well:
114
135
  @value.value = 'a'
115
136
  @value.delete
116
137
 
138
+ Of course complex data is no problem:
139
+
140
+ @account = Account.create!(params[:account])
141
+ @newest = Redis::Value.new('newest_account')
142
+ @newest.value = @account
143
+
117
144
  == Example 2: Class Usage
118
145
 
119
- This method of use makes it easy to integrate Redis types with an existing
120
- ActiveRecord model, DataMapper resource, or other class. Redis::Objects
146
+ Using Redis::Objects this way makes it trivial to integrate Redis types with an
147
+ existing ActiveRecord model, DataMapper resource, or other class. Redis::Objects
121
148
  will work with any class that provides an +id+ method that returns a unique
122
149
  value. Redis::Objects will automatically create keys that are unique to
123
150
  each object.
@@ -158,7 +185,7 @@ Familiar Ruby array operations Just Work (TM):
158
185
  @team.on_base.length # 1
159
186
  @team.on_base.delete('player3')
160
187
 
161
- Sets work like the Ruby {Set}[http://ruby-doc.org/core/classes/Set.html] class:
188
+ Sets operations work too:
162
189
 
163
190
  @team.outfielders << 'outfielder1' << 'outfielder1'
164
191
  @team.outfielders << 'outfielder2'
@@ -168,7 +195,7 @@ Sets work like the Ruby {Set}[http://ruby-doc.org/core/classes/Set.html] class:
168
195
  end
169
196
  player = @team.outfielders.detect{|of| of == 'outfielder2'}
170
197
 
171
- Note counters cannot be assigned to, only incremented/decremented:
198
+ Counters can be atomically incremented/decremented (but not assigned):
172
199
 
173
200
  @team.hits.increment # or incr
174
201
  @team.hits.decrement # or decr
data/lib/redis/counter.rb CHANGED
@@ -22,38 +22,31 @@ class Redis
22
22
  # disconnecting all players).
23
23
  def reset(to=options[:start])
24
24
  redis.set(key, to.to_i)
25
- @value = to.to_i
26
25
  end
27
26
 
28
- # Re-gets the current value of the counter. Normally just calling the
27
+ # Returns the current value of the counter. Normally just calling the
29
28
  # counter will lazily fetch the value, and only update it if increment
30
29
  # or decrement is called. This forces a network call to redis-server
31
30
  # to get the current value.
32
- def get
33
- @value = redis.get(key).to_i
31
+ def value
32
+ redis.get(key).to_i
34
33
  end
34
+ alias_method :get, :value
35
35
 
36
36
  # Delete a counter. Usage discouraged. Consider +reset+ instead.
37
37
  def delete
38
38
  redis.del(key)
39
- @value = nil
40
39
  end
41
40
  alias_method :del, :delete
42
41
 
43
- # Returns the (possibly cached) value of the counter. Use +get+ to
44
- # force a re-get from the Redis server.
45
- def value
46
- @value ||= get
47
- end
48
-
49
42
  # Increment the counter atomically and return the new value. If passed
50
43
  # a block, that block will be evaluated with the new value of the counter
51
44
  # as an argument. If the block returns nil or throws an exception, the
52
45
  # counter will automatically be decremented to its previous value. This
53
46
  # method is aliased as incr() for brevity.
54
47
  def increment(by=1, &block)
55
- @value = redis.incr(key, by).to_i
56
- block_given? ? rewindable_block(:decrement, @value, &block) : @value
48
+ val = redis.incr(key, by).to_i
49
+ block_given? ? rewindable_block(:decrement, val, &block) : val
57
50
  end
58
51
  alias_method :incr, :increment
59
52
 
@@ -63,8 +56,8 @@ class Redis
63
56
  # counter will automatically be incremented to its previous value. This
64
57
  # method is aliased as incr() for brevity.
65
58
  def decrement(by=1, &block)
66
- @value = redis.decr(key, by).to_i
67
- block_given? ? rewindable_block(:increment, @value, &block) : @value
59
+ val = redis.decr(key, by).to_i
60
+ block_given? ? rewindable_block(:increment, val, &block) : val
68
61
  end
69
62
  alias_method :decr, :decrement
70
63
 
data/lib/redis/list.rb CHANGED
@@ -6,6 +6,8 @@ class Redis
6
6
  class List
7
7
  require 'enumerator'
8
8
  include Enumerable
9
+ require 'redis/serialize'
10
+ include Redis::Serialize
9
11
 
10
12
  attr_reader :key, :options, :redis
11
13
  def initialize(key, redis=$redis, options={})
@@ -22,27 +24,27 @@ class Redis
22
24
 
23
25
  # Add a member to the end of the list. Redis: RPUSH
24
26
  def push(value)
25
- redis.rpush(key, value)
27
+ redis.rpush(key, to_redis(value))
26
28
  end
27
29
 
28
30
  # Remove a member from the end of the list. Redis: RPOP
29
31
  def pop
30
- redis.rpop(key)
32
+ from_redis redis.rpop(key)
31
33
  end
32
34
 
33
35
  # Add a member to the start of the list. Redis: LPUSH
34
36
  def unshift(value)
35
- redis.lpush(key, value)
37
+ redis.lpush(key, to_redis(value))
36
38
  end
37
39
 
38
40
  # Remove a member from the start of the list. Redis: LPOP
39
41
  def shift
40
- redis.lpop(key)
42
+ from_redis redis.lpop(key)
41
43
  end
42
44
 
43
45
  # Return all values in the list. Redis: LRANGE(0,-1)
44
46
  def values
45
- range(0, -1)
47
+ from_redis range(0, -1)
46
48
  end
47
49
  alias_method :get, :values
48
50
 
@@ -64,7 +66,6 @@ class Redis
64
66
  # Redis: LREM
65
67
  def delete(name, count=0)
66
68
  redis.lrem(key, count, name) # weird api
67
- get
68
69
  end
69
70
 
70
71
  # Iterate through each member of the set. Redis::Objects mixes in Enumerable,
@@ -76,13 +77,13 @@ class Redis
76
77
  # Return a range of values from +start_index+ to +end_index+. Can also use
77
78
  # the familiar list[start,end] Ruby syntax. Redis: LRANGE
78
79
  def range(start_index, end_index)
79
- redis.lrange(key, start_index, end_index)
80
+ from_redis redis.lrange(key, start_index, end_index)
80
81
  end
81
82
 
82
83
  # Return the value at the given index. Can also use familiar list[index] syntax.
83
84
  # Redis: LINDEX
84
85
  def at(index)
85
- redis.lindex(key, index)
86
+ from_redis redis.lindex(key, index)
86
87
  end
87
88
 
88
89
  # Return the first element in the list. Redis: LINDEX(0)
data/lib/redis/objects.rb CHANGED
@@ -58,10 +58,6 @@ class Redis
58
58
  klass.send :include, InstanceMethods
59
59
  klass.extend ClassMethods
60
60
 
61
- # Adapted from Redis::Model for marshaling complex data
62
- require 'redis/data_types'
63
- klass.send :include, Redis::DataTypes
64
-
65
61
  # Pull in each object type
66
62
  klass.send :include, Redis::Objects::Counters
67
63
  klass.send :include, Redis::Objects::Values
@@ -0,0 +1,23 @@
1
+ class Redis
2
+ module Serialize
3
+ include Marshal
4
+
5
+ def to_redis(value)
6
+ case value
7
+ when String, Fixnum, Bignum, Float
8
+ value
9
+ else
10
+ dump(value)
11
+ end
12
+ end
13
+
14
+ def from_redis(value)
15
+ case value
16
+ when Array
17
+ value.collect{|v| from_redis(v)}
18
+ else
19
+ restore(value) rescue value
20
+ end
21
+ end
22
+ end
23
+ end
data/lib/redis/set.rb CHANGED
@@ -5,6 +5,8 @@ class Redis
5
5
  class Set
6
6
  require 'enumerator'
7
7
  include Enumerable
8
+ require 'redis/serialize'
9
+ include Redis::Serialize
8
10
 
9
11
  attr_reader :key, :options, :redis
10
12
 
@@ -24,25 +26,24 @@ class Redis
24
26
  # Add the specified value to the set only if it does not exist already.
25
27
  # Redis: SADD
26
28
  def add(value)
27
- redis.sadd(key, value)
29
+ redis.sadd(key, to_redis(value))
28
30
  end
29
31
 
30
32
  # Return all members in the set. Redis: SMEMBERS
31
33
  def members
32
- redis.smembers(key)
34
+ from_redis redis.smembers(key)
33
35
  end
34
36
  alias_method :get, :members
35
37
 
36
38
  # Returns true if the specified value is in the set. Redis: SISMEMBER
37
39
  def member?(value)
38
- redis.sismember(key, value)
40
+ redis.sismember(key, to_redis(value))
39
41
  end
40
42
  alias_method :include?, :member?
41
43
 
42
44
  # Delete the value from the set. Redis: SREM
43
- def delete(name)
44
- redis.srem(key, name)
45
- get
45
+ def delete(value)
46
+ redis.srem(key, value)
46
47
  end
47
48
 
48
49
  # Wipe the set entirely. Redis: DEL
@@ -68,7 +69,7 @@ class Redis
68
69
  #
69
70
  # Redis: SINTER
70
71
  def intersection(*sets)
71
- redis.sinter(key, *keys_from_objects(sets))
72
+ from_redis redis.sinter(key, *keys_from_objects(sets))
72
73
  end
73
74
  alias_method :intersect, :intersection
74
75
  alias_method :inter, :intersection
@@ -92,7 +93,7 @@ class Redis
92
93
  #
93
94
  # Redis: SUNION
94
95
  def union(*sets)
95
- redis.sunion(key, *keys_from_objects(sets))
96
+ from_redis redis.sunion(key, *keys_from_objects(sets))
96
97
  end
97
98
  alias_method :|, :union
98
99
  alias_method :+, :union
data/lib/redis/value.rb CHANGED
@@ -3,6 +3,9 @@ class Redis
3
3
  # Class representing a simple value. You can use standard Ruby operations on it.
4
4
  #
5
5
  class Value
6
+ require 'redis/serialize'
7
+ include Redis::Serialize
8
+
6
9
  attr_reader :key, :options, :redis
7
10
  def initialize(key, redis=$redis, options={})
8
11
  @key = key
@@ -11,22 +14,17 @@ class Redis
11
14
  @redis.setnx(key, @options[:default]) if @options[:default]
12
15
  end
13
16
 
14
- def value
15
- @value ||= get
16
- end
17
-
18
17
  def value=(val)
19
- redis.set(key, val)
20
- @value = val
18
+ redis.set(key, to_redis(val))
21
19
  end
22
20
 
23
- def get
24
- @value = redis.get(key)
21
+ def value
22
+ from_redis redis.get(key)
25
23
  end
26
-
24
+ alias_method :get, :value
25
+
27
26
  def delete
28
27
  redis.del(key)
29
- @value = nil
30
28
  end
31
29
  alias_method :del, :delete
32
30
 
@@ -1,18 +1,270 @@
1
1
 
2
2
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
+ require 'redis/counter'
5
+ require 'redis/list'
6
+ require 'redis/set'
7
+ require 'redis/value'
8
+
9
+ describe Redis::Value do
10
+ before :all do
11
+ @value = Redis::Value.new('spec/value')
12
+ end
13
+
14
+ before :each do
15
+ @value.delete
16
+ end
17
+
18
+ it "should handle simple values" do
19
+ @value.should == nil
20
+ @value.value = 'Trevor Hoffman'
21
+ @value.should == 'Trevor Hoffman'
22
+ @value.get.should == 'Trevor Hoffman'
23
+ @value.del.should be_true
24
+ @value.should be_nil
25
+ end
26
+
27
+ it "should handle complex marshaled values" do
28
+ @value.should == nil
29
+ @value.value = {:json => 'data'}
30
+ @value.should == {:json => 'data'}
31
+ @value.get.should == {:json => 'data'}
32
+ @value.value = [[1,2], {:t3 => 4}]
33
+ @value.should == [[1,2], {:t3 => 4}]
34
+ @value.get.should == [[1,2], {:t3 => 4}]
35
+ @value.del.should be_true
36
+ @value.should be_nil
37
+ end
38
+
39
+ after :all do
40
+ @value.delete
41
+ end
42
+ end
43
+
44
+
4
45
  describe Redis::List do
46
+ before :all do
47
+ @list = Redis::List.new('spec/list')
48
+ end
49
+
50
+ before :each do
51
+ @list.clear
52
+ end
53
+
54
+ it "should handle lists of simple values" do
55
+ @list.should be_empty
56
+ @list << 'a'
57
+ @list.should == ['a']
58
+ @list.get.should == ['a']
59
+ @list.unshift 'b'
60
+ @list.to_s.should == 'b, a'
61
+ @list.should == ['b','a']
62
+ @list.get.should == ['b','a']
63
+ @list.push 'c'
64
+ @list.should == ['b','a','c']
65
+ @list.get.should == ['b','a','c']
66
+ @list.first.should == 'b'
67
+ @list.last.should == 'c'
68
+ @list << 'd'
69
+ @list.should == ['b','a','c','d']
70
+ @list[1].should == 'a'
71
+ @list[0].should == 'b'
72
+ @list[2].should == 'c'
73
+ @list[3].should == 'd'
74
+ @list.include?('c').should be_true
75
+ @list.include?('no').should be_false
76
+ @list.pop.should == 'd'
77
+ @list[0].should == @list.at(0)
78
+ @list[1].should == @list.at(1)
79
+ @list[2].should == @list.at(2)
80
+ @list.should == ['b','a','c']
81
+ @list.get.should == ['b','a','c']
82
+ @list.shift.should == 'b'
83
+ @list.should == ['a','c']
84
+ @list.get.should == ['a','c']
85
+ @list << 'e' << 'f' << 'e'
86
+ @list.should == ['a','c','e','f','e']
87
+ @list.get.should == ['a','c','e','f','e']
88
+ @list.delete('e').should == 2
89
+ @list.should == ['a','c','f']
90
+ @list.get.should == ['a','c','f']
91
+ @list << 'j'
92
+ @list.should == ['a','c','f','j']
93
+ @list[0..2].should == ['a','c','f']
94
+ @list[1, 3].should == ['c','f','j']
95
+ @list.length.should == 4
96
+ @list.size.should == 4
97
+ @list.should == ['a','c','f','j']
98
+ @list.get.should == ['a','c','f','j']
5
99
 
100
+ i = -1
101
+ @list.each do |st|
102
+ st.should == @list[i += 1]
103
+ end
104
+ @list.should == ['a','c','f','j']
105
+ @list.get.should == ['a','c','f','j']
6
106
 
107
+ @list.each_with_index do |st,i|
108
+ st.should == @list[i]
109
+ end
110
+ @list.should == ['a','c','f','j']
111
+ @list.get.should == ['a','c','f','j']
112
+
113
+ coll = @list.collect{|st| st}
114
+ coll.should == ['a','c','f','j']
115
+ @list.should == ['a','c','f','j']
116
+ @list.get.should == ['a','c','f','j']
117
+
118
+ @list << 'a'
119
+ coll = @list.select{|st| st == 'a'}
120
+ coll.should == ['a','a']
121
+ @list.should == ['a','c','f','j','a']
122
+ @list.get.should == ['a','c','f','j','a']
123
+ end
124
+
125
+ it "should handle lists of complex data types" do
126
+ @list << {:json => 'data'}
127
+ @list << {:json2 => 'data2'}
128
+ @list.first.should == {:json => 'data'}
129
+ @list.last.should == {:json2 => 'data2'}
130
+ @list << [1,2,3,[4,5]]
131
+ @list.last.should == [1,2,3,[4,5]]
132
+ @list.shift.should == {:json => 'data'}
133
+ end
134
+
135
+ after :all do
136
+ @list.clear
137
+ end
7
138
  end
8
139
 
9
140
  describe Redis::Set do
141
+ before :all do
142
+ @set = Redis::Set.new('spec/set')
143
+ @set_1 = Redis::Set.new('spec/set_1')
144
+ @set_2 = Redis::Set.new('spec/set_2')
145
+ @set_3 = Redis::Set.new('spec/set_3')
146
+ end
10
147
 
148
+ before :each do
149
+ @set.clear
150
+ @set_1.clear
151
+ @set_2.clear
152
+ @set_3.clear
153
+ end
11
154
 
12
- end
155
+ it "should handle sets of simple values" do
156
+ @set.should be_empty
157
+ @set << 'a' << 'a' << 'a'
158
+ @set.should == ['a']
159
+ @set.get.should == ['a']
160
+ @set << 'b' << 'b'
161
+ @set.to_s.should == 'a, b'
162
+ @set.should == ['a','b']
163
+ @set.members.should == ['a','b']
164
+ @set.get.should == ['a','b']
165
+ @set << 'c'
166
+ @set.sort.should == ['a','b','c']
167
+ @set.get.sort.should == ['a','b','c']
168
+ @set.delete('c')
169
+ @set.should == ['a','b']
170
+ @set.get.sort.should == ['a','b']
171
+ @set.length.should == 2
172
+ @set.size.should == 2
173
+
174
+ i = 0
175
+ @set.each do |st|
176
+ i += 1
177
+ end
178
+ i.should == @set.length
13
179
 
14
- describe Redis::Value do
180
+ coll = @set.collect{|st| st}
181
+ coll.should == ['a','b']
182
+ @set.should == ['a','b']
183
+ @set.get.should == ['a','b']
15
184
 
185
+ @set << 'c'
186
+ @set.member?('c').should be_true
187
+ @set.include?('c').should be_true
188
+ @set.member?('no').should be_false
189
+ coll = @set.select{|st| st == 'c'}
190
+ coll.should == ['c']
191
+ @set.sort.should == ['a','b','c']
192
+ end
193
+
194
+ it "should handle set intersections and unions" do
195
+ @set_1 << 'a' << 'b' << 'c' << 'd' << 'e'
196
+ @set_2 << 'c' << 'd' << 'e' << 'f' << 'g'
197
+ @set_3 << 'a' << 'd' << 'g' << 'l' << 'm'
198
+ @set_1.sort.should == %w(a b c d e)
199
+ @set_2.sort.should == %w(c d e f g)
200
+ @set_3.sort.should == %w(a d g l m)
201
+ (@set_1 & @set_2).sort.should == ['c','d','e']
202
+ @set_1.intersection(@set_2).sort.should == ['c','d','e']
203
+ @set_1.intersection(@set_2, @set_3).sort.should == ['d']
204
+ @set_1.intersect(@set_2).sort.should == ['c','d','e']
205
+ @set_1.inter(@set_2, @set_3).sort.should == ['d']
206
+ @set_1.interstore(INTERSTORE_KEY, @set_2).should == 3
207
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['c','d','e']
208
+ @set_1.interstore(INTERSTORE_KEY, @set_2, @set_3).should == 1
209
+ @set_1.redis.smembers(INTERSTORE_KEY).sort.should == ['d']
16
210
 
211
+ (@set_1 | @set_2).sort.should == ['a','b','c','d','e','f','g']
212
+ (@set_1 + @set_2).sort.should == ['a','b','c','d','e','f','g']
213
+ @set_1.union(@set_2).sort.should == ['a','b','c','d','e','f','g']
214
+ @set_1.union(@set_2, @set_3).sort.should == ['a','b','c','d','e','f','g','l','m']
215
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2).should == 7
216
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g']
217
+ @set_1.unionstore(UNIONSTORE_KEY, @set_2, @set_3).should == 9
218
+ @set_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g','l','m']
219
+ end
220
+
221
+ after :all do
222
+ @set.clear
223
+ @set_1.clear
224
+ @set_2.clear
225
+ @set_3.clear
226
+ end
17
227
  end
18
228
 
229
+ describe Redis::Counter do
230
+ before :all do
231
+ @counter = Redis::Counter.new('spec/counter')
232
+ @counter2 = Redis::Counter.new('spec/counter')
233
+ end
234
+
235
+ before :each do
236
+ @counter.reset
237
+ end
238
+
239
+ it "should support increment/decrement of counters" do
240
+ @counter.key.should == 'spec/counter'
241
+ @counter.incr(10)
242
+ @counter.should == 10
243
+
244
+ # math proxy ops
245
+ (@counter == 10).should be_true
246
+ (@counter <= 10).should be_true
247
+ (@counter < 11).should be_true
248
+ (@counter > 9).should be_true
249
+ (@counter >= 10).should be_true
250
+ "#{@counter}".should == "10"
251
+
252
+ @counter.increment.should == 11
253
+ @counter.increment.should == 12
254
+ @counter2.increment.should == 13
255
+ @counter2.increment(2).should == 15
256
+ @counter.decrement.should == 14
257
+ @counter2.decrement.should == 13
258
+ @counter.decrement.should == 12
259
+ @counter2.decrement(4).should == 8
260
+ @counter.should == 8
261
+ @counter.reset.should be_true
262
+ @counter.should == 0
263
+ @counter.reset(15).should be_true
264
+ @counter.should == 15
265
+ end
266
+
267
+ after :all do
268
+ @counter.delete
269
+ end
270
+ end
@@ -1,8 +1,8 @@
1
1
 
2
2
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
3
 
4
- UNIONSTORE_KEY = 'test:unionstore'
5
- INTERSTORE_KEY = 'test:interstore'
4
+ require 'redis/objects'
5
+ Redis::Objects.redis = $redis
6
6
 
7
7
  class Roster
8
8
  include Redis::Objects
@@ -76,11 +76,10 @@ describe Redis::Objects do
76
76
  @roster2.available_slots.decrement.should == 13
77
77
  @roster.available_slots.decrement.should == 12
78
78
  @roster2.available_slots.decrement(4).should == 8
79
- @roster.available_slots.should == 12
80
- @roster.available_slots.get.should == 8
81
- @roster.available_slots.reset.should == 10
79
+ @roster.available_slots.should == 8
80
+ @roster.available_slots.reset.should be_true
82
81
  @roster.available_slots.should == 10
83
- @roster.available_slots.reset(15).should == 15
82
+ @roster.available_slots.reset(15).should be_true
84
83
  @roster.available_slots.should == 15
85
84
  @roster.pitchers.increment.should == 1
86
85
  @roster.basic.increment.should == 1
@@ -260,7 +259,16 @@ describe Redis::Objects do
260
259
  @roster.starting_pitcher = 'Trevor Hoffman'
261
260
  @roster.starting_pitcher.should == 'Trevor Hoffman'
262
261
  @roster.starting_pitcher.get.should == 'Trevor Hoffman'
263
- @roster.starting_pitcher.del
262
+ @roster.starting_pitcher.del.should be_true
263
+ @roster.starting_pitcher.should be_nil
264
+ end
265
+
266
+ it "should handle complex marshaled values" do
267
+ @roster.starting_pitcher.should == nil
268
+ @roster.starting_pitcher = {:json => 'data'}
269
+ @roster.starting_pitcher.should == {:json => 'data'}
270
+ @roster.starting_pitcher.get.should == {:json => 'data'}
271
+ @roster.starting_pitcher.del.should be_true
264
272
  @roster.starting_pitcher.should be_nil
265
273
  end
266
274
 
@@ -286,19 +294,19 @@ describe Redis::Objects do
286
294
  @roster.player_stats[3].should == 'd'
287
295
  @roster.player_stats.include?('c').should be_true
288
296
  @roster.player_stats.include?('no').should be_false
289
- @roster.player_stats.pop
297
+ @roster.player_stats.pop.should == 'd'
290
298
  @roster.player_stats[0].should == @roster.player_stats.at(0)
291
299
  @roster.player_stats[1].should == @roster.player_stats.at(1)
292
300
  @roster.player_stats[2].should == @roster.player_stats.at(2)
293
301
  @roster.player_stats.should == ['b','a','c']
294
302
  @roster.player_stats.get.should == ['b','a','c']
295
- @roster.player_stats.shift
303
+ @roster.player_stats.shift.should == 'b'
296
304
  @roster.player_stats.should == ['a','c']
297
305
  @roster.player_stats.get.should == ['a','c']
298
306
  @roster.player_stats << 'e' << 'f' << 'e'
299
307
  @roster.player_stats.should == ['a','c','e','f','e']
300
308
  @roster.player_stats.get.should == ['a','c','e','f','e']
301
- @roster.player_stats.delete('e')
309
+ @roster.player_stats.delete('e').should == 2
302
310
  @roster.player_stats.should == ['a','c','f']
303
311
  @roster.player_stats.get.should == ['a','c','f']
304
312
  @roster.player_stats << 'j'
@@ -401,6 +409,26 @@ describe Redis::Objects do
401
409
  @roster_1.redis.smembers(UNIONSTORE_KEY).sort.should == ['a','b','c','d','e','f','g','l','m']
402
410
  end
403
411
 
412
+ it "should handle lists of complex data types" do
413
+ @roster.player_stats << {:json => 'data'}
414
+ @roster.player_stats << {:json2 => 'data2'}
415
+ @roster.player_stats.first.should == {:json => 'data'}
416
+ @roster.player_stats.last.should == {:json2 => 'data2'}
417
+ @roster.player_stats << [1,2,3,[4,5]]
418
+ @roster.player_stats.last.should == [1,2,3,[4,5]]
419
+ @roster.player_stats.shift.should == {:json => 'data'}
420
+ end
421
+
422
+ it "should handle sets of complex data types" do
423
+ @roster.outfielders << {:a => 1} << {:b => 2}
424
+ @roster.outfielders.member?({:b => 2})
425
+ @roster.outfielders.members.should == [{:b => 2}, {:a => 1}]
426
+ @roster_1.outfielders << {:a => 1} << {:b => 2}
427
+ @roster_2.outfielders << {:b => 2} << {:c => 3}
428
+ (@roster_1.outfielders & @roster_2.outfielders).should == [{:b => 2}]
429
+ (@roster_1.outfielders | @roster_2.outfielders).should == [{:b=>2}, {:c=>3}, {:a=>1}]
430
+ end
431
+
404
432
  it "should provide a lock method that accepts a block" do
405
433
  @roster.resort_lock.key.should == 'roster:1:resort_lock'
406
434
  a = false
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
2
  require 'redis'
3
- require 'redis/objects'
4
3
 
5
- Redis::Objects.redis = Redis.new(:host => ENV['REDIS_HOST'], :port => ENV['REDIS_PORT'])
4
+ $redis = Redis.new(:host => ENV['REDIS_HOST'], :port => ENV['REDIS_PORT'])
5
+
6
+ UNIONSTORE_KEY = 'test:unionstore'
7
+ INTERSTORE_KEY = 'test:interstore'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Wiger
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-26 00:00:00 -08:00
12
+ date: 2009-11-27 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -33,7 +33,6 @@ extra_rdoc_files:
33
33
  - README.rdoc
34
34
  files:
35
35
  - lib/redis/counter.rb
36
- - lib/redis/data_types.rb
37
36
  - lib/redis/list.rb
38
37
  - lib/redis/lock.rb
39
38
  - lib/redis/objects/core.rb
@@ -43,6 +42,7 @@ files:
43
42
  - lib/redis/objects/sets.rb
44
43
  - lib/redis/objects/values.rb
45
44
  - lib/redis/objects.rb
45
+ - lib/redis/serialize.rb
46
46
  - lib/redis/set.rb
47
47
  - lib/redis/value.rb
48
48
  - spec/redis_objects_instance_spec.rb
@@ -1,84 +0,0 @@
1
- class Redis
2
- module DataTypes
3
- TYPES = %w(String Integer Float EpochTime DateTime Json Yaml IPAddress FilePath Uri Slug)
4
- def self.included(klass)
5
- TYPES.each do |data_type|
6
- if Object.const_defined?(data_type)
7
- klass = Object.const_get(data_type)
8
- else
9
- klass = Object.const_set(data_type, Class.new)
10
- end
11
- if const_defined?(data_type)
12
- klass.extend const_get(data_type)
13
- end
14
- end
15
- end
16
-
17
- module String
18
- def to_redis; to_s; end
19
- end
20
-
21
- module Integer
22
- def from_redis(value); value && value.to_i end
23
- end
24
-
25
- module Float
26
- def from_redis(value); value && value.to_f end
27
- end
28
-
29
- module EpochTime
30
- def to_redis(value)
31
- value.is_a?(DateTime) ? value.to_time.to_i : value.to_i
32
- end
33
-
34
- def from_redis(value) Time.at(value.to_i) end
35
- end
36
-
37
- module DateTime
38
- def to_redis(value); value.strftime('%FT%T%z') end
39
- def from_redis(value); value && ::DateTime.strptime(value, '%FT%T%z') end
40
- end
41
-
42
- module Json
43
- def to_redis(value); Yajl::Encoder.encode(value) end
44
- def from_redis(value); value && Yajl::Parser.parse(value) end
45
- end
46
-
47
- module Yaml
48
- def to_redis(value); Yaml.dump(value) end
49
- def from_redis(value); Yaml.load(value) end
50
- end
51
-
52
- module IPAddress
53
- def from_redis(value)
54
- return nil if value.nil?
55
- if value.is_a?(String)
56
- IPAddr.new(value.empty? ? '0.0.0.0' : value)
57
- else
58
- raise "+value+ must be nil or a String"
59
- end
60
- end
61
- end
62
-
63
- module FilePath
64
- require 'pathname'
65
- def from_redis(value)
66
- value.blank? ? nil : Pathname.new(value)
67
- end
68
- end
69
-
70
- module Uri
71
- require 'addressable/uri'
72
- def from_redis(value)
73
- Addressable::URI.parse(value)
74
- end
75
- end
76
-
77
- module Slug
78
- require 'addressable/uri'
79
- def to_redis(value)
80
- Addressable::URI.parse(value).display_uri
81
- end
82
- end
83
- end
84
- end