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,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Lifecycle do
@@ -11,7 +10,7 @@ describe ActiveData::Model::Lifecycle do
11
10
 
12
11
  subject { User.new }
13
12
 
14
- [:save, :create, :update, :destroy].each do |action|
13
+ %i[save create update destroy].each do |action|
15
14
  specify { expect { subject.public_send "_#{action}_performer=", '' }.to raise_error NoMethodError }
16
15
  end
17
16
 
@@ -19,9 +18,9 @@ describe ActiveData::Model::Lifecycle do
19
18
  let(:foo) { true }
20
19
 
21
20
  specify { expect { subject.save { foo } }.to raise_error NameError }
22
- specify { expect { subject.save { |instance| attributes } }.to raise_error NameError }
21
+ specify { expect { subject.save { |_| attributes } }.to raise_error NameError }
23
22
  specify { expect(subject.save { attributes }).to eq(true) }
24
- specify { expect(subject.save { |instance| foo }).to eq(true) }
23
+ specify { expect(subject.save { |_| foo }).to eq(true) }
25
24
  end
26
25
 
27
26
  context 'save' do
@@ -87,7 +86,7 @@ describe ActiveData::Model::Lifecycle do
87
86
 
88
87
  attribute :actions, Array, default: []
89
88
 
90
- def append action
89
+ def append(action)
91
90
  self.actions = actions + [action]
92
91
  end
93
92
 
@@ -106,7 +105,7 @@ describe ActiveData::Model::Lifecycle do
106
105
  subject.destroy
107
106
  subject.destroy
108
107
  subject.save
109
- expect(subject.actions).to eq([:destroy, :create, :update, :destroy, :destroy, :create])
108
+ expect(subject.actions).to eq(%i[destroy create update destroy destroy create])
110
109
  end
111
110
  end
112
111
  end
@@ -198,10 +197,14 @@ describe ActiveData::Model::Lifecycle do
198
197
  specify { expect { subject.update({}) }.not_to change { subject.persisted? } }
199
198
  specify { expect { subject.update!({}) }.to raise_error ActiveData::ValidationError }
200
199
 
201
- specify { expect { subject.update(name: 'Jonny') }
202
- .to change { Storage.storage.keys }.from([]).to([subject.id]) }
203
- specify { expect { subject.update!(name: 'Jonny') }
204
- .to change { Storage.storage.keys }.from([]).to([subject.id]) }
200
+ specify do
201
+ expect { subject.update(name: 'Jonny') }
202
+ .to change { Storage.storage.keys }.from([]).to([subject.id])
203
+ end
204
+ specify do
205
+ expect { subject.update!(name: 'Jonny') }
206
+ .to change { Storage.storage.keys }.from([]).to([subject.id])
207
+ end
205
208
  end
206
209
 
207
210
  describe '#update_attributes, #update_attributes!' do
@@ -213,10 +216,14 @@ describe ActiveData::Model::Lifecycle do
213
216
  specify { expect { subject.update_attributes({}) }.not_to change { subject.persisted? } }
214
217
  specify { expect { subject.update_attributes!({}) }.to raise_error ActiveData::ValidationError }
215
218
 
216
- specify { expect { subject.update_attributes(name: 'Jonny') }
217
- .to change { Storage.storage.keys }.from([]).to([subject.id]) }
218
- specify { expect { subject.update_attributes!(name: 'Jonny') }
219
- .to change { Storage.storage.keys }.from([]).to([subject.id]) }
219
+ specify do
220
+ expect { subject.update_attributes(name: 'Jonny') }
221
+ .to change { Storage.storage.keys }.from([]).to([subject.id])
222
+ end
223
+ specify do
224
+ expect { subject.update_attributes!(name: 'Jonny') }
225
+ .to change { Storage.storage.keys }.from([]).to([subject.id])
226
+ end
220
227
  end
221
228
 
222
229
  describe '#save, #save!' do
@@ -230,7 +237,10 @@ describe ActiveData::Model::Lifecycle do
230
237
  specify { expect { subject.save! }.to raise_error ActiveData::ValidationError }
231
238
 
232
239
  specify { expect { subject.save }.not_to change { subject.persisted? } }
