remodel 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ module Remodel
3
+
4
+ class CachingContext
5
+
6
+ # use Remodel.create_context instead
7
+ class << self
8
+ private :new
9
+ end
10
+
11
+ def initialize(context)
12
+ @context = context
13
+ @cache = {}
14
+ end
15
+
16
+ def key
17
+ @context.key
18
+ end
19
+
20
+ def hget(field)
21
+ @cache[field] = @context.hget(field) unless @cache.has_key?(field)
22
+ @cache[field]
23
+ end
24
+
25
+ def hmget(*fields)
26
+ load(fields - @cache.keys)
27
+ @cache.values_at(*fields)
28
+ end
29
+
30
+ def hset(field, value)
31
+ value = value.to_s if value
32
+ @cache[field] = value
33
+ @context.hset(field, value)
34
+ end
35
+
36
+ def hincrby(field, value)
37
+ result = @context.hincrby(field, value)
38
+ @cache[field] = result.to_s
39
+ result
40
+ end
41
+
42
+ def hdel(field)
43
+ @cache[field] = nil
44
+ @context.hdel(field)
45
+ end
46
+
47
+ def inspect
48
+ "\#<#{self.class.name}(#{@context.inspect})>"
49
+ end
50
+
51
+ private
52
+
53
+ def load(fields)
54
+ return if fields.empty?
55
+ fields.zip(@context.hmget(*fields)).each do |field, value|
56
+ @cache[field] = value
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,41 @@
1
+ module Remodel
2
+
3
+ class Context
4
+
5
+ # use Remodel.create_context instead
6
+ class << self
7
+ private :new
8
+ end
9
+
10
+ attr_reader :key
11
+
12
+ def initialize(key)
13
+ @key = key
14
+ end
15
+
16
+ def hget(field)
17
+ Remodel.redis.hget(@key, field)
18
+ end
19
+
20
+ def hmget(*fields)
21
+ Remodel.redis.hmget(@key, *fields)
22
+ end
23
+
24
+ def hset(field, value)
25
+ Remodel.redis.hset(@key, field, value)
26
+ end
27
+
28
+ def hincrby(field, value)
29
+ Remodel.redis.hincrby(@key, field, value)
30
+ end
31
+
32
+ def hdel(field)
33
+ Remodel.redis.hdel(@key, field)
34
+ end
35
+
36
+ def inspect
37
+ "\#<#{self.class.name}(#{@key})>"
38
+ end
39
+ end
40
+
41
+ end
@@ -19,7 +19,7 @@ module Remodel
19
19
 
20
20
  def save
21
21
  @key = next_key unless @key
22
- Remodel.redis.hset(@context, @key, to_json)
22
+ @context.hset(@key, to_json)
23
23
  self
24
24
  end
25
25
 
@@ -41,9 +41,9 @@ module Remodel
41
41
 
42
42
  def delete
43
43
  raise EntityNotSaved unless @key
44
- Remodel.redis.hdel(@context, @key)
44
+ @context.hdel(@key)
45
45
  self.class.associations.each do |name|
46
- Remodel.redis.hdel(@context, "#{@key}_#{name}")
46
+ @context.hdel("#{@key}_#{name}")
47
47
  end
48
48
  end
49
49
 
@@ -57,7 +57,7 @@ module Remodel
57
57
 
58
58
  def inspect
59
59
  properties = attributes.map { |name, value| "#{name}: #{value.inspect}" }.join(', ')
60
- "\#<#{self.class.name}(#{context}, #{id}) #{properties}>"
60
+ "\#<#{self.class.name}(#{context.key}, #{id}) #{properties}>"
61
61
  end
62
62
 
63
63
  def self.create(context, attributes = {})
@@ -112,7 +112,7 @@ module Remodel
112
112
  instance_variable_get(var)
113
113
  else
114
114
  clazz = Class[options[:class]]
115
- value_key = Remodel.redis.hget(self.context, "#{key}_#{name}")
115
+ value_key = self.context.hget("#{key}_#{name}")
116
116
  value = value_key && clazz.find(self.context, value_key) rescue nil
117
117
  instance_variable_set(var, value)
118
118
  end
@@ -126,10 +126,10 @@ module Remodel
126
126
  define_method("_#{name}=") do |value|
127
127
  if value
128
128
  instance_variable_set(var, value)
129
- Remodel.redis.hset(self.context, "#{key}_#{name}", value.key)
129
+ self.context.hset("#{key}_#{name}", value.key)
130
130
  else
131
131
  remove_instance_variable(var) if instance_variable_defined? var
132
- Remodel.redis.hdel(self.context, "#{key}_#{name}")
132
+ self.context.hdel("#{key}_#{name}")
133
133
  end
134
134
  end; private "_#{name}="
135
135
 
@@ -166,12 +166,12 @@ module Remodel
166
166
  end
167
167
 
168
168
  def self.fetch(context, key)
169
- Remodel.redis.hget(context, key) || raise(EntityNotFound, "no #{name} with key #{key} in context #{context}")
169
+ context.hget(key) || raise(EntityNotFound, "no #{name} with key #{key} in context #{context}")
170
170
  end
171
171
 
172
172
  # Each entity has its own sequence to generate unique ids.
173
173
  def next_key
174
- id = Remodel.redis.hincrby(@context, "#{self.class.key_prefix}", 1)
174
+ id = @context.hincrby("#{self.class.key_prefix}", 1)
175
175
  "#{self.class.key_prefix}#{id}"
176
176
  end
177
177
 
@@ -56,12 +56,12 @@ module Remodel
56
56
  end
57
57
 
58
58
  def _store
59
- Remodel.redis.hset(@this.context, @key, JSON.generate(self.map(&:key)))
59
+ @this.context.hset(@key, JSON.generate(self.map(&:key)))
60
60
  end
