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,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Associations::ReferencesMany do
@@ -6,13 +5,15 @@ describe ActiveData::Model::Associations::ReferencesMany do
6
5
  stub_model(:dummy)
7
6
  stub_class(:author, ActiveRecord::Base) do
8
7
  scope :name_starts_with_a, -> { where('name LIKE "a%"') }
8
+
9
+ validates :name, presence: true
9
10
  end
10
11
 
11
12
  stub_model(:book) do
12
13
  include ActiveData::Model::Persistence
13
14
  include ActiveData::Model::Associations
14
15
 
15
- attribute :title
16
+ attribute :title, String
16
17
  references_many :authors
17
18
  end
18
19
  end
@@ -31,6 +32,333 @@ describe ActiveData::Model::Associations::ReferencesMany do
31
32
  specify { expect(association).to eq(book.association(:authors)) }
32
33
  end
33
34
 
35
+ describe 'book#inspect' do
36
+ specify { expect(existing_book.inspect).to eq('#<Book authors: #<ReferencesMany [#<Author id: 1, name: "Rick">]>, title: "Genesis", author_ids: [1]>') }
37
+ end
38
+
39
+ describe '#build' do
40
+ specify { expect(association.build).to be_a Author }
41
+ specify { expect(association.build).not_to be_persisted }
42
+
43
+ specify do
44
+ expect { association.build(name: 'Morty') }
45
+ .to change { book.author_ids }
46
+ .from([]).to([nil])
47
+ end
48
+ specify do
49
+ expect { association.build(name: 'Morty') }
50
+ .to change { association.reader }.from([])
51
+ .to([an_instance_of(Author).and(have_attributes(name: 'Morty'))])
52
+ end
53
+
54
+ specify do
55
+ expect { existing_association.build(name: 'Morty') }
56
+ .to change { existing_book.author_ids }
57
+ .from([author.id]).to([author.id, nil])
58
+ end
59
+ specify do
60
+ expect { existing_association.build(name: 'Morty') }
61
+ .to change { existing_association.reader }.from([author])
62
+ .to([author, an_instance_of(Author).and(have_attributes(name: 'Morty'))])
63
+ end
64
+
65
+ context 'dirty' do
66
+ before do
67
+ Book.include ActiveData::Model::Dirty
68
+ end
69
+
70
+ specify do
71
+ expect { existing_association.build(name: 'Morty') }
72
+ .to change { existing_book.changes }
73
+ .from({}).to('author_ids' => [[author.id], [author.id, nil]])
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#create' do
79
+ specify { expect(association.create).to be_a Author }
80
+ specify { expect(association.create).not_to be_persisted }
81
+
82
+ specify { expect(association.create(name: 'Morty')).to be_a Author }
83
+ specify { expect(association.create(name: 'Morty')).to be_persisted }
84
+
85
+ specify do
86
+ expect { association.create }
87
+ .to change { book.author_ids }
88
+ .from([]).to([nil])
89
+ end
90
+ specify do
91
+ expect { association.create }
92
+ .to change { association.target }
93
+ .from([]).to([an_instance_of(Author).and(be_new_record)])
94
+ end
95
+
96
+ specify do
97
+ expect { association.create(name: 'Morty') }
98
+ .to change { book.author_ids }
99
+ .from([]).to([be_a(Integer)])
100
+ end
101
+ specify do
102
+ expect { association.create(name: 'Morty') }
103
+ .to change { association.target }.from([])
104
+ .to([an_instance_of(Author)
105
+ .and(have_attributes(name: 'Morty'))
106
+ .and(be_persisted)])
107
+ end
108
+
109
+ specify do
110
+ expect { existing_association.create }
111
+ .to change { existing_book.author_ids }
112
+ .from([author.id]).to([author.id, nil])
113
+ end
114
+ specify do
115
+ expect { existing_association.create }
116
+ .to change { existing_association.reader }.from([author])
117
+ .to([author, an_instance_of(Author).and(be_new_record)])
118
+ end
119
+
120
+ specify do
121
+ expect { existing_association.create(name: 'Morty') }
122
+ .to change { existing_book.author_ids }
123
+ .from([author.id]).to([author.id, be_a(Integer)])
124
+ end
125
+ specify do
126
+ expect { existing_association.create(name: 'Morty') }
127
+ .to change { existing_association.reader }.from([author])
128
+ .to([author, an_instance_of(Author)
129
+ .and(have_attributes(name: 'Morty'))
130
+ .and(be_persisted)])
131
+ end
132
+
133
+ context 'dirty' do
134
+ before do
135
+ Book.include ActiveData::Model::Dirty
136
+ end
137
+
138
+ specify do
139
+ expect { existing_association.create(name: 'Morty') }
140
+ .to change { existing_book.changes }
141
+ .from({}).to('author_ids' => [[author.id], [author.id, be_a(Integer)]])
142
+ end
143
+ end
144
+ end
145
+
146
+ describe '#create!' do
147
+ specify { expect { association.create! }.to raise_error ActiveRecord::RecordInvalid }
148
+
149
+ specify { expect(association.create!(name: 'Morty')).to be_a Author }
150
+ specify { expect(association.create!(name: 'Morty')).to be_persisted }
151
+
152
+ specify do
153
+ expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
154
+ .to change { book.author_ids }
155
+ .from([]).to([nil])
156
+ end
157
+ specify do
158
+ expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
159
+ .to change { association.target }
160
+ .from([]).to([an_instance_of(Author).and(be_new_record)])
161
+ end
162
+
163
+ specify do
164
+ expect { association.create!(name: 'Morty') }
165
+ .to change { book.author_ids }
166
+ .from([]).to([be_a(Integer)])
167
+ end
168
+ specify do
169
+ expect { association.create!(name: 'Morty') }
170
+ .to change { association.target }.from([])
171
+ .to([an_instance_of(Author)
172
+ .and(have_attributes(name: 'Morty'))
173
+ .and(be_persisted)])
174
+ end
175
+
176
+ specify do
177
+ expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
178
+ .to change { existing_book.author_ids }
179
+ .from([author.id]).to([author.id, nil])
180
+ end
181
+ specify do
182
+ expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
183
+ .to change { existing_association.reader }.from([author])
184
+ .to([author, an_instance_of(Author).and(be_new_record)])
185
+ end
186
+
187
+ specify do
188
+ expect { existing_association.create!(name: 'Morty') }
189
+ .to change { existing_book.author_ids }
190
+ .from([author.id]).to([author.id, be_a(Integer)])
191
+ end
192
+ specify do
193
+ expect { existing_association.create!(name: 'Morty') }
194
+ .to change { existing_association.reader }.from([author])
195
+ .to([author, an_instance_of(Author)
196
+ .and(have_attributes(name: 'Morty'))
197
+ .and(be_persisted)])
198
+ end
199
+ end
200
+
201
+ describe '#apply_changes' do
202
+ specify do
203
+ association.build
204
+ expect(association.apply_changes).to eq(false)
205
+ end
206
+ specify do
207
+ association.build
208
+ expect { association.apply_changes }
209
+ .not_to change { association.target.map(&:persisted?) }
210
+ .from([false])
211
+ end
212
+ specify do
213
+ association.build(name: 'Rick')
214
+ expect(association.apply_changes).to eq(true)
215
+ end
216
+ specify do
217
+ association.build(name: 'Rick')
218
+ expect { association.apply_changes }
219
+ .to change { association.target.map(&:persisted?) }
220
+ .from([false]).to([true])
221
+ end
222
+ specify do
223
+ association.build(name: 'Rick')
224
+ expect { association.apply_changes }
225
+ .to change { book.author_ids }
226
+ .from([nil]).to([be_a(Integer)])
227
+ end
228
+ specify do
229
+ existing_association.target.first.name = 'Morty'
230
+ expect { existing_association.apply_changes }
231
+ .not_to change { author.reload.name }
232
+ end
233
+ specify do
234
+ existing_association.target.first.mark_for_destruction
235
+ existing_association.build(name: 'Morty')
236
+ expect { existing_association.apply_changes }
237
+ .to change { existing_book.author_ids }
238
+ .from([author.id, nil]).to([author.id, be_a(Integer)])
239
+ end
240
+ specify do
241
+ existing_association.target.first.mark_for_destruction
242
+ existing_association.build(name: 'Morty')
243
+ expect { existing_association.apply_changes }
244
+ .to change { existing_association.target.map(&:persisted?) }
245
+ .from([true, false]).to([true, true])
246
+ end
247
+ specify do
248
+ existing_association.target.first.destroy!
249
+ existing_association.build(name: 'Morty')
250
+ expect { existing_association.apply_changes }
251
+ .to change { existing_book.author_ids }
252
+ .from([author.id, nil]).to([author.id, be_a(Integer)])
253
+ end
254
+ specify do
255
+ existing_association.target.first.destroy!
256
+ existing_association.build(name: 'Morty')
257
+ expect { existing_association.apply_changes }
258
+ .to change { existing_association.target.map(&:persisted?) }
259
+ .from([false, false]).to([false, true])
260
+ end
261
+
262
+ context ':autosave' do
263
+ before do
264
+ Book.references_many :authors, autosave: true
265
+ end
266
+
267
+ specify do
268
+ association.build
269
+ expect(association.apply_changes).to eq(false)
270
+ end
271
+ specify do
272
+ association.build
273
+ expect { association.apply_changes }
274
+ .not_to change { association.target.map(&:persisted?) }
275
+ .from([false])
276
+ end
277
+ specify do
278
+ association.build(name: 'Rick')
279
+ expect(association.apply_changes).to eq(true)
280
+ end
281
+ specify do
282
+ association.build(name: 'Rick')
283
+ expect { association.apply_changes }
284
+ .to change { association.target.map(&:persisted?) }
285
+ .from([false]).to([true])
286
+ end
287
+ specify do
288
+ association.build(name: 'Rick')
289
+ expect { association.apply_changes }
290
+ .to change { book.author_ids }
291
+ .from([nil]).to([be_a(Integer)])
292
+ end
293
+ specify do
294
+ existing_association.target.first.name = 'Morty'
295
+ expect { existing_association.apply_changes }
296
+ .to change { author.reload.name }
297
+ .from('Rick').to('Morty')
298
+ end
299
+ specify do
300
+ existing_association.target.first.mark_for_destruction
301
+ existing_association.build(name: 'Morty')
302
+ expect { existing_association.apply_changes }
303
+ .to change { existing_book.author_ids }
304
+ .from([author.id, nil]).to([author.id, be_a(Integer)])
305
+ end
306
+ specify do
307
+ existing_association.target.first.mark_for_destruction
308
+ existing_association.build(name: 'Morty')
309
+ expect { existing_association.apply_changes }
310
+ .to change { existing_association.target.map(&:persisted?) }
311
+ .from([true, false]).to([false, true])
312
+ end
313
+ specify do
314
+ existing_association.target.first.destroy!
315
+ existing_association.build(name: 'Morty')
316
+ expect { existing_association.apply_changes }
317
+ .to change { existing_book.author_ids }
318
+ .from([author.id, nil]).to([author.id, be_a(Integer)])
319
+ end
320
+ specify do
321
+ existing_association.target.first.destroy!
322
+ existing_association.build(name: 'Morty')
323
+ expect { existing_association.apply_changes }
324
+ .to change { existing_association.target.map(&:persisted?) }
325
+ .from([false, false]).to([false, true])
326
+ end
327
+ end
328
+ end
329
+
330
+ describe '#apply_changes!' do
331
+ specify do
332
+ association.build
333
+ expect { association.apply_changes! }
334
+ .to raise_error(ActiveData::AssociationChangesNotApplied)
335
+ end
336
+ specify do
337
+ association.build
338
+ expect { muffle(ActiveData::AssociationChangesNotApplied) { association.apply_changes! } }
339
+ .not_to change { association.target.map(&:persisted?) }
340
+ .from([false])
341
+ end
342
+
343
+ context ':autosave' do
344
+ before do
345
+ Book.references_many :authors, autosave: true
346
+ end
347
+
348
+ specify do
349
+ association.build
350
+ expect { association.apply_changes! }
351
+ .to raise_error(ActiveData::AssociationChangesNotApplied)
352
+ end
353
+ specify do
354
+ association.build
355
+ expect { muffle(ActiveData::AssociationChangesNotApplied) { association.apply_changes! } }
356
+ .not_to change { association.target.map(&:persisted?) }
357
+ .from([false])
358
+ end
359
+ end
360
+ end
361
+
34
362
  describe '#scope' do
