novelys_mongo_mapper 0.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +38 -0
  4. data/Rakefile +54 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +124 -0
  8. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  9. data/lib/mongo_mapper/document.rb +423 -0
  10. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  11. data/lib/mongo_mapper/embedded_document.rb +67 -0
  12. data/lib/mongo_mapper/finder_options.rb +127 -0
  13. data/lib/mongo_mapper/plugins.rb +14 -0
  14. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  15. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  16. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  17. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  18. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  19. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  20. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  21. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  22. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  23. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  25. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  26. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  27. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  28. data/lib/mongo_mapper/plugins/callbacks.rb +76 -0
  29. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  30. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  31. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  32. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  33. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  34. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  35. data/lib/mongo_mapper/plugins/keys.rb +300 -0
  36. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  37. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  38. data/lib/mongo_mapper/plugins/protected.rb +41 -0
  39. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  40. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  41. data/lib/mongo_mapper/plugins/validations.rb +62 -0
  42. data/lib/mongo_mapper/support.rb +214 -0
  43. data/mongo_mapper.gemspec +179 -0
  44. data/performance/read_write.rb +52 -0
  45. data/specs.watchr +51 -0
  46. data/test/NOTE_ON_TESTING +1 -0
  47. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  48. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  49. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  50. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  51. data/test/functional/associations/test_many_documents_proxy.rb +431 -0
  52. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  53. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  54. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  55. data/test/functional/associations/test_one_proxy.rb +161 -0
  56. data/test/functional/test_associations.rb +44 -0
  57. data/test/functional/test_binary.rb +27 -0
  58. data/test/functional/test_callbacks.rb +81 -0
  59. data/test/functional/test_dirty.rb +163 -0
  60. data/test/functional/test_document.rb +1245 -0
  61. data/test/functional/test_embedded_document.rb +125 -0
  62. data/test/functional/test_identity_map.rb +508 -0
  63. data/test/functional/test_logger.rb +20 -0
  64. data/test/functional/test_modifiers.rb +252 -0
  65. data/test/functional/test_pagination.rb +93 -0
  66. data/test/functional/test_protected.rb +139 -0
  67. data/test/functional/test_string_id_compatibility.rb +67 -0
  68. data/test/functional/test_validations.rb +329 -0
  69. data/test/models.rb +232 -0
  70. data/test/support/custom_matchers.rb +55 -0
  71. data/test/support/timing.rb +16 -0
  72. data/test/test_helper.rb +55 -0
  73. data/test/unit/associations/test_base.rb +207 -0
  74. data/test/unit/associations/test_proxy.rb +105 -0
  75. data/test/unit/serializers/test_json_serializer.rb +189 -0
  76. data/test/unit/test_descendant_appends.rb +71 -0
  77. data/test/unit/test_document.rb +231 -0
  78. data/test/unit/test_dynamic_finder.rb +125 -0
  79. data/test/unit/test_embedded_document.rb +663 -0
  80. data/test/unit/test_finder_options.rb +329 -0
  81. data/test/unit/test_keys.rb +169 -0
  82. data/test/unit/test_mongo_mapper.rb +65 -0
  83. data/test/unit/test_pagination.rb +127 -0
  84. data/test/unit/test_plugins.rb +50 -0
  85. data/test/unit/test_rails.rb +123 -0
  86. data/test/unit/test_rails_compatibility.rb +52 -0
  87. data/test/unit/test_serialization.rb +51 -0
  88. data/test/unit/test_support.rb +354 -0
  89. data/test/unit/test_time_zones.rb +39 -0
  90. data/test/unit/test_validations.rb +544 -0
  91. metadata +248 -0
