active_data 1.0.0 → 1.1.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 (115) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +13 -0
  3. data/.rubocop.yml +56 -0
  4. data/.rubocop_todo.yml +53 -0
  5. data/.rvmrc +1 -1
  6. data/.travis.yml +15 -2
  7. data/Appraisals +1 -1
  8. data/CHANGELOG.md +31 -0
  9. data/Guardfile +8 -8
  10. data/README.md +256 -0
  11. data/Rakefile +2 -4
  12. data/active_data.gemspec +8 -7
  13. data/gemfiles/rails.4.0.gemfile +1 -1
  14. data/gemfiles/rails.4.1.gemfile +1 -1
  15. data/gemfiles/rails.4.2.gemfile +1 -1
  16. data/gemfiles/rails.5.0.gemfile +1 -1
  17. data/gemfiles/rails.5.1.gemfile +14 -0
  18. data/lib/active_data/active_record/associations.rb +18 -13
  19. data/lib/active_data/active_record/nested_attributes.rb +8 -14
  20. data/lib/active_data/base.rb +13 -0
  21. data/lib/active_data/config.rb +4 -4
  22. data/lib/active_data/errors.rb +29 -13
  23. data/lib/active_data/extensions.rb +22 -21
  24. data/lib/active_data/model/associations/base.rb +22 -6
  25. data/lib/active_data/model/associations/embeds_any.rb +17 -0
  26. data/lib/active_data/model/associations/embeds_many.rb +29 -19
  27. data/lib/active_data/model/associations/embeds_one.rb +30 -26
  28. data/lib/active_data/model/associations/nested_attributes.rb +82 -50
  29. data/lib/active_data/model/associations/persistence_adapters/active_record/referenced_proxy.rb +31 -0
  30. data/lib/active_data/model/associations/persistence_adapters/active_record.rb +66 -0
  31. data/lib/active_data/model/associations/persistence_adapters/base.rb +53 -0
  32. data/lib/active_data/model/associations/references_any.rb +41 -0
  33. data/lib/active_data/model/associations/references_many.rb +51 -37
  34. data/lib/active_data/model/associations/references_one.rb +43 -41
  35. data/lib/active_data/model/associations/reflections/base.rb +19 -29
  36. data/lib/active_data/model/associations/reflections/embeds_any.rb +43 -0
  37. data/lib/active_data/model/associations/reflections/embeds_many.rb +3 -13
  38. data/lib/active_data/model/associations/reflections/embeds_one.rb +5 -37
  39. data/lib/active_data/model/associations/reflections/references_any.rb +62 -0
  40. data/lib/active_data/model/associations/reflections/references_many.rb +7 -7
  41. data/lib/active_data/model/associations/reflections/references_one.rb +9 -7
  42. data/lib/active_data/model/associations/reflections/singular.rb +35 -0
  43. data/lib/active_data/model/associations/validations.rb +2 -27
  44. data/lib/active_data/model/associations.rb +12 -10
  45. data/lib/active_data/model/attributes/attribute.rb +10 -10
  46. data/lib/active_data/model/attributes/base.rb +8 -7
  47. data/lib/active_data/model/attributes/localized.rb +4 -4
  48. data/lib/active_data/model/attributes/reference_many.rb +6 -8
  49. data/lib/active_data/model/attributes/reference_one.rb +17 -9
  50. data/lib/active_data/model/attributes/reflections/attribute.rb +2 -2
  51. data/lib/active_data/model/attributes/reflections/base.rb +8 -11
  52. data/lib/active_data/model/attributes/reflections/localized.rb +2 -2
  53. data/lib/active_data/model/attributes/reflections/reference_one.rb +11 -22
  54. data/lib/active_data/model/attributes/reflections/represents.rb +5 -6
  55. data/lib/active_data/model/attributes/represents.rb +6 -5
  56. data/lib/active_data/model/attributes.rb +33 -87
  57. data/lib/active_data/model/callbacks.rb +6 -7
  58. data/lib/active_data/model/conventions.rb +2 -0
  59. data/lib/active_data/model/dirty.rb +4 -4
  60. data/lib/active_data/model/lifecycle.rb +18 -20
  61. data/lib/active_data/model/localization.rb +5 -2
  62. data/lib/active_data/model/persistence.rb +2 -2
  63. data/lib/active_data/model/primary.rb +19 -14
  64. data/lib/active_data/model/representation.rb +81 -0
  65. data/lib/active_data/model/scopes.rb +22 -12
  66. data/lib/active_data/model/validations/associated.rb +3 -2
  67. data/lib/active_data/model/validations/nested.rb +6 -1
  68. data/lib/active_data/model/validations.rb +3 -3
  69. data/lib/active_data/model.rb +2 -1
  70. data/lib/active_data/undefined_class.rb +9 -0
  71. data/lib/active_data/version.rb +1 -1
  72. data/lib/active_data.rb +40 -17
  73. data/spec/lib/active_data/active_record/associations_spec.rb +107 -45
  74. data/spec/lib/active_data/active_record/nested_attributes_spec.rb +1 -2
  75. data/spec/lib/active_data/config_spec.rb +37 -15
  76. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +475 -172
  77. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +353 -96
  78. data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +108 -12
  79. data/spec/lib/active_data/model/associations/persistence_adapters/active_record_spec.rb +58 -0
  80. data/spec/lib/active_data/model/associations/references_many_spec.rb +440 -64
  81. data/spec/lib/active_data/model/associations/references_one_spec.rb +347 -36
  82. data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +8 -7
  83. data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +7 -6
  84. data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +81 -33
  85. data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +116 -37
  86. data/spec/lib/active_data/model/associations/validations_spec.rb +27 -43
  87. data/spec/lib/active_data/model/associations_spec.rb +34 -25
  88. data/spec/lib/active_data/model/attributes/attribute_spec.rb +26 -23
  89. data/spec/lib/active_data/model/attributes/base_spec.rb +5 -6
  90. data/spec/lib/active_data/model/attributes/collection_spec.rb +7 -8
  91. data/spec/lib/active_data/model/attributes/dictionary_spec.rb +40 -33
  92. data/spec/lib/active_data/model/attributes/localized_spec.rb +27 -28
  93. data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +6 -6
  94. data/spec/lib/active_data/model/attributes/represents_spec.rb +10 -78
  95. data/spec/lib/active_data/model/attributes_spec.rb +150 -45
  96. data/spec/lib/active_data/model/callbacks_spec.rb +69 -70
  97. data/spec/lib/active_data/model/conventions_spec.rb +0 -1
  98. data/spec/lib/active_data/model/dirty_spec.rb +22 -13
  99. data/spec/lib/active_data/model/lifecycle_spec.rb +49 -23
  100. data/spec/lib/active_data/model/persistence_spec.rb +5 -6
  101. data/spec/lib/active_data/model/representation_spec.rb +126 -0
  102. data/spec/lib/active_data/model/scopes_spec.rb +1 -3
  103. data/spec/lib/active_data/model/typecasting_spec.rb +6 -5
  104. data/spec/lib/active_data/model/validations/associated_spec.rb +26 -18
  105. data/spec/lib/active_data/model/validations/nested_spec.rb +89 -18
  106. data/spec/lib/active_data/model_spec.rb +1 -2
  107. data/spec/lib/active_data_spec.rb +0 -1
  108. data/spec/shared/nested_attribute_examples.rb +332 -0
  109. data/spec/spec_helper.rb +3 -0
  110. data/spec/support/model_helpers.rb +2 -2
  111. data/spec/support/muffle_helper.rb +7 -0
  112. metadata +52 -18
  113. data/lib/active_data/model/associations/collection/referenced.rb +0 -26
  114. data/lib/active_data/model/associations/reflections/reference_reflection.rb +0 -45
  115. data/spec/lib/active_data/model/nested_attributes.rb +0 -202