35
363
  specify { expect(association.scope).to be_a ActiveRecord::Relation }
36
364
  specify { expect(association.scope).to respond_to(:where) }
@@ -44,7 +372,7 @@ describe ActiveData::Model::Associations::ReferencesMany do
44
372
  end
45
373
 
46
374
  describe '#default' do
47
- before { Book.references_many :authors, default: ->(book) { author.id } }
375
+ before { Book.references_many :authors, default: ->(_book) { author.id } }
48
376
  let(:existing_book) { Book.instantiate title: 'Genesis' }
49
377
 
50
378
  specify { expect(association.target).to eq([author]) }
@@ -70,15 +398,17 @@ describe ActiveData::Model::Associations::ReferencesMany do
70
398
 
71
399
  context do
72
400
  before { existing_association.reader.last.name = 'Conan' }
73
- specify { expect { existing_association.reload }
74
- .to change { existing_association.reader.map(&:name) }
75
- .from(['Conan']).to(['Rick']) }
401
+ specify do
402
+ expect { existing_association.reload }
403
+ .to change { existing_association.reader.map(&:name) }
404
+ .from(['Conan']).to(['Rick'])
405
+ end
76
406
  end
77
407
  end
78
408
 
79
409
  describe '#reader' do
80
410
  specify { expect(association.reader).to eq([]) }
