drogus-mongo_mapper 0.6.10

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.
Files changed (91) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +29 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +131 -0
  8. data/lib/mongo_mapper/document.rb +417 -0
  9. data/lib/mongo_mapper/embedded_document.rb +55 -0
  10. data/lib/mongo_mapper/finder_options.rb +127 -0
  11. data/lib/mongo_mapper/plugins.rb +30 -0
  12. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  13. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  14. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  15. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  16. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  17. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  18. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  19. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  20. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  21. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  22. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  23. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  24. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  25. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  26. data/lib/mongo_mapper/plugins/callbacks.rb +134 -0
  27. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  28. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  29. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  30. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  31. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  32. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  33. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  34. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  35. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  36. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  37. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  38. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  39. data/lib/mongo_mapper/plugins/validations.rb +57 -0
  40. data/lib/mongo_mapper/support.rb +217 -0
  41. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  42. data/lib/mongo_mapper/support/find.rb +77 -0
  43. data/mongo_mapper.gemspec +195 -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 +1264 -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 +155 -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 +60 -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 +123 -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 +290 -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