61
61
 
62
62
  def _fetch(clazz, context, key)
63
- keys = JSON.parse(Remodel.redis.hget(context, key) || '[]').uniq
64
- values = keys.empty? ? [] : Remodel.redis.hmget(context, *keys)
63
+ keys = JSON.parse(context.hget(key) || '[]').uniq
64
+ values = keys.empty? ? [] : context.hmget(*keys)
65
65
  keys.zip(values).map do |key, json|
66
66
  clazz.restore(context, key, json) if json
67
67
  end.compact
data/lib/remodel.rb CHANGED
@@ -24,6 +24,8 @@ end
24
24
  require File.join(File.dirname(__FILE__), 'remodel', 'mapper')
25
25
  require File.join(File.dirname(__FILE__), 'remodel', 'has_many')
26
26
  require File.join(File.dirname(__FILE__), 'remodel', 'entity')
27
+ require File.join(File.dirname(__FILE__), 'remodel', 'context')
28
+ require File.join(File.dirname(__FILE__), 'remodel', 'caching_context')
27
29
 
28
30
 
29
31
  module Remodel
@@ -46,6 +48,12 @@ module Remodel
46
48
  def self.redis=(redis)
47
49
  @redis = redis
48
50
  end
51
+
52
+ def self.create_context(key, options = {})
53
+ context = Context.send(:new, key)
54
+ context = CachingContext.send(:new, context) if options[:caching]
55
+ context
56
+ end
49
57
 
50
58
  # Returns the mapper defined for a given class, or the identity mapper.
51
59
  def self.mapper_for(clazz)
data/test/helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
+ require 'mocha'
4
5
 
5
6
  require File.dirname(__FILE__) + '/../lib/remodel.rb'
6
7
 
@@ -10,4 +11,8 @@ class Test::Unit::TestCase
10
11
  Remodel.redis
11
12
  end
12
13
 
14
+ def context
15
+ @context ||= Remodel.create_context('test')
16
+ end
17
+
13
18
  end
@@ -0,0 +1,116 @@
1
+ # encoding: UTF-8
2
+ require 'helper'
3
+
4
+ class Remodel::CachingContext
5
+ attr_accessor :cache
6
+ class << self
7
+ public :new
8
+ end
9
+ end
10
+
11
+ class TestCachingContext < Test::Unit::TestCase
12
+
13
+ context "CachingContext" do
14
+ setup do
15
+ @cache = Remodel::CachingContext.new(context)
16
+ end
17
+
18
+ context 'hget' do
19
+ should "fetch and cache value" do
20
+ context.expects(:hget).with('x').returns('33')
21
+ assert_equal '33', @cache.hget('x')
22
+ assert_equal '33', @cache.cache['x']
23
+ end
24
+
25
+ should "return cached value" do
26
+ @cache.cache['x'] = '42'
27
+ context.expects(:hget).never
28
+ assert_equal '42', @cache.hget('x')
29
+ end
30
+
31
+ should "return cached nil" do
32
+ @cache.cache['x'] = nil
33
+ context.expects(:hget).never
34
+ assert_nil @cache.hget('x')
35
+ end
36
+ end
37
+
38
+ context 'hmget' do
39
+ should "fetch and cache values" do
40
+ context.expects(:hmget).with('x', 'y', 'z').returns %w[4 5 6]
41
+ assert_equal %w[4 5 6], @cache.hmget('x', 'y', 'z')
42
+ assert_equal %w[4 5 6], @cache.cache.values_at('x', 'y', 'z')
43
+ end
44
+
45
+ should 'only fetch uncached values' do
46
+ @cache.cache['y'] = '5'
47
+ context.expects(:hmget).with('x', 'z').returns %w[4 6]
48
+ assert_equal %w[4 5 6], @cache.hmget('x', 'y', 'z')
49
+ assert_equal %w[4 5 6], @cache.cache.values_at('x', 'y', 'z')
50
+ end
51
+
52
+ should 'not fetch cached nil values' do
53
+ @cache.cache['y'] = nil
54
+ context.expects(:hmget).with('x', 'z').returns %w[4 6]
55
+ assert_equal ['4', nil, '6'], @cache.hmget('x', 'y', 'z')
56
+ assert_equal ['4', nil, '6'], @cache.cache.values_at('x', 'y', 'z')
57
+ end
58
+
59
+ should 'not call redis if all values are cached' do
60
+ @cache.cache['x'] = '4'
61
+ @cache.cache['y'] = '5'
62
+ @cache.cache['z'] = '6'
63
+ context.expects(:hmget).never
64
+ assert_equal %w[4 5 6], @cache.hmget('x', 'y', 'z')
65
+ end
66
+ end
67
+
68
+ context 'hset' do
69
+ should 'store value in redis' do
70
+ context.expects(:hset).with('x', '21')
71
+ @cache.hset('x', 21)
72
+ end
73
+
74
+ should 'cache value as string' do
75
+ context.expects(:hset).with('x', '21')
76
+ @cache.hset('x', 21)
77
+ assert_equal '21', @cache.cache['x']
78
+ end
79
+
80
+ should 'cache nil' do
81
+ context.expects(:hset).with('x', nil)
82
+ @cache.hset('x', nil)
83
+ assert_nil @cache.cache['x']
84
+ assert @cache.cache.has_key?('x')
85
+ end
86
+ end
87
+
88
+ context 'hincrby' do
89
+ should 'increment value in redis' do
90
+ context.expects(:hincrby).with('i', 1).returns(3)
91
+ assert_equal 3, @cache.hincrby('i', 1)
92
+ end
93
+
94
+ should 'cache result as string' do
95
+ context.expects(:hincrby).with('i', 1).returns(3)
96
+ @cache.hincrby('i', 1)
97
+ assert_equal '3', @cache.cache['i']
98
+ end
99
+ end
100
+
101
+ context 'hdel' do
102
+ should 'delete field in redis' do
103
+ context.expects(:hdel).with('x')
104
+ @cache.hdel('x')
105
+ end
106
+
107
+ should 'cache nil for field' do
108
+ context.expects(:hdel).with('x')
109
+ @cache.hdel('x')
110
+ assert_nil @cache.cache['x']
111
+ assert @cache.cache.has_key?('x')
112
+ end
113
+ end
114
+ end
115
+
116
+ end
data/test/test_entity.rb CHANGED
@@ -13,23 +13,23 @@ class TestEntity < Test::Unit::TestCase
13
13
 