@@ -1,16 +1,16 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Associations::Reflections::ReferencesMany do
5
4
  before do
6
5
  stub_class(:author, ActiveRecord::Base) do
7
- scope :name_starts_with_a, -> { where('name LIKE "a%"') }
6
+ scope :name_starts_with_a, -> { name_starts_with('a') }
7
+ scope :name_starts_with, ->(letter) { where("name LIKE '#{letter}%'") }
8
8
  end
9
9
 
10
10
  stub_model(:book) do
11
11
  include ActiveData::Model::Associations
12
12
 
13
- attribute :title
13
+ attribute :title, String
14
14
  references_many :authors
15
15
  end
16
16
  end
@@ -27,17 +27,21 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
27
27
  stub_model(:book) do
28
28
  include ActiveData::Model::Associations
29
29
 
30
- attribute :title
30
+ attribute :title, String
31
31
  references_many :creators, class_name: 'Author'
32
32
  end
33
33
  end
34
34
 
35
35
  let(:book) { Book.new }
36
36
 
37
- specify { expect { book.creators << author }
38
- .to change { book.creators }.from([]).to([author]) }
39
- specify { expect { book.creators << author }
40
- .to change { book.creator_ids }.from([]).to([author.id]) }
37
+ specify do
38
+ expect { book.creators << author }
39
+ .to change { book.creators }.from([]).to([author])
40
+ end
41
+ specify do
42
+ expect { book.creators << author }
43
+ .to change { book.creator_ids }.from([]).to([author.id])
44
+ end
41
45
  end