81
- specify { expect(association.reader).to be_a ActiveData::Model::Associations::Collection::Referenced }
411
+ specify { expect(association.reader).to be_a ActiveData::Model::Associations::PersistenceAdapters::ActiveRecord::ReferencedProxy }
82
412
 
83
413
  specify { expect(existing_association.reader.first).to be_a Author }
84
414
  specify { expect(existing_association.reader.first).to be_persisted }
@@ -109,60 +439,90 @@ describe ActiveData::Model::Associations::ReferencesMany do
109
439
  let(:new_author2) { Author.create!(name: 'Adam') }
110
440
  let(:new_author3) { Author.new(name: 'Jane') }
111
441
 
112
- specify { expect { association.writer([Dummy.new]) }
113
- .to raise_error ActiveData::AssociationTypeMismatch }
442
+ specify do
443
+ expect { association.writer([Dummy.new]) }
444
+ .to raise_error ActiveData::AssociationTypeMismatch
445
+ end
114
446
 
115
447
  specify { expect { association.writer(nil) }.to raise_error NoMethodError }
116
448
  specify { expect { association.writer(new_author1) }.to raise_error NoMethodError }
117
449
  specify { expect(association.writer([])).to eq([]) }
118
450
 
119
451
  specify { expect(association.writer([new_author1])).to eq([new_author1]) }
