dm-core 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.autotest +29 -0
  2. data/.document +5 -0
  3. data/.gitignore +27 -0
  4. data/LICENSE +20 -0
  5. data/{README.txt → README.rdoc} +14 -3
  6. data/Rakefile +23 -22
  7. data/VERSION +1 -0
  8. data/dm-core.gemspec +201 -10
  9. data/lib/dm-core.rb +32 -23
  10. data/lib/dm-core/adapters.rb +0 -1
  11. data/lib/dm-core/adapters/data_objects_adapter.rb +230 -151
  12. data/lib/dm-core/adapters/mysql_adapter.rb +7 -8
  13. data/lib/dm-core/adapters/oracle_adapter.rb +39 -59
  14. data/lib/dm-core/adapters/postgres_adapter.rb +0 -1
  15. data/lib/dm-core/adapters/sqlite3_adapter.rb +5 -0
  16. data/lib/dm-core/adapters/sqlserver_adapter.rb +114 -0
  17. data/lib/dm-core/adapters/yaml_adapter.rb +0 -5
  18. data/lib/dm-core/associations/many_to_many.rb +118 -56
  19. data/lib/dm-core/associations/many_to_one.rb +48 -21
  20. data/lib/dm-core/associations/one_to_many.rb +8 -30
  21. data/lib/dm-core/associations/one_to_one.rb +1 -5
  22. data/lib/dm-core/associations/relationship.rb +89 -97
  23. data/lib/dm-core/collection.rb +299 -184
  24. data/lib/dm-core/core_ext/enumerable.rb +28 -0
  25. data/lib/dm-core/core_ext/kernel.rb +0 -2
  26. data/lib/dm-core/migrations.rb +314 -170
  27. data/lib/dm-core/model.rb +97 -66
  28. data/lib/dm-core/model/descendant_set.rb +1 -1
  29. data/lib/dm-core/model/hook.rb +0 -3
  30. data/lib/dm-core/model/property.rb +7 -10
  31. data/lib/dm-core/model/relationship.rb +79 -26
  32. data/lib/dm-core/model/scope.rb +3 -4
  33. data/lib/dm-core/property.rb +152 -90
  34. data/lib/dm-core/property_set.rb +18 -37
  35. data/lib/dm-core/query.rb +452 -153
  36. data/lib/dm-core/query/conditions/comparison.rb +266 -173
  37. data/lib/dm-core/query/conditions/operation.rb +499 -57
  38. data/lib/dm-core/query/direction.rb +0 -3
  39. data/lib/dm-core/query/operator.rb +0 -4
  40. data/lib/dm-core/query/path.rb +10 -12
  41. data/lib/dm-core/query/sort.rb +4 -10
  42. data/lib/dm-core/repository.rb +10 -6
  43. data/lib/dm-core/resource.rb +343 -148
  44. data/lib/dm-core/spec/adapter_shared_spec.rb +17 -1
  45. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +277 -17
  46. data/lib/dm-core/support/chainable.rb +0 -2
  47. data/lib/dm-core/support/equalizer.rb +27 -3
  48. data/lib/dm-core/transaction.rb +75 -75
  49. data/lib/dm-core/type.rb +19 -5
  50. data/lib/dm-core/types/discriminator.rb +4 -4
  51. data/lib/dm-core/types/object.rb +2 -7
  52. data/lib/dm-core/types/paranoid_boolean.rb +8 -2
  53. data/lib/dm-core/types/paranoid_datetime.rb +8 -2
  54. data/lib/dm-core/version.rb +1 -1
  55. data/script/performance.rb +7 -7
  56. data/script/profile.rb +6 -6
  57. data/spec/lib/collection_helpers.rb +2 -2
  58. data/spec/lib/pending_helpers.rb +22 -3
  59. data/spec/lib/rspec_immediate_feedback_formatter.rb +1 -0
  60. data/spec/public/associations/many_to_many_spec.rb +6 -4
  61. data/spec/public/associations/many_to_one_spec.rb +10 -1
  62. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +39 -0
  63. data/spec/public/associations/one_to_many_spec.rb +4 -3
  64. data/spec/public/associations/one_to_one_spec.rb +19 -1
  65. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +45 -0
  66. data/spec/public/collection_spec.rb +4 -3
  67. data/spec/public/migrations_spec.rb +144 -0
  68. data/spec/public/model/relationship_spec.rb +115 -55
  69. data/spec/public/model_spec.rb +13 -13
  70. data/spec/public/property/object_spec.rb +106 -0
  71. data/spec/public/property_spec.rb +18 -14
  72. data/spec/public/resource_spec.rb +10 -1
  73. data/spec/public/sel_spec.rb +16 -49
  74. data/spec/public/setup_spec.rb +1 -1
  75. data/spec/public/shared/association_collection_shared_spec.rb +6 -14
  76. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  77. data/spec/public/shared/collection_shared_spec.rb +214 -217
  78. data/spec/public/shared/finder_shared_spec.rb +259 -365
  79. data/spec/public/shared/resource_shared_spec.rb +524 -248
  80. data/spec/public/transaction_spec.rb +27 -3
  81. data/spec/public/types/discriminator_spec.rb +1 -1
  82. data/spec/rcov.opts +6 -0
  83. data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +17 -0
  84. data/spec/semipublic/associations/many_to_one_spec.rb +3 -20
  85. data/spec/semipublic/associations_spec.rb +2 -2
  86. data/spec/semipublic/collection_spec.rb +0 -32
  87. data/spec/semipublic/model_spec.rb +96 -0
  88. data/spec/semipublic/property_spec.rb +3 -3
  89. data/spec/semipublic/query/conditions/comparison_spec.rb +1719 -0
  90. data/spec/semipublic/query/conditions/operation_spec.rb +1292 -0
  91. data/spec/semipublic/query_spec.rb +1285 -144
  92. data/spec/semipublic/resource_spec.rb +0 -24
  93. data/spec/semipublic/shared/resource_shared_spec.rb +103 -38
  94. data/spec/spec.opts +1 -1
  95. data/spec/spec_helper.rb +15 -6
  96. data/tasks/ci.rake +1 -0
  97. data/tasks/metrics.rake +37 -0
  98. data/tasks/spec.rake +41 -0
  99. data/tasks/yard.rake +9 -0
  100. data/tasks/yardstick.rake +19 -0
  101. metadata +99 -29
  102. data/CONTRIBUTING +0 -51
  103. data/FAQ +0 -93
  104. data/History.txt +0 -27
  105. data/MIT-LICENSE +0 -22
  106. data/Manifest.txt +0 -121
  107. data/QUICKLINKS +0 -11
  108. data/SPECS +0 -35
  109. data/TODO +0 -1
  110. data/spec/semipublic/query/conditions_spec.rb +0 -528
  111. data/tasks/ci.rb +0 -24
  112. data/tasks/dm.rb +0 -58
  113. data/tasks/doc.rb +0 -17
  114. data/tasks/gemspec.rb +0 -23
  115. data/tasks/hoe.rb +0 -45
  116. data/tasks/install.rb +0 -18
