vidibus-inheritance 0.3.6 → 0.3.9

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.
@@ -1,66 +1,10 @@
1
1
  require "spec_helper"
2
2
 
3
- class Model
4
- include Mongoid::Document
5
- include Mongoid::Timestamps
6
- include Vidibus::Uuid::Mongoid
7
- include Vidibus::Inheritance::Mongoid
8
- field :name
9
- field :age, :type => Integer
10
- embeds_many :children
11
- embeds_many :puppets
12
- embeds_one :location
13
- end
14
-
15
- class Child
16
- include Mongoid::Document
17
- field :name
18
- field :mutated, :type => Boolean
19
- validates :name, :presence => true
20
- embedded_in :model, :inverse_of => :children
21
- embeds_many :puppets
22
- embeds_one :location
23
- end
24
-
25
- class Puppet
26
- include Mongoid::Document
27
- field :name
28
- validates :name, :presence => true
29
- embedded_in :child, :inverse_of => :puppets
30
- embedded_in :model, :inverse_of => :puppets
31
- embedded_in :location, :inverse_of => :puppets
32
- embeds_one :location
33
- end
34
-
35
- class Location
36
- include Mongoid::Document
37
- field :name
38
- field :mutated, :type => Boolean
39
- validates :name, :presence => true
40
- embedded_in :model, :inverse_of => :location
41
- embedded_in :child, :inverse_of => :location
42
- embedded_in :puppet, :inverse_of => :location
43
- embeds_many :puppets
44
- end
45
-
46
- class Manager
47
- include Mongoid::Document
48
- include Vidibus::Uuid::Mongoid
49
- include Vidibus::Inheritance::Mongoid
50
- field :name
51
- validates :name, :presence => true
52
- end
53
-
54
- class Clerk
55
- include Mongoid::Document
56
- field :name
57
- validates :name, :presence => true
58
- end
59
-
60
3
  describe "Vidibus::Inheritance::Mongoid" do
61
4
  let(:ancestor) { Model.create }
62
- let(:anna) { Model.create!(:name => "Anna", :age => 35) }
63
5
  let(:inheritor) { Model.new }
6
+ let(:anna) { Model.create!(:name => "Anna", :age => 35) }
7
+ let(:jeanny) { Model.create!(:name => "Jeanny", :age => 17) }
64
8
 
65
9
  describe "validation" do
66
10
  it "should fail if ancestor does not have an UUID" do
@@ -114,6 +58,12 @@ describe "Vidibus::Inheritance::Mongoid" do
114
58
  inheritor.update_attributes(:name => "Jenny")
115
59
  inheritor.mutated_attributes.should eql(["name"])
116
60
  end
61
+
62
+ it "should be tracked if data gets modified in a before_validation callback" do
63
+ model = Trude.create
64
+ model.name.should eql("Trude")
65
+ model.mutated_attributes.should eql(["name"])
66
+ end
117
67
  end
118
68
 
119
69
  describe "#mutated?" do
@@ -136,13 +86,6 @@ describe "Vidibus::Inheritance::Mongoid" do
136
86
  end
137
87
  end
138
88
 
139
- describe "#ancestor" do
140
- it "should return an ancestor object by uuid" do
141
- inheritor.ancestor_uuid = ancestor.uuid
142
- inheritor.ancestor.should eql(ancestor)
143
- end
144
- end
145
-
146
89
  describe "#ancestor=" do
147
90
  it "should set an ancestor object" do
148
91
  inheritor.ancestor = ancestor
@@ -168,6 +111,21 @@ describe "Vidibus::Inheritance::Mongoid" do
168
111
  end
169
112
  end
170
113
 
114
+ describe "#ancestor" do
115
+ it "should return an ancestor object by uuid" do
116
+ inheritor.ancestor_uuid = ancestor.uuid
117
+ inheritor.ancestor.should eql(ancestor)
118
+ end
119
+ end
120
+
121
+ describe "#ancestors" do
122
+ it "should return a list of all ancestors" do
123
+ inheritor = Model.create!(:ancestor => ancestor)
124
+ nextgen = Model.create!(:ancestor => inheritor)
125
+ nextgen.ancestors.should eql([inheritor, ancestor])
126
+ end
127
+ end
128
+
171
129
  describe "#inherit!" do
172
130
  it "should call #inherit_attributes once" do