120
- specify { expect { association.writer([new_author1]) }
121
- .to change { association.reader.map(&:name) }.from([]).to(['John']) }
122
- specify { expect { association.writer([new_author1]) }
123
- .to change { book.read_attribute(:author_ids) }
124
- .from([]).to([new_author1.id]) }
125
-
126
- specify { expect { existing_association.writer([new_author1, Dummy.new, new_author2]) }
127
- .to raise_error ActiveData::AssociationTypeMismatch }
128
- specify { expect { existing_association.writer([new_author1, Dummy.new, new_author2]) rescue nil }
129
- .not_to change { existing_book.read_attribute(:author_ids) } }
130
- specify { expect { existing_association.writer([new_author1, Dummy.new, new_author2]) rescue nil }
131
- .not_to change { existing_association.reader } }
452
+ specify do
453
+ expect { association.writer([new_author1]) }
454
+ .to change { association.reader.map(&:name) }.from([]).to(['John'])
455
+ end
456
+ specify do
457
+ expect { association.writer([new_author1]) }
458
+ .to change { book.read_attribute(:author_ids) }
459
+ .from([]).to([new_author1.id])
460
+ end
461
+
462
+ specify do
463
+ expect { existing_association.writer([new_author1, Dummy.new, new_author2]) }
464
+ .to raise_error ActiveData::AssociationTypeMismatch
465
+ end
466
+ specify do
467
+ expect { muffle(ActiveData::AssociationTypeMismatch) { existing_association.writer([new_author1, Dummy.new, new_author2]) } }
468
+ .not_to change { existing_book.read_attribute(:author_ids) }
469
+ end
470
+ specify do
471
+ expect { muffle(ActiveData::AssociationTypeMismatch) { existing_association.writer([new_author1, Dummy.new, new_author2]) } }
472
+ .not_to change { existing_association.reader }
473
+ end
132
474
 
