remodel 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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