173
131
  stub(inheritor)._inherited { true }
@@ -233,368 +191,117 @@ describe "Vidibus::Inheritance::Mongoid" do
233
191
  it "should return all inheritors" do
234
192
  inheritor1 = Model.create(:ancestor => ancestor)
235
193
  inheritor2 = Model.create(:ancestor => ancestor)
236
- ancestor.inheritors.should have(2).inheritors
237
- ancestor.inheritors.should include(inheritor1)
238
- ancestor.inheritors.should include(inheritor2)
194
+ list = ancestor.inheritors.to_a
195
+ list.should have(2).inheritors
196
+ list.should include(inheritor1)
197
+ list.should include(inheritor2)
239
198
  end
240
199
  end
241
200
 
242
- describe "inheritance" do
243
- it "should happen when creating objects" do
244
- ancestor # trigger object creation before mocking
245
- mock.instance_of(Model).inherit_attributes
246
- Model.create!(:ancestor => ancestor)
201
+ describe "#inheritable_documents" do
202
+ it "should perform .inheritable_documents with current object" do
203
+ mock(Model).inheritable_documents(anna, {})
204
+ anna.inheritable_documents
247
205
  end
248
206
 
249
- it "should happen when ancestor did change" do
250
- inheritor = Model.create!
251
- inheritor.ancestor = ancestor
252
- stub(inheritor).inherit_attributes
253
- inheritor.save
254
- inheritor.should have_received.inherit_attributes
207
+ it "should allow options" do
208
+ mock(Model).inheritable_documents(anna, :keys => true)
209
+ anna.inheritable_documents(:keys => true)
255
210
  end
256
-
257
- it "should not happen when ancestor did not change" do
258
- inheritor = Model.create!(:ancestor => ancestor)
259
- dont_allow(inheritor).inherit
260
- inheritor.save
261
- # Does not work with RR:
262
- # inheritor.should_not have_received.inherit
211
+ end
212
+
213
+ describe "#clone!" do
214
+ it "should create a sibling" do
215
+ twin = anna.clone!
216
+ twin.should_not eql(anna)
217
+ twin.name.should eql(anna.name)
218
+ twin.age.should eql(anna.age)
263
219
  end
264
220
 
265
- it "should apply ancestor's attributes to inheritor" do
266
- inheritor.update_attributes(:ancestor => anna)
267
- inheritor.name.should eql("Anna")
268
- inheritor.age.should eql(35)
221
+ it "should preserve ancestor relation" do
222
+ anna.inherit_from!(ancestor)
223
+ twin = anna.clone!
224
+ twin.ancestor.should eql(ancestor)
269
225
  end
270
226
 
271
- it "should not inherit acquired attributes" do
272
- inheritor.update_attributes(:ancestor => ancestor)
273
- Model::ACQUIRED_ATTRIBUTES.should include("uuid")
274
- inheritor.uuid.should_not eql(ancestor.uuid)
227
+ it "should not clone inheritors (should it?)" do
228
+ anna.inherit_from!(ancestor)
229
+ twin = ancestor.clone!
230
+ twin.inheritors.should be_empty
275
231
  end
276
232
 
277
- it "should apply ancestor's attributes to inheritor but keep previously mutated attributes" do
278
- inheritor.update_attributes(:name => "Jenny")
279
- inheritor.update_attributes(:ancestor => anna)
280
- inheritor.name.should eql("Jenny")
281
- inheritor.age.should eql(35)
233
+ it "should clone embedded documents" do
234
+ anna.children.create(:name => "Lisa")
235
+ twin = anna.clone!
236
+ twin.children.should have(1).child
282
237
  end
283
238
 
284
- it "should apply ancestor's attributes to inheritor but keep recently mutated attributes" do
285
- inheritor.update_attributes(:ancestor => anna, :name => "Jenny")
286
- inheritor.name.should eql("Jenny")
287
- inheritor.age.should eql(35)
239
+ it "should clone a single embedded document" do
240
+ anna.create_location(:name => "Bathroom")
241
+ twin = anna.clone!
242
+ twin.location.name.should eql("Bathroom")
288
243
  end
289
244
 