233
- specify { expect { subject.save! rescue nil }.not_to change { subject.persisted? } }
240
+ specify do
241
+ expect { muffle(ActiveData::ValidationError) { subject.save! } }
242
+ .not_to change { subject.persisted? }
243
+ end
234
244
  end
235
245
 
236
246
  context 'create' do
@@ -257,7 +267,10 @@ describe ActiveData::Model::Lifecycle do
257
267
  specify { expect { subject.save! }.to raise_error ActiveData::ObjectNotSaved }
258
268
 
259
269
  specify { expect { subject.save }.not_to change { subject.persisted? } }
260
- specify { expect { subject.save! rescue nil }.not_to change { subject.persisted? } }
270
+ specify do
271
+ expect { muffle(ActiveData::ObjectNotSaved) { subject.save! } }
272
+ .not_to change { subject.persisted? }
273
+ end
261
274
  end
262
275
  end
263
276
 
@@ -273,10 +286,14 @@ describe ActiveData::Model::Lifecycle do
273
286
  specify { expect { subject.save }.not_to change { subject.persisted? } }
274
287
  specify { expect { subject.save! }.not_to change { subject.persisted? } }
275
288
 
276
- specify { expect { subject.save }.to change { Storage.storage[subject.id] }
277
- .from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy')) }
278
- specify { expect { subject.save! }.to change { Storage.storage[subject.id] }
279
- .from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy')) }
289
+ specify do
290
+ expect { subject.save }.to change { Storage.storage[subject.id] }
291
+ .from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy'))
292
+ end
293
+ specify do
294
+ expect { subject.save! }.to change { Storage.storage[subject.id] }
295
+ .from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy'))
296
+ end
280
297
 
281
298
  context 'save failed' do
282
299
  before { User.define_save { false } }
@@ -287,7 +304,10 @@ describe ActiveData::Model::Lifecycle do
287
304
  specify { expect { subject.save! }.to raise_error ActiveData::ObjectNotSaved }
288
305
 
289
306
  specify { expect { subject.save }.not_to change { subject.persisted? } }
290
- specify { expect { subject.save! rescue nil }.not_to change { subject.persisted? } }
307
+ specify do
308
+ expect { muffle(ActiveData::ObjectNotSaved) { subject.save! } }
309
+ .not_to change { subject.persisted? }
310
+ end
291
311
  end
292
312
  end
293
313
  end
@@ -320,10 +340,16 @@ describe ActiveData::Model::Lifecycle do
320
340
  specify { expect { subject.destroy! }.to raise_error ActiveData::ObjectNotDestroyed }
321
341
 
322
342
  specify { expect { subject.destroy }.not_to change { subject.persisted? } }
323
- specify { expect { subject.destroy! rescue nil }.not_to change { subject.persisted? } }
343
+ specify do
344
+ expect { muffle(ActiveData::ObjectNotDestroyed) { subject.destroy! } }
345
+ .not_to change { subject.persisted? }
346
+ end
324
347
 
325
348
  specify { expect { subject.destroy }.not_to change { subject.destroyed? } }
326
- specify { expect { subject.destroy! rescue nil }.not_to change { subject.destroyed? } }
349
+ specify do
350
+ expect { muffle(ActiveData::ObjectNotDestroyed) { subject.destroy! } }
351
+ .not_to change { subject.destroyed? }
352
+ end
327
353
  end
328
354
  end
329
355
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Persistence do
@@ -22,7 +21,7 @@ describe ActiveData::Model::Persistence do
22
21
  context do
23
22
  subject(:instance) { model.instantiate(name: 'Hello', foo: 'Bar') }
24
23
 
25
- specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys) }
24
+ specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
26
25
  end
27
26
  end
28
27
 
@@ -31,17 +30,17 @@ describe ActiveData::Model::Persistence do
31
30
  subject(:instances) { model.instantiate_collection(name: 'Hello', foo: 'Bar') }
32
31
 
33
32
  specify { expect(subject).to be_a Array }
34
- specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys) }
33
+ specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
35
34
  end
36
35
 
37
36
  context do
38
37
  before { model.send(:include, ActiveData::Model::Scopes) }
39
- subject(:instances) { model.instantiate_collection([{ name: 'Hello', foo: 'Bar' }, {name: 'World'}]) }
38
+ subject(:instances) { model.instantiate_collection([{name: 'Hello', foo: 'Bar'}, {name: 'World'}]) }
40
39
 