133
475
  specify { expect { existing_association.writer(nil) }.to raise_error NoMethodError }
134
- specify { expect { existing_association.writer(nil) rescue nil }
135
- .not_to change { existing_book.read_attribute(:author_ids) } }
136
- specify { expect { existing_association.writer(nil) rescue nil }
137
- .not_to change { existing_association.reader } }
476
+ specify do
477
+ expect { muffle(NoMethodError) { existing_association.writer(nil) } }
478
+ .not_to change { existing_book.read_attribute(:author_ids) }
479
+ end
480
+ specify do
481
+ expect { muffle(NoMethodError) { existing_association.writer(nil) } }
482
+ .not_to change { existing_association.reader }
483
+ end
138
484
 
139
485
  specify { expect(existing_association.writer([])).to eq([]) }
140
- specify { expect { existing_association.writer([]) }
141
- .to change { existing_book.read_attribute(:author_ids) }.to([]) }
142
- specify { expect { existing_association.writer([]) }
143
- .to change { existing_association.reader }.from([author]).to([]) }
486
+ specify do
487
+ expect { existing_association.writer([]) }
488
+ .to change { existing_book.read_attribute(:author_ids) }.to([])
489
+ end
490
+ specify do
491
+ expect { existing_association.writer([]) }
492
+ .to change { existing_association.reader }.from([author]).to([])
493
+ end
144
494
 
145
495
  specify { expect(existing_association.writer([new_author1, new_author2])).to eq([new_author1, new_author2]) }
146
- specify { expect { existing_association.writer([new_author1, new_author2]) }
147
- .to change { existing_association.reader.map(&:name) }
148
- .from(['Rick']).to(['John', 'Adam']) }
149
- specify { expect { existing_association.writer([new_author1, new_author2]) }
150
- .to change { existing_book.read_attribute(:author_ids) }
151
- .from([author.id]).to([new_author1.id, new_author2.id]) }
496
+ specify do
497
+ expect { existing_association.writer([new_author1, new_author2]) }
498
+ .to change { existing_association.reader.map(&:name) }
499
+ .from(['Rick']).to(%w[John Adam])
500
+ end
501
+ specify do
502
+ expect { existing_association.writer([new_author1, new_author2]) }
503
+ .to change { existing_book.read_attribute(:author_ids) }
504
+ .from([author.id]).to([new_author1.id, new_author2.id])
505
+ end
152
506
 
153
- specify { expect { existing_association.writer([new_author3]) }
154
- .to change { existing_association.target }.from([author]).to([new_author3]) }
155
- specify { expect { existing_association.writer([new_author3]) }
156
- .to change { existing_book.read_attribute(:author_ids) }
157
- .from([author.id]).to([nil]) }
507
+ specify do
508
+ expect { existing_association.writer([new_author3]) }
509
+ .to change { existing_association.target }.from([author]).to([new_author3])
510
+ end
511
+ specify do
512
+ expect { existing_association.writer([new_author3]) }
513
+ .to change { existing_book.read_attribute(:author_ids) }
514
+ .from([author.id]).to([nil])
515
+ end
158
516
  end
159
517
 
160
518
  describe '#concat' do
161
519
  let(:new_author1) { Author.create!(name: 'John') }
162
520
  let(:new_author2) { Author.create!(name: 'Adam') }