42
46
 
43
47
  describe ':primary_key' do
@@ -51,10 +55,14 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
51
55
 
52
56
  let(:author) { Author.create!(name: 'Rick') }
53
57
 
54
- specify { expect { book.author_names = [author.name] }
55
- .to change { book.authors }.from([]).to([author]) }
56
- specify { expect { book.authors = [author] }
57
- .to change { book.author_names }.from([]).to([author.name]) }
58
+ specify do
59
+ expect { book.author_names = [author.name] }
60
+ .to change { book.authors }.from([]).to([author])
61
+ end
62
+ specify do
63
+ expect { book.authors = [author] }
64
+ .to change { book.author_names }.from([]).to([author.name])
65
+ end
58
66
  end
59
67
 
60
68
  describe ':reference_key' do
@@ -67,10 +75,14 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
67
75
 
68
76
  let(:author) { Author.create!(name: 'Rick') }
69
77
 
70
- specify { expect { book.identify = [author.id] }
71
- .to change { book.authors }.from([]).to([author]) }
72
- specify { expect { book.authors = [author] }
73
- .to change { book.identify }.from([]).to([author.id]) }
78
+ specify do
79
+ expect { book.identify = [author.id] }
80
+ .to change { book.authors }.from([]).to([author])
81
+ end
82
+ specify do
83
+ expect { book.authors = [author] }
84
+ .to change { book.identify }.from([]).to([author.id])
85
+ end
74
86
  end
75
87
 
76
88
  describe ':default' do
@@ -146,30 +158,63 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
146
158
  it_behaves_like :new_record_default, -> { Author.new(name: 'Author') }
147
159
  end
148
160
 
161
+ describe 'Book.inspect' do
162
+ specify { expect(Book.inspect).to eq('Book(authors: ReferencesMany(Author), title: String, author_ids: (reference))') }
163
+ end
164
+
149
165
  describe '#scope' do
150
166
  before do
151
167
  stub_model(:book) do
152
168
  include ActiveData::Model::Associations
153
- references_many :authors, -> { name_starts_with_a }
169
+ references_many :authors, ->(owner) { name_starts_with(owner.letter) }
170
+ attribute :letter, String
154
171
  end
155
172
  end
156
173
 
174
+ let(:book) { Book.new(letter: 'a') }
157
175
  let!(:author1) { Author.create!(name: 'Rick') }
158
176
  let!(:author2) { Author.create!(name: 'Aaron') }
159
- specify { expect { book.authors = [author1, author2] }
160
- .to change { book.authors }.from([]).to([author1, author2]) }
161
- specify { expect { book.authors = [author1, author2] }
162
- .to change { book.author_ids }.from([]).to([author1.id, author2.id]) }
163
-
164
- specify { expect { book.author_ids = [author1.id, author2.id] }
165
- .to change { book.authors }.from([]).to([author2]) }
166
- specify { expect { book.author_ids = [author1.id, author2.id] }
167
- .to change { book.author_ids }.from([]).to([author2.id]) }
168
-
169
- specify { expect { book.authors = [author1, author2] }
170
- .to change { book.authors.reload }.from([]).to([author2]) }
171
- specify { expect { book.authors = [author1, author2] }
172
- .to change { book.authors.reload; book.author_ids }.from([]).to([author2.id]) }
177
+
178
+ specify do
179
+ expect { book.authors = [author1, author2] }
180
+ .to change { book.authors }.from([]).to([author1, author2])
181
+ end
182
+ specify do
183
+ expect { book.authors = [author1, author2] }
184
+ .to change { book.author_ids }.from([]).to([author1.id, author2.id])
185
+ end
186
+
187
+ specify do
188
+ expect { book.author_ids = [author1.id, author2.id] }
189
+ .to change { book.authors }.from([]).to([author2])
190
+ end
191
+ specify do
192
+ expect { book.author_ids = [author1.id, author2.id] }
193
+ .to change { book.author_ids }.from([]).to([author2.id])
194
+ end
195
+
196
+ specify do
197
+ expect { book.authors = [author1, author2] }
198
+ .to change { book.authors.reload }.from([]).to([author2])
199
+ end
200
+ specify do
201
+ expect { book.authors = [author1, author2] }
202
+ .to change {
203
+ book.authors.reload
204
+ book.author_ids
205
+ }.from([]).to([author2.id])
206
+ end
207
+
208
+ context do
209
+ let(:book2) { Book.new(letter: 'r') }
210
+
211
+ specify 'scope is not cached too much' do
212
+ expect { book.author_ids = [author1.id, author2.id] }
213
+ .to change { book.authors }.from([]).to([author2])
214
+ expect { book2.author_ids = [author1.id, author2.id] }
215
+ .to change { book2.authors }.from([]).to([author1])
216
+ end
217
+ end
173
218
  end
