datamapper-dm-core 0.9.11 → 0.10.0

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 (192) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -39
  5. data/Manifest.txt +67 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +16 -15
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/dm-core.gemspec +11 -15
  12. data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
  13. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  14. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  15. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  16. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  19. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  20. data/lib/dm-core/adapters.rb +135 -16
  21. data/lib/dm-core/associations/many_to_many.rb +372 -90
  22. data/lib/dm-core/associations/many_to_one.rb +220 -73
  23. data/lib/dm-core/associations/one_to_many.rb +319 -255
  24. data/lib/dm-core/associations/one_to_one.rb +66 -53
  25. data/lib/dm-core/associations/relationship.rb +560 -158
  26. data/lib/dm-core/collection.rb +1104 -381
  27. data/lib/dm-core/core_ext/kernel.rb +12 -0
  28. data/lib/dm-core/core_ext/symbol.rb +10 -0
  29. data/lib/dm-core/identity_map.rb +4 -34
  30. data/lib/dm-core/migrations.rb +1283 -0
  31. data/lib/dm-core/model/descendant_set.rb +81 -0
  32. data/lib/dm-core/model/hook.rb +45 -0
  33. data/lib/dm-core/model/is.rb +32 -0
  34. data/lib/dm-core/model/property.rb +248 -0
  35. data/lib/dm-core/model/relationship.rb +335 -0
  36. data/lib/dm-core/model/scope.rb +90 -0
  37. data/lib/dm-core/model.rb +570 -369
  38. data/lib/dm-core/property.rb +753 -280
  39. data/lib/dm-core/property_set.rb +141 -98
  40. data/lib/dm-core/query/conditions/comparison.rb +814 -0
  41. data/lib/dm-core/query/conditions/operation.rb +247 -0
  42. data/lib/dm-core/query/direction.rb +43 -0
  43. data/lib/dm-core/query/operator.rb +42 -0
  44. data/lib/dm-core/query/path.rb +102 -0
  45. data/lib/dm-core/query/sort.rb +45 -0
  46. data/lib/dm-core/query.rb +974 -492
  47. data/lib/dm-core/repository.rb +147 -107
  48. data/lib/dm-core/resource.rb +644 -429
  49. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  50. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  51. data/lib/dm-core/support/chainable.rb +20 -0
  52. data/lib/dm-core/support/deprecate.rb +12 -0
  53. data/lib/dm-core/support/equalizer.rb +23 -0
  54. data/lib/dm-core/support/logger.rb +13 -0
  55. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  56. data/lib/dm-core/transaction.rb +333 -92
  57. data/lib/dm-core/type.rb +98 -60
  58. data/lib/dm-core/types/boolean.rb +1 -1
  59. data/lib/dm-core/types/discriminator.rb +34 -20
  60. data/lib/dm-core/types/object.rb +7 -4
  61. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  62. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  63. data/lib/dm-core/types/serial.rb +3 -3
  64. data/lib/dm-core/types/text.rb +3 -4
  65. data/lib/dm-core/version.rb +1 -1
  66. data/lib/dm-core.rb +106 -110
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/model/relationship_spec.rb +924 -0
  80. data/spec/public/model_spec.rb +159 -0
  81. data/spec/public/property_spec.rb +829 -0
  82. data/spec/public/resource_spec.rb +71 -0
  83. data/spec/public/sel_spec.rb +44 -0
  84. data/spec/public/setup_spec.rb +145 -0
  85. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  86. data/spec/public/shared/collection_shared_spec.rb +1723 -0
  87. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  88. data/spec/public/shared/resource_shared_spec.rb +924 -0
  89. data/spec/public/shared/sel_shared_spec.rb +112 -0
  90. data/spec/public/transaction_spec.rb +129 -0
  91. data/spec/public/types/discriminator_spec.rb +130 -0
  92. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  93. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  94. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  95. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  96. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  97. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  99. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  100. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  101. data/spec/semipublic/associations_spec.rb +177 -0
  102. data/spec/semipublic/collection_spec.rb +142 -0
  103. data/spec/semipublic/property_spec.rb +61 -0
  104. data/spec/semipublic/query/conditions_spec.rb +528 -0
  105. data/spec/semipublic/query/path_spec.rb +443 -0
  106. data/spec/semipublic/query_spec.rb +2626 -0
  107. data/spec/semipublic/resource_spec.rb +47 -0
  108. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  109. data/spec/spec.opts +3 -1
  110. data/spec/spec_helper.rb +80 -57
  111. data/tasks/ci.rb +19 -31
  112. data/tasks/dm.rb +43 -48
  113. data/tasks/doc.rb +8 -11
  114. data/tasks/gemspec.rb +5 -5
  115. data/tasks/hoe.rb +15 -16
  116. data/tasks/install.rb +8 -10
  117. metadata +72 -93
  118. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  119. data/lib/dm-core/associations.rb +0 -207
  120. data/lib/dm-core/auto_migrations.rb +0 -105
  121. data/lib/dm-core/dependency_queue.rb +0 -32
  122. data/lib/dm-core/hook.rb +0 -11
  123. data/lib/dm-core/is.rb +0 -16
  124. data/lib/dm-core/logger.rb +0 -232
  125. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  126. data/lib/dm-core/migrator.rb +0 -29
  127. data/lib/dm-core/scope.rb +0 -58
  128. data/lib/dm-core/support/array.rb +0 -13
  129. data/lib/dm-core/support/assertions.rb +0 -8
  130. data/lib/dm-core/support/errors.rb +0 -23
  131. data/lib/dm-core/support/kernel.rb +0 -11
  132. data/lib/dm-core/support/symbol.rb +0 -41
  133. data/lib/dm-core/support.rb +0 -7
  134. data/lib/dm-core/type_map.rb +0 -80
  135. data/lib/dm-core/types.rb +0 -19
  136. data/script/all +0 -4
  137. data/spec/integration/association_spec.rb +0 -1382
  138. data/spec/integration/association_through_spec.rb +0 -203
  139. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  140. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  141. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  142. data/spec/integration/auto_migrations_spec.rb +0 -413
  143. data/spec/integration/collection_spec.rb +0 -1073
  144. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  145. data/spec/integration/dependency_queue_spec.rb +0 -46
  146. data/spec/integration/model_spec.rb +0 -197
  147. data/spec/integration/mysql_adapter_spec.rb +0 -85
  148. data/spec/integration/postgres_adapter_spec.rb +0 -731
  149. data/spec/integration/property_spec.rb +0 -253
  150. data/spec/integration/query_spec.rb +0 -514
  151. data/spec/integration/repository_spec.rb +0 -61
  152. data/spec/integration/resource_spec.rb +0 -513
  153. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  154. data/spec/integration/sti_spec.rb +0 -273
  155. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  156. data/spec/integration/transaction_spec.rb +0 -75
  157. data/spec/integration/type_spec.rb +0 -275
  158. data/spec/lib/logging_helper.rb +0 -18
  159. data/spec/lib/mock_adapter.rb +0 -27
  160. data/spec/lib/model_loader.rb +0 -100
  161. data/spec/lib/publicize_methods.rb +0 -28
  162. data/spec/models/content.rb +0 -16
  163. data/spec/models/vehicles.rb +0 -34
  164. data/spec/models/zoo.rb +0 -48
  165. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  166. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  167. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  168. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  169. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  170. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  171. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  172. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  173. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  174. data/spec/unit/associations/relationship_spec.rb +0 -71
  175. data/spec/unit/associations_spec.rb +0 -242
  176. data/spec/unit/auto_migrations_spec.rb +0 -111
  177. data/spec/unit/collection_spec.rb +0 -182
  178. data/spec/unit/data_mapper_spec.rb +0 -35
  179. data/spec/unit/identity_map_spec.rb +0 -126
  180. data/spec/unit/is_spec.rb +0 -80
  181. data/spec/unit/migrator_spec.rb +0 -33
  182. data/spec/unit/model_spec.rb +0 -321
  183. data/spec/unit/naming_conventions_spec.rb +0 -36
  184. data/spec/unit/property_set_spec.rb +0 -90
  185. data/spec/unit/property_spec.rb +0 -753
  186. data/spec/unit/query_spec.rb +0 -571
  187. data/spec/unit/repository_spec.rb +0 -93
  188. data/spec/unit/resource_spec.rb +0 -649
  189. data/spec/unit/scope_spec.rb +0 -142
  190. data/spec/unit/transaction_spec.rb +0 -493
  191. data/spec/unit/type_map_spec.rb +0 -114
  192. data/spec/unit/type_spec.rb +0 -119
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Resource do
4
+ before :all do
5
+ module ::Blog
6
+ class User
7
+ include DataMapper::Resource
8
+
9
+ property :name, String, :key => true
10
+ property :age, Integer
11
+ property :summary, Text
12
+ property :description, Text
13
+ property :admin, Boolean, :accessor => :private
14
+
15
+ belongs_to :referrer, self, :nullable => true
16
+ has n, :comments
17
+
18
+ # FIXME: figure out a different approach than stubbing things out
19
+ def comment=(*)
20
+ # do nothing with comment
21
+ end
22
+ end
23
+
24
+ class Author < User; end
25
+
26
+ class Comment
27
+ include DataMapper::Resource
28
+
29
+ property :id, Serial
30
+ property :body, Text
31
+
32
+ belongs_to :user
33
+ end
34
+
35
+ class Article
36
+ include DataMapper::Resource
37
+
38
+ property :id, Serial
39
+ property :body, Text
40
+
41
+ has n, :paragraphs
42
+ end
43
+
44
+ class Paragraph
45
+ include DataMapper::Resource
46
+
47
+ property :id, Serial
48
+ property :text, String
49
+
50
+ belongs_to :article
51
+ end
52
+ end
53
+
54
+ @user_model = Blog::User
55
+ @author_model = Blog::Author
56
+ @comment_model = Blog::Comment
57
+ @article_model = Blog::Article
58
+ @paragraph_model = Blog::Paragraph
59
+ end
60
+
61
+ supported_by :all do
62
+ before :all do
63
+ user = @user_model.create(:name => 'dbussink', :age => 25, :description => 'Test')
64
+
65
+ @user = @user_model.get(*user.key)
66
+ end
67
+
68
+ it_should_behave_like 'A public Resource'
69
+ it_should_behave_like 'A Resource supporting Strategic Eager Loading'
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe 'SEL', 'with different key types' do
4
+ before :all do
5
+ module ::Blog
6
+ class Author
7
+ include DataMapper::Resource
8
+
9
+ property :id, Serial
10
+ property :name, String
11
+
12
+ has n, :articles
13
+ end
14
+
15
+ class Article
16
+ include DataMapper::Resource
17
+
18
+ property :id, Serial
19
+ property :title, String, :nullable => false
20
+
21
+ property :author_id, String # different type
22
+
23
+ belongs_to :author
24
+ end
25
+ end
26
+
27
+ @author_model = Blog::Author
28
+ @article_model = Blog::Article
29
+ end
30
+
31
+ supported_by :all do
32
+ before :all do
33
+ @author1 = @author_model.create(:name => 'Dan Kubb')
34
+ @author2 = @author_model.create(:name => 'Carl Porth')
35
+
36
+ @article1 = @author1.articles.create(:title => 'Sample Article')
37
+ @article2 = @author2.articles.create(:title => 'Other Article')
38
+ end
39
+
40
+ it 'should return expected results' do
41
+ @article_model.all.map { |article| article.author }.should == [ @author1, @author2 ]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,145 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe DataMapper do
4
+ describe '.setup' do
5
+ describe 'using connection string' do
6
+ before :all do
7
+ @return = DataMapper.setup(:setup_test, 'in_memory://user:pass@hostname:1234/path?foo=bar&baz=foo#fragment')
8
+
9
+ @options = @return.options
10
+ end
11
+
12
+ after :all do
13
+ DataMapper::Repository.adapters.delete(@return.name)
14
+ end
15
+
16
+ it 'should return an Adapter' do
17
+ @return.should be_kind_of(DataMapper::Adapters::AbstractAdapter)
18
+ end
19
+
20
+ it 'should set up the repository' do
21
+ DataMapper.repository(:setup_test).adapter.should equal(@return)
22
+ end
23
+
24
+ {
25
+ :adapter => 'in_memory',
26
+ :user => 'user',
27
+ :password => 'pass',
28
+ :host => 'hostname',
29
+ :port => 1234,
30
+ :path => '/path',
31
+ :fragment => 'fragment'
32
+ }.each do |key, val|
33
+ it "should extract the #{key.inspect} option from the uri" do
34
+ @options[key].should == val
35
+ end
36
+ end
37
+
38
+ it 'should alias the scheme of the uri as the adapter' do
39
+ @options[:scheme].should == @options[:adapter]
40
+ end
41
+
42
+ it 'should leave the query param intact' do
43
+ @options[:query].should == 'foo=bar&baz=foo'
44
+ end
45
+
46
+ it 'should extract the query param as top-level options' do
47
+ @options[:foo].should == 'bar'
48
+ @options[:baz].should == 'foo'
49
+ end
50
+ end
51
+
52
+ describe 'using options' do
53
+ before :all do
54
+ @return = DataMapper.setup(:setup_test, :adapter => :in_memory, :foo => 'bar')
55
+
56
+ @options = @return.options
57
+ end
58
+
59
+ after :all do
60
+ DataMapper::Repository.adapters.delete(@return.name)
61
+ end
62
+
63
+ it 'should return an Adapter' do
64
+ @return.should be_kind_of(DataMapper::Adapters::AbstractAdapter)
65
+ end
66
+
67
+ it 'should set up the repository' do
68
+ DataMapper.repository(:setup_test).adapter.should equal(@return)
69
+ end
70
+
71
+ {
72
+ :adapter => :in_memory,
73
+ :foo => 'bar'
74
+ }.each do |key, val|
75
+ it "should set the #{key.inspect} option" do
76
+ @options[key].should == val
77
+ end
78
+ end
79
+ end
80
+
81
+ describe 'using invalid options' do
82
+ it 'should raise an exception' do
83
+ lambda {
84
+ DataMapper.setup(:setup_test, :invalid)
85
+ }.should raise_error(ArgumentError, '+options+ should be Hash or Addressable::URI or String, but was Symbol')
86
+ end
87
+ end
88
+
89
+ describe 'using an instance of an adapter' do
90
+ before :all do
91
+ @adapter = DataMapper::Adapters::InMemoryAdapter.new(:setup_test)
92
+
93
+ @return = DataMapper.setup(@adapter)
94
+ end
95
+
96
+ after :all do
97
+ DataMapper::Repository.adapters.delete(@return.name)
98
+ end
99
+
100
+ it 'should return an Adapter' do
101
+ @return.should be_kind_of(DataMapper::Adapters::AbstractAdapter)
102
+ end
103
+
104
+ it 'should set up the repository' do
105
+ DataMapper.repository(:setup_test).adapter.should equal(@return)
106
+ end
107
+
108
+ it 'should use the adapter given' do
109
+ @return.should == @adapter
110
+ end
111
+
112
+ it 'should use the name given to the adapter' do
113
+ @return.name.should == @adapter.name
114
+ end
115
+ end
116
+
117
+ supported_by :postgres, :mysql, :sqlite3 do
118
+ { :path => :database, :user => :username }.each do |original_key, new_key|
119
+ describe "using #{new_key.inspect} option" do
120
+ before :all do
121
+ @return = DataMapper.setup(:setup_test, :adapter => @adapter.options[:adapter], new_key => @adapter.options[original_key])
122
+
123
+ @options = @return.options
124
+ end
125
+
126
+ after :all do
127
+ DataMapper::Repository.adapters.delete(@return.name)
128
+ end
129
+
130
+ it 'should return an Adapter' do
131
+ @return.should be_kind_of(DataMapper::Adapters::AbstractAdapter)
132
+ end
133
+
134
+ it 'should set up the repository' do
135
+ DataMapper.repository(:setup_test).adapter.should equal(@return)
136
+ end
137
+
138
+ it "should set the #{new_key.inspect} option" do
139
+ @options[new_key].should == @adapter.options[original_key]
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,317 @@
1
+ share_examples_for 'It can transfer a Resource from another association' do
2
+ before :all do
3
+ @no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
4
+ defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
5
+
6
+ @one_to_many = @articles.kind_of?(DataMapper::Associations::OneToMany::Collection)
7
+ @many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
8
+
9
+ @skip = @no_join && @many_to_many
10
+ end
11
+
12
+ before :all do
13
+ unless @skip
14
+ %w[ @resource @original ].each do |ivar|
15
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
16
+ raise "+#{ivar}+ should not be nil in before block" unless instance_variable_get(ivar)
17
+ end
18
+ end
19
+ end
20
+
21
+ before do
22
+ pending if @skip
23
+ end
24
+
25
+ it 'should relate the Resource to the Collection' do
26
+ @resource.collection.should equal(@articles)
27
+ end
28
+
29
+ it 'should remove the Resource from the original Collection' do
30
+ pending do
31
+ @original.should_not be_include(@resource)
32
+ end
33
+ end
34
+ end
35
+
36
+ share_examples_for 'A public Association Collection' do
37
+ before :all do
38
+ @no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
39
+ defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
40
+
41
+ @one_to_many = @articles.kind_of?(DataMapper::Associations::OneToMany::Collection)
42
+ @many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
43
+
44
+ @skip = @no_join && @many_to_many
45
+ end
46
+
47
+ before :all do
48
+ unless @skip
49
+ %w[ @articles @other_articles ].each do |ivar|
50
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
51
+ end
52
+ end
53
+
54
+ @articles.loaded?.should == loaded
55
+ end
56
+
57
+ before do
58
+ pending if @skip
59
+ end
60
+
61
+ describe '#<<' do
62
+ describe 'when provided a Resource belonging to another association' do
63
+ before :all do
64
+ @original = @other_articles
65
+ @resource = @original.first
66
+
67
+ rescue_if 'TODO', @skip do
68
+ @return = @articles << @resource
69
+ end
70
+ end
71
+
72
+ it 'should return a Collection' do
73
+ @return.should be_kind_of(DataMapper::Collection)
74
+ end
75
+
76
+ it 'should return self' do
77
+ @return.should equal(@articles)
78
+ end
79
+
80
+ it_should_behave_like 'It can transfer a Resource from another association'
81
+ end
82
+ end
83
+
84
+ describe '#collect!' do
85
+ describe 'when provided a Resource belonging to another association' do
86
+ before :all do
87
+ @original = @other_articles
88
+ @resource = @original.first
89
+ @return = @articles.collect! { |resource| @resource }
90
+ end
91
+
92
+ it 'should return a Collection' do
93
+ @return.should be_kind_of(DataMapper::Collection)
94
+ end
95
+
96
+ it 'should return self' do
97
+ @return.should equal(@articles)
98
+ end
99
+
100
+ it_should_behave_like 'It can transfer a Resource from another association'
101
+ end
102
+ end
103
+
104
+ describe '#concat' do
105
+ describe 'when provided a Resource belonging to another association' do
106
+ before :all do
107
+ @original = @other_articles
108
+ @resource = @original.first
109
+
110
+ rescue_if 'TODO', @skip do
111
+ @return = @articles.concat([ @resource ])
112
+ end
113
+ end
114
+
115
+ it 'should return a Collection' do
116
+ @return.should be_kind_of(DataMapper::Collection)
117
+ end
118
+
119
+ it 'should return self' do
120
+ @return.should equal(@articles)
121
+ end
122
+
123
+ it_should_behave_like 'It can transfer a Resource from another association'
124
+ end
125
+ end
126
+
127
+ describe '#create' do
128
+ describe 'when the parent is not saved' do
129
+ it 'should raise an exception' do
130
+ author = @author_model.new(:name => 'Dan Kubb')
131
+ lambda {
132
+ author.articles.create
133
+ }.should raise_error(DataMapper::UnsavedParentError)
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '#destroy' do
139
+ describe 'when the parent is not saved' do
140
+ it 'should raise an exception' do
141
+ author = @author_model.new(:name => 'Dan Kubb')
142
+ lambda {
143
+ author.articles.destroy
144
+ }.should raise_error(DataMapper::UnsavedParentError, 'The source must be saved before mass-deleting the collection')
145
+ end
146
+ end
147
+ end
148
+
149
+ describe '#destroy!' do
150
+ describe 'when the parent is not saved' do
151
+ it 'should raise an exception' do
152
+ author = @author_model.new(:name => 'Dan Kubb')
153
+ lambda {
154
+ author.articles.destroy!
155
+ }.should raise_error(DataMapper::UnsavedParentError, 'The source must be saved before mass-deleting the collection')
156
+ end
157
+ end
158
+ end
159
+
160
+ describe '#insert' do
161
+ describe 'when provided a Resource belonging to another association' do
162
+ before :all do
163
+ @original = @other_articles
164
+ @resource = @original.first
165
+
166
+ rescue_if 'TODO', @skip do
167
+ @return = @articles.insert(0, @resource)
168
+ end
169
+ end
170
+
171
+ it 'should return a Collection' do
172
+ @return.should be_kind_of(DataMapper::Collection)
173
+ end
174
+
175
+ it 'should return self' do
176
+ @return.should equal(@articles)
177
+ end
178
+
179
+ it_should_behave_like 'It can transfer a Resource from another association'
180
+ end
181
+ end
182
+
183
+ it 'should respond to a public collection method with #method_missing' do
184
+ @articles.respond_to?(:to_a)
185
+ end
186
+
187
+ describe '#method_missing' do
188
+ describe 'with a public collection method' do
189
+ before :all do
190
+ @return = @articles.to_a
191
+ end
192
+
193
+ it 'should return expected object' do
194
+ @return.should == @articles
195
+ end
196
+ end
197
+
198
+ describe 'with unknown method' do
199
+ it 'should raise an exception' do
200
+ lambda {
201
+ @articles.unknown
202
+ }.should raise_error(NoMethodError)
203
+ end
204
+ end
205
+ end
206
+
207
+ describe '#new' do
208
+ before :all do
209
+ @resource = @author.articles.new
210
+ end
211
+
212
+ it 'should associate the Resource to the Collection' do
213
+ if @resource.respond_to?(:authors)
214
+ pending 'TODO: make sure the association is bidirectional' do
215
+ @resource.authors.should == [ @author ]
216
+ end
217
+ else
218
+ @resource.author.should == @author
219
+ end
220
+ end
221
+ end
222
+
223
+ describe '#push' do
224
+ describe 'when provided a Resource belonging to another association' do
225
+ before :all do
226
+ @original = @other_articles
227
+ @resource = @original.first
228
+
229
+ rescue_if 'TODO', @skip do
230
+ @return = @articles.push(@resource)
231
+ end
232
+ end
233
+
234
+ it 'should return a Collection' do
235
+ @return.should be_kind_of(DataMapper::Collection)
236
+ end
237
+
238
+ it 'should return self' do
239
+ @return.should equal(@articles)
240
+ end
241
+
242
+ it_should_behave_like 'It can transfer a Resource from another association'
243
+ end
244
+ end
245
+
246
+ describe '#replace' do
247
+ describe 'when provided a Resource belonging to another association' do
248
+ before :all do
249
+ @original = @other_articles
250
+ @resource = @original.first
251
+
252
+ rescue_if 'TODO', @skip do
253
+ @return = @articles.replace([ @resource ])
254
+ end
255
+ end
256
+
257
+ it 'should return a Collection' do
258
+ @return.should be_kind_of(DataMapper::Collection)
259
+ end
260
+
261
+ it 'should return self' do
262
+ @return.should equal(@articles)
263
+ end
264
+
265
+ it 'should relate the Resource to the Collection' do
266
+ @resource.collection.should equal(@articles)
267
+ end
268
+
269
+ it_should_behave_like 'It can transfer a Resource from another association'
270
+ end
271
+ end
272
+
273
+ describe '#unshift' do
274
+ describe 'when provided a Resource belonging to another association' do
275
+ before :all do
276
+ @original = @other_articles
277
+ @resource = @original.first
278
+
279
+ rescue_if 'TODO', @skip do
280
+ @return = @articles.unshift(@resource)
281
+ end
282
+ end
283
+
284
+ it 'should return a Collection' do
285
+ @return.should be_kind_of(DataMapper::Collection)
286
+ end
287
+
288
+ it 'should return self' do
289
+ @return.should equal(@articles)
290
+ end
291
+
292
+ it_should_behave_like 'It can transfer a Resource from another association'
293
+ end
294
+ end
295
+
296
+ describe '#update' do
297
+ describe 'when the parent is not saved' do
298
+ it 'should raise an exception' do
299
+ author = @author_model.new(:name => 'Dan Kubb')
300
+ lambda {
301
+ author.articles.update(:title => 'New Title')
302
+ }.should raise_error(DataMapper::UnsavedParentError, 'The source must be saved before mass-updating the collection')
303
+ end
304
+ end
305
+ end
306
+
307
+ describe '#update!' do
308
+ describe 'when the parent is not saved' do
309
+ it 'should raise an exception' do
310
+ author = @author_model.new(:name => 'Dan Kubb')
311
+ lambda {
312
+ author.articles.update!(:title => 'New Title')
313
+ }.should raise_error(DataMapper::UnsavedParentError, 'The source must be saved before mass-updating the collection')
314
+ end
315
+ end
316
+ end
317
+ end