14
14
  context "new" do
15
15
  should "set properties" do
16
- foo = Foo.new('cx', :x => 1, :y => 2)
16
+ foo = Foo.new(context, :x => 1, :y => 2)
17
17
  assert_equal 1, foo.x
18
18
  assert_equal 2, foo.y
19
19
  end
20
20
 
21
21
  should "ignore undefined properties" do
22
- foo = Foo.new('cx', :z => 3)
22
+ foo = Foo.new(context, :z => 3)
23
23
  assert foo.instance_eval { !@attributes.key? :z }
24
24
  end
25
25
 
26
26
  should "not set the key" do
27
- foo = Foo.new('cx', :x => 23)
27
+ foo = Foo.new(context, :x => 23)
28
28
  assert_equal nil, foo.key
29
29
  end
30
30
 
31
31
  should "not set the id" do
32
- foo = Foo.new('cx', :x => 23)
32
+ foo = Foo.new(context, :x => 23)
33
33
  assert_equal nil, foo.id
34
34
  end
35
35
  end
@@ -40,37 +40,37 @@ class TestEntity < Test::Unit::TestCase
40
40
  end
41
41
 
42
42
  should "work without attributes" do
43
- foo = Foo.create('cx')
43
+ foo = Foo.create(context)
44
44
  assert foo.is_a?(Foo)
45
45
  end
46
46
 
47
47
  should "give the entity a key based on the class name" do
48
- assert_equal 'f1', Foo.create('cx').key
49
- assert_equal 'b1', Bar.create('cx').key
50
- assert_equal 'b2', Bar.create('cx').key
48
+ assert_equal 'f1', Foo.create(context).key
49
+ assert_equal 'b1', Bar.create(context).key
50
+ assert_equal 'b2', Bar.create(context).key
51
51
  end
52
52
 
53
53
  should "give the entity an id which is unique per entity class" do
54
- assert_equal 1, Foo.create('cx').id
55
- assert_equal 1, Bar.create('cx').id
56
- assert_equal 2, Bar.create('cx').id
54
+ assert_equal 1, Foo.create(context).id
55
+ assert_equal 1, Bar.create(context).id
56
+ assert_equal 2, Bar.create(context).id
57
57
  end
58
58
 
59
59
  should "store the entity under its key" do
60
- foo = Foo.create('cx', :x => 'hello', :y => false)
61
- assert redis.hexists('cx', foo.key)
60
+ foo = Foo.create(context, :x => 'hello', :y => false)
61
+ assert redis.hexists(context.key, foo.key)
62
62
  end
63
63
 
64
64
  should "store all properties" do
65
- foo = Foo.create('cx', :x => 'hello', :y => false)
65
+ foo = Foo.create(context, :x => 'hello', :y => false)
66
66
  foo.reload
67
67
  assert_equal 'hello', foo.x
68
68
  assert_equal false, foo.y
69
69
  end
70
70
 
71
71
  should "not store the key as a property" do
72
- foo = Foo.create('cx', :x => 'hello', :y => false)
73
- assert !(/f1/ =~ redis.hget('cx', foo.key))
72
+ foo = Foo.create(context, :x => 'hello', :y => false)
73
+ assert !(/f1/ =~ redis.hget(context.key, foo.key))
74
74
  end
75
75
  end
76
76
 
@@ -80,18 +80,18 @@ class TestEntity < Test::Unit::TestCase
80
80
  end
81
81
 
82
82
  should "give the entity a key, if necessary" do
83
- foo = Foo.new('cx').save
83
+ foo = Foo.new(context).save
84
84
  assert foo.key
85
85
  end
86
86
 
87
87
  should "store the entity under its key" do
88
- foo = Foo.new('cx', :x => 'hello', :y => false)
88
+ foo = Foo.new(context, :x => 'hello', :y => false)
89
89
  foo.save
90
- assert redis.hexists(foo.context, foo.key)
90
+ assert redis.hexists(context.key, foo.key)
91
91
  end
92
92
 
93
93
  should "store all properties" do
94
- foo = Foo.new('cx', :x => 'hello', :y => false)
94
+ foo = Foo.new(context, :x => 'hello', :y => false)
95
95
  foo.save
96
96
  foo.reload
97
97
  assert_equal 'hello', foo.x
@@ -101,11 +101,11 @@ class TestEntity < Test::Unit::TestCase
101
101
 
102
102
  context "reload" do
103
103
  setup do
104
- @foo = Foo.create('cx', :x => 'hello', :y => true)
104
+ @foo = Foo.create(context, :x => 'hello', :y => true)
105
105
  end
106
106
 
107
107
  should "reload all properties" do
108
- redis.hset @foo.context, @foo.key, %q({"x":23,"y":"adios"})
108
+ redis.hset(context.key, @foo.key, %q({"x":23,"y":"adios"}))
109
109
  @foo.reload
110
110
  assert_equal 23, @foo.x