@@ -0,0 +1,431 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyDocumentsProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Project.collection.remove
7
+ Status.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ project = Project.new
12
+ project.statuses.should == []
13
+ end
14
+
15
+ should "allow adding to association like it was an array" do
16
+ project = Project.new
17
+ project.statuses << Status.new(:name => 'Foo1!')
18
+ project.statuses.push Status.new(:name => 'Foo2!')
19
+ project.statuses.concat Status.new(:name => 'Foo3!')
20
+ project.statuses.size.should == 3
21
+ end
22
+
23
+ should "be able to replace the association" do
24
+ project = Project.new
25
+ project.statuses = [Status.new(:name => "ready")]
26
+ project.save.should be_true
27
+
28
+ project.reload
29
+ project.statuses.size.should == 1
30
+ project.statuses[0].name.should == "ready"
31
+ end
32
+
33
+ should "correctly assign foreign key when using <<, push and concat" do
34
+ project = Project.new
35
+ project.statuses << Status.new(:name => '<<')
36
+ project.statuses.push Status.new(:name => 'push')
37
+ project.statuses.concat Status.new(:name => 'concat')
38
+
39
+ project.reload
40
+ project.statuses[0].project_id.should == project.id
41
+ project.statuses[1].project_id.should == project.id
42
+ project.statuses[2].project_id.should == project.id
43
+ end
44
+
45
+ context "build" do
46
+ should "assign foreign key" do
47
+ project = Project.create
48
+ status = project.statuses.build
49
+ status.project_id.should == project.id
50
+ end
51
+
52
+ should "allow assigning attributes" do
53
+ project = Project.create
54
+ status = project.statuses.build(:name => 'Foo')
55
+ status.name.should == 'Foo'
56
+ end
57
+ end
58
+
59
+ context "create" do
60
+ should "assign foreign key" do
61
+ project = Project.create
62
+ status = project.statuses.create(:name => 'Foo!')
63
+ status.project_id.should == project.id
64
+ end
65
+
66
+ should "save record" do
67
+ project = Project.create
68
+ lambda {
69
+ project.statuses.create(:name => 'Foo!')
70
+ }.should change { Status.count }
71
+ end
72
+
73
+ should "allow passing attributes" do
74
+ project = Project.create
75
+ status = project.statuses.create(:name => 'Foo!')
76
+ status.name.should == 'Foo!'
77
+ end
78
+ end
79
+
80
+ context "create!" do
81
+ should "assign foreign key" do
82
+ project = Project.create
83
+ status = project.statuses.create!(:name => 'Foo!')
84
+ status.project_id.should == project.id
85
+ end
86
+
87
+ should "save record" do
88
+ project = Project.create
89
+ lambda {
90
+ project.statuses.create!(:name => 'Foo!')
91
+ }.should change { Status.count }
92
+ end
93
+
94
+ should "allow passing attributes" do
95
+ project = Project.create
96
+ status = project.statuses.create!(:name => 'Foo!')
97
+ status.name.should == 'Foo!'
98
+ end
99
+
100
+ should "raise exception if not valid" do
101
+ project = Project.create
102
+ lambda {
103
+ project.statuses.create!(:name => nil)
104
+ }.should raise_error(MongoMapper::DocumentNotValid)
105
+ end
106
+ end
107
+
108
+ context "count" do
109
+ should "work scoped to association" do
110
+ project = Project.create
111
+ 3.times { project.statuses.create(:name => 'Foo!') }
112
+
113
+ other_project = Project.create
114
+ 2.times { other_project.statuses.create(:name => 'Foo!') }
115
+
116
+ project.statuses.count.should == 3
117
+ other_project.statuses.count.should == 2
118
+ end
119
+
120
+ should "work with conditions" do
121
+ project = Project.create
122
+ project.statuses.create(:name => 'Foo')
123
+ project.statuses.create(:name => 'Other 1')
124
+ project.statuses.create(:name => 'Other 2')
125
+
126
+ project.statuses.count(:name => 'Foo').should == 1
127
+ end
128
+ end
129
+
130
+ context "Unassociating documents" do
131
+ setup do
132
+ @project = Project.create
133
+ @project.statuses << Status.create(:name => '1')
134
+ @project.statuses << Status.create(:name => '2')
135
+
136
+ @project2 = Project.create
137
+ @project2.statuses << Status.create(:name => '1')
138
+ @project2.statuses << Status.create(:name => '2')
139
+ end
140
+
141
+ should "work with destroy all" do
142
+ @project.statuses.count.should == 2
143
+ @project.statuses.destroy_all
144
+ @project.statuses.count.should == 0
145
+
146
+ @project2.statuses.count.should == 2
147
+ Status.count.should == 2
148
+ end
149
+
150
+ should "work with destroy all and conditions" do
151
+ @project.statuses.count.should == 2
152
+ @project.statuses.destroy_all(:name => '1')
153
+ @project.statuses.count.should == 1
154
+
155
+ @project2.statuses.count.should == 2
156
+ Status.count.should == 3
157
+ end
158
+
159
+ should "work with delete all" do
160
+ @project.statuses.count.should == 2
161
+ @project.statuses.delete_all
162
+ @project.statuses.count.should == 0
163
+
164
+ @project2.statuses.count.should == 2
165
+ Status.count.should == 2
166
+ end
167
+
168
+ should "work with delete all and conditions" do
169
+ @project.statuses.count.should == 2
170
+ @project.statuses.delete_all(:name => '1')
171
+ @project.statuses.count.should == 1
172
+
173
+ @project2.statuses.count.should == 2
174
+ Status.count.should == 3
175
+ end
176
+
177
+ should "work with nullify" do
178
+ @project.statuses.count.should == 2
179
+ @project.statuses.nullify
180
+ @project.statuses.count.should == 0
181
+
182
+ @project2.statuses.count.should == 2
183
+ Status.count.should == 4
184
+ Status.count(:name => '1').should == 2
185
+ Status.count(:name => '2').should == 2
186
+ end
187
+ end
188
+
189
+ context "Finding scoped to association" do
190
+ setup do
191
+ @project1 = Project.new(:name => 'Project 1')
192
+ @brand_new = Status.create(:name => 'New', :position => 1 )
193
+ @complete = Status.create(:name => 'Complete', :position => 2)
194
+ @project1.statuses = [@brand_new, @complete]
195
+ @project1.save
196
+
197
+ @project2 = Project.create(:name => 'Project 2')
198
+ @in_progress = Status.create(:name => 'In Progress')
199
+ @archived = Status.create(:name => 'Archived')
200
+ @another_complete = Status.create(:name => 'Complete')
201
+ @project2.statuses = [@in_progress, @archived, @another_complete]
202
+ @project2.save
203
+ end
204
+
205
+ context "dynamic finders" do
206
+ should "work with single key" do
207
+ @project1.statuses.find_by_name('New').should == @brand_new
208
+ @project1.statuses.find_by_name!('New').should == @brand_new
209
+ @project2.statuses.find_by_name('In Progress').should == @in_progress
210
+ @project2.statuses.find_by_name!('In Progress').should == @in_progress
211
+ end
212
+
213
+ should "work with multiple keys" do
214
+ @project1.statuses.find_by_name_and_position('New', 1).should == @brand_new
215
+ @project1.statuses.find_by_name_and_position!('New', 1).should == @brand_new
216
+ @project1.statuses.find_by_name_and_position('New', 2).should be_nil
217
+ end
218
+
219
+ should "raise error when using !" do
220
+ lambda {
221
+ @project1.statuses.find_by_name!('Fake')
222
+ }.should raise_error(MongoMapper::DocumentNotFound)
223
+ end
224
+
225
+ context "find_or_create_by" do
226
+ should "not create document if found" do
227
+ lambda {
228
+ status = @project1.statuses.find_or_create_by_name('New')
229
+ status.project.should == @project1
230
+ status.should == @brand_new
231
+ }.should_not change { Status.count }
232
+ end
233
+
234
+ should "create document if not found" do
235
+ lambda {
236
+ status = @project1.statuses.find_or_create_by_name('Delivered')
237
+ status.project.should == @project1
238
+ }.should change { Status.count }
239
+ end
240
+ end
241
+ end
242
+
243
+ context "all" do
244
+ should "work" do
245
+ @project1.statuses.all(:order => "position asc").should == [@brand_new, @complete]
246
+ end
247
+
248
+ should "work with conditions" do
249
+ @project1.statuses.all(:name => 'Complete').should == [@complete]
250
+ end
251
+ end
252
+
253
+ context "first" do
254
+ should "work" do
255
+ @project1.statuses.first(:order => 'name').should == @complete
256
+ end
257
+
258
+ should "work with conditions" do
259
+ @project1.statuses.first(:name => 'Complete').should == @complete
260
+ end
261
+ end
262
+
263
+ context "last" do
264
+ should "work" do
265
+ @project1.statuses.last(:order => "position asc").should == @complete
266
+ end
267
+
268
+ should "work with conditions" do
269
+ @project1.statuses.last(:order => 'position', :name => 'New').should == @brand_new
270
+ end
271
+ end
272
+
273
+ context "with one id" do
274
+ should "work for id in association" do
275
+ @project1.statuses.find(@complete.id).should == @complete
276
+ end
277
+
278
+ should "not work for id not in association" do
279
+ lambda {
280
+ @project1.statuses.find!(@archived.id)
281
+ }.should raise_error(MongoMapper::DocumentNotFound)
282
+ end
283
+ end
284
+
285
+ context "with multiple ids" do
286
+ should "work for ids in association" do
287
+ statuses = @project1.statuses.find(@brand_new.id, @complete.id)
288
+ statuses.should == [@brand_new, @complete]
289
+ end
290
+
291
+ should "not work for ids not in association" do
292
+ assert_raises(MongoMapper::DocumentNotFound) do
293
+ @project1.statuses.find!(@brand_new.id, @complete.id, @archived.id)
294
+ end
295
+ end
296
+ end
297
+
298
+ context "with #paginate" do
299
+ setup do
300
+ @statuses = @project2.statuses.paginate(:per_page => 2, :page => 1, :order => 'name asc')
301
+ end
302
+
303
+ should "return total pages" do
304
+ @statuses.total_pages.should == 2
305
+ end
306
+
307
+ should "return total entries" do
308
+ @statuses.total_entries.should == 3
309
+ end
310
+
311
+ should "return the subject" do
312
+ @statuses.collect(&:name).should == %w(Archived Complete)
313
+ end
314
+ end
315
+ end
316
+
317
+ context "extending the association" do
318
+ should "work using a block passed to many" do
319
+ project = Project.new(:name => "Some Project")
320
+ status1 = Status.new(:name => "New")
321
+ status2 = Status.new(:name => "Assigned")
322
+ status3 = Status.new(:name => "Closed")
323
+ project.statuses = [status1, status2, status3]
324
+ project.save
325
+
326
+ open_statuses = project.statuses.open
327
+ open_statuses.should include(status1)
328
+ open_statuses.should include(status2)
329
+ open_statuses.should_not include(status3)
330
+ end
331
+
332
+ should "work using many's :extend option" do
333
+ project = Project.new(:name => "Some Project")
334
+ collaborator1 = Collaborator.new(:name => "zing")
335
+ collaborator2 = Collaborator.new(:name => "zang")
336
+ project.collaborators = [collaborator1, collaborator2]
337
+ project.save
338
+ project.collaborators.top.should == collaborator1
339
+ end
340
+ end
341
+
342
+ context ":dependent" do
343
+ setup do
344
+ # FIXME: make use of already defined models
345
+ class ::Property
346
+ include MongoMapper::Document
347
+ end
348
+ Property.collection.remove
349
+
350
+ class ::Thing
351
+ include MongoMapper::Document
352
+ key :name, String
353
+ end
354
+ Thing.collection.remove
355
+ end
356
+
357
+ teardown do
358
+ Object.send :remove_const, 'Property' if defined?(::Property)
359
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
360
+ end
361
+
362
+ context "=> destroy" do
363
+ setup do
364
+ Property.key :thing_id, ObjectId
365
+ Property.belongs_to :thing, :dependent => :destroy
366
+ Thing.many :properties, :dependent => :destroy
367
+
368
+ @thing = Thing.create(:name => "Tree")
369
+ @property1 = Property.create
370
+ @property2 = Property.create
371
+ @property3 = Property.create
372
+ @thing.properties << @property1
373
+ @thing.properties << @property2
374
+ @thing.properties << @property3
375
+ end
376
+
377
+ should "should destroy the associated documents" do
378
+ @thing.properties.count.should == 3
379
+ @thing.destroy
380
+ @thing.properties.count.should == 0
381
+ Property.count.should == 0
382
+ end
383
+ end
384
+
385
+ context "=> delete_all" do
386
+ setup do
387
+ Property.key :thing_id, ObjectId
388
+ Property.belongs_to :thing
389
+ Thing.has_many :properties, :dependent => :delete_all
390
+
391
+ @thing = Thing.create(:name => "Tree")
392
+ @property1 = Property.create
393
+ @property2 = Property.create
394
+ @property3 = Property.create
395
+ @thing.properties << @property1
396
+ @thing.properties << @property2
397
+ @thing.properties << @property3
398
+ end
399
+
400
+ should "should delete associated documents" do
401
+ @thing.properties.count.should == 3
402
+ @thing.destroy
403
+ @thing.properties.count.should == 0
404
+ Property.count.should == 0
405
+ end
406
+ end
407
+
408
+ context "=> nullify" do
409
+ setup do
410
+ Property.key :thing_id, ObjectId
411
+ Property.belongs_to :thing
412
+ Thing.has_many :properties, :dependent => :nullify
413
+
414
+ @thing = Thing.create(:name => "Tree")
415
+ @property1 = Property.create
416
+ @property2 = Property.create
417
+ @property3 = Property.create
418
+ @thing.properties << @property1
419
+ @thing.properties << @property2
420
+ @thing.properties << @property3
421
+ end
422
+
423
+ should "should nullify relationship but not destroy associated documents" do
424
+ @thing.properties.count.should == 3
425
+ @thing.destroy
426
+ @thing.properties.count.should == 0
427
+ Property.count.should == 3
428
+ end
429
+ end
430
+ end
431
+ end
@@ -0,0 +1,176 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Catalog.collection.remove
7
+ TrModels::Fleet.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ catalog = Catalog.new
12
+ catalog.medias.should == []
13
+ end
14
+
15
+ should "allow adding to association like it was an array" do
16
+ catalog = Catalog.new
17
+ catalog.medias << Video.new
18
+ catalog.medias.push Video.new
19
+ catalog.medias.size.should == 2
20
+ end
21
+
22
+ should "be able to replace the association" do
23
+ catalog = Catalog.new
24
+ catalog.medias = [Video.new('file' => 'video.mpg', 'length' => 3600)]
25
+ catalog.save.should be_true
26
+
27
+ catalog = catalog.reload
28
+ catalog.medias.size.should == 1
29
+ catalog.medias[0].file.should == 'video.mpg'
30
+ catalog.medias[0].new?.should == false
31
+ end
32
+
33
+ context "count" do
34
+ should "default to 0" do
35
+ Catalog.new.medias.count.should == 0
36
+ end
37
+
38
+ should 'return correct count if any are embedded' do
39
+ catalog = Catalog.new
40
+ catalog.medias = [
41
+ Video.new('file' => 'video.mpg', 'length' => 3600),
42
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
43
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
44
+ ]
45
+ catalog.medias.count.should == 3
46
+ catalog.save.should be_true
47
+ catalog.reload
48
+ catalog.medias.count.should == 3
49
+ end
50
+ end
51
+
52
+ should "store different associations" do
53
+ catalog = Catalog.new
54
+ catalog.medias = [
55
+ Video.new('file' => 'video.mpg', 'length' => 3600),
56
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
57
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
58
+ ]
59
+ catalog.save.should be_true
60
+
61
+ catalog = catalog.reload
62
+ catalog.medias.size.should == 3
63
+ catalog.medias[0].file.should == 'video.mpg'
64
+ catalog.medias[0].length.should == 3600
65
+ catalog.medias[1].file.should == 'music.mp3'
66
+ catalog.medias[1].bitrate.should == "128kbps"
67
+ catalog.medias[2].file.should == 'image.png'
68
+ catalog.medias[2].width.should == 800
69
+ catalog.medias[2].height.should == 600
70
+ end
71
+
72
+ context "With modularized models" do
73
+ should "set associations correctly" do
74
+ fleet_attributes = {
75
+ 'name' => 'My Fleet',
76
+ 'transports' => [
77
+ {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true},
78
+ {'_type' => 'TrModels::Car', 'license_plate' => 'ABC123', 'model' => 'VW Golf', 'year' => 2001},
79
+ {'_type' => 'TrModels::Car', 'license_plate' => 'DEF123', 'model' => 'Honda Accord', 'year' => 2008},
80
+ ]
81
+ }
82
+
83
+ fleet = TrModels::Fleet.new(fleet_attributes)
84
+ fleet.transports.size.should == 3
85
+ fleet.transports[0].class.should == TrModels::Ambulance
86
+ fleet.transports[0].license_plate.should == 'GGG123'
87
+ fleet.transports[0].icu.should be_true
88
+ fleet.transports[1].class.should == TrModels::Car
89
+ fleet.transports[1].license_plate.should == 'ABC123'
90
+ fleet.transports[1].model.should == 'VW Golf'
91
+ fleet.transports[1].year.should == 2001
92
+ fleet.transports[2].class.should == TrModels::Car
93
+ fleet.transports[2].license_plate.should == 'DEF123'
94
+ fleet.transports[2].model.should == 'Honda Accord'
95
+ fleet.transports[2].year.should == 2008
96
+ fleet.save.should be_true
97
+
98
+ fleet = fleet.reload
99
+ fleet.transports.size.should == 3
100
+ fleet.transports[0].license_plate.should == 'GGG123'
101
+ fleet.transports[0].icu.should be_true
102
+ fleet.transports[1].license_plate.should == 'ABC123'
103
+ fleet.transports[1].model.should == 'VW Golf'
104
+ fleet.transports[1].year.should == 2001
105
+ fleet.transports[2].license_plate.should == 'DEF123'
106
+ fleet.transports[2].model.should == 'Honda Accord'
107
+ fleet.transports[2].year.should == 2008
108
+ end
109
+
110
+ should "default reader to empty array" do
111
+ fleet = TrModels::Fleet.new
112
+ fleet.transports.should == []
113
+ end
114
+
115
+ should "allow adding to association like it was an array" do
116
+ fleet = TrModels::Fleet.new
117
+ fleet.transports << TrModels::Car.new
118
+ fleet.transports.push TrModels::Bus.new
119
+ fleet.transports.size.should == 2
120
+ end
121
+
122
+ should "be able to replace the association" do
123
+ fleet = TrModels::Fleet.new
124
+ fleet.transports = [TrModels::Car.new('license_plate' => 'DCU2013', 'model' => 'Honda Civic')]
125
+ fleet.save.should be_true
126
+
127
+ fleet = fleet.reload
128
+ fleet.transports.size.should == 1
129
+ fleet.transports[0].license_plate.should == 'DCU2013'
130
+ end
131
+
132
+ should "store different associations" do
133
+ fleet = TrModels::Fleet.new
134
+ fleet.transports = [
135
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003),
136
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51),
137
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true)
138
+ ]
139
+ fleet.save.should be_true
140
+
141
+ fleet = fleet.reload
142
+ fleet.transports.size.should == 3
143
+ fleet.transports[0].license_plate.should == 'ABC1223'
144
+ fleet.transports[0].model.should == 'Honda Civic'
145
+ fleet.transports[0].year.should == 2003
146
+ fleet.transports[1].license_plate.should == 'XYZ9090'
147
+ fleet.transports[1].max_passengers.should == 51
148
+ fleet.transports[2].license_plate.should == 'HDD3030'
149
+ fleet.transports[2].icu.should == true
150
+ end
151
+ end
152
+
153
+ context "extending the association" do
154
+ should "work using a block passed to many" do
155
+ catalog = Catalog.new
156
+ medias = catalog.medias = [
157
+ Video.new('file' => 'video.mpg', 'length' => 3600, :visible => true),
158
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps', :visible => true),
159
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600, :visible => false)
160
+ ]
161
+ catalog.save
162
+ catalog.medias.visible.should == [medias[0], medias[1]]
163
+ end
164
+
165
+ should "work using many's :extend option" do
166
+ fleet = TrModels::Fleet.new
167
+ transports = fleet.transports = [
168
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003, :purchased_on => 2.years.ago.to_date),
169
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51, :purchased_on => 3.years.ago.to_date),
170
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true, :purchased_on => 1.year.ago.to_date)
171
+ ]
172
+ fleet.save
173
+ fleet.transports.to_be_replaced.should == [transports[1]]
174
+ end
175
+ end
176
+ end