290
- it "should allow switching the ancestor" do
291
- inheritor.inherit_from!(anna)
292
- another_ancestor = Model.create!(:name => "Leah", :age => 30)
293
- inheritor.inherit_from!(another_ancestor)
294
- inheritor.ancestor.should eql(another_ancestor)
295
- inheritor.name.should eql("Leah")
296
- inheritor.age.should eql(30)
245
+ it "should clone children of embedded documents" do
246
+ lisa = anna.children.create(:name => "Lisa")
247
+ lisa.puppets.create(:name => "Gonzo")
248
+ twin = anna.clone!
249
+ lisa_twin = twin.children.first
250
+ lisa_twin.puppets.should have(1).puppet
251
+ # lisa_twin.puppets.first._id.should_not eql(lisa_twin.puppets.first._id)
297
252
  end
298
-
299
- it "should apply changes on ancestor to inheritor" do
300
- inheritor.inherit_from!(anna)
301
- inheritor.name.should eql("Anna")
302
- anna.update_attributes(:name => "Leah")
303
- inheritor.reload
304
- inheritor.name.should eql("Leah")
253
+ end
254
+
255
+ describe ".inheritable_documents" do
256
+ it "should return embedded relations of a given object" do
257
+ docs = Model.inheritable_documents(anna)
258
+ docs.length.should eql(3)
259
+ docs.should have_key("location")
260
+ docs.should have_key("children")
261
+ docs.should have_key("puppets")
305
262
  end
306
263
 
307
- it "should preserve changes on inheritor" do
308
- inheritor = Model.create(:ancestor => anna)
309
- inheritor.update_attributes(:name => "Sara")
310
- inheritor.mutated_attributes.should eql(["name"])
311
- anna.update_attributes(:name => "Leah")
312
- inheritor.reload
313
- inheritor.name.should eql("Sara")
264
+ it "should return a collection of documents embedded by embeds_many" do
265
+ anna.children.create(:name => "Lisa")
266
+ docs = Model.inheritable_documents(anna)
267
+ docs["children"].should eql([anna.children.first])
314
268
  end
315
269
 
316
- it "should not update inheritor if acquired attributes were changed on ancestor" do
317
- inheritor.inherit_from!(ancestor)
318
- Model::ACQUIRED_ATTRIBUTES.should include("updated_at")
319
- dont_allow(ancestor.inheritors.first).inherit!
320
- ancestor.update_attributes(:updated_at => Time.now)
270
+ it "should return a document embedded by embeds_one" do
271
+ anna.create_location(:name => "Beach")
272
+ docs = Model.inheritable_documents(anna)
273
+ docs["location"].should eql(anna.location)
321
274
  end
322
275
 
323
- it "should not update inheritor if no inheritable attributes were changed on ancestor" do
324
- inheritor.inherit_from!(anna)
325
- dont_allow(anna.inheritors.first).inherit!
326
- anna.update_attributes(:name => "Anna")
276
+ it "should return the keys of embedded relations if option :keys is given" do
277
+ keys = Model.inheritable_documents(anna, :keys => true)
278
+ keys.should eql(%w[location puppets children])
327
279
  end
328
-
329
- it "should be applied before validation" do
330
- ancestor = Manager.create!(:name => "John")
331
- invalid = Manager.new
332
- invalid.should_not be_valid
333
- valid = Manager.new(:ancestor => ancestor)
334
- valid.should be_valid
280
+ end
281
+
282
+ describe ".roots" do
283
+ before do
284
+ inheritor.inherit_from!(anna)
285
+ jeanny
335
286
  end
336
287
 