@@ -22,7 +22,9 @@ share_examples_for 'A public Collection' do
22
22
  pending if @skip
23
23
  end
24
24
 
25
- it { @articles.should respond_to(:<<) }
25
+ subject { @articles }
26
+
27
+ it { should respond_to(:<<) }
26
28
 
27
29
  describe '#<<' do
28
30
  before :all do
@@ -42,13 +44,9 @@ share_examples_for 'A public Collection' do
42
44
  it 'should append one Resource to the Collection' do
43
45
  @articles.last.should equal(@resource)
44
46
  end
45
-
46
- it 'should not relate the Resource to the Collection' do
47
- @resource.collection.should_not equal(@articles)
48
- end
49
47
  end
50
48
 
51
- it { @articles.should respond_to(:blank?) }
49
+ it { should respond_to(:blank?) }
52
50
 
53
51
  describe '#blank?' do
54
52
  describe 'when the collection is empty' do
@@ -64,7 +62,7 @@ share_examples_for 'A public Collection' do
64
62
  end
65
63
  end
66
64
 
67
- it { @articles.should respond_to(:clean?) }
65
+ it { should respond_to(:clean?) }
68
66
 
69
67
  describe '#clean?' do
70
68
  describe 'with all clean resources in the collection' do
@@ -84,7 +82,7 @@ share_examples_for 'A public Collection' do
84
82
  end
85
83
  end
86
84
 
87
- it { @articles.should respond_to(:clear) }
85
+ it { should respond_to(:clear) }
88
86
 
89
87
  describe '#clear' do
90
88
  before :all do
@@ -104,14 +102,10 @@ share_examples_for 'A public Collection' do
104
102
  it 'should make the Collection empty' do
105
103
  @articles.should be_empty
106
104
  end
107
-
108
- it 'should orphan the Resources' do
109
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
110
- end
111
105
  end
112
106
 
113
107
  [ :collect!, :map! ].each do |method|
114
- it { @articles.should respond_to(method) }
108
+ it { should respond_to(method) }
115
109
 
116
110
  describe "##{method}" do
117
111
  before :all do
@@ -131,14 +125,10 @@ share_examples_for 'A public Collection' do
131
125
  it 'should update the Collection inline' do
132
126
  @articles.each { |resource| resource.attributes.only(:title, :content).should == { :title => 'Sample Article', :content => 'New Content' } }
133
127
  end
134
-
135
- it 'should orphan each replaced Resource in the Collection' do
136
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
137
- end
138
128
  end
139
129
  end
140
130
 
141
- it { @articles.should respond_to(:concat) }
131
+ it { should respond_to(:concat) }
142
132
 
143
133
  describe '#concat' do
144
134
  before :all do
@@ -156,14 +146,10 @@ share_examples_for 'A public Collection' do
156
146
  it 'should concatenate the two collections' do
157
147
  @return.should == [ @article, @other ]
158
148
  end
159
-
160
- it 'should relate each Resource to the Collection' do
161
- @other_articles.each { |resource| resource.collection.should equal(@articles) }
162
- end
163
149
  end
164
150
 
165
151
  [ :create, :create! ].each do |method|
166
- it { @articles.should respond_to(method) }
152
+ it { should respond_to(method) }
167
153
 
168
154
  describe "##{method}" do
169
155
  describe 'when scoped to a property' do
@@ -278,7 +264,45 @@ share_examples_for 'A public Collection' do
278
264
  end
279
265
  end
280
266
 
