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 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. install the super-fast [yajl](http://github.com/lloyd/yajl) json parser
33
- plus ruby bindings:
32
+ 2. start redis:
34
33
 
35
- $ brew install yajl
36
- $ gem install yajl-ruby
34
+ $ ./redis-server
37
35
 
38
- 3. start redis:
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.063041 seconds.
48
- 65 tests, 103 assertions, 0 failures, 0 errors
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 i started with
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
- * documentation ([rocco](http://github.com/rtomayko/rocco))
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. play around at your own risk :)
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.2
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 &mdash;
@@ -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.2"
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-04-30}
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
@@ -5,9 +5,9 @@ require 'shoulda'
5
5
  require File.dirname(__FILE__) + '/../lib/remodel.rb'
6
6
 
7
7
  class Test::Unit::TestCase
8
-
8
+
9
9
  def redis
10
10
  Remodel.redis
11
11
  end
12
-
12
+
13
13
  end
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
@@ -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
@@ -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 }
@@ -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
@@ -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
@@ -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.2
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-04-30 00:00:00 +02:00
12
+ date: 2010-05-03 00:00:00 +02:00
13
13
  default_executable: redis-monitor.rb
14
14
  dependencies: []
15
15