41
40
  specify { expect(subject).to be_a ActiveData::Model::Scopes::ScopeProxy }
42
41
  specify { expect(subject.count).to eq(2) }
43
- specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys) }
44
- specify { expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({ name: 'World' }.stringify_keys) }
42
+ specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
43
+ specify { expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({name: 'World'}.stringify_keys) }
45
44
  end
46
45
  end
47
46
  end
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveData::Model::Representation do
4
+ context 'integration' do
5
+ before do
6
+ stub_model(:author) do
7
+ attribute :rate, Integer
8
+ end
9
+
10
+ stub_model(:post) do
11
+ include ActiveData::Model::Representation
12
+
13
+ attribute :author, Object
14
+ alias_attribute :a, :author
15
+ represents :rate, of: :a
16
+ alias_attribute :r, :rate
17
+ end
18
+ end
19
+ let(:author) { Author.new(rate: '42') }
20
+
21
+ specify { expect(Post.reflect_on_attribute(:rate).reference).to eq('author') }
22
+
23
+ specify { expect(Post.new(author: author).rate).to eq(42) }
24
+ specify { expect(Post.new(author: author).rate_before_type_cast).to eq('42') }
25
+ specify { expect(Post.new(rate: '33', author: author).rate).to eq(33) }
26
+ specify { expect(Post.new(rate: '33', author: author).author.rate).to eq(33) }
27
+ specify { expect(Post.new(r: '33', author: author).rate).to eq(33) }
28
+ specify { expect(Post.new(r: '33', author: author).author.rate).to eq(33) }
29
+ specify { expect(Post.new(author: author).rate?).to eq(true) }
30
+ specify { expect(Post.new(rate: nil, author: author).rate?).to eq(false) }
31
+
32
+ specify { expect(Post.new.rate).to be_nil }
33
+ specify { expect(Post.new.rate_before_type_cast).to be_nil }
34
+ specify { expect { Post.new(rate: '33') }.to raise_error(NoMethodError) }
35
+
36
+ context 'ActionController::Parameters' do
37
+ let(:params) { instance_double('ActionController::Parameters', to_unsafe_hash: {rate: '33', author: author}) }
38
+ specify { expect { Post.new(params) }.not_to raise_error }
39
+ end
40
+
41
+ context 'dirty' do
42
+ before { Post.include ActiveData::Model::Dirty }
43
+
44
+ specify do
45
+ expect(Post.new(author: author, rate: '33').changes)
46
+ .to eq('author' => [nil, author], 'rate' => [42, 33])
47
+ end
48
+ end
49
+
50
+ context do
51
+ before do
52
+ stub_class(:author, ActiveRecord::Base)
53
+
54
+ stub_model(:post) do
55
+ include ActiveData::Model::Associations
56
+ include ActiveData::Model::Representation
57
+
58
+ references_one :author
59
+ alias_association :a, :author
60
+ represents :name, of: :a
61
+ end
62
+ end
63
+ let!(:author) { Author.create!(name: 42) }
64
+
65
+ specify { expect(Post.reflect_on_attribute(:name).reference).to eq('author') }
66
+
67
+ specify { expect(Post.new(name: '33', author: author).name).to eq('33') }
68
+ specify { expect(Post.new(name: '33', author: author).author.name).to eq('33') }
69
+ end
70
+
71
+ context 'multiple attributes in a single represents definition' do
72
+ before do
73
+ stub_model(:author) do
74
+ attribute :first_name, String
75
+ attribute :last_name, String
76
+ end
77
+
78
+ stub_model(:post) do
79
+ include ActiveData::Model::Representation
80
+
81
+ attribute :author, Object
82
+ represents :first_name, :last_name, of: :author
83
+ end
84
+ end
85
+
86
+ let(:author) { Author.new(first_name: 'John', last_name: 'Doe') }
87
+ let(:post) { Post.new }
88
+
89
+ specify do
90
+ expect { post.update(author: author) }
91
+ .to change { post.first_name }.to('John')
92
+ .and change { post.last_name }.to('Doe')
93
+ end
94
+ end
95
+ end
96
+
97
+ describe '#validate' do
98
+ before do
99
+ stub_class(:author, ActiveRecord::Base) do
100
+ validates :name, presence: true
101
+
102
+ # Emulate Active Record association auto save error.
103
+ def errors
104
+ super.tap do |errors|
105
+ errors.add(:'user.email', 'is invalid') if errors[:'user.email'].empty?
106
+ end
107
+ end
108
+ end
109
+
110
+ stub_model(:post) do
111
+ include ActiveData::Model::Associations
112
+ include ActiveData::Model::Representation
113
+
114
+ references_one :author
115
+ represents :name, :email, of: :author
116
+ end
117
+ end
118
+
119
+ let(:post) { Post.new(author: Author.new) }
120
+
121
+ specify do
122
+ expect { post.validate }.to change { post.errors.messages }
123
+ .to(hash_including(:'author.user.email' => ['is invalid'], name: ["can't be blank"]))
124
+ end
125
+ end
126
+ end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Scopes do
@@ -19,8 +18,7 @@ describe ActiveData::Model::Scopes do
19
18
 