111
111
  assert_equal 'adios', @foo.y
@@ -124,19 +124,19 @@ class TestEntity < Test::Unit::TestCase
124
124
  end
125
125
 
126
126
  should "raise EntityNotFound if the entity does not exist any more" do
127
- redis.hdel @foo.context, @foo.key
127
+ redis.hdel(context.key, @foo.key)
128
128
  assert_raise(Remodel::EntityNotFound) { @foo.reload }
129
129
  end
130
130
 
131
131
  should "raise EntityNotSaved if the entity was never saved" do
132
- assert_raise(Remodel::EntityNotSaved) { Foo.new('cx').reload }
132
+ assert_raise(Remodel::EntityNotSaved) { Foo.new(context).reload }
133
133
  end
134
134
  end
135
135
 
136
136
  context "update" do
137
137
  setup do
138
138
  redis.flushdb
139
- @foo = Foo.create('cx', :x => 'Tim', :y => true)
139
+ @foo = Foo.create(context, :x => 'Tim', :y => true)
140
140
  end
141
141
 
142
142
  should "set the given properties" do
@@ -155,7 +155,7 @@ class TestEntity < Test::Unit::TestCase
155
155
 
156
156
  context "to_json" do
157
157
  should "serialize to json" do
158
- foo = Foo.new('cx', :x => 42, :y => true)
158
+ foo = Foo.new(context, :x => 42, :y => true)
159
159
  assert_match /"x":42/, foo.to_json
160
160
  assert_match /"y":true/, foo.to_json
161
161
  end
@@ -163,7 +163,7 @@ class TestEntity < Test::Unit::TestCase
163
163
 
164
164
  context "as_json" do
165
165
  should "serialize into a hash" do
166
- foo = Foo.create('cx', :x => 42, :y => true)
166
+ foo = Foo.create(context, :x => 42, :y => true)
167
167
  expected = { :id => foo.id, :x => 42, :y => true }
168
168
  assert_equal expected, foo.as_json
169
169
  end
@@ -172,7 +172,7 @@ class TestEntity < Test::Unit::TestCase
172
172
  context "#set_key_prefix" do
173
173
  should "use the given key prefix" do
174
174
  class Custom < Remodel::Entity; set_key_prefix 'my'; end
175
- assert_match /^my\d+$/, Custom.create('cx').key
175
+ assert_match /^my\d+$/, Custom.create(context).key
176
176
  end
177
177
 
178
178
  should "ensure that the prefix is letters only" do
@@ -185,8 +185,8 @@ class TestEntity < Test::Unit::TestCase
185
185
  context "#find" do
186
186
  setup do
187
187
  redis.flushdb
188
- @foo = Foo.create('cx', :x => 'hello', :y => 123)
189
- Foo.create('cx', :x => 'hallo', :y => 124)
188
+ @foo = Foo.create(context, :x => 'hello', :y => 123)
189
+ Foo.create(context, :x => 'hallo', :y => 124)
190
190
  end
191
191
 
192
192
  should "find and load an entity by key" do
@@ -202,17 +202,17 @@ class TestEntity < Test::Unit::TestCase
202
202
  end
203
203
 
204
204
  should "reject a key which does not exist" do
205
- assert_raise(Remodel::EntityNotFound) { Foo.find('cx', 'x66') }
205
+ assert_raise(Remodel::EntityNotFound) { Foo.find(context, 'x66') }
206
206
  end
207
207
 
208
208
  should "reject an id which does not exist" do
209
- assert_raise(Remodel::EntityNotFound) { Foo.find('cx', 66) }
209
+ assert_raise(Remodel::EntityNotFound) { Foo.find(context, 66) }
210
210
  end
211
211
  end
212
212
 
213
213
  context "properties" do
214
214
  should "have property x" do
215
- foo = Foo.new('cx')
215
+ foo = Foo.new(context)
216
216
  foo.x = 23
217
217
  assert_equal 23, foo.x
218
218
  foo.x += 10
@@ -220,45 +220,45 @@ class TestEntity < Test::Unit::TestCase
220
220
  end
221
221
 
222
222
  should "not have property z" do
223
- foo = Foo.new('cx')
223
+ foo = Foo.new(context)
224
224
  assert_raise(NoMethodError) { foo.z }
225
225
  assert_raise(NoMethodError) { foo.z = 42 }
226
226
  end
227
227
 
228
228
  context "types" do
229
229
  should "work with nil" do
230
- foo = Foo.create('cx', :x => nil)
230
+ foo = Foo.create(context, :x => nil)
231
231
  assert_equal nil, foo.reload.x
232
232
  end
233
233
 
234
234
  should "work with booleans" do
235
- foo = Foo.create('cx', :x => false)
235
+ foo = Foo.create(context, :x => false)
236
236
  assert_equal false, foo.reload.x
237
237
  end
238
238
 
239
239
  should "work with integers" do
240
- foo = Foo.create('cx', :x => -42)
240
+ foo = Foo.create(context, :x => -42)
241
241
  assert_equal -42, foo.reload.x
242
242
  end
243
243
 
244
244
  should "work with floats" do
245
- foo = Foo.create('cx', :x => 3.141)
245
+ foo = Foo.create(context, :x => 3.141)
246
246
  assert_equal 3.141, foo.reload.x
247
247
  end
248
248
 
249
249
  should "work with strings" do
250
- foo = Foo.create('cx', :x => 'hello')
250
+ foo = Foo.create(context, :x => 'hello')
251
251
  assert_equal 'hello', foo.reload.x
252
252
  end
253
253
 
254
254
  should "work with lists" do
255
- foo = Foo.create('cx', :x => [1, 2, 3])
255
+ foo = Foo.create(context, :x => [1, 2, 3])
256
256
  assert_equal [1, 2, 3], foo.reload.x