281
- it { @articles.should respond_to(:delete) }
267
+ [ :difference, :- ].each do |method|
268
+ it { should respond_to(method) }
269
+
270
+ describe "##{method}" do
271
+ subject { @articles.send(method, @other_articles) }
272
+
273
+ describe 'with a Collection' do
274
+ it { should be_kind_of(DataMapper::Collection) }
275
+
276
+ it { should == [ @article ] }
277
+
278
+ it { subject.query.should == @articles.query.difference(@other_articles.query) }
279
+
280
+ it { should == @articles.to_a - @other_articles.to_a }
281
+ end
282
+
283
+ describe 'with an Array' do
284
+ before { @other_articles = @other_articles.to_ary }
285
+
286
+ it { should be_kind_of(DataMapper::Collection) }
287
+
288
+ it { should == [ @article ] }
289
+
290
+ it { should == @articles.to_a - @other_articles.to_a }
291
+ end
292
+
293
+ describe 'with a Set' do
294
+ before { @other_articles = @other_articles.to_set }
295
+
296
+ it { should be_kind_of(DataMapper::Collection) }
297
+
298
+ it { should == [ @article ] }
299
+
300
+ it { should == @articles.to_a - @other_articles.to_a }
301
+ end
302
+ end
303
+ end
304
+
305
+ it { should respond_to(:delete) }
282
306
 
283
307
  describe '#delete' do
284
308
  describe 'with a Resource within the Collection' do
@@ -299,10 +323,6 @@ share_examples_for 'A public Collection' do
299
323
  it 'should remove the Resource from the Collection' do
300
324
  @articles.should_not be_include(@resource)
301
325
  end
302
-
303
- it 'should orphan the Resource' do
304
- @resource.collection.should_not equal(@articles)
305
- end
306
326
  end
307
327
 
308
328
  describe 'with a Resource not within the Collection' do
@@ -316,7 +336,7 @@ share_examples_for 'A public Collection' do
316
336
  end
317
337
  end
318
338
 
319
- it { @articles.should respond_to(:delete_at) }
339
+ it { should respond_to(:delete_at) }
320
340
 
321
341
  describe '#delete_at' do
322
342
  describe 'with an offset within the Collection' do
@@ -335,10 +355,6 @@ share_examples_for 'A public Collection' do
335
355
  it 'should remove the Resource from the Collection' do
336
356
  @articles.should_not be_include(@resource)
337
357
  end
338
-
339
- it 'should orphan the Resource' do
340
- @resource.collection.should_not equal(@articles)
341
- end
342
358
  end
343
359
 
344
360
  describe 'with an offset not within the Collection' do
@@ -352,7 +368,7 @@ share_examples_for 'A public Collection' do
352
368
  end
353
369
  end
354
370
 
355
- it { @articles.should respond_to(:delete_if) }
371
+ it { should respond_to(:delete_if) }
356
372
 
357
373
  describe '#delete_if' do
358
374
  describe 'with a block that matches a Resource in the Collection' do
@@ -373,10 +389,6 @@ share_examples_for 'A public Collection' do
373
389
  it 'should remove the Resources from the Collection' do
374
390
  @resources.each { |resource| @articles.should_not be_include(resource) }
375
391
  end
376
-
377
- it 'should orphan the Resources' do
378
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
379
- end
380
392
  end
381
393
 
382
394
  describe 'with a block that does not match a Resource in the Collection' do
@@ -401,7 +413,7 @@ share_examples_for 'A public Collection' do
401
413
  end
402
414
 
403
415
  [ :destroy, :destroy! ].each do |method|
404
- it { @articles.should respond_to(method) }
416
+ it { should respond_to(method) }
405
417
 
406
418
  describe "##{method}" do
407
419
  describe 'on a normal collection' do
@@ -424,7 +436,7 @@ share_examples_for 'A public Collection' do
424
436
 
425
437
  describe 'on a limited collection' do
426
438
  before :all do
427
- @other = @articles.create.freeze
439
+ @other = @articles.create
428
440
  @limited = @articles.all(:limit => 1)
429
441
 
430
442
  @return = @limited.send(method)
@@ -449,7 +461,7 @@ share_examples_for 'A public Collection' do
449
461
  end
450
462
  end
451
463
 
452
- it { @articles.should respond_to(:dirty?) }
464
+ it { should respond_to(:dirty?) }
453
465
 
454
466
  describe '#dirty?' do
455
467
  describe 'with all clean resources in the collection' do
@@ -469,7 +481,52 @@ share_examples_for 'A public Collection' do
469
481
  end
470
482
  end
471
483
 
472
- it { @articles.should respond_to(:insert) }
484
+ # TODO: move this to enumerable_shared_spec.rb
485
+ it { should respond_to(:each) }
486
+
487
+ describe '#each' do
488
+ before :all do
489
+ rescue_if @skip do
490
+ @resources = @articles.dup.entries
491
+ @resources.should_not be_empty
492
+
493
+ @yield = []
494
+ @collections = []
495
+
496
+ @return = @articles.each do |resource|
497
+ @yield << resource
498
+ @collections << [ resource, resource.collection.object_id ]
499
+ end
500
+ end
501
+ end
502
+
503
+ it 'should return a Collection' do
504
+ @return.should be_kind_of(DataMapper::Collection)
505
+ end
506
+
507
+ it 'should return self' do
508
+ @return.should equal(@articles)
509
+ end
510
+
511
+ it 'should yield to each entry' do
512
+ @yield.should == @articles
513
+ end
514
+
515
+ it 'should yield Resources' do
516
+ @yield.each { |resource| resource.should be_kind_of(DataMapper::Resource) }
517
+ end
518
+
519
+ it 'should relate the Resource collection to the Collection within the block only' do
520
+ pending_if 'Fix SEL for m:m', @many_to_many do
521
+ @collections.each do |resource, object_id|
522
+ resource.collection.should_not equal(@articles) # collection outside block
523
+ object_id.should == @articles.object_id # collection inside block
524
+ end
525
+ end
526
+ end
527
+ end
528
+
529
+ it { should respond_to(:insert) }
473
530
 
