active_data 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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