163
521
 
164
- specify { expect { association.concat(Dummy.new) }
165
- .to raise_error ActiveData::AssociationTypeMismatch }
522
+ specify do
523
+ expect { association.concat(Dummy.new) }
524
+ .to raise_error ActiveData::AssociationTypeMismatch
525
+ end
166
526
 
167
527
  specify { expect { association.concat(nil) }.to raise_error ActiveData::AssociationTypeMismatch }
168
528
  specify { expect(association.concat([])).to eq([]) }
@@ -170,27 +530,43 @@ describe ActiveData::Model::Associations::ReferencesMany do
170
530
  specify { expect(existing_association.concat).to eq(existing_book.authors) }
171
531
 
172
532
  specify { expect(association.concat(new_author1)).to eq([new_author1]) }
173
- specify { expect { association.concat(new_author1) }
174
- .to change { association.reader.map(&:name) }.from([]).to(['John']) }
175
- specify { expect { association.concat(new_author1) }
176
- .to change { book.read_attribute(:author_ids) }.from([]).to([1]) }
177
-
178
- specify { expect { existing_association.concat(new_author1, Dummy.new, new_author2) }
179
- .to raise_error ActiveData::AssociationTypeMismatch }
180
- specify { expect { existing_association.concat(new_author1, Dummy.new, new_author2) rescue nil }
181
- .to change { existing_book.read_attribute(:author_ids) }
182
- .from([author.id]).to([author.id, new_author1.id]) }
183
- specify { expect { existing_association.concat(new_author1, Dummy.new, new_author2) rescue nil }
184
- .to change { existing_association.reader.map(&:name) }
185
- .from(['Rick']).to(['Rick', 'John']) }
186
-
187
- specify { expect(existing_association.concat(new_author1, new_author2))
188
- .to eq([author, new_author1, new_author2]) }
189
- specify { expect { existing_association.concat([new_author1, new_author2]) }
190
- .to change { existing_association.reader.map(&:name) }
191
- .from(['Rick']).to(['Rick', 'John', 'Adam']) }
192
- specify { expect { existing_association.concat([new_author1, new_author2]) }
193
- .to change { existing_book.read_attribute(:author_ids) }
194
- .from([author.id]).to([author.id, new_author1.id, new_author2.id]) }
533
+ specify do
534
+ expect { association.concat(new_author1) }
535
+ .to change { association.reader.map(&:name) }.from([]).to(['John'])
536
+ end
537
+ specify do
538
+ expect { association.concat(new_author1) }
539
+ .to change { book.read_attribute(:author_ids) }.from([]).to([1])
540
+ end
541
+
542
+ specify do
543
+ expect { existing_association.concat(new_author1, Dummy.new, new_author2) }
544
+ .to raise_error ActiveData::AssociationTypeMismatch
545
+ end
546
+ specify do
547
+ expect { muffle(ActiveData::AssociationTypeMismatch) { existing_association.concat(new_author1, Dummy.new, new_author2) } }
548
+ .to change { existing_book.read_attribute(:author_ids) }
549
+ .from([author.id]).to([author.id, new_author1.id])
550
+ end
551
+ specify do
552
+ expect { muffle(ActiveData::AssociationTypeMismatch) { existing_association.concat(new_author1, Dummy.new, new_author2) } }
553
+ .to change { existing_association.reader.map(&:name) }
554
+ .from(['Rick']).to(%w[Rick John])
555
+ end
556
+
557
+ specify do
558
+ expect(existing_association.concat(new_author1, new_author2))
559
+ .to eq([author, new_author1, new_author2])
560
+ end
561
+ specify do
562
+ expect { existing_association.concat([new_author1, new_author2]) }
563
+ .to change { existing_association.reader.map(&:name) }
564
+ .from(['Rick']).to(%w[Rick John Adam])
565
+ end
566
+ specify do
567
+ expect { existing_association.concat([new_author1, new_author2]) }
568
+ .to change { existing_book.read_attribute(:author_ids) }
569
+ .from([author.id]).to([author.id, new_author1.id, new_author2.id])
570
+ end
195
571
  end
196
572
  end