20
19
  private
21
20
 
22
- def hidden_method
23
- end
21
+ def hidden_method() end
24
22
  end
25
23
  end
26
24
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model::Attributes do
@@ -96,10 +95,11 @@ describe ActiveData::Model::Attributes do
96
95
  let(:model) { stub_model { attribute :column, Array } }
97
96
 
98
97
  specify { expect(model.new(column: [1, 2, 3]).column).to eq([1, 2, 3]) }
99
- specify { expect(model.new(column: 'hello, world').column).to eq(['hello', 'world']) }
98
+ specify { expect(model.new(column: 'hello, world').column).to eq(%w[hello world]) }
100
99
  specify { expect(model.new(column: 10).column).to be_nil }
101
100
  end
102
101
 
102
+ # rubocop:disable Style/DateTime
103
103
  context 'date' do
104
104
  let(:model) { stub_model { attribute :column, Date } }
105
105
  let(:date) { Date.new(2013, 6, 13) }
@@ -149,6 +149,7 @@ describe ActiveData::Model::Attributes do
149
149
  specify { expect(model.new(column: Time.new(2013, 6, 13, 23, 13)).column).to eq(Time.new(2013, 6, 13, 23, 13)) }
150
150
  end
151
151
  end
152
+ # rubocop:enable Style/DateTime
152
153
 
153
154
  context 'time_zone' do
154
155
  let(:model) { stub_model { attribute :column, ActiveSupport::TimeZone } }
@@ -175,13 +176,13 @@ describe ActiveData::Model::Attributes do
175
176
  let(:uuid_tools) { UUIDTools::UUID.random_create }
176
177
 
177
178
  specify { expect(uuid.as_json).to eq(uuid.to_s) }
178
- specify { expect(uuid.to_json).to eq("\"#{uuid.to_s}\"") }
179
+ specify { expect(uuid.to_json).to eq("\"#{uuid}\"") }
179
180
  specify { expect(uuid.to_param).to eq(uuid.to_s) }
180
- specify { expect(uuid.to_query(:key)).to eq("key=#{uuid.to_s}") }
181
+ specify { expect(uuid.to_query(:key)).to eq("key=#{uuid}") }
181
182
 
182
183
  specify { expect(model.new(column: nil).column).to be_nil }
183
184
  specify { expect(model.new(column: Object.new).column).to be_nil }
184
- specify { expect(model.new(column: uuid_tools).column).to be_a ActiveData::UUID }
185
+ specify { expect(model.new(column: uuid_tools).column).to be_a ActiveData::UUID }
185
186
  specify { expect(model.new(column: uuid_tools).column).to eq(uuid_tools) }
186
187
  specify { expect(model.new(column: uuid).column).to eq(uuid) }
187
188
  specify { expect(model.new(column: uuid.to_s).column).to eq(uuid) }
@@ -35,60 +35,68 @@ describe ActiveData::Model::Validations::AssociatedValidator do
35
35
  end
36
36
 
37
37
  context do
38
- subject(:instance) { Main.instantiate name: 'hello', validated_one: { name: 'name' } }
38
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: {name: 'name'} }
39
39
  it { is_expected.to be_valid }
40
40
  end
41
41
 
42
42
  context do
43
- subject(:instance) { Main.instantiate name: 'hello', validated_one: { } }
43
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: {} }
44
44
  it { is_expected.not_to be_valid }