257
257
  end
258
258
 
259
259
  should "work with hashes" do
260
260
  hash = { 'a' => 17, 'b' => 'test' }
261
- foo = Foo.create('cx', :x => hash)
261
+ foo = Foo.create(context, :x => hash)
262
262
  assert_equal hash, foo.reload.x
263
263
  end
264
264
  end
@@ -266,8 +266,8 @@ class TestEntity < Test::Unit::TestCase
266
266
 
267
267
  context "#restore" do
268
268
  should "restore an entity from json" do
269
- before = Foo.create('cx', :x => 42, :y => true)
270
- after = Foo.restore(before.context, before.key, before.to_json)
269
+ before = Foo.create(context, :x => 42, :y => true)
270
+ after = Foo.restore(context, before.key, before.to_json)
271
271
  assert_equal before.key, after.key
272
272
  assert_equal before.x, after.x
273
273
  assert_equal before.y, after.y
@@ -10,35 +10,35 @@ class TestEntityDefaults < Test::Unit::TestCase
10
10
 
11
11
  context "[default values]" do
12
12
  should "be returned for missing properties" do
13
- bar = Bar.new('cx')
13
+ bar = Bar.new(context)
14
14
  assert_equal 123, bar.simple
15
15
  end
16
16
 
17
17
  should "be returned for properties that are nil" do
18
- bar = Bar.new('cx', :simple => 'cool')
18
+ bar = Bar.new(context, :simple => 'cool')
19
19
  bar.simple = nil
20
20
  assert_equal 123, bar.simple
21
21
  end
22
22
 
23
23
  should "not be returned for given properties" do
24
- bar = Bar.new('cx', :simple => 'cool')
24
+ bar = Bar.new(context, :simple => 'cool')
25
25
  assert_equal 'cool', bar.simple
26
26
  end
27
27
 
28
28
  should "not be stored" do
29
- bar = Bar.create('cx')
30
- assert !(/123/ =~ redis.hget('cx', bar.key))
29
+ bar = Bar.create(context)
30
+ assert !(/123/ =~ redis.hget(context, bar.key))
31
31
  end
32
32
 
33
33
  should "be returned by as_json" do
34
- bar = Bar.new('cx')
34
+ bar = Bar.new(context)
35
35
  assert_equal 123, bar.as_json[:simple]
36
36
  end
37
37
  end
38
38
 
39
39
  context "[collections]" do
40
40
  setup do
41
- @bar, @baz = Bar.new('cx'), Bar.new('cx')
41
+ @bar, @baz = Bar.new(context), Bar.new(context)
42
42
  end
43
43
 
44
44
  should "not share arrays" do
@@ -19,27 +19,27 @@ class TestEntityDelete < Test::Unit::TestCase
19
19
  context "delete" do
20
20
  setup do
21
21
  redis.flushdb
22
- @group = Group.create('cx', :name => 'ruby user group')
22
+ @group = Group.create(context, :name => 'ruby user group')
23
23
  @tim = @group.members.create(:name => 'Tim')
24
24
  @group.members.create(:name => 'Ben')
25
- @room = Room.create(:name => 'some office')
25
+ @room = Room.create(context, :name => 'some office')
26
26
  @group.room = @room
27
27
  @group.reload
28
28
  end
29
29
 
30
30
  should "ensure that the entity is persistent" do
31
- assert_raise(Remodel::EntityNotSaved) { Group.new('cx').delete }
31
+ assert_raise(Remodel::EntityNotSaved) { Group.new(context).delete }
32
32
  end
33
33
 
34
34
  should "delete the given entity" do
35
35
  @group.delete
36
- assert_nil redis.hget(@group.context, @group.key)
36
+ assert_nil redis.hget(context.key, @group.key)
37
37
  end
38
38
 
39
39
  should "delete any associations in redis" do
40
40
  @group.delete
41
- assert_nil redis.hget(@group.context, "#{@group.key}_members")
42
- assert_nil redis.hget(@group.context, "#{@group.key}_room")
41
+ assert_nil redis.hget(context.key, "#{@group.key}_members")
42
+ assert_nil redis.hget(context.key, "#{@group.key}_room")
43
43
  end
44
44
 
45
45
  context "has_one" do
@@ -8,25 +8,25 @@ class TestEntityShortnames < Test::Unit::TestCase
8
8
 
9
9
  context "[short names]" do
10
10
  setup do
11
- @bar = Bar.create('cx', :foo => 42)
11
+ @bar = Bar.create(context, :foo => 42)
12
12
  end
13
-
13
+
14
14
  should "be used when storing properties" do
15
- serialized = redis.hget('cx', @bar.key)
15
+ serialized = redis.hget(context.key, @bar.key)
16
16
  assert !serialized.match(/foo/)
17
17
  assert serialized.match(/z/)
18
18
  end
19
-
19
+
20
20
  should "work in roundtrip" do
21
21
  @bar.reload
22
22
  assert_equal 42, @bar.foo
23
23
  end
24
-
24
+
25
25
  should "not be used in as_json" do
26
26
  assert !@bar.as_json.has_key?(:z)
27
27
  assert @bar.as_json.has_key?(:foo)
28
28
  end
29
-
29
+
30
30
  should "not be used in inspect" do
31
31
  assert !@bar.inspect.match(/z/)
32
32
  assert @bar.inspect.match(/foo/)
@@ -14,19 +14,19 @@ class TestManyToMany < Test::Unit::TestCase
14
14
 
15
15
  context "both associations" do
16
16
  should "be empty by default" do
