remodel 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +12 -19
- data/VERSION +1 -1
- data/lib/remodel.rb +40 -36
- data/remodel.gemspec +2 -2
- data/test/helper.rb +2 -2
- data/test/test_entity.rb +45 -45
- data/test/test_many_to_many.rb +10 -10
- data/test/test_many_to_one.rb +25 -9
- data/test/test_mappers.rb +5 -5
- data/test/test_monkeypatches.rb +2 -2
- data/test/test_one_to_many.rb +7 -7
- data/test/test_one_to_one.rb +7 -7
- metadata +2 -2
data/README.md
CHANGED
@@ -29,24 +29,17 @@ persistence to disk. for example, on my macbook (2 ghz):
|
|
29
29
|
$ brew install redis
|
30
30
|
$ gem install redis
|
31
31
|
|
32
|
-
2.
|
33
|
-
plus ruby bindings:
|
32
|
+
2. start redis:
|
34
33
|
|
35
|
-
$
|
36
|
-
$ gem install yajl-ruby
|
34
|
+
$ ./redis-server
|
37
35
|
|
38
|
-
3.
|
39
|
-
|
40
|
-
$ redis-server
|
41
|
-
|
42
|
-
4. now the tests should run successfully:
|
36
|
+
3. now the tests should run successfully:
|
43
37
|
|
44
38
|
$ rake
|
45
39
|
Started
|
46
|
-
|
47
|
-
Finished in 0.
|
48
|
-
|
49
|
-
|
40
|
+
.......................................................................................
|
41
|
+
Finished in 0.072304 seconds.
|
42
|
+
87 tests, 138 assertions, 0 failures, 0 errors
|
50
43
|
|
51
44
|
## example
|
52
45
|
|
@@ -79,23 +72,23 @@ now you can do:
|
|
79
72
|
|
80
73
|
* [how to redis](http://www.paperplanes.de/2009/10/30/how_to_redis.html)
|
81
74
|
— good overview of different mapping options by [mattmatt](http://github.com/mattmatt).
|
82
|
-
* [hurl](http://github.com/defunkt/hurl) — basically
|
83
|
-
defunkts [Hurl::Model](http://github.com/defunkt/hurl/blob/master/models/model.rb).
|
75
|
+
* [hurl](http://github.com/defunkt/hurl) — basically
|
76
|
+
defunkts [Hurl::Model](http://github.com/defunkt/hurl/blob/master/models/model.rb) is what i started with.
|
84
77
|
* [ohm](http://github.com/soveran/ohm) — object-hash mapping for redis.
|
85
78
|
somewhat similar, but instead of serializing to json, stores each attribute under a separate key.
|
86
79
|
|
87
80
|
|
88
81
|
## todo
|
89
82
|
|
90
|
-
*
|
91
|
-
* benchmarks
|
92
|
-
* `delete`
|
83
|
+
* better docs
|
93
84
|
* `find_by`
|
85
|
+
* make serializer (json, messagepack, marshal ...) configurable
|
86
|
+
* benchmarks
|
94
87
|
|
95
88
|
|
96
89
|
## status
|
97
90
|
|
98
|
-
alpha
|
91
|
+
still pretty alpha — play around at your own risk :)
|
99
92
|
|
100
93
|
|
101
94
|
## license
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/lib/remodel.rb
CHANGED
@@ -16,7 +16,7 @@ end
|
|
16
16
|
|
17
17
|
# Define `Boolean` as the superclass of `true` and `false`.
|
18
18
|
module Boolean; end
|
19
|
-
true.extend(Boolean)
|
19
|
+
true.extend(Boolean)
|
20
20
|
false.extend(Boolean)
|
21
21
|
|
22
22
|
# Find the `Class` object for a given class name, which can be a `String` or `Symbol` (or `Class`).
|
@@ -28,7 +28,7 @@ end
|
|
28
28
|
#### Remodel
|
29
29
|
|
30
30
|
module Remodel
|
31
|
-
|
31
|
+
|
32
32
|
# By default, we expect to find the redis server on `localhost:6379` —
|
33
33
|
# otherwise you will have to set `Remodel.redis` to a suitably initialized redis client.
|
34
34
|
def self.redis
|
@@ -45,7 +45,7 @@ module Remodel
|
|
45
45
|
class EntityNotSaved < Error; end
|
46
46
|
class InvalidKeyPrefix < Error; end
|
47
47
|
class InvalidType < Error; end
|
48
|
-
|
48
|
+
|
49
49
|
#### Mapper
|
50
50
|
|
51
51
|
# A mapper converts a given value into a native JSON value —
|
@@ -60,13 +60,13 @@ module Remodel
|
|
60
60
|
@pack_method = pack_method
|
61
61
|
@unpack_method = unpack_method
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def pack(value)
|
65
65
|
return nil if value.nil?
|
66
66
|
raise(InvalidType, "#{value.inspect} is not a #{@clazz}") if @clazz && !value.is_a?(@clazz)
|
67
67
|
@pack_method ? value.send(@pack_method) : value
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
def unpack(value)
|
71
71
|
return nil if value.nil?
|
72
72
|
@unpack_method ? @clazz.send(@unpack_method, value) : value
|
@@ -105,11 +105,15 @@ module Remodel
|
|
105
105
|
add(@clazz.create(attributes))
|
106
106
|
end
|
107
107
|
|
108
|
+
def find(id)
|
109
|
+
detect { |x| x.id == id } || raise(EntityNotFound, "no element with id #{id}")
|
110
|
+
end
|
111
|
+
|
108
112
|
def add(entity)
|
109
113
|
_add_to_reverse_association_of(entity) if @reverse
|
110
114
|
_add(entity)
|
111
115
|
end
|
112
|
-
|
116
|
+
|
113
117
|
def remove(entity)
|
114
118
|
_remove_from_reverse_association_of(entity) if @reverse
|
115
119
|
_remove(entity)
|
@@ -136,7 +140,7 @@ module Remodel
|
|
136
140
|
entity.send("_#{@reverse}=", @this)
|
137
141
|
end
|
138
142
|
end
|
139
|
-
|
143
|
+
|
140
144
|
def _remove_from_reverse_association_of(entity)
|
141
145
|
if entity.send(@reverse).is_a? HasMany
|
142
146
|
entity.send(@reverse).send(:_remove, @this)
|
@@ -153,13 +157,13 @@ module Remodel
|
|
153
157
|
end.compact
|
154
158
|
end
|
155
159
|
end
|
156
|
-
|
160
|
+
|
157
161
|
#### Entity
|
158
162
|
|
159
163
|
# The superclass of all persistent remodel entities.
|
160
164
|
class Entity
|
161
165
|
attr_accessor :key
|
162
|
-
|
166
|
+
|
163
167
|
def initialize(attributes = {}, key = nil)
|
164
168
|
@attributes = {}
|
165
169
|
@key = key
|
@@ -168,22 +172,22 @@ module Remodel
|
|
168
172
|
send("#{name}=", value) if respond_to? "#{name}="
|
169
173
|
end
|
170
174
|
end
|
171
|
-
|
175
|
+
|
172
176
|
def id
|
173
177
|
key && key.split(':').last.to_i
|
174
178
|
end
|
175
|
-
|
179
|
+
|
176
180
|
def save
|
177
181
|
@key = self.class.next_key unless @key
|
178
182
|
Remodel.redis.set(@key, to_json)
|
179
183
|
self
|
180
184
|
end
|
181
|
-
|
185
|
+
|
182
186
|
def update(properties)
|
183
187
|
properties.each { |name, value| send("#{name}=", value) }
|
184
188
|
save
|
185
189
|
end
|
186
|
-
|
190
|
+
|
187
191
|
def reload
|
188
192
|
raise EntityNotSaved unless @key
|
189
193
|
initialize(self.class.parse(self.class.fetch(@key)), @key)
|
@@ -192,7 +196,7 @@ module Remodel
|
|
192
196
|
end
|
193
197
|
self
|
194
198
|
end
|
195
|
-
|
199
|
+
|
196
200
|
def delete
|
197
201
|
raise EntityNotSaved unless @key
|
198
202
|
Remodel.redis.del(@key)
|
@@ -205,7 +209,7 @@ module Remodel
|
|
205
209
|
def to_json
|
206
210
|
JSON.generate(self.class.pack(@attributes))
|
207
211
|
end
|
208
|
-
|
212
|
+
|
209
213
|
def inspect
|
210
214
|
properties = @attributes.map { |name, value| "#{name}: #{value.inspect}" }.join(', ')
|
211
215
|
"\#<#{self.class.name}(#{id}) #{properties}>"
|
@@ -214,12 +218,12 @@ module Remodel
|
|
214
218
|
def self.create(attributes = {})
|
215
219
|
new(attributes).save
|
216
220
|
end
|
217
|
-
|
221
|
+
|
218
222
|
def self.find(key)
|
219
223
|
key = "#{key_prefix}:#{key}" if key.kind_of? Integer
|
220
224
|
restore(key, fetch(key))
|
221
225
|
end
|
222
|
-
|
226
|
+
|
223
227
|
def self.all
|
224
228
|
keys = Remodel.redis.keys("#{key_prefix}:*").select { |k| k =~ /:[0-9]+$/ }
|
225
229
|
values = keys.empty? ? [] : Remodel.redis.mget(keys)
|
@@ -231,7 +235,7 @@ module Remodel
|
|
231
235
|
def self.restore(key, json)
|
232
236
|
new(parse(json), key)
|
233
237
|
end
|
234
|
-
|
238
|
+
|
235
239
|
#### DSL for subclasses
|
236
240
|
|
237
241
|
protected
|
@@ -248,10 +252,10 @@ module Remodel
|
|
248
252
|
define_method(name) { @attributes[name] }
|
249
253
|
define_method("#{name}=") { |value| @attributes[name] = value }
|
250
254
|
end
|
251
|
-
|
255
|
+
|
252
256
|
def self.has_many(name, options)
|
253
257
|
var = "@association_#{name}".to_sym
|
254
|
-
|
258
|
+
|
255
259
|
define_method(name) do
|
256
260
|
if instance_variable_defined? var
|
257
261
|
instance_variable_get(var)
|
@@ -261,10 +265,10 @@ module Remodel
|
|
261
265
|
end
|
262
266
|
end
|
263
267
|
end
|
264
|
-
|
268
|
+
|
265
269
|
def self.has_one(name, options)
|
266
270
|
var = "@association_#{name}".to_sym
|
267
|
-
|
271
|
+
|
268
272
|
define_method(name) do
|
269
273
|
if instance_variable_defined? var
|
270
274
|
instance_variable_get(var)
|
@@ -274,12 +278,12 @@ module Remodel
|
|
274
278
|
instance_variable_set(var, clazz.find(value_key)) if value_key
|
275
279
|
end
|
276
280
|
end
|
277
|
-
|
281
|
+
|
278
282
|
define_method("#{name}=") do |value|
|
279
283
|
send("_reverse_association_of_#{name}=", value) if options[:reverse]
|
280
284
|
send("_#{name}=", value)
|
281
285
|
end
|
282
|
-
|
286
|
+
|
283
287
|
define_method("_#{name}=") do |value|
|
284
288
|
if value
|
285
289
|
instance_variable_set(var, value)
|
@@ -289,7 +293,7 @@ module Remodel
|
|
289
293
|
Remodel.redis.del("#{key}:#{name}")
|
290
294
|
end
|
291
295
|
end; private "_#{name}="
|
292
|
-
|
296
|
+
|
293
297
|
if options[:reverse]
|
294
298
|
define_method("_reverse_association_of_#{name}=") do |value|
|
295
299
|
if value
|
@@ -312,30 +316,30 @@ module Remodel
|
|
312
316
|
end; private "_reverse_association_of_#{name}="
|
313
317
|
end
|
314
318
|
end
|
315
|
-
|
319
|
+
|
316
320
|
#### Helper methods
|
317
321
|
|
318
322
|
private
|
319
|
-
|
323
|
+
|
320
324
|
def self.fetch(key)
|
321
325
|
Remodel.redis.get(key) || raise(EntityNotFound, "no #{name} with key #{key}")
|
322
326
|
end
|
323
|
-
|
327
|
+
|
324
328
|
# Each entity has its own sequence to generate unique ids.
|
325
329
|
def self.next_key
|
326
330
|
id = Remodel.redis.incr("#{key_prefix}:seq")
|
327
331
|
"#{key_prefix}:#{id}"
|
328
332
|
end
|
329
|
-
|
333
|
+
|
330
334
|
# Default key prefix is the first letter of the class name, in lowercase.
|
331
335
|
def self.key_prefix
|
332
336
|
@key_prefix ||= name.split('::').last[0,1].downcase
|
333
337
|
end
|
334
|
-
|
338
|
+
|
335
339
|
def self.parse(json)
|
336
340
|
unpack(JSON.parse(json))
|
337
341
|
end
|
338
|
-
|
342
|
+
|
339
343
|
def self.pack(attributes)
|
340
344
|
result = {}
|
341
345
|
attributes.each do |name, value|
|
@@ -343,7 +347,7 @@ module Remodel
|
|
343
347
|
end
|
344
348
|
result
|
345
349
|
end
|
346
|
-
|
350
|
+
|
347
351
|
def self.unpack(attributes)
|
348
352
|
result = {}
|
349
353
|
attributes.each do |name, value|
|
@@ -352,16 +356,16 @@ module Remodel
|
|
352
356
|
end
|
353
357
|
result
|
354
358
|
end
|
355
|
-
|
359
|
+
|
356
360
|
# Lazy init
|
357
361
|
def self.mapper
|
358
362
|
@mapper ||= {}
|
359
363
|
end
|
360
|
-
|
364
|
+
|
361
365
|
def self.default_values
|
362
366
|
@default_values ||= {}
|
363
367
|
end
|
364
|
-
|
368
|
+
|
365
369
|
end
|
366
|
-
|
370
|
+
|
367
371
|
end
|
data/remodel.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{remodel}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tim Lossen"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-05-03}
|
13
13
|
s.default_executable = %q{redis-monitor.rb}
|
14
14
|
s.description = %q{build your domain model in ruby, persist your objects to redis.}
|
15
15
|
s.email = %q{tim@lossen.de}
|
data/test/helper.rb
CHANGED
data/test/test_entity.rb
CHANGED
@@ -17,60 +17,60 @@ class TestEntity < Test::Unit::TestCase
|
|
17
17
|
assert 1, foo.x
|
18
18
|
assert 2, foo.y
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
should "ignore undefined properties" do
|
22
22
|
foo = Foo.new :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
27
|
foo = Foo.new :x => 23
|
28
28
|
assert_equal nil, foo.key
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
should "not set the id" do
|
32
32
|
foo = Foo.new :x => 23
|
33
33
|
assert_equal nil, foo.id
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
should "use default values for missing properties" do
|
37
37
|
bar = Bar.new
|
38
38
|
assert_equal 123, bar.d
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
should "not use default values for given properties" do
|
42
42
|
bar = Bar.new :d => 'cool'
|
43
43
|
assert_equal 'cool', bar.d
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
context "create" do
|
48
48
|
setup do
|
49
49
|
redis.flushdb
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
should "work without attributes" do
|
53
53
|
foo = Foo.create
|
54
54
|
assert foo.is_a?(Foo)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
should "give the entity a key based on the class name" do
|
58
58
|
assert_equal 'f:1', Foo.create.key
|
59
59
|
assert_equal 'b:1', Bar.create.key
|
60
60
|
assert_equal 'b:2', Bar.create.key
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
should "give the entity an id which is unique per entity class" do
|
64
64
|
assert_equal 1, Foo.create.id
|
65
65
|
assert_equal 1, Bar.create.id
|
66
66
|
assert_equal 2, Bar.create.id
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
should "store the entity under its key" do
|
70
70
|
foo = Foo.create :x => 'hello', :y => false
|
71
71
|
assert redis.exists(foo.key)
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
should "store all properties" do
|
75
75
|
foo = Foo.create :x => 'hello', :y => false
|
76
76
|
foo.reload
|
@@ -87,23 +87,23 @@ class TestEntity < Test::Unit::TestCase
|
|
87
87
|
bar = Bar.create
|
88
88
|
assert_equal 123, bar.d
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
should "not use default values for given properties" do
|
92
92
|
bar = Bar.create :d => 'cool'
|
93
93
|
assert_equal 'cool', bar.d
|
94
94
|
end
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
context "save" do
|
98
98
|
setup do
|
99
99
|
redis.flushdb
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
should "give the entity a key, if necessary" do
|
103
103
|
foo = Foo.new.save
|
104
104
|
assert foo.key
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
should "store the entity under its key" do
|
108
108
|
foo = Foo.new :x => 'hello', :y => false
|
109
109
|
foo.save
|
@@ -118,7 +118,7 @@ class TestEntity < Test::Unit::TestCase
|
|
118
118
|
assert_equal false, foo.y
|
119
119
|
end
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
context "reload" do
|
123
123
|
setup do
|
124
124
|
@foo = Foo.create :x => 'hello', :y => true
|
@@ -130,41 +130,41 @@ class TestEntity < Test::Unit::TestCase
|
|
130
130
|
assert_equal 23, @foo.x
|
131
131
|
assert_equal 'adios', @foo.y
|
132
132
|
end
|
133
|
-
|
133
|
+
|
134
134
|
should "keep the key" do
|
135
135
|
key = @foo.key
|
136
136
|
@foo.reload
|
137
137
|
assert_equal key, @foo.key
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
should "stay the same object" do
|
141
141
|
id = @foo.object_id
|
142
142
|
@foo.reload
|
143
143
|
assert_equal id, @foo.object_id
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
should "raise EntityNotFound if the entity does not exist any more" do
|
147
147
|
redis.del @foo.key
|
148
148
|
assert_raise(Remodel::EntityNotFound) { @foo.reload }
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
should "raise EntityNotSaved if the entity was never saved" do
|
152
152
|
assert_raise(Remodel::EntityNotSaved) { Foo.new.reload }
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
context "update" do
|
157
157
|
setup do
|
158
158
|
redis.flushdb
|
159
159
|
@foo = Foo.create :x => 'Tim', :y => true
|
160
160
|
end
|
161
|
-
|
161
|
+
|
162
162
|
should "set the given properties" do
|
163
163
|
@foo.update(:x => 12, :y => 'Jan')
|
164
164
|
assert_equal 12, @foo.x
|
165
165
|
assert_equal 'Jan', @foo.y
|
166
166
|
end
|
167
|
-
|
167
|
+
|
168
168
|
should "save the entity" do
|
169
169
|
@foo.update(:x => 12, :y => 'Jan')
|
170
170
|
@foo.reload
|
@@ -172,13 +172,13 @@ class TestEntity < Test::Unit::TestCase
|
|
172
172
|
assert_equal 'Jan', @foo.y
|
173
173
|
end
|
174
174
|
end
|
175
|
-
|
175
|
+
|
176
176
|
context "delete" do
|
177
177
|
setup do
|
178
178
|
redis.flushdb
|
179
179
|
@foo = Foo.create :x => 'Tim', :y => true
|
180
180
|
end
|
181
|
-
|
181
|
+
|
182
182
|
should "delete the given entity" do
|
183
183
|
@foo.delete
|
184
184
|
assert_nil redis.get(@foo.key)
|
@@ -188,7 +188,7 @@ class TestEntity < Test::Unit::TestCase
|
|
188
188
|
assert_raise(Remodel::EntityNotSaved) { Foo.new.delete }
|
189
189
|
end
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
context "to_json" do
|
193
193
|
should "serialize to json" do
|
194
194
|
foo = Foo.new :x => 42, :y => true
|
@@ -196,7 +196,7 @@ class TestEntity < Test::Unit::TestCase
|
|
196
196
|
assert_match /"y":true/, foo.to_json
|
197
197
|
end
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
context "as_json" do
|
201
201
|
should "serialize into a hash" do
|
202
202
|
foo = Foo.create :x => 42, :y => true
|
@@ -204,39 +204,39 @@ class TestEntity < Test::Unit::TestCase
|
|
204
204
|
assert_equal expected, foo.as_json
|
205
205
|
end
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
context "#set_key_prefix" do
|
209
209
|
should "use the given key prefix" do
|
210
210
|
class Custom < Remodel::Entity; set_key_prefix 'my'; end
|
211
211
|
assert_match /^my:\d+$/, Custom.create.key
|
212
212
|
end
|
213
|
-
|
213
|
+
|
214
214
|
should "ensure that the prefix is letters only" do
|
215
215
|
assert_raise(Remodel::InvalidKeyPrefix) do
|
216
216
|
class InvalidPrefix < Remodel::Entity; set_key_prefix '666'; end
|
217
217
|
end
|
218
218
|
end
|
219
219
|
end
|
220
|
-
|
220
|
+
|
221
221
|
context "#find" do
|
222
222
|
setup do
|
223
223
|
redis.flushdb
|
224
224
|
@foo = Foo.create :x => 'hello', :y => 123
|
225
225
|
Foo.create :x => 'hallo', :y => 124
|
226
226
|
end
|
227
|
-
|
227
|
+
|
228
228
|
should "find and load an entity by key" do
|
229
229
|
foo = Foo.find(@foo.key)
|
230
230
|
assert_equal foo.x, @foo.x
|
231
231
|
assert_equal foo.y, @foo.y
|
232
232
|
end
|
233
|
-
|
233
|
+
|
234
234
|
should "find and load an entity by id" do
|
235
235
|
foo = Foo.find(@foo.id)
|
236
236
|
assert_equal foo.x, @foo.x
|
237
237
|
assert_equal foo.y, @foo.y
|
238
238
|
end
|
239
|
-
|
239
|
+
|
240
240
|
should "reject a key which does not exist" do
|
241
241
|
assert_raise(Remodel::EntityNotFound) { Foo.find('x:66') }
|
242
242
|
end
|
@@ -245,20 +245,20 @@ class TestEntity < Test::Unit::TestCase
|
|
245
245
|
assert_raise(Remodel::EntityNotFound) { Foo.find(66) }
|
246
246
|
end
|
247
247
|
end
|
248
|
-
|
248
|
+
|
249
249
|
context "#all" do
|
250
250
|
setup do
|
251
251
|
redis.flushdb
|
252
252
|
17.times { |i| Foo.create :x => 'hello', :y => i }
|
253
253
|
5.times { |i| Bar.create }
|
254
254
|
end
|
255
|
-
|
255
|
+
|
256
256
|
should "find all entities of the given class" do
|
257
257
|
assert_equal 17, Foo.all.size
|
258
258
|
assert_equal 5, Bar.all.size
|
259
259
|
end
|
260
260
|
end
|
261
|
-
|
261
|
+
|
262
262
|
context "properties" do
|
263
263
|
should "have property x" do
|
264
264
|
foo = Foo.new
|
@@ -267,34 +267,34 @@ class TestEntity < Test::Unit::TestCase
|
|
267
267
|
foo.x += 10
|
268
268
|
assert_equal 33, foo.x
|
269
269
|
end
|
270
|
-
|
270
|
+
|
271
271
|
should "not have property z" do
|
272
272
|
foo = Foo.new
|
273
273
|
assert_raise(NoMethodError) { foo.z }
|
274
274
|
assert_raise(NoMethodError) { foo.z = 42 }
|
275
275
|
end
|
276
|
-
|
276
|
+
|
277
277
|
context "types" do
|
278
278
|
should "work with nil" do
|
279
279
|
foo = Foo.create :x => nil
|
280
280
|
assert_equal nil, foo.reload.x
|
281
281
|
end
|
282
|
-
|
282
|
+
|
283
283
|
should "work with booleans" do
|
284
284
|
foo = Foo.create :x => false
|
285
285
|
assert_equal false, foo.reload.x
|
286
286
|
end
|
287
|
-
|
287
|
+
|
288
288
|
should "work with integers" do
|
289
289
|
foo = Foo.create :x => -42
|
290
290
|
assert_equal -42, foo.reload.x
|
291
291
|
end
|
292
|
-
|
292
|
+
|
293
293
|
should "work with floats" do
|
294
294
|
foo = Foo.create :x => 3.141
|
295
295
|
assert_equal 3.141, foo.reload.x
|
296
296
|
end
|
297
|
-
|
297
|
+
|
298
298
|
should "work with strings" do
|
299
299
|
foo = Foo.create :x => 'hello'
|
300
300
|
assert_equal 'hello', foo.reload.x
|
@@ -304,7 +304,7 @@ class TestEntity < Test::Unit::TestCase
|
|
304
304
|
foo = Foo.create :x => [1, 2, 3]
|
305
305
|
assert_equal [1, 2, 3], foo.reload.x
|
306
306
|
end
|
307
|
-
|
307
|
+
|
308
308
|
should "work with hashes" do
|
309
309
|
hash = { 'a' => 17, 'b' => 'test' }
|
310
310
|
foo = Foo.create :x => hash
|
@@ -312,7 +312,7 @@ class TestEntity < Test::Unit::TestCase
|
|
312
312
|
end
|
313
313
|
end
|
314
314
|
end
|
315
|
-
|
315
|
+
|
316
316
|
context "#restore" do
|
317
317
|
should "restore an entity from json" do
|
318
318
|
before = Foo.create :x => 42, :y => true
|
@@ -322,5 +322,5 @@ class TestEntity < Test::Unit::TestCase
|
|
322
322
|
assert_equal before.y, after.y
|
323
323
|
end
|
324
324
|
end
|
325
|
-
|
325
|
+
|
326
326
|
end
|
data/test/test_many_to_many.rb
CHANGED
@@ -17,40 +17,40 @@ class TestManyToMany < Test::Unit::TestCase
|
|
17
17
|
assert_equal [], Person.new.groups
|
18
18
|
assert_equal [], Group.new.members
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
context "create" do
|
22
22
|
should "add a new group to both associations" do
|
23
23
|
tim = Person.create :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
29
|
rugb = Group.create :name => 'rug-b'
|
30
30
|
tim = rugb.members.create :name => 'tim'
|
31
31
|
assert_equal [rugb], tim.groups
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
context "add" do
|
36
36
|
setup do
|
37
37
|
@tim = Person.create :name => 'tim'
|
38
38
|
@rugb = Group.create :name => 'rug-b'
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
should "add a new group to both associations" do
|
42
42
|
@tim.groups.add(@rugb)
|
43
43
|
assert_equal [@tim], @rugb.members
|
44
44
|
assert_equal [@rugb], @tim.groups
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
should "add a new person to both associations" do
|
48
48
|
@rugb.members.add(@tim)
|
49
49
|
assert_equal [@tim], @rugb.members
|
50
50
|
assert_equal [@rugb], @tim.groups
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
context "remove" do
|
55
55
|
setup do
|
56
56
|
@tim = Person.create :name => 'tim'
|
@@ -58,20 +58,20 @@ class TestManyToMany < Test::Unit::TestCase
|
|
58
58
|
@erlang = @tim.groups.create(:name => 'erlang')
|
59
59
|
@aws = @tim.groups.create(:name => 'aws')
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
should "remove a group from both associations" do
|
63
63
|
@tim.groups.remove(@erlang)
|
64
64
|
assert_equal [@rugb, @aws], @tim.groups
|
65
65
|
assert_equal [], @erlang.members
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
should "remove a person from both associations" do
|
69
69
|
@erlang.members.remove(@tim)
|
70
70
|
assert_equal [@rugb, @aws], @tim.groups
|
71
71
|
assert_equal [], @erlang.members
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
end
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
end
|
data/test/test_many_to_one.rb
CHANGED
@@ -17,11 +17,11 @@ class TestManyToOne < Test::Unit::TestCase
|
|
17
17
|
should "exist" do
|
18
18
|
assert Puzzle.create.respond_to?(:pieces)
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
should "return an empty list by default" do
|
22
22
|
assert_equal [], Puzzle.create.pieces
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
should "return any existing children" do
|
26
26
|
puzzle = Puzzle.create
|
27
27
|
redis.rpush "#{puzzle.key}:pieces", Piece.create(:color => 'red').key
|
@@ -30,18 +30,18 @@ class TestManyToOne < Test::Unit::TestCase
|
|
30
30
|
assert_equal Piece, puzzle.pieces[0].class
|
31
31
|
assert_equal 'red', puzzle.pieces[0].color
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
context "create" do
|
35
35
|
should "have a create method" do
|
36
36
|
assert Puzzle.create.pieces.respond_to?(:create)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
should "work without attributes" do
|
40
40
|
puzzle = Puzzle.create
|
41
41
|
piece = puzzle.pieces.create
|
42
42
|
assert piece.is_a?(Piece)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
should "create and store a new child" do
|
46
46
|
puzzle = Puzzle.create
|
47
47
|
puzzle.pieces.create :color => 'green'
|
@@ -51,7 +51,7 @@ class TestManyToOne < Test::Unit::TestCase
|
|
51
51
|
assert_equal Piece, puzzle.pieces[0].class
|
52
52
|
assert_equal 'green', puzzle.pieces[0].color
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
should "associate the created child with self" do
|
56
56
|
puzzle = Puzzle.create :topic => 'provence'
|
57
57
|
piece = puzzle.pieces.create :color => 'green'
|
@@ -71,10 +71,26 @@ class TestManyToOne < Test::Unit::TestCase
|
|
71
71
|
assert_equal 'white', puzzle.pieces[0].color
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
|
+
context "find" do
|
76
|
+
setup do
|
77
|
+
@puzzle = Puzzle.create
|
78
|
+
5.times { @puzzle.pieces.create :color => 'blue' }
|
79
|
+
end
|
80
|
+
|
81
|
+
should "find the element with the given id" do
|
82
|
+
piece = @puzzle.pieces[2]
|
83
|
+
assert_equal piece, @puzzle.pieces.find(piece.id)
|
84
|
+
end
|
85
|
+
|
86
|
+
should "raise an exception if no element with the given id exists" do
|
87
|
+
assert_raises(Remodel::EntityNotFound) { @puzzle.pieces.find(-1) }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
75
91
|
end
|
76
92
|
end
|
77
|
-
|
93
|
+
|
78
94
|
context "reload" do
|
79
95
|
should "reset has_many associations" do
|
80
96
|
puzzle = Puzzle.create
|
@@ -84,5 +100,5 @@ class TestManyToOne < Test::Unit::TestCase
|
|
84
100
|
assert_equal [], puzzle.pieces
|
85
101
|
end
|
86
102
|
end
|
87
|
-
|
103
|
+
|
88
104
|
end
|
data/test/test_mappers.rb
CHANGED
@@ -17,12 +17,12 @@ class TestMappers < Test::Unit::TestCase
|
|
17
17
|
setup do
|
18
18
|
@item = Item.create :time => Time.at(1234567890), :date => Date.parse("1972-06-16")
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
should "store unmapped values" do
|
22
22
|
assert_equal Time, @item.instance_eval { @attributes[:time].class }
|
23
23
|
assert_equal Date, @item.instance_eval { @attributes[:date].class }
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
should "not change mapped values" do
|
27
27
|
assert_equal Time.at(1234567890), @item.time
|
28
28
|
assert_equal Date.parse("1972-06-16"), @item.date
|
@@ -33,13 +33,13 @@ class TestMappers < Test::Unit::TestCase
|
|
33
33
|
assert_equal Time.at(1234567890), @item.time
|
34
34
|
assert_equal Date.parse("1972-06-16"), @item.date
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
should "serialize mapped values correctly" do
|
38
38
|
json = redis.get(@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
44
|
item = Item.create
|
45
45
|
assert_nil item.boolean
|
@@ -51,7 +51,7 @@ class TestMappers < Test::Unit::TestCase
|
|
51
51
|
assert_nil item.time
|
52
52
|
assert_nil item.date
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
should "reject invalid types" do
|
56
56
|
assert_raise(Remodel::InvalidType) { Item.create :boolean => 'hello' }
|
57
57
|
assert_raise(Remodel::InvalidType) { Item.create :string => true }
|
data/test/test_monkeypatches.rb
CHANGED
@@ -13,7 +13,7 @@ class TestMonkeypatches < Test::Unit::TestCase
|
|
13
13
|
should "return given Class objects" do
|
14
14
|
assert_equal String, Class[String]
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
should "return the Class object for a given String" do
|
18
18
|
assert_equal String, Class['String']
|
19
19
|
end
|
@@ -21,7 +21,7 @@ class TestMonkeypatches < Test::Unit::TestCase
|
|
21
21
|
should "return the Class object for a given Symbol" do
|
22
22
|
assert_equal String, Class[:String]
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
should "work for nested classes" do
|
26
26
|
assert_equal Remodel::Entity, Class['Remodel::Entity']
|
27
27
|
end
|
data/test/test_one_to_many.rb
CHANGED
@@ -18,18 +18,18 @@ class TestOneToMany < Test::Unit::TestCase
|
|
18
18
|
should "exist" do
|
19
19
|
assert Piece.create.respond_to?(:puzzle)
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
should "return nil by default" do
|
23
23
|
assert_nil Piece.create.puzzle
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
should "return the associated entity" do
|
27
27
|
puzzle = Puzzle.create :topic => 'animals'
|
28
28
|
piece = Piece.create
|
29
29
|
redis.set("#{piece.key}:puzzle", puzzle.key)
|
30
30
|
assert_equal 'animals', piece.puzzle.topic
|
31
31
|
end
|
32
|
-
end
|
32
|
+
end
|
33
33
|
|
34
34
|
context "association setter" do
|
35
35
|
should "exist" do
|
@@ -42,14 +42,14 @@ class TestOneToMany < Test::Unit::TestCase
|
|
42
42
|
piece.puzzle = puzzle
|
43
43
|
assert_equal puzzle.key, redis.get("#{piece.key}:puzzle")
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
should "add the entity to the reverse association" do
|
47
47
|
puzzle = Puzzle.create
|
48
48
|
piece = Piece.create
|
49
49
|
piece.puzzle = puzzle
|
50
50
|
assert_equal 1, puzzle.pieces.size
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
should "be settable to nil" do
|
54
54
|
piece = Piece.create
|
55
55
|
piece.puzzle = nil
|
@@ -62,7 +62,7 @@ class TestOneToMany < Test::Unit::TestCase
|
|
62
62
|
piece.puzzle = nil
|
63
63
|
assert_nil redis.get("#{piece.key}:puzzle")
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
should "remove the entity from the reverse association if set to nil" do
|
67
67
|
puzzle = Puzzle.create
|
68
68
|
piece = Piece.create
|
@@ -83,5 +83,5 @@ class TestOneToMany < Test::Unit::TestCase
|
|
83
83
|
assert_nil piece.puzzle
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
end
|
data/test/test_one_to_one.rb
CHANGED
@@ -17,35 +17,35 @@ class TestOneToOne < Test::Unit::TestCase
|
|
17
17
|
assert_equal nil, Man.new.wife
|
18
18
|
assert_equal nil, Woman.new.husband
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
context "setter" do
|
22
22
|
setup do
|
23
23
|
@bill = Man.create :name => 'Bill'
|
24
24
|
@mary = Woman.create :name => 'Mary'
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
context "non-nil value" do
|
28
28
|
should "also set husband" do
|
29
29
|
@bill.wife = @mary
|
30
30
|
assert_equal @bill, @mary.husband
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
should "also set wife" do
|
34
34
|
@mary.husband = @bill
|
35
35
|
assert_equal @mary, @bill.wife
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
context "nil value" do
|
40
40
|
setup do
|
41
41
|
@bill.wife = @mary
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
should "also clear husband" do
|
45
45
|
@bill.wife = nil
|
46
46
|
assert_equal nil, @mary.husband
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
should "also clear wife" do
|
50
50
|
@mary.husband = nil
|
51
51
|
assert_equal nil, @bill.wife
|
@@ -53,5 +53,5 @@ class TestOneToOne < Test::Unit::TestCase
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Lossen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-05-03 00:00:00 +02:00
|
13
13
|
default_executable: redis-monitor.rb
|
14
14
|
dependencies: []
|
15
15
|
|