45
- specify { expect { instance.validate }.to change { instance.errors.messages }
46
- .to(validated_one: ['is invalid']) }
45
+ specify do
46
+ expect { instance.validate }.to change { instance.errors.messages }
47
+ .to(validated_one: ['is invalid'])
48
+ end
47
49
  end
48
50
 
49
51
  context do
50
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: { name: 'name' } }
52
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {name: 'name'} }
51
53
  it { is_expected.to be_valid }
52
54
  end
53
55
 
54
56
  context do
55
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: { } }
57
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {} }
56
58
  it { is_expected.to be_valid }
57
59
  end
58
60
 
59
61
  context do
60
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }] }
62
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}] }
61
63
  it { is_expected.to be_valid }
62
64
  end
63
65
 
64
66
  context do
65
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ }] }
67
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}] }
66
68
  it { is_expected.not_to be_valid }
67
- specify { expect { instance.validate }.to change { instance.errors.messages }
68
- .to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid']) }
69
+ specify do
70
+ expect { instance.validate }.to change { instance.errors.messages }
71
+ .to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid'])
72
+ end
69
73
  end
70
74
 
71
75
  context do
72
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{ name: 'name' }] }
76
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{name: 'name'}] }
73
77
  it { is_expected.to be_valid }
74
78
  end
75
79
 
76
80
  context do
77
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{ }] }
81
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{}] }
78
82
  it { is_expected.to be_valid }
79
83
  end
80
84
 
81
85
  context do
82
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }], validated_one: { } }
86
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}], validated_one: {} }
83
87
  it { is_expected.not_to be_valid }
84
- specify { expect { instance.validate }.to change { instance.errors.messages }
85
- .to(validated_one: ['is invalid']) }
88
+ specify do
89
+ expect { instance.validate }.to change { instance.errors.messages }
90
+ .to(validated_one: ['is invalid'])
91
+ end
86
92
  end
87
93
 
88
94
  context do
89
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ }], validated_one: { name: 'name' } }
95
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: {name: 'name'} }
90
96
  it { is_expected.not_to be_valid }
91
- specify { expect { instance.validate }.to change { instance.errors.messages }
92
- .to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid']) }
97
+ specify do
98
+ expect { instance.validate }.to change { instance.errors.messages }
99
+ .to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid'])
100
+ end
93
101
  end
94
102
  end
@@ -5,7 +5,9 @@ describe ActiveData::Model::Validations::NestedValidator do
5
5
  stub_model(:validated_assoc) do
6
6
  include ActiveData::Model
7
7
  include ActiveData::Model::Lifecycle
8
+ include ActiveData::Model::Primary
8
9
 
10
+ primary :id, Integer
9
11
  attribute :name, String
10
12
 
11
13
  validates_presence_of :name
@@ -34,60 +36,129 @@ describe ActiveData::Model::Validations::NestedValidator do
34
36
  end
35
37
 
36
38
  context do
37
- subject(:instance) { Main.instantiate name: 'hello', validated_one: { name: 'name' } }
39
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: {name: 'name'} }
38
40
  it { is_expected.to be_valid }
39
41
  end
40
42
 
41
43
  context do
42
- subject(:instance) { Main.instantiate name: 'hello', validated_one: { } }
44
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: {} }
43
45
  it { is_expected.not_to be_valid }
44
- specify { expect { instance.validate }.to change { instance.errors.messages }
45
- .to(:'validated_one.name' => ["can't be blank"]) }
46
+ specify do
47
+ expect { instance.validate }.to change { instance.errors.messages }
48
+ .to(:'validated_one.name' => ["can't be blank"])
49
+ end
46
50
  end
47
51
 
48
52
  context do
49
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: { name: 'name' } }
53
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {name: 'name'} }
50
54
  it { is_expected.to be_valid }
51
55
  end
52
56
 
53
57
  context do
54
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: { } }
58
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {} }
55
59
  it { is_expected.to be_valid }
56
60
  end
57
61
 
58
62
  context do
59
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }] }
63
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}] }
60
64
  it { is_expected.to be_valid }
61
65
  end
62
66
 
63
67
  context do
64
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ }] }
68
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}] }
65
69
  it { is_expected.not_to be_valid }
