redis-objects 0.2.0 → 0.2.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/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