17
- assert_equal [], Person.new('cx').groups
18
- assert_equal [], Group.new('cx').members
17
+ assert_equal [], Person.new(context).groups
18
+ assert_equal [], Group.new(context).members
19
19
  end
20
20
 
21
21
  context "create" do
22
22
  should "add a new group to both associations" do
23
- tim = Person.create('cx', :name => 'tim')
23
+ tim = Person.create(context, :name => 'tim')
24
24
  rugb = tim.groups.create :name => 'rug-b'
25
25
  assert_equal [tim], rugb.members
26
26
  end
27
27
 
28
28
  should "add a new person to both associations" do
29
- rugb = Group.create('cx', :name => 'rug-b')
29
+ rugb = Group.create(context, :name => 'rug-b')
30
30
  tim = rugb.members.create :name => 'tim'
31
31
  assert_equal [rugb], tim.groups
32
32
  end
@@ -34,8 +34,8 @@ class TestManyToMany < Test::Unit::TestCase
34
34
 
35
35
  context "add" do
36
36
  setup do
37
- @tim = Person.create('cx', :name => 'tim')
38
- @rugb = Group.create('cx', :name => 'rug-b')
37
+ @tim = Person.create(context, :name => 'tim')
38
+ @rugb = Group.create(context, :name => 'rug-b')
39
39
  end
40
40
 
41
41
  should "add a new group to both associations" do
@@ -53,7 +53,7 @@ class TestManyToMany < Test::Unit::TestCase
53
53
 
54
54
  context "remove" do
55
55
  setup do
56
- @tim = Person.create('cx', :name => 'tim')
56
+ @tim = Person.create(context, :name => 'tim')
57
57
  @rugb = @tim.groups.create(:name => 'rug-b')
58
58
  @erlang = @tim.groups.create(:name => 'erlang')
59
59
  @aws = @tim.groups.create(:name => 'aws')
@@ -16,29 +16,29 @@ class TestManyToOne < Test::Unit::TestCase
16
16
  context "has_many" do
17
17
  context "association" do
18
18
  should "exist" do
19
- assert Puzzle.create('cx').respond_to?(:pieces)
19
+ assert Puzzle.create(context).respond_to?(:pieces)
20
20
  end
21
21
 
22
22
  should "return an empty list by default" do
23
- assert_equal [], Puzzle.create('cx').pieces
23
+ assert_equal [], Puzzle.create(context).pieces
24
24
  end
25
25
 
26
26
  should "return any existing children" do
27
- puzzle = Puzzle.create('cx')
28
- red_piece = Piece.create('cx', :color => 'red')
29
- blue_piece = Piece.create('cx', :color => 'blue')
27
+ puzzle = Puzzle.create(context)
28
+ red_piece = Piece.create(context, :color => 'red')
29
+ blue_piece = Piece.create(context, :color => 'blue')
30
30
  value = JSON.generate([red_piece.key, blue_piece.key])
31
- redis.hset 'cx', "#{puzzle.key}_pieces", value
31
+ redis.hset(context.key, "#{puzzle.key}_pieces", value)
32
32
  assert_equal 2, puzzle.pieces.size
33
33
  assert_equal Piece, puzzle.pieces[0].class
34
34
  assert_equal 'red', puzzle.pieces[0].color
35
35
  end
36
36
 
37
37
  should "not return any child multiple times" do
38
- puzzle = Puzzle.create('cx')
39
- red_piece = Piece.create('cx', :color => 'red')
38
+ puzzle = Puzzle.create(context)
39
+ red_piece = Piece.create(context, :color => 'red')
40
40
  value = JSON.generate([red_piece.key, red_piece.key])
41
- redis.hset 'cx', "#{puzzle.key}_pieces", value
41
+ redis.hset(context.key, "#{puzzle.key}_pieces", value)
42
42
  assert_equal 1, puzzle.pieces.size
43
43
  assert_equal Piece, puzzle.pieces[0].class
44
44
  assert_equal 'red', puzzle.pieces[0].color
@@ -46,17 +46,17 @@ class TestManyToOne < Test::Unit::TestCase
46
46
 
47
47
  context "create" do
48
48
  should "have a create method" do
49
- assert Puzzle.create('cx').pieces.respond_to?(:create)
49
+ assert Puzzle.create(context).pieces.respond_to?(:create)
50
50
  end
51
51
 
52
52
  should "work without attributes" do
53
- puzzle = Puzzle.create('cx')
53
+ puzzle = Puzzle.create(context)
54
54
  piece = puzzle.pieces.create
55
55
  assert piece.is_a?(Piece)
56
56
  end
57
57
 
58
58
  should "create and store a new child" do
59
- puzzle = Puzzle.create('cx')
59
+ puzzle = Puzzle.create(context)
60
60
  puzzle.pieces.create :color => 'green'
61
61
  assert_equal 1, puzzle.pieces.size
62
62
  puzzle.reload
@@ -66,7 +66,7 @@ class TestManyToOne < Test::Unit::TestCase
66
66
  end
67
67
 
68
68
  should "associate the created child with self" do
69
- puzzle = Puzzle.create('cx', :topic => 'provence')
69
+ puzzle = Puzzle.create(context, :topic => 'provence')
70
70
  piece = puzzle.pieces.create :color => 'green'
71
71
  assert_equal 'provence', piece.puzzle.topic
72
72
  end
@@ -74,8 +74,8 @@ class TestManyToOne < Test::Unit::TestCase
74
74
 
75
75
  context "add" do
76
76
  should "add the given entity to the association" do
77
- puzzle = Puzzle.create('cx')
78
- piece = Piece.create('cx', :color => 'white')
77
+ puzzle = Puzzle.create(context)
78
+ piece = Piece.create(context, :color => 'white')
79
79
  puzzle.pieces.add piece