474
531
  describe '#insert' do
475
532
  before :all do
@@ -487,15 +544,11 @@ share_examples_for 'A public Collection' do
487
544
  end
488
545
 
489
546
  it 'should insert one or more Resources at a given offset' do
490
- @articles.should == @resources + [ @article ]
491
- end
492
-
493
- it 'should relate the Resources to the Collection' do
494
- @resources.each { |resource| resource.collection.should equal(@articles) }
547
+ @articles.should == @resources << @article
495
548
  end
496
549
  end
497
550
 
498
- it { @articles.should respond_to(:inspect) }
551
+ it { should respond_to(:inspect) }
499
552
 
500
553
  describe '#inspect' do
501
554
  before :all do
@@ -515,7 +568,45 @@ share_examples_for 'A public Collection' do
515
568
  it { @return.should match(/\bcontent=\"Other Article\"\s/) }
516
569
  end
517
570
 
518
- it { @articles.should respond_to(:new) }
571
+ [ :intersection, :& ].each do |method|
572
+ it { should respond_to(method) }
573
+
574
+ describe "##{method}" do
575
+ subject { @articles.send(method, @other_articles) }
576
+
577
+ describe 'with a Collection' do
578
+ it { should be_kind_of(DataMapper::Collection) }
579
+
580
+ it { should == [] }
581
+
582
+ it { subject.query.should == @articles.query.intersection(@other_articles.query) }
583
+
584
+ it { should == @articles.to_a & @other_articles.to_a }
585
+ end
586
+
587
+ describe 'with an Array' do
588
+ before { @other_articles = @other_articles.to_ary }
589
+
590
+ it { should be_kind_of(DataMapper::Collection) }
591
+
592
+ it { should == [] }
593
+
594
+ it { should == @articles.to_a & @other_articles.to_a }
595
+ end
596
+
597
+ describe 'with a Set' do
598
+ before { @other_articles = @other_articles.to_set }
599
+
600
+ it { should be_kind_of(DataMapper::Collection) }
601
+
602
+ it { should == [] }
603
+
604
+ it { should == @articles.to_a & @other_articles.to_a }
605
+ end
606
+ end
607
+ end
608
+
609
+ it { should respond_to(:new) }
519
610
 
520
611
  describe '#new' do
521
612
  describe 'when scoped to a property' do
@@ -613,7 +704,7 @@ share_examples_for 'A public Collection' do
613
704
  end
614
705
  end
615
706
 
616
- it { @articles.should respond_to(:pop) }
707
+ it { should respond_to(:pop) }
617
708
 
618
709
  describe '#pop' do
619
710
  before :all do
@@ -636,10 +727,6 @@ share_examples_for 'A public Collection' do
636
727
  it 'should remove the Resource from the Collection' do
637
728
  @articles.should_not be_include(@new)
638
729
  end
639
-
640
- it 'should orphan the Resource' do
641
- @return.collection.should_not equal(@articles)
642
- end
643
730
  end
644
731
 
645
732
  if RUBY_VERSION >= '1.8.7'
@@ -659,15 +746,11 @@ share_examples_for 'A public Collection' do
659
746
  it 'should remove the Resource from the Collection' do
660
747
  @articles.should_not be_include(@new)
661
748
  end
662
-
663
- it 'should orphan the Resource' do
664
- @return.each { |resource| resource.collection.should_not equal(@articles) }
665
- end
666
749
  end
667
750
  end
668
751
  end
669
752
 
670
- it { @articles.should respond_to(:push) }
753
+ it { should respond_to(:push) }
671
754
 
672
755
  describe '#push' do
673
756
  before :all do
@@ -687,13 +770,9 @@ share_examples_for 'A public Collection' do
687
770
  it 'should append the Resources to the Collection' do
688
771
  @articles.should == [ @article ] + @resources
689
772
  end
690
-
691
- it 'should relate the Resources to the Collection' do
692
- @resources.each { |resource| resource.collection.should equal(@articles) }
693
- end
694
773
  end
695
774
 
696
- it { @articles.should respond_to(:reject!) }
775
+ it { should respond_to(:reject!) }
697
776
 
698
777
  describe '#reject!' do
699
778
  describe 'with a block that matches a Resource in the Collection' do
@@ -714,10 +793,6 @@ share_examples_for 'A public Collection' do
714
793
  it 'should remove the Resources from the Collection' do
715
794
  @resources.each { |resource| @articles.should_not be_include(resource) }
716
795
  end
717
-
718
- it 'should orphan the Resources' do
719
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
720
- end
721
796
  end
722
797
 
723
798
  describe 'with a block that does not match a Resource in the Collection' do
@@ -737,7 +812,7 @@ share_examples_for 'A public Collection' do
737
812
  end
738
813
  end
739
814
 
740
- it { @articles.should respond_to(:reload) }
815
+ it { should respond_to(:reload) }
741
816
 
742
817
  describe '#reload' do
743
818
  describe 'with no arguments' do
@@ -797,9 +872,9 @@ share_examples_for 'A public Collection' do
797
872
  @return.should equal(@articles)
798
873
  end
799
874
 
800
- { :id => true, :content => true, :title => true }.each do |attribute, expected|
801
- it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
802
- @collection.each { |resource| resource.attribute_loaded?(attribute).should == expected }
875
+ [ :id, :content, :title ].each do |attribute|
876
+ it "should have query field #{attribute.inspect} loaded" do
877
+ @collection.each { |resource| resource.attribute_loaded?(attribute).should be_true }
803
878
  end
804
879
  end
805
880
  end
@@ -829,17 +904,15 @@ share_examples_for 'A public Collection' do
829
904
  @return.should equal(@articles)
830
905
  end
831
906
 
832
- { :id => true, :content => true, :title => loaded }.each do |attribute, expected|
833
- it "should have query field #{attribute.inspect} #{'not' unless expected} loaded".squeeze(' ') do
834
- pending_if "TODO: #{@articles.class}#reload should not be a kicker", @one_to_many && loaded == false && attribute == :title do
835
- @collection.each { |resource| resource.attribute_loaded?(attribute).should == expected }
836
- end
907
+ [ :id, :content, :title ].each do |attribute|
908
+ it "should have query field #{attribute.inspect} loaded" do
909
+ @collection.each { |resource| resource.attribute_loaded?(attribute).should be_true }
837
910
  end
838
911
  end
839
912
  end
840
913
  end
841
914
 
842
- it { @articles.should respond_to(:replace) }
915
+ it { should respond_to(:replace) }
843
916
 
844
917
  describe '#replace' do
845
918
  describe 'when provided an Array of Resources' do
@@ -860,14 +933,6 @@ share_examples_for 'A public Collection' do
860
933
  it 'should update the Collection with new Resources' do
861
934
  @articles.should == @other_articles
862
935
  end
863
-
864
- it 'should relate each Resource added to the Collection' do
865
- @articles.each { |resource| resource.collection.should equal(@articles) }
866
- end
867
-
868
- it 'should orphan each Resource removed from the Collection' do
869
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
870
- end
871
936
  end
872
937
 
873
938
  describe 'when provided an Array of Hashes' do
@@ -899,7 +964,7 @@ share_examples_for 'A public Collection' do
899
964
  end
900
965
  end
901
966
 
902
- it { @articles.should respond_to(:reverse!) }
967
+ it { should respond_to(:reverse!) }
903
968
 
904
969
  describe '#reverse!' do
905
970
  before :all do
@@ -928,7 +993,7 @@ share_examples_for 'A public Collection' do
928
993
  end
929
994
 
930
995
  [ :save, :save! ].each do |method|
931
- it { @articles.should respond_to(method) }
996
+ it { should respond_to(method) }
932
997
 
933
998
  describe "##{method}" do
934
999
  describe 'when Resources are not saved' do
@@ -958,15 +1023,11 @@ share_examples_for 'A public Collection' do
958
1023
  it 'should return true' do
959
1024
  @return.should be_true
960
1025
  end
961
-
962
- it 'should orphan the Resources' do
963
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
964
- end
965
1026
  end
966
1027
  end
967
1028
  end
968
1029
 
969
- it { @articles.should respond_to(:shift) }
1030
+ it { should respond_to(:shift) }
970
1031
 
971
1032
  describe '#shift' do
972
1033
  describe 'with no arguments' do
@@ -985,10 +1046,6 @@ share_examples_for 'A public Collection' do
985
1046
  it 'should remove the Resource from the Collection' do
986
1047
  @articles.should_not be_include(@return)
987
1048
  end
988
-
989
- it 'should orphan the Resource' do
990
- @return.collection.should_not equal(@articles)
991
- end
992
1049
  end
993
1050
 
994
1051
  if RUBY_VERSION >= '1.8.7'
@@ -1009,15 +1066,11 @@ share_examples_for 'A public Collection' do
1009
1066
  it 'should remove the Resource from the Collection' do
1010
1067
  @articles.should_not be_include(@article)
1011
1068
  end
1012
-
1013
- it 'should orphan the Resource' do
1014
- @return.each { |resource| resource.collection.should_not equal(@articles) }
1015
- end
1016
1069
  end
1017
1070
  end
1018
1071
  end
1019
1072
 
1020
- it { @articles.should respond_to(:slice!) }
1073
+ it { should respond_to(:slice!) }
1021
1074
 
1022
1075
  describe '#slice!' do
1023
1076
  before :all do
@@ -1048,10 +1101,6 @@ share_examples_for 'A public Collection' do
1048
1101
  it 'should remove the Resource from the Collection' do
1049
1102
  @articles.should_not be_include(@resource)
1050
1103
  end
1051
-
1052
- it 'should orphan the Resource' do
1053
- @resource.collection.should_not equal(@articles)
1054
- end
1055
1104
  end
1056
1105
 
1057
1106
  describe 'with a positive offset and length' do
@@ -1073,10 +1122,6 @@ share_examples_for 'A public Collection' do
1073
1122
  @resources.each { |resource| @articles.should_not be_include(resource) }
1074
1123
  end
1075
1124
 
1076
- it 'should orphan the Resources' do
1077
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
1078
- end
1079
-
1080
1125
  it 'should scope the Collection' do
1081
1126
  @resources.reload.should == @copy.entries.slice!(5, 5)
1082
1127
  end
@@ -1101,10 +1146,6 @@ share_examples_for 'A public Collection' do
1101
1146
  @resources.each { |resource| @articles.should_not be_include(resource) }
1102
1147
  end
1103
1148
 
1104
- it 'should orphan the Resources' do
1105
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
1106
- end
1107
-
1108
1149
  it 'should scope the Collection' do
1109
1150
  @resources.reload.should == @copy.entries.slice!(5..10)
1110
1151
  end
@@ -1128,10 +1169,6 @@ share_examples_for 'A public Collection' do
1128
1169
  it 'should remove the Resource from the Collection' do
1129
1170
  @articles.should_not be_include(@resource)
1130
1171
  end
1131
-
1132
- it 'should orphan the Resource' do
1133
- @resource.collection.should_not equal(@articles)
1134
- end
1135
1172
  end
1136
1173
 
1137
1174
  describe 'with a negative offset and length' do
@@ -1153,10 +1190,6 @@ share_examples_for 'A public Collection' do
1153
1190
  @resources.each { |resource| @articles.should_not be_include(resource) }
1154
1191
  end
1155
1192
 
1156
- it 'should orphan the Resources' do
1157
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
1158
- end
1159
-
1160
1193
  it 'should scope the Collection' do
1161
1194
  @resources.reload.should == @copy.entries.slice!(-5, 5)
1162
1195
  end
@@ -1181,10 +1214,6 @@ share_examples_for 'A public Collection' do
1181
1214
  @resources.each { |resource| @articles.should_not be_include(resource) }
1182
1215
  end
1183
1216
 
1184
- it 'should orphan the Resources' do
1185
- @resources.each { |resource| resource.collection.should_not equal(@articles) }
1186
- end
1187
-
1188
1217
  it 'should scope the Collection' do
1189
1218
  @resources.reload.should == @copy.entries.slice!(-3..-2)
1190
1219
  end
@@ -1227,7 +1256,7 @@ share_examples_for 'A public Collection' do
1227
1256
  end
1228
1257
  end
1229
1258
 
1230
- it { @articles.should respond_to(:sort!) }
1259
+ it { should respond_to(:sort!) }
1231
1260
 
1232
1261
  describe '#sort!' do
1233
1262
  describe 'without a block' do
@@ -1268,7 +1297,7 @@ share_examples_for 'A public Collection' do
1268
1297
  end
1269
1298
 
1270
1299
  [ :splice, :[]= ].each do |method|
1271
- it { @articles.should respond_to(method) }
1300
+ it { should respond_to(method) }
1272
1301
 
1273
1302
  describe "##{method}" do
1274
1303
  before :all do
@@ -1293,9 +1322,8 @@ share_examples_for 'A public Collection' do
1293
1322
 
1294
1323
  describe 'with a positive offset and a Resource' do
1295
1324
  before :all do
1296
- rescue_if 'TODO', @skip do
1325
+ rescue_if @skip do
1297
1326
  @original = @copy[1]
1298
- @original.collection.should equal(@articles)
1299
1327
 
1300
1328
  @return = @resource = @articles.send(method, 1, @new)
1301
1329
  end
@@ -1318,21 +1346,12 @@ share_examples_for 'A public Collection' do
1318
1346
  it 'should include the Resource in the Collection' do
1319
1347
  @articles.should be_include(@resource)
1320
1348
  end
1321
-
1322
- it 'should relate the Resource to the Collection' do
1323
- @resource.collection.should equal(@articles)
1324
- end
1325
-
1326
- it 'should orphan the original Resource' do
1327
- @original.collection.should_not equal(@articles)
1328
- end
1329
1349
  end
1330
1350
 
1331
1351
  describe 'with a positive offset and length and a Resource' do
1332
1352
  before :all do
1333
- rescue_if 'TODO', @skip do
1353
+ rescue_if @skip do
1334
1354
  @original = @copy[2]
1335
- @original.collection.should equal(@articles)
1336
1355
 
1337
1356
  @return = @resource = @articles.send(method, 2, 1, @new)
1338
1357
  end
@@ -1355,17 +1374,12 @@ share_examples_for 'A public Collection' do
1355
1374
  it 'should include the Resource in the Collection' do
1356
1375
  @articles.should be_include(@resource)
1357
1376
  end
1358
-
1359
- it 'should orphan the original Resource' do
1360
- @original.collection.should_not equal(@articles)
1361
- end
1362
1377
  end
1363
1378
 
1364
1379
  describe 'with a positive range and a Resource' do
1365
1380
  before :all do
1366
- rescue_if 'TODO', @skip do
1381
+ rescue_if @skip do
1367
1382
  @originals = @copy.values_at(2..3)
1368
- @originals.each { |resource| resource.collection.should equal(@articles) }
1369
1383
 
1370
1384
  @return = @resource = @articles.send(method, 2..3, @new)
1371
1385
  end
@@ -1388,17 +1402,12 @@ share_examples_for 'A public Collection' do
1388
1402
  it 'should include the Resource in the Collection' do
1389
1403
  @articles.should be_include(@resource)
1390
1404
  end
1391
-
1392
- it 'should orphan the original Resources' do
1393
- @originals.each { |resource| resource.collection.should_not equal(@articles) }
1394
- end
1395
1405
  end
1396
1406
 
1397
1407
  describe 'with a negative offset and a Resource' do
1398
1408
  before :all do
1399
- rescue_if 'TODO', @skip do
1409
+ rescue_if @skip do
1400
1410
  @original = @copy[-1]
1401
- @original.collection.should equal(@articles)
1402
1411
 
1403
1412
  @return = @resource = @articles.send(method, -1, @new)
1404
1413
  end
@@ -1421,21 +1430,12 @@ share_examples_for 'A public Collection' do
1421
1430
  it 'should include the Resource in the Collection' do
1422
1431
  @articles.should be_include(@resource)
1423
1432
  end
1424
-
1425
- it 'should relate the Resource to the Collection' do
1426
- @resource.collection.should equal(@articles)
1427
- end
1428
-
1429
- it 'should orphan the original Resource' do
1430
- @original.collection.should_not equal(@articles)
1431
- end
1432
1433
  end
1433
1434
 
1434
1435
  describe 'with a negative offset and length and a Resource' do
1435
1436
  before :all do
1436
- rescue_if 'TODO', @skip do
1437
+ rescue_if @skip do
1437
1438
  @original = @copy[-2]
1438
- @original.collection.should equal(@articles)
1439
1439
 
1440
1440
  @return = @resource = @articles.send(method, -2, 1, @new)
1441
1441
  end
@@ -1458,17 +1458,12 @@ share_examples_for 'A public Collection' do
1458
1458
  it 'should include the Resource in the Collection' do
1459
1459
  @articles.should be_include(@resource)
1460
1460
  end
1461
-
1462
- it 'should orphan the original Resource' do
1463
- @original.collection.should_not equal(@articles)
1464
- end
1465
1461
  end
1466
1462
 
1467
1463
  describe 'with a negative range and a Resource' do
1468
1464
  before :all do
1469
- rescue_if 'TODO', @skip do
1465
+ rescue_if @skip do
1470
1466
  @originals = @articles.values_at(-3..-2)
1471
- @originals.each { |resource| resource.collection.should equal(@articles) }
1472
1467
 
1473
1468
  @return = @resource = @articles.send(method, -3..-2, @new)
1474
1469
  end
@@ -1491,10 +1486,6 @@ share_examples_for 'A public Collection' do
1491
1486
  it 'should include the Resource in the Collection' do
1492
1487
  @articles.should be_include(@resource)
1493
1488
  end
1494
-
1495
- it 'should orphan the original Resources' do
1496
- @originals.each { |resource| resource.collection.should_not equal(@articles) }
1497
- end
1498
1489
  end
1499
1490
  end
1500
1491
  end
@@ -1502,7 +1493,7 @@ share_examples_for 'A public Collection' do
1502
1493
  describe '#[]=' do
1503
1494
  describe 'when swapping resources' do
1504
1495
  before :all do
1505
- rescue_if 'TODO', @skip do
1496
+ rescue_if @skip do
1506
1497
  @articles.create(:content => 'Another Article')
1507
1498
 
1508
1499
  @entries = @articles.entries
@@ -1514,14 +1505,48 @@ share_examples_for 'A public Collection' do
1514
1505
  it 'should include the Resource in the Collection' do
1515
1506
  @articles.should == @entries.reverse
1516
1507
  end
1508
+ end
1509
+ end
1510
+
1511
+ [ :union, :|, :+ ].each do |method|
1512
+ it { should respond_to(method) }
1513
+
1514
+ describe "##{method}" do
1515
+ subject { @articles.send(method, @other_articles) }
1516
+
1517
+ describe 'with a Collection' do
1518
+ it { should be_kind_of(DataMapper::Collection) }
1519
+
1520
+ it { should == [ @article, @other ] }
1521
+
1522
+ it { subject.query.should == @articles.query.union(@other_articles.query) }
1523
+
1524
+ it { should == @articles.to_a | @other_articles.to_a }
1525
+ end
1526
+
1527
+ describe 'with an Array' do
1528
+ before { @other_articles = @other_articles.to_ary }
1529
+
1530
+ it { should be_kind_of(DataMapper::Collection) }
1531
+
1532
+ it { should == [ @article, @other ] }
1533
+
1534
+ it { should == @articles.to_a | @other_articles.to_a }
1535
+ end
1536
+
1537
+ describe 'with a Set' do
1538
+ before { @other_articles = @other_articles.to_set }
1539
+
1540
+ it { should be_kind_of(DataMapper::Collection) }
1541
+
1542
+ it { should == [ @article, @other ] }
1517
1543
 
1518
- it 'should relate the Resource to the Collection' do
1519
- @articles.each { |resource| resource.collection.should equal(@articles) }
1544
+ it { should == @articles.to_a | @other_articles.to_a }
1520
1545
  end
1521
1546
  end
1522
1547
  end
1523
1548
 
1524
- it { @articles.should respond_to(:unshift) }
1549
+ it { should respond_to(:unshift) }
1525
1550
 
1526
1551
  describe '#unshift' do
1527
1552
  before :all do
@@ -1541,14 +1566,10 @@ share_examples_for 'A public Collection' do
1541
1566
  it 'should prepend the Resources to the Collection' do
1542
1567
  @articles.should == @resources + [ @article ]
1543
1568
  end
1544
-
1545
- it 'should relate the Resources to the Collection' do
1546
- @resources.each { |resource| resource.collection.should equal(@articles) }
1547
- end
1548
1569
  end
1549
1570
 
1550
1571
  [ :update, :update! ].each do |method|
1551
- it { @articles.should respond_to(method) }
1572
+ it { should respond_to(method) }
1552
1573
 
1553
1574
  describe "##{method}" do
1554
1575
  describe 'with no arguments' do
@@ -1573,15 +1594,7 @@ share_examples_for 'A public Collection' do
1573
1594
  end
1574
1595
 
1575
1596
  if method == :update!
1576
- # FIXME: this is spec order dependent, move this into a helper method
1577
- # and execute in the before :all block
1578
- unless loaded
1579
- it 'should not be a kicker' do
1580
- pending_if 'TODO', @many_to_many do
1581
- @articles.should_not be_loaded
1582
- end
1583
- end
1584
- end
1597
+ should_not_be_a_kicker
1585
1598
  end
1586
1599
 
1587
1600
  it 'should return true' do
@@ -1589,12 +1602,12 @@ share_examples_for 'A public Collection' do
1589
1602
  end
1590
1603
 
1591
1604
  it 'should update attributes of all Resources' do
1592
- @articles.each { |resource| @attributes.each { |key, value| resource.send(key).should == value } }
1605
+ @articles.each { |resource| @attributes.each { |key, value| resource.__send__(key).should == value } }
1593
1606
  end
1594
1607
 
1595
1608
  it 'should persist the changes' do
1596
1609
  resource = @article_model.get(*@article.key)
1597
- @attributes.each { |key, value| resource.send(key).should == value }
1610
+ @attributes.each { |key, value| resource.__send__(key).should == value }
1598
1611
  end
1599
1612
  end
1600
1613
 
@@ -1606,15 +1619,7 @@ share_examples_for 'A public Collection' do
1606
1619
  end
1607
1620
 
1608
1621
  if method == :update!
1609
- # FIXME: this is spec order dependent, move this into a helper method
1610
- # and execute in the before :all block
1611
- unless loaded
1612
- it 'should not be a kicker' do
1613
- pending_if 'TODO', @many_to_many do
1614
- @articles.should_not be_loaded
1615
- end
1616
- end
1617
- end
1622
+ should_not_be_a_kicker
1618
1623
  end
1619
1624
 
1620
1625
  it 'should return true' do
@@ -1622,16 +1627,16 @@ share_examples_for 'A public Collection' do
1622
1627
  end
1623
1628
 
1624
1629
  it 'should update attributes of all Resources' do
1625
- @articles.each { |resource| @attributes.each { |key, value| resource.send(key).should == value } }
1630
+ @articles.each { |resource| @attributes.each { |key, value| resource.__send__(key).should == value } }
1626
1631
  end
1627
1632
 
1628
1633
  it 'should persist the changes' do
1629
1634
  resource = @article_model.get(*@article.key)
1630
- @attributes.each { |key, value| resource.send(key).should == value }
1635
+ @attributes.each { |key, value| resource.__send__(key).should == value }
1631
1636
  end
1632
1637
  end
1633
1638
 
1634
- describe 'with attributes where a not-nullable property is nil' do
1639
+ describe 'with attributes where a required property is nil' do
1635
1640
  before :all do
1636
1641
  @return = @articles.send(method, :title => nil)
1637
1642
  end
@@ -1655,15 +1660,7 @@ share_examples_for 'A public Collection' do
1655
1660
  end
1656
1661
 
1657
1662
  if method == :update!
1658
- # FIXME: this is spec order dependent, move this into a helper method
1659
- # and execute in the before :all block
1660
- unless loaded
1661
- it 'should not be a kicker' do
1662
- pending "Update Collection##{method} to use a subquery" do
1663
- @limited.should_not be_loaded
1664
- end
1665
- end
1666
- end
1663
+ should_not_be_a_kicker(:@limited)
1667
1664
  end
1668
1665
 
1669
1666
  it 'should return true' do
@@ -1675,17 +1672,17 @@ share_examples_for 'A public Collection' do
1675
1672
  end
1676
1673
 
1677
1674
  it 'should update attributes of all Resources' do
1678
- @limited.each { |resource| @attributes.each { |key, value| resource.send(key).should == value } }
1675
+ @limited.each { |resource| @attributes.each { |key, value| resource.__send__(key).should == value } }
1679
1676
  end
1680
1677
 
1681
1678
  it 'should persist the changes' do
1682
1679
  resource = @article_model.get(*@article.key)
1683
- @attributes.each { |key, value| resource.send(key).should == value }
1680
+ @attributes.each { |key, value| resource.__send__(key).should == value }
1684
1681
  end
1685
1682
 
1686
1683
  it 'should not update the other Resource' do
1687
1684
  @other.reload
1688
- @attributes.each { |key, value| @other.send(key).should_not == value }
1685
+ @attributes.each { |key, value| @other.__send__(key).should_not == value }
1689
1686
  end
1690
1687
  end
1691
1688
 
@@ -1697,7 +1694,7 @@ share_examples_for 'A public Collection' do
1697
1694
  it 'should raise an exception' do
1698
1695
  lambda {
1699
1696
  @articles.send(method, :content => 'New Content')
1700
- }.should raise_error(DataMapper::UpdateConflictError, "##{method} cannot be called on a dirty collection")
1697
+ }.should raise_error(DataMapper::UpdateConflictError, "#{@articles.class}##{method} cannot be called on a dirty collection")
1701
1698
  end
1702
1699
  end
1703
1700
  end