66
- specify { expect { instance.validate }.to change { instance.errors.messages }
67
- .to(:'validated_many.0.name' => ["can't be blank"]) }
70
+ specify do
71
+ expect { instance.validate }.to change { instance.errors.messages }
72
+ .to(:'validated_many.0.name' => ["can't be blank"])
73
+ end
68
74
  end
69
75
 
70
76
  context do
71
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{ name: 'name' }] }
77
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{name: 'name'}] }
72
78
  it { is_expected.to be_valid }
73
79
  end
74
80
 
75
81
  context do
76
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{ }] }
82
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{}] }
77
83
  it { is_expected.to be_valid }
78
84
  end
79
85
 
80
86
  context do
81
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }], validated_one: { } }
87
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}], validated_one: {} }
82
88
  it { is_expected.not_to be_valid }
83
- specify { expect { instance.validate }.to change { instance.errors.messages }
84
- .to(:'validated_one.name' => ["can't be blank"]) }
89
+ specify do
90
+ expect { instance.validate }.to change { instance.errors.messages }
91
+ .to(:'validated_one.name' => ["can't be blank"])
92
+ end
93
+ end
94
+
95
+ context 'accepts nested attributes for one' do
96
+ before { Main.accepts_nested_attributes_for :validated_one, allow_destroy: true }
97
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: {id: 1, name: 'name'} }
98
+
99
+ specify do
100
+ instance.validated_one_attributes = {id: 1, name: '', _destroy: true}
101
+ is_expected.to be_valid
102
+ end
103
+ end
104
+
105
+ context 'accepts nested attributes for many' do
106
+ before { Main.accepts_nested_attributes_for :validated_many, allow_destroy: true }
107
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{id: 1, name: 'name'}] }
108
+
109
+ specify do
110
+ instance.validated_many_attributes = [{id: 1, name: '', _destroy: true}]
111
+ is_expected.to be_valid
112
+ end
113
+ end
114
+
115
+ context 'object field is invalid and referenced object does not include AutosaveAssociation' do
116
+ before do
117
+ stub_class(:validated_object) do
118
+ include ActiveData::Model::Validations
119
+ include ActiveData::Model::Attributes
120
+ include ActiveData::Model::Primary
121
+
122
+ primary :id
123
+ attribute :title, String
124
+ validates_presence_of :title
125
+ end
126
+
127
+ Main.class_eval do
128
+ include ActiveData::Model::Associations
129
+ attribute :object, Object
130
+ validates :object, nested: true
131
+ end
132
+ end
133
+
134
+ subject(:instance) { Main.instantiate name: 'hello', object: object, validated_one: {name: 'name'} }
135
+
136
+ context do
137
+ let(:object) { ValidatedObject.new(title: 'Mr.') }
138
+ it { is_expected.to be_valid }
139
+ end
140
+
141
+ context do
142
+ let(:object) { ValidatedObject.new }
143
+ it do
144
+ expect { subject.valid? }.not_to raise_error
145
+ expect(subject).not_to be_valid
146
+ end
147
+ end
85
148
  end
86
149
 
87
150
  context do
88
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ }], validated_one: { name: 'name' } }
151
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: {name: 'name'} }
89
152
  it { is_expected.not_to be_valid }
90
- specify { expect { instance.validate }.to change { instance.errors.messages }
91
- .to(:'validated_many.0.name' => ["can't be blank"]) }
153
+ specify do
154
+ expect { instance.validate }.to change { instance.errors.messages }
155
+ .to(:'validated_many.0.name' => ["can't be blank"])
156
+ end
157
+ end
158
+
159
+ describe '.validates_nested?' do
160
+ specify { expect(Main).to be_validates_nested(:validated_one) }
161
+ specify { expect(Main).to be_validates_nested(:unvalidated_one) }
162
+ specify { expect(Main).not_to be_validates_nested(:something_else) }
92
163
  end
93
164
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData::Model do
@@ -6,6 +5,6 @@ describe ActiveData::Model do
6
5
  specify { expect { model.blablabla }.to raise_error NoMethodError }
7
6
 
8
7
  context 'Fault tolerance' do
9
- specify{ expect { model.new(foo: 'bar') }.not_to raise_error }
8
+ specify { expect { model.new(foo: 'bar') }.not_to raise_error }
10
9
  end
11
10
  end
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe ActiveData do