174
219
 
175
220
  describe '#author' do
@@ -227,8 +272,10 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
227
272
 
228
273
  context do
229
274
  before { book.authors = [author, other] }
230
- specify { expect { author.save! }.to change { book.author_ids }.from([nil, other.id])
231
- .to(match([an_instance_of(Fixnum), other.id])) }
275
+ specify do
276
+ expect { author.save! }.to change { book.author_ids }.from([nil, other.id])
277
+ .to(match([be_a(Integer), other.id]))
278
+ end
232
279
  specify { expect { author.save! }.not_to change { book.authors } }
233
280
  end
234
281
  end
@@ -237,6 +284,7 @@ describe ActiveData::Model::Associations::Reflections::ReferencesMany do
237
284
  describe '#author_ids=' do
238
285
  specify { expect { book.author_ids = [author.id] }.to change { book.author_ids }.from([]).to([author.id]) }
239
286
  specify { expect { book.author_ids = [author.id] }.to change { book.authors }.from([]).to([author]) }
287
+ specify { expect { book.author_ids = [author] }.to change { book.authors }.from([]).to([author]) }
240
288
 
241
289
  specify { expect { book.author_ids = [author.id.next.to_s] }.not_to change { book.author_ids }.from([]) }
242
290
  specify { expect { book.author_ids = [author.id.next.to_s] }.not_to change { book.authors }.from([]) }
@@ -1,16 +1,16 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Associations::Reflections::ReferencesOne do
5
4
  before do
6
5
  stub_class(:author, ActiveRecord::Base) do
7
- scope :name_starts_with_a, -> { where('name LIKE "a%"') }
6
+ scope :name_starts_with_a, -> { name_starts_with('a') }
7
+ scope :name_starts_with, ->(letter) { where("name LIKE '#{letter}%'") }
8
8
  end
9
9
 
10
10
  stub_model(:book) do
11
11
  include ActiveData::Model::Associations
12
12
 
13
- attribute :title
13
+ attribute :title, String
14
14
  references_one :author
15
15
  end
16
16
  end
@@ -23,16 +23,20 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
23
23
  stub_model(:book) do
24
24
  include ActiveData::Model::Associations
25
25
 
26
- attribute :title
26
+ attribute :title, String
27
27
  references_one :creator, class_name: 'Author'
28
28
  end
29
29
  end
30
30
  let(:author) { Author.create!(name: 'Rick') }
31
31
 
32
- specify { expect { book.creator = author }
33
- .to change { book.creator }.from(nil).to(author) }
34
- specify { expect { book.creator = author }
35
- .to change { book.creator_id }.from(nil).to(author.id) }
32
+ specify do
33
+ expect { book.creator = author }
34
+ .to change { book.creator }.from(nil).to(author)
35
+ end
36
+ specify do
37
+ expect { book.creator = author }
38
+ .to change { book.creator_id }.from(nil).to(author.id)
39
+ end
36
40
  end
37
41
 
38
42
  describe ':primary_key' do
@@ -46,10 +50,14 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
46
50
 
47
51
  let(:author) { Author.create!(name: 'Rick') }
48
52
 
49
- specify { expect { book.author_name = author.name }
50
- .to change { book.author }.from(nil).to(author) }
51
- specify { expect { book.author = author }
52
- .to change { book.author_name }.from(nil).to(author.name) }
53
+ specify do
54
+ expect { book.author_name = author.name }
55
+ .to change { book.author }.from(nil).to(author)
56
+ end
57
+ specify do
58
+ expect { book.author = author }
59
+ .to change { book.author_name }.from(nil).to(author.name)
60
+ end
53
61
  end
54
62
 
55
63
  describe ':reference_key' do
@@ -62,10 +70,14 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
62
70
 
63
71
  let(:author) { Author.create!(name: 'Rick') }
64
72
 
65
- specify { expect { book.identify = author.id }
66
- .to change { book.author }.from(nil).to(author) }
67
- specify { expect { book.author = author }
68
- .to change { book.identify }.from(nil).to(author.id) }
73
+ specify do
74
+ expect { book.identify = author.id }
75
+ .to change { book.author }.from(nil).to(author)
76
+ end
77
+ specify do
78
+ expect { book.author = author }
79
+ .to change { book.identify }.from(nil).to(author.id)
80
+ end
69
81
  end
70
82
 
71
83
  describe ':default' do
@@ -129,36 +141,81 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
129
141
  it_behaves_like :new_record_default, -> { Author.new(name: 'Author') }
130
142
  end