337
- context "with embedded collections" do
338
- before do
339
- inheritor.inherit_from!(ancestor)
340
- ancestor.children.create(:name => "Han")
341
- ancestor.save
342
- inheritor.reload
343
- end
344
-
345
- it "should inherit subobjects on existing relationship" do
346
- inheritor.children.should have(1).child
347
- end
348
-
349
- it "should inherit subobjects when relationship gets established" do
350
- inheritor = Model.new
351
- inheritor.inherit_from!(ancestor)
352
- inheritor.children.should have(1).child
353
- inheritor.reload.children.should have(1).child
354
- end
355
-
356
- it "should add subobjects" do
357
- ancestor.children << Child.new(:name => "Leah")
358
- ancestor.save
359
- ancestor.children.should have(2).children
360
- inheritor.reload
361
- inheritor.children.should have(2).children
362
- end
363
-
364
- it "should add subobjects with saving" do
365
- ancestor.children << Child.new(:name => "Leah")
366
- ancestor.save
367
- ancestor.children.should have(2).children
368
- inheritor.save
369
- inheritor.reload
370
- inheritor.children.should have(2).children
371
- end
372
-
373
- it "should not add existing subobjects twice" do
374
- inheritor.inherit_from!(ancestor)
375
- inheritor.children.should have(1).child
376
- inheritor.reload.children.should have(1).child
377
- end
378
-
379
- it "should remove subobjects" do
380
- inheritor.children.should have(1).child
381
- ancestor.children.first.destroy
382
- ancestor.save
383
- inheritor.reload
384
- ancestor.children.should have(0).children
385
- inheritor.children.should have(0).children
386
- end
387
-
388
- it "should update subobjects" do
389
- ancestor.children.first.name = "Luke"
390
- ancestor.save
391
- inheritor.reload
392
- inheritor.children.first.name.should eql("Luke")
393
- end
394
-
395
- it "should call #update_inherited_attributes for updating subobjects, if available" do
396
- Child.send(:define_method, :update_inherited_attributes) do
397
- self.update_attributes(:name => "Callback")
398
- end
399
- Child.send(:protected, :update_inherited_attributes)
400
- ancestor.children.first.name = "Luke"
401
- ancestor.save
402
- Child.send(:remove_method, :update_inherited_attributes)
403
- inheritor.reload
404
- inheritor.children.first.name.should eql("Callback")
405
- end
406
-
407
- it "should exclude acquired attributes of subobjects" do
408
- ancestor.children.first.mutated = true
409
- ancestor.save
410
- ancestor.children.first.mutated.should be_true
411
- inheritor.reload
412
- inheritor.children.first.mutated.should be_false
413
- end
414
-
415
- it "should inherit embedded documents of subobjects" do
416
- ancestor.children.first.puppets.create(:name => "Goofy")
417
- ancestor.save
418
- inheritor.reload
419
- inheritor.children.first.puppets.should have(1).puppet
420
- end
288
+ it "should return all model that have no ancestor" do
289
+ Model.all.to_a.should have(3).models
290
+ list = Model.roots.to_a
291
+ list.should have(2).models
421
292
  end
422
293
 
423
- context "with embedded items" do
424
- before do
425
- inheritor.inherit_from!(ancestor)
426
- ancestor.create_location(:name => "Home")
427
- ancestor.save
428
- inheritor.reload
429
- end
430
-
431
- it "should inherit subobject on existing relationship" do
432
- inheritor.location.should_not be_nil
433
- end
434
-
435
- it "should inherit subobjects when relationship gets established" do
436
- inheritor = Model.new
437
- inheritor.inherit_from!(ancestor)
438
- inheritor.location.should_not be_nil
439
- end
440
-
441
- it "should update subobject" do
442
- ancestor.location.name = "Studio"
443
- ancestor.save
444
- inheritor.reload
445
- ancestor.location.name.should eql("Studio")
446
- inheritor.location.name.should eql("Studio")
447
- end
448
-
449
- it "should remove subobject" do
450
- ancestor.location.destroy
451
- ancestor.save
452
- inheritor.reload
453
- ancestor.location.should be_nil
454
- inheritor.location.should be_nil
455
- end
456
-
457
- it "should exclude acquired attributes of subobject" do
458
- ancestor.location.mutated = true
459
- ancestor.save
460
- ancestor.location.mutated.should be_true
461
- inheritor.reload
462
- inheritor.location.mutated.should be_false
463
- end
464
-
465
- it "should inherit embedded documents of subobject" do
466
- ancestor.location.puppets.create(:name => "Goofy")
467
- ancestor.save
468
- inheritor.reload
469
- inheritor.location.puppets.should have(1).puppet
470
- end
294
+ it "should accept sorting criteria" do
295
+ Model.all.to_a.should have(3).models
296
+ stub_time!(1.hour.since)
297
+ anna.update_attributes(:age => 20)
298
+ list = Model.roots.desc(:updated_at).to_a
299
+ list[0].updated_at.should > list[1].updated_at
471
300
  end
472
301
 