80
80
  assert_equal 1, puzzle.pieces.size
81
81
  puzzle.reload
@@ -87,7 +87,7 @@ class TestManyToOne < Test::Unit::TestCase
87
87
 
88
88
  context "find" do
89
89
  setup do
90
- @puzzle = Puzzle.create('cx')
90
+ @puzzle = Puzzle.create(context)
91
91
  5.times { @puzzle.pieces.create :color => 'blue' }
92
92
  end
93
93
 
@@ -106,9 +106,9 @@ class TestManyToOne < Test::Unit::TestCase
106
106
 
107
107
  context "reload" do
108
108
  should "reset has_many associations" do
109
- puzzle = Puzzle.create('cx')
109
+ puzzle = Puzzle.create(context)
110
110
  piece = puzzle.pieces.create :color => 'black'
111
- redis.hdel 'cx', "#{puzzle.key}_pieces"
111
+ redis.hdel(context.key, "#{puzzle.key}_pieces")
112
112
  puzzle.reload
113
113
  assert_equal [], puzzle.pieces
114
114
  end
data/test/test_mappers.rb CHANGED
@@ -15,7 +15,7 @@ class TestMappers < Test::Unit::TestCase
15
15
 
16
16
  context "create" do
17
17
  setup do
18
- @item = Item.create('cx', :time => Time.at(1234567890), :date => Date.parse("1972-06-16"))
18
+ @item = Item.create(context, :time => Time.at(1234567890), :date => Date.parse("1972-06-16"))
19
19
  end
20
20
 
21
21
  should "store unmapped values" do
@@ -35,13 +35,13 @@ class TestMappers < Test::Unit::TestCase
35
35
  end
36
36
 
37
37
  should "serialize mapped values correctly" do
38
- json = redis.hget(@item.context, @item.key)
38
+ json = redis.hget(context.key, @item.key)
39
39
  assert_match /1234567890/, json
40
40
  assert_match /"1972-06-16"/, json
41
41
  end
42
42
 
43
43
  should "handle nil values" do
44
- item = Item.create('cx')
44
+ item = Item.create(context)
45
45
  assert_nil item.boolean
46
46
  assert_nil item.string
47
47
  assert_nil item.integer
@@ -53,14 +53,14 @@ class TestMappers < Test::Unit::TestCase
53
53
  end
54
54
 
55
55
  should "reject invalid types" do
56
- assert_raise(Remodel::InvalidType) { Item.create('cx', :boolean => 'hello') }
57
- assert_raise(Remodel::InvalidType) { Item.create('cx', :string => true) }
58
- assert_raise(Remodel::InvalidType) { Item.create('cx', :integer => 33.5) }
59
- assert_raise(Remodel::InvalidType) { Item.create('cx', :float => 5) }
60
- assert_raise(Remodel::InvalidType) { Item.create('cx', :array => {}) }
61
- assert_raise(Remodel::InvalidType) { Item.create('cx', :hash => []) }
62
- assert_raise(Remodel::InvalidType) { Item.create('cx', :time => Date.new) }
63
- assert_raise(Remodel::InvalidType) { Item.create('cx', :date => Time.now) }
56
+ assert_raise(Remodel::InvalidType) { Item.create(context, :boolean => 'hello') }
57
+ assert_raise(Remodel::InvalidType) { Item.create(context, :string => true) }
58
+ assert_raise(Remodel::InvalidType) { Item.create(context, :integer => 33.5) }
59
+ assert_raise(Remodel::InvalidType) { Item.create(context, :float => 5) }
60
+ assert_raise(Remodel::InvalidType) { Item.create(context, :array => {}) }
61
+ assert_raise(Remodel::InvalidType) { Item.create(context, :hash => []) }
62
+ assert_raise(Remodel::InvalidType) { Item.create(context, :time => Date.new) }
63
+ assert_raise(Remodel::InvalidType) { Item.create(context, :date => Time.now) }
64
64
  end
65
65
  end
66
66
 
@@ -16,65 +16,65 @@ class TestOneToMany < Test::Unit::TestCase
16
16
  context "has_one" do
17
17
  context "association getter" do
18
18
  should "exist" do
19
- assert Piece.create('cx').respond_to?(:puzzle)
19
+ assert Piece.create(context).respond_to?(:puzzle)
20
20
  end
21
21
 
22
22
  should "return nil by default" do
23
- assert_nil Piece.create('cx').puzzle
23
+ assert_nil Piece.create(context).puzzle
24
24
  end
25
25
 
26
26
  should "return the associated entity" do
27
- puzzle = Puzzle.create('cx', :topic => 'animals')
28
- piece = Piece.create('cx')
29
- redis.hset('cx', "#{piece.key}_puzzle", puzzle.key)
27
+ puzzle = Puzzle.create(context, :topic => 'animals')
28
+ piece = Piece.create(context)
29
+ redis.hset(context.key, "#{piece.key}_puzzle", puzzle.key)
30
30
  assert_equal 'animals', piece.puzzle.topic
31
31
  end
32
32
  end
33
33
 
34
34
  context "association setter" do
35
35
  should "exist" do
36
- assert Piece.create('cx').respond_to?(:'puzzle=')
36
+ assert Piece.create(context).respond_to?(:'puzzle=')
37
37
  end
38
38
 
39
39
  should "store the key of the associated entity" do
40
- puzzle = Puzzle.create('cx')
41
- piece = Piece.create('cx')
40
+ puzzle = Puzzle.create(context)
41
+ piece = Piece.create(context)
42
42
  piece.puzzle = puzzle
43
- assert_equal puzzle.key, redis.hget(puzzle.context, "#{piece.key}_puzzle")
43
+ assert_equal puzzle.key, redis.hget(context.key, "#{piece.key}_puzzle")
44
44
  end