131
143
 
144
+ describe 'Book.inspect' do
145
+ specify { expect(Book.inspect).to eq('Book(author: ReferencesOne(Author), title: String, author_id: (reference))') }
146
+ end
147
+
132
148
  describe '#scope' do
133
149
  before do
134
150
  stub_model(:book) do
135
151
  include ActiveData::Model::Associations
136
- references_one :author, -> { name_starts_with_a }
152
+ references_one :author, ->(owner) { name_starts_with(owner.letter) }
153
+ attribute :letter, String
137
154
  end
138
155
  end
139
156
 
157
+ let(:book) { Book.new(letter: 'a') }
140
158
  let!(:author1) { Author.create!(name: 'Rick') }
141
159
  let!(:author2) { Author.create!(name: 'Aaron') }
142
160
 
143
- specify { expect { book.author_id = author1.id }
144
- .not_to change { book.author } }
145
- specify { expect { book.author_id = author2.id }
146
- .to change { book.author }.from(nil).to(author2) }
147
-
148
- specify { expect { book.author = author1 }
149
- .to change { book.author_id }.from(nil).to(author1.id) }
150
- specify { expect { book.author = author2 }
151
- .to change { book.author_id }.from(nil).to(author2.id) }
152
-
153
- specify { expect { book.author = author1 }
154
- .to change { book.association(:author).reload; book.author_id }.from(nil).to(author1.id) }
155
- specify { expect { book.author = author2 }
156
- .to change { book.association(:author).reload; book.author_id }.from(nil).to(author2.id) }
157
-
158
- specify { expect { book.author = author1 }
159
- .not_to change { book.association(:author).reload; book.author } }
160
- specify { expect { book.author = author2 }
161
- .to change { book.association(:author).reload; book.author }.from(nil).to(author2) }
161
+ specify do
162
+ expect { book.author_id = author1.id }
163
+ .not_to change { book.author }
164
+ end
165
+ specify do
166
+ expect { book.author_id = author2.id }
167
+ .to change { book.author }.from(nil).to(author2)
168
+ end
169
+
170
+ specify do
171
+ expect { book.author = author1 }
172
+ .to change { book.author_id }.from(nil).to(author1.id)
173
+ end
174
+ specify do
175
+ expect { book.author = author2 }
176
+ .to change { book.author_id }.from(nil).to(author2.id)
177
+ end
178
+
179
+ specify do
180
+ expect { book.author = author1 }
181
+ .to change {
182
+ book.association(:author).reload
183
+ book.author_id
184
+ }.from(nil).to(author1.id)
185
+ end
186
+ specify do
187
+ expect { book.author = author2 }
188
+ .to change {
189
+ book.association(:author).reload
190
+ book.author_id
191
+ }.from(nil).to(author2.id)
192
+ end
193
+
194
+ specify do
195
+ expect { book.author = author1 }
196
+ .not_to change {
197
+ book.association(:author).reload
198
+ book.author
199
+ }
200
+ end
201
+ specify do
202
+ expect { book.author = author2 }
203
+ .to change {
204
+ book.association(:author).reload
205
+ book.author
206
+ }.from(nil).to(author2)
207
+ end
208
+
209
+ context do
210
+ let(:book2) { Book.new(letter: 'r') }
211
+
212
+ specify 'scope is not cached too much' do
213
+ expect { book.author_id = author2.id }
214
+ .to change { book.author }.from(nil).to(author2)
215
+ expect { book2.author_id = author1.id }
216
+ .to change { book2.author }.from(nil).to(author1)
217
+ end
218
+ end
162
219
  end
163
220
 
164
221
  describe '#author=' do
@@ -182,7 +239,7 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
182
239
 
183
240
  context do
184
241
  before { book.author = author }
185
- specify { expect { author.save! }.to change { book.author_id }.from(nil).to(an_instance_of(Fixnum)) }
242
+ specify { expect { author.save! }.to change { book.author_id }.from(nil).to(be_a(Integer)) }
186
243
  specify { expect { author.save! }.not_to change { book.author } }
187
244
  end
188
245
  end
@@ -192,6 +249,7 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
192
249
  let(:author) { Author.create!(name: 'Author') }
193
250
  specify { expect { book.author_id = author.id }.to change { book.author_id }.from(nil).to(author.id) }
194
251
  specify { expect { book.author_id = author.id }.to change { book.author }.from(nil).to(author) }
252
+ specify { expect { book.author_id = author }.to change { book.author }.from(nil).to(author) }
195
253
 
196
254
  specify { expect { book.author_id = author.id.next.to_s }.to change { book.author_id }.from(nil).to(author.id.next) }
197
255
  specify { expect { book.author_id = author.id.next.to_s }.not_to change { book.author }.from(nil) }