473
- context "across several generations" do
474
- let(:grand_ancestor) { Model.create!(:name => "Anna", :age => 97) }
475
-
476
- before do
477
- ancestor.inherit_from!(grand_ancestor)
478
- inheritor.inherit_from!(ancestor)
479
- end
480
-
481
- it "should apply changes on grand ancestor to inheritor" do
482
- inheritor.name.should eql("Anna")
483
- grand_ancestor.update_attributes(:name => "Leah")
484
- inheritor.reload
485
- inheritor.name.should eql("Leah")
486
- end
487
-
488
- it "should not apply changes on grand ancestor to inheritor if predecessor has mutations" do
489
- ancestor.update_attributes(:name => "Jenny")
490
- grand_ancestor.update_attributes(:name => "Leah")
491
- inheritor.reload
492
- inheritor.name.should eql("Jenny")
493
- end
494
-
495
- it "should allow resetting mutated attributes" do
496
- ancestor.update_attributes(:name => "Sara")
497
- ancestor.name.should eql("Sara")
498
- inheritor.reload
499
- inheritor.name.should eql("Sara")
500
- ancestor.inherit!(:reset => :name)
501
- ancestor.name.should eql("Anna")
502
- inheritor.reload
503
- inheritor.name.should eql("Anna")
504
- end
505
-
506
- context "with embedded collections" do
507
- before do
508
- grand_ancestor.children.create(:name => "Han")
509
- grand_ancestor.save
510
- ancestor.reload
511
- inheritor.reload
512
- end
513
-
514
- it "should inherit subobjects" do
515
- inheritor.children.should have(1).child
516
- end
517
-
518
- it "should add subobjects" do
519
- grand_ancestor.children << Child.new(:name => "Leah")
520
- grand_ancestor.save
521
- inheritor.reload
522
- inheritor.children.should have(2).children
523
- end
524
-
525
- it "should not add existing subobjects twice" do
526
- ancestor.inherit_from!(grand_ancestor)
527
- inheritor.reload
528
- inheritor.children.should have(1).child
529
- end
530
-
531
- it "should remove subobjects" do
532
- inheritor.children.should have(1).child
533
- grand_ancestor.children.first.destroy
534
- grand_ancestor.save
535
- grand_ancestor.children.should have(0).children
536
- inheritor.reload
537
- inheritor.children.should have(0).children
538
- end
539
-
540
- it "should update subobjects" do
541
- grand_ancestor.children.first.name = "Luke"
542
- grand_ancestor.save
543
- grand_ancestor.children.first.name.should eql("Luke")
544
- inheritor.reload
545
- inheritor.children.first.name.should eql("Luke")
546
- end
547
-
548
- it "should inherit embedded documents of subobjects" do
549
- grand_ancestor.children.first.puppets.create(:name => "Goofy")
550
- grand_ancestor.save
551
- inheritor.reload
552
- inheritor.children.first.puppets.should have(1).puppet
553
- end
554
- end
555
-
556
- context "with embedded items" do
557
- before do
558
- grand_ancestor.create_location(:name => "Home")
559
- grand_ancestor.save
560
- ancestor.reload
561
- inheritor.reload
562
- end
563
-
564
- it "should inherit subobject on existing relationship" do
565
- inheritor.location.should_not be_nil
566
- end
567
-
568
- it "should inherit subobject when relationship gets established" do
569
- ancestor = Model.new
570
- ancestor.inherit_from!(grand_ancestor)
571
- inheritor = Model.new
572
- inheritor.inherit_from!(ancestor)
573
- inheritor.location.should_not be_nil
574
- end
575
-
576
- it "should update subobject" do
577
- grand_ancestor.location.name = "Studio"
578
- grand_ancestor.save
579
- inheritor.reload
580
- inheritor.location.name.should eql("Studio")
581
- end
582
-
583
- it "should remove subobject" do
584
- grand_ancestor.location.destroy
585
- grand_ancestor.save
586
- inheritor.reload
587
- grand_ancestor.location.should be_nil
588
- inheritor.location.should be_nil
589
- end
590
-
591
- it "should inherit embedded documents of subobject" do
592
- grand_ancestor.location.puppets.create(:name => "Goofy")
593
- grand_ancestor.save
594
- inheritor.reload
595
- inheritor.location.puppets.should have(1).puppet
596
- end
597
- end
302
+ it "should accept conditions" do
303
+ list = Model.roots.where(:name => ancestor.name).to_a
304
+ list.should have(1).models
598
305
  end
599
306
  end
600
307
  end