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