@@ -205,4 +263,25 @@ describe ActiveData::Model::Associations::Reflections::ReferencesOne do
205
263
  specify { expect { book.author_id = nil }.to change { book.author }.from(other).to(nil) }
206
264
  end
207
265
  end
266
+
267
+ describe '#build_author' do
268
+ specify { expect(book.build_author(name: 'Author')).to be_a(Author) }
269
+ specify { expect(book.build_author(name: 'Author')).not_to be_persisted }
270
+ specify { expect { book.build_author(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
271
+ specify { expect { book.build_author(name: 'Author') }.not_to change { book.author_id }.from(nil) }
272
+ end
273
+
274
+ describe '#create_author' do
275
+ specify { expect(book.create_author(name: 'Author')).to be_a(Author) }
276
+ specify { expect(book.create_author(name: 'Author')).to be_persisted }
277
+ specify { expect { book.create_author(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
278
+ specify { expect { book.create_author(name: 'Author') }.to change { book.author_id }.from(nil).to(be_a(Integer)) }
279
+ end
280
+
281
+ describe '#create_author!' do
282
+ specify { expect(book.create_author!(name: 'Author')).to be_a(Author) }
283
+ specify { expect(book.create_author!(name: 'Author')).to be_persisted }
284
+ specify { expect { book.create_author!(name: 'Author') }.to change { book.author }.from(nil).to(an_instance_of(Author)) }
285
+ specify { expect { book.create_author!(name: 'Author') }.to change { book.author_id }.from(nil).to(be_a(Integer)) }
286
+ end
208
287
  end
@@ -5,6 +5,7 @@ describe ActiveData::Model::Associations::Validations do
5
5
  stub_model(:project) do
6
6
  include ActiveData::Model::Lifecycle
7
7
  include ActiveData::Model::Associations
8
+ include ActiveData::Model::Associations::Validations
8
9
 
9
10
  attribute :title, String
10
11
  validates :title, presence: true
@@ -25,6 +26,7 @@ describe ActiveData::Model::Associations::Validations do
25
26
 
26
27
  stub_model(:user) do
27
28
  include ActiveData::Model::Associations
29
+ include ActiveData::Model::Associations::Validations
28
30
 
29
31
  attribute :login, String
30
32
  validates :login, presence: true
@@ -39,7 +41,7 @@ describe ActiveData::Model::Associations::Validations do
39
41
  let(:project) { Project.new title: 'Project' }
40
42
  let(:projects) { [project] }
41
43
  let(:user) { User.new(login: 'Login', profile: profile, projects: projects) }
42
- let(:author_attributes) { { name: 'Author' } }
44
+ let(:author_attributes) { {name: 'Author'} }
43
45
  before { project.build_author(author_attributes) }
44
46
 
45
47
  specify { expect(user.validate).to eq(true) }
@@ -49,8 +51,10 @@ describe ActiveData::Model::Associations::Validations do
49
51
  let(:author_attributes) { {} }
50
52
 
51
53
  specify { expect(user.validate).to eq(false) }
52
- specify { expect { user.validate }.to change { user.errors.messages }
53
- .to(:'projects.0.author.name' => ["can't be blank"]) }
54
+ specify do
55
+ expect { user.validate }.to change { user.errors.messages }
56
+ .to(:'projects.0.author.name' => ["can't be blank"])
57
+ end
54
58
  end
55
59
 
56
60
  context do
@@ -64,8 +68,10 @@ describe ActiveData::Model::Associations::Validations do
64
68
  let(:projects) { [project, Project.new] }
65
69
 
66
70
  specify { expect(user.validate).to eq(false) }
67
- specify { expect { user.validate }.to change { user.errors.messages }
68
- .to(:'projects.1.title' => ["can't be blank"]) }
71
+ specify do
72
+ expect { user.validate }.to change { user.errors.messages }
73
+ .to(:'projects.1.title' => ["can't be blank"])
74
+ end
69
75
  end
70
76
  end
71
77
 
@@ -74,7 +80,7 @@ describe ActiveData::Model::Associations::Validations do
74
80
  let(:project) { Project.new title: 'Project' }
75
81
  let(:projects) { [project] }
76
82
  let(:user) { User.new(login: 'Login', profile: profile, projects: projects) }
77
- let(:author_attributes) { { name: 'Author' } }
83
+ let(:author_attributes) { {name: 'Author'} }
78
84
  before { project.build_author(author_attributes) }
79
85
 
80
86
  specify { expect(user.validate_ancestry).to eq(true) }
@@ -90,8 +96,10 @@ describe ActiveData::Model::Associations::Validations do
90
96
  specify { expect { user.validate_ancestry! }.to raise_error ActiveData::ValidationError }
91
97
  specify { expect(user.valid_ancestry?).to eq(false) }
92
98
  specify { expect(user.invalid_ancestry?).to eq(true) }
93
- specify { expect { user.validate_ancestry }.to change { user.errors.messages }
94
- .to(:'projects.0.author.name' => ["can't be blank"]) }
99
+ specify do
100
+ expect { user.validate_ancestry }.to change { user.errors.messages }
101
+ .to(:'projects.0.author.name' => ["can't be blank"])
102
+ end
95
103
  end
96
104
 
97
105
  context do
@@ -100,8 +108,10 @@ describe ActiveData::Model::Associations::Validations do
100
108
  specify { expect { user.validate_ancestry! }.to raise_error ActiveData::ValidationError }
101
109
  specify { expect(user.valid_ancestry?).to eq(false) }
102
110
  specify { expect(user.invalid_ancestry?).to eq(true) }
103
- specify { expect { user.validate_ancestry }.to change { user.errors.messages }
104
- .to(:'profile.first_name' => ["can't be blank"]) }
111
+ specify do
112
+ expect { user.validate_ancestry }.to change { user.errors.messages }
113
+ .to(:'profile.first_name' => ["can't be blank"])
114
+ end
105
115
  end
106
116
 
107
117
  context do
@@ -110,44 +120,18 @@ describe ActiveData::Model::Associations::Validations do
110
120
  specify { expect { user.validate_ancestry! }.to raise_error ActiveData::ValidationError }
111
121
  specify { expect(user.valid_ancestry?).to eq(false) }
112
122
  specify { expect(user.invalid_ancestry?).to eq(true) }
113
- specify { expect { user.validate_ancestry }.to change { user.errors.messages }
114
- .to(:'projects.1.title' => ["can't be blank"]) }
123
+ specify do
124
+ expect { user.validate_ancestry }.to change { user.errors.messages }
125
+ .to(:'projects.1.title' => ["can't be blank"])
126
+ end
115
127
 
116
128
  context do
117
129
  before { user.update(login: '') }
118
- specify { expect { user.validate_ancestry }.to change { user.errors.messages }
119
- .to(:'projects.1.title' => ["can't be blank"], login: ["can't be blank"]) }
120
- end
121
- end
122
- end
123
-
124
- context 'represent attributes' do
125
- before do
126
- stub_class(:author, ActiveRecord::Base) do
127
- validates :name, presence: true
128
-
129
- # Emulate Active Record association auto save error.
130
- def errors
131
- super.tap do |errors|
132
- errors.add(:'user.email', 'is invalid') if errors[:'user.email'].empty?
133
- end
130
+ specify do
131
+ expect { user.validate_ancestry }.to change { user.errors.messages }
132
+ .to(:'projects.1.title' => ["can't be blank"], login: ["can't be blank"])
134
133
  end
135
134
  end
136
-
137
- stub_model(:post) do
138
- include ActiveData::Model::Associations
139
-
140
- references_one :author
141
- represents :name, of: :author
142
- represents :email, of: :author
143
- end
144
135
  end
145
-
146
- let(:post) { Post.new(author: Author.new) }
147
-
148
- specify { expect { post.validate_ancestry }.to change { post.errors.messages }
149
- .to(hash_including(:'author.user.email' => ['is invalid'], name: ["can't be blank"])) }
150
- specify { expect { post.validate }.to change { post.errors.messages }
151
- .to(hash_including(:'author.user.email' => ['is invalid'], name: ["can't be blank"])) }
152
136
  end
153
137
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Associations do
@@ -30,7 +29,7 @@ describe ActiveData::Model::Associations do
30
29
  specify { expect(Nobody.reflections.keys).to eq([]) }
31
30
  specify { expect(User.reflections.keys).to eq([:projects]) }
32
31
  specify { expect(Manager.reflections.keys).to eq([:managed_project]) }
33
- specify { expect(Admin.reflections.keys).to eq([:projects, :admin_projects]) }
32
+ specify { expect(Admin.reflections.keys).to eq(%i[projects admin_projects]) }
34
33
  end
35
34
 
36
35
  describe '#reflect_on_association' do
@@ -43,21 +42,23 @@ describe ActiveData::Model::Associations do
43
42
 
44
43
  context 'class determine errors' do
45
44
  specify do
46
- expect { stub_model do
47
- include ActiveData::Model::Associations
45
+ expect do
46
+ stub_model do
47
+ include ActiveData::Model::Associations
48
48
 
49
- embeds_one :author, class_name: 'Borogoves'
50
- end.reflect_on_association(:author).klass }.to raise_error NameError
49
+ embeds_one :author, class_name: 'Borogoves'
50
+ end.reflect_on_association(:author).data_source end.to raise_error NameError
51
51
  end
52
52
 
53
53
  specify do
54
- expect { stub_model(:user) do
55
- include ActiveData::Model::Associations
56
-
57
- embeds_many :projects, class_name: 'Borogoves' do
58
- attribute :title
59
- end
60
- end.reflect_on_association(:projects).klass }.to raise_error NameError
54
+ expect do
55
+ stub_model(:user) do
56
+ include ActiveData::Model::Associations
57
+
58
+ embeds_many :projects, class_name: 'Borogoves' do
59
+ attribute :title
60
+ end
61
+ end.reflect_on_association(:projects).data_source end.to raise_error NameError
61
62
  end
62
63
  end
63
64
 
@@ -103,22 +104,24 @@ describe ActiveData::Model::Associations do
103
104
 
104
105
  let(:user) { User.new }
105
106
 
106
- its(:projects) { should = [] }
107
- its(:profile) { should = nil }
107
+ specify { expect(user.projects).to eq([]) }
108
+ specify { expect(user.profile).to be_nil }
108
109
 
109
110
  describe '.inspect' do
110
111
  specify { expect(User.inspect).to eq('User(profile: EmbedsOne(Profile), projects: EmbedsMany(Project), login: Object)') }
111
112
  end
112
113
 
113
114
  describe '.association_names' do
114
- specify { expect(User.association_names).to eq([:profile, :projects]) }
115
+ specify { expect(User.association_names).to eq(%i[profile projects]) }
115
116
  end
116
117
 
117
118
  describe '#inspect' do
118
119
  let(:profile) { Profile.new first_name: 'Name' }
119
120
  let(:project) { Project.new title: 'Project' }
120
- specify { expect(User.new(login: 'Login', profile: profile, projects: [project]).inspect)
121
- .to eq('#<User profile: #<EmbedsOne #<Profile first_name: "Name", last_name: nil>>, projects: #<EmbedsMany [#<Project author: #<EmbedsOne nil>, title: "P...]>, login: "Login">') }
121
+ specify do
122
+ expect(User.new(login: 'Login', profile: profile, projects: [project]).inspect)
123
+ .to eq('#<User profile: #<EmbedsOne #<Profile first_name: "Name", last_name: nil>>, projects: #<EmbedsMany [#<Project author: #<EmbedsOne nil>, title: "P...]>, login: "Login">')
124
+ end
122
125
  end
123
126
 
124
127
  describe '#==' do
@@ -154,7 +157,7 @@ describe ActiveData::Model::Associations do
154
157
  end
155
158
 
156
159
  describe '#association_names' do
157
- specify { expect(user.association_names).to eq([:profile, :projects]) }
160
+ specify { expect(user.association_names).to eq(%i[profile projects]) }
158
161
  end
159
162
 
160
163
  describe '#apply_association_changes!' do
@@ -163,10 +166,14 @@ describe ActiveData::Model::Associations do
163
166
  let(:user) { User.new(profile: profile, projects: [project]) }
164
167
  before { project.build_author(name: 'Author') }
165
168
 
166
- specify { expect { user.apply_association_changes! }.to change { user.attributes['profile'] }
167
- .from(nil).to('first_name' => 'Name', 'last_name' => nil) }
168
- specify { expect { user.apply_association_changes! }.to change { user.attributes['projects'] }
169
- .from(nil).to([{ 'title' => 'Project', 'author' => { 'name' => 'Author' } }]) }
169
+ specify do
170
+ expect { user.apply_association_changes! }.to change { user.attributes['profile'] }
171
+ .from(nil).to('first_name' => 'Name', 'last_name' => nil)
172
+ end
173
+ specify do
174
+ expect { user.apply_association_changes! }.to change { user.attributes['projects'] }
175
+ .from(nil).to([{'title' => 'Project', 'author' => {'name' => 'Author'}}])
176
+ end
170
177
 
171
178
  context do
172
179
  let(:project) { Project.new }
@@ -182,8 +189,10 @@ describe ActiveData::Model::Associations do
182
189
  before { project.build_author(name: 'Author') }
183
190
 
184
191
  specify { expect(User.instantiate(JSON.parse(user.to_json))).to eq(user) }
185
- specify { expect(User.instantiate(JSON.parse(user.to_json))
186
- .tap { |u| u.projects.first.author.name = 'Other' }).not_to eq(user) }
192
+ specify do
193
+ expect(User.instantiate(JSON.parse(user.to_json))
194
+ .tap { |u| u.projects.first.author.name = 'Other' }).not_to eq(user)
195
+ end
187
196
  end
188
197
  end
189
198
  end