45
45
 
46
46
  should "add the entity to the reverse association" do
47
- puzzle = Puzzle.create('cx')
48
- piece = Piece.create('cx')
47
+ puzzle = Puzzle.create(context)
48
+ piece = Piece.create(context)
49
49
  piece.puzzle = puzzle
50
50
  assert_equal 1, puzzle.pieces.size
51
51
  assert_equal piece.id, puzzle.pieces.first.id
52
52
  end
53
53
 
54
54
  should "remove the entity from the old reverse association" do
55
- puzzle = Puzzle.create('cx')
55
+ puzzle = Puzzle.create(context)
56
56
  piece = puzzle.pieces.create
57
- new_puzzle = Puzzle.create('cx')
57
+ new_puzzle = Puzzle.create(context)
58
58
  piece.puzzle = new_puzzle
59
59
  assert_equal [], puzzle.reload.pieces
60
60
  end
61
61
 
62
62
  should "be settable to nil" do
63
- piece = Piece.create('cx')
63
+ piece = Piece.create(context)
64
64
  piece.puzzle = nil
65
65
  assert_nil piece.puzzle
66
66
  end
67
67
 
68
68
  should "remove the key if set to nil" do
69
- piece = Piece.create('cx')
70
- piece.puzzle = Puzzle.create('cx')
69
+ piece = Piece.create(context)
70
+ piece.puzzle = Puzzle.create(context)
71
71
  piece.puzzle = nil
72
72
  assert_nil redis.hget(piece.context, "#{piece.key}_puzzle")
73
73
  end
74
74
 
75
75
  should "remove the entity from the reverse association if set to nil" do
76
- puzzle = Puzzle.create('cx')
77
- piece = Piece.create('cx')
76
+ puzzle = Puzzle.create(context)
77
+ piece = Piece.create(context)
78
78
  piece.puzzle = puzzle
79
79
  piece.puzzle = nil
80
80
  puzzle.reload
@@ -85,9 +85,9 @@ class TestOneToMany < Test::Unit::TestCase
85
85
 
86
86
  context "reload" do
87
87
  should "reset has_one associations" do
88
- piece = Piece.create('cx', :color => 'black')
89
- piece.puzzle = Puzzle.create('cx')
90
- redis.hdel 'cx', "#{piece.key}_puzzle"
88
+ piece = Piece.create(context, :color => 'black')
89
+ piece.puzzle = Puzzle.create(context)
90
+ redis.hdel(context.key, "#{piece.key}_puzzle")
91
91
  piece.reload
92
92
  assert_nil piece.puzzle
93
93
  end
@@ -14,14 +14,14 @@ class TestOneToOne < Test::Unit::TestCase
14
14
 
15
15
  context "both associations" do
16
16
  should "be nil by default" do
17
- assert_equal nil, Man.new('cx').wife
18
- assert_equal nil, Woman.new('cx').husband
17
+ assert_equal nil, Man.new(context).wife
18
+ assert_equal nil, Woman.new(context).husband
19
19
  end
20
20
 
21
21
  context "setter" do
22
22
  setup do
23
- @bill = Man.create('cx', :name => 'Bill')
24
- @mary = Woman.create('cx', :name => 'Mary')
23
+ @bill = Man.create(context, :name => 'Bill')
24
+ @mary = Woman.create(context, :name => 'Mary')
25
25
  end
26
26
 
27
27
  context "non-nil value" do
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ class TestRemodel < Test::Unit::TestCase
4
+
5
+ context "create_context" do
6
+ should "create a context" do
7
+ context = Remodel.create_context('foo')
8
+ assert_equal Remodel::Context, context.class
9
+ assert_equal 'foo', context.key
10
+ end
11
+
12
+ should "create a caching context, if specified" do
13
+ context = Remodel.create_context('foo', :caching => true)
14
+ assert_equal Remodel::CachingContext, context.class
15
+ assert_equal 'foo', context.key
16
+ end
17
+ end
18
+
19
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 1
9
- version: 0.3.1
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tim Lossen
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-06-16 00:00:00 +02:00
17
+ date: 2011-07-05 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -36,10 +36,13 @@ files:
36
36
  - docs/remodel.html
37
37
  - example/book.rb
38
38
  - lib/remodel.rb
39
+ - lib/remodel/caching_context.rb
40
+ - lib/remodel/context.rb
39
41
  - lib/remodel/entity.rb
40
42
  - lib/remodel/has_many.rb
41
43
  - lib/remodel/mapper.rb
42
44
  - test/helper.rb
45
+ - test/test_caching_context.rb
43
46
  - test/test_entity.rb
44
47
  - test/test_entity_defaults.rb
45
48
  - test/test_entity_delete.rb
@@ -50,6 +53,7 @@ files:
50
53
  - test/test_monkeypatches.rb
51
54
  - test/test_one_to_many.rb
52
55
  - test/test_one_to_one.rb
56
+ - test/test_remodel.rb
53
57
  has_rdoc: true
54
58
  homepage: http://github.com/tlossen/remodel
55
59
  licenses: []
@@ -84,6 +88,7 @@ specification_version: 3
84
88
  summary: a minimal ORM (object-redis-mapper)
85
89
  test_files:
86
90
  - test/helper.rb
91
+ - test/test_caching_context.rb
87
92
  - test/test_entity.rb
88
93
  - test/test_entity_defaults.rb
89
94
  - test/test_entity_delete.rb
@@ -94,3 +99,4 @@ test_files:
94
99
  - test/test_monkeypatches.rb
95
100
  - test/test_one_to_many.rb
96
101
  - test/test_one_to_one.rb
102
+ - test/test_remodel.rb