granite-form 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -48
  3. data/.rubocop_todo.yml +304 -27
  4. data/CHANGELOG.md +7 -2
  5. data/granite-form.gemspec +2 -1
  6. data/lib/granite/form/active_record/associations.rb +4 -3
  7. data/lib/granite/form/config.rb +1 -1
  8. data/lib/granite/form/errors.rb +34 -32
  9. data/lib/granite/form/extensions.rb +2 -1
  10. data/lib/granite/form/model/associations/base.rb +6 -2
  11. data/lib/granite/form/model/associations/collection/embedded.rb +1 -1
  12. data/lib/granite/form/model/associations/collection/proxy.rb +3 -3
  13. data/lib/granite/form/model/associations/embeds_any.rb +1 -1
  14. data/lib/granite/form/model/associations/embeds_many.rb +15 -11
  15. data/lib/granite/form/model/associations/embeds_one.rb +9 -8
  16. data/lib/granite/form/model/associations/nested_attributes.rb +60 -32
  17. data/lib/granite/form/model/associations/persistence_adapters/active_record/referenced_proxy.rb +2 -1
  18. data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +7 -6
  19. data/lib/granite/form/model/associations/persistence_adapters/base.rb +8 -4
  20. data/lib/granite/form/model/associations/references_any.rb +1 -1
  21. data/lib/granite/form/model/associations/references_many.rb +3 -2
  22. data/lib/granite/form/model/associations/references_one.rb +1 -1
  23. data/lib/granite/form/model/associations/reflections/base.rb +3 -2
  24. data/lib/granite/form/model/associations/reflections/embeds_any.rb +4 -4
  25. data/lib/granite/form/model/associations/reflections/embeds_many.rb +4 -1
  26. data/lib/granite/form/model/associations/reflections/embeds_one.rb +4 -1
  27. data/lib/granite/form/model/associations/reflections/references_any.rb +6 -6
  28. data/lib/granite/form/model/associations/reflections/references_many.rb +1 -1
  29. data/lib/granite/form/model/associations/reflections/references_one.rb +1 -1
  30. data/lib/granite/form/model/associations/validations.rb +6 -6
  31. data/lib/granite/form/model/associations.rb +6 -4
  32. data/lib/granite/form/model/attributes/attribute.rb +1 -0
  33. data/lib/granite/form/model/attributes/base.rb +9 -7
  34. data/lib/granite/form/model/attributes/reference_one.rb +1 -1
  35. data/lib/granite/form/model/attributes/reflections/base/build_type_definition.rb +2 -1
  36. data/lib/granite/form/model/attributes/reflections/represents/build_type_definition.rb +2 -2
  37. data/lib/granite/form/model/attributes/represents.rb +1 -1
  38. data/lib/granite/form/model/attributes.rb +21 -13
  39. data/lib/granite/form/model/conventions.rb +1 -1
  40. data/lib/granite/form/model/persistence.rb +1 -1
  41. data/lib/granite/form/model/primary.rb +1 -1
  42. data/lib/granite/form/model/representation.rb +4 -4
  43. data/lib/granite/form/model/scopes.rb +5 -5
  44. data/lib/granite/form/model/validations.rb +4 -3
  45. data/lib/granite/form/types/active_support/time_zone.rb +1 -1
  46. data/lib/granite/form/types/array.rb +1 -1
  47. data/lib/granite/form/types/big_decimal.rb +1 -1
  48. data/lib/granite/form/types/boolean.rb +1 -1
  49. data/lib/granite/form/types/date.rb +1 -1
  50. data/lib/granite/form/types/date_time.rb +1 -1
  51. data/lib/granite/form/types/dictionary.rb +1 -1
  52. data/lib/granite/form/types/float.rb +1 -1
  53. data/lib/granite/form/types/has_subtype.rb +1 -0
  54. data/lib/granite/form/types/hash_with_action_controller_parameters.rb +2 -2
  55. data/lib/granite/form/types/integer.rb +1 -1
  56. data/lib/granite/form/types/object.rb +2 -1
  57. data/lib/granite/form/types/string.rb +1 -1
  58. data/lib/granite/form/types/time.rb +1 -1
  59. data/lib/granite/form/types/uuid.rb +1 -1
  60. data/lib/granite/form/util.rb +1 -1
  61. data/lib/granite/form/version.rb +1 -1
  62. data/spec/granite/form/active_record/associations_spec.rb +35 -13
  63. data/spec/granite/form/config_spec.rb +8 -4
  64. data/spec/granite/form/model/associations/embeds_many_spec.rb +99 -51
  65. data/spec/granite/form/model/associations/embeds_one_spec.rb +48 -25
  66. data/spec/granite/form/model/associations/persistence_adapters/active_record_spec.rb +12 -7
  67. data/spec/granite/form/model/associations/references_many_spec.rb +51 -10
  68. data/spec/granite/form/model/associations/references_one_spec.rb +17 -6
  69. data/spec/granite/form/model/associations/reflections/embeds_many_spec.rb +51 -16
  70. data/spec/granite/form/model/associations/reflections/embeds_one_spec.rb +19 -9
  71. data/spec/granite/form/model/associations/reflections/references_many_spec.rb +67 -15
  72. data/spec/granite/form/model/associations/reflections/references_one_spec.rb +34 -11
  73. data/spec/granite/form/model/associations/validations_spec.rb +16 -5
  74. data/spec/granite/form/model/associations_spec.rb +28 -9
  75. data/spec/granite/form/model/attributes/attribute_spec.rb +33 -11
  76. data/spec/granite/form/model/attributes/base_spec.rb +9 -3
  77. data/spec/granite/form/model/attributes/reflections/attribute_spec.rb +1 -0
  78. data/spec/granite/form/model/attributes/reflections/base_spec.rb +1 -0
  79. data/spec/granite/form/model/attributes/reflections/represents/build_type_definition_spec.rb +3 -1
  80. data/spec/granite/form/model/attributes/reflections/represents_spec.rb +2 -2
  81. data/spec/granite/form/model/attributes/represents_spec.rb +2 -2
  82. data/spec/granite/form/model/attributes_spec.rb +76 -36
  83. data/spec/granite/form/model/dirty_spec.rb +3 -0
  84. data/spec/granite/form/model/persistence_spec.rb +15 -5
  85. data/spec/granite/form/model/primary_spec.rb +17 -2
  86. data/spec/granite/form/model/representation_spec.rb +13 -3
  87. data/spec/granite/form/model/scopes_spec.rb +8 -3
  88. data/spec/granite/form/model/validations/associated_spec.rb +20 -6
  89. data/spec/granite/form/model/validations/nested_spec.rb +30 -14
  90. data/spec/granite/form/model/validations_spec.rb +1 -1
  91. data/spec/granite/form/model_spec.rb +1 -0
  92. data/spec/granite/form/types/collection_spec.rb +2 -1
  93. data/spec/granite/form/types/date_spec.rb +1 -1
  94. data/spec/granite/form/types/date_time_spec.rb +0 -2
  95. data/spec/granite/form/types/dictionary_spec.rb +1 -0
  96. data/spec/granite/form/types/has_subtype_spec.rb +6 -1
  97. data/spec/granite/form/types/hash_with_action_controller_parameters_spec.rb +1 -1
  98. data/spec/granite/form/types/object_spec.rb +2 -0
  99. data/spec/granite/form/types/time_spec.rb +0 -2
  100. data/spec/granite/form/util_spec.rb +6 -3
  101. data/spec/support/active_record.rb +13 -0
  102. data/spec/support/shared/nested_attribute_examples.rb +110 -54
  103. metadata +23 -9
@@ -7,12 +7,16 @@ describe Granite::Form::Model::Attributes::Base do
7
7
 
8
8
  def attribute(*args)
9
9
  options = args.extract_options!
10
- Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Base, :field, options.reverse_merge(type: Object))
10
+ Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Base, :field,
11
+ options.reverse_merge(type: Object))
11
12
  model.attribute(:field)
12
13
  end
13
14
 
14
15
  describe '#read' do
15
- let(:field) { attribute(type: String, normalizer: ->(v) { v ? v.strip : v }, default: :world, enum: %w[hello 42 world]) }
16
+ let(:field) do
17
+ normalizer = ->(v) { v ? v.strip : v }
18
+ attribute(type: String, normalizer: normalizer, default: :world, enum: %w[hello 42 world])
19
+ end
16
20
  let(:object) { Object.new }
17
21
 
18
22
  specify { expect(field.tap { |r| r.write(nil) }.read).to be_nil }
@@ -99,6 +103,7 @@ describe Granite::Form::Model::Attributes::Base do
99
103
 
100
104
  describe '#type_definition' do
101
105
  subject { attr.type_definition }
106
+
102
107
  let(:attr) { attribute(type: String) }
103
108
 
104
109
  it { is_expected.to have_attributes(type: String, reflection: subject.reflection, owner: model) }
@@ -112,11 +117,12 @@ describe Granite::Form::Model::Attributes::Base do
112
117
  'hello' => 'field: "hello"',
113
118
  123 => 'field: 123',
114
119
  Date.new(2023, 6, 20) => 'field: "2023-06-20"',
115
- DateTime.new(2023, 6, 20, 12, 30) => 'field: "2023-06-20 12:30:00"', # rubocop:disable Style/DateTime
120
+ DateTime.new(2023, 6, 20, 12, 30) => 'field: "2023-06-20 12:30:00"',
116
121
  Time.new(2023, 6, 20, 12, 30) => 'field: "2023-06-20 12:30:00"'
117
122
  }.each do |input, expected_output|
118
123
  context "attribute type is #{input.class}" do
119
124
  let(:type) { input.class }
125
+
120
126
  specify { expect(field.tap { |r| r.write(input) }.inspect_attribute).to eq(expected_output) }
121
127
  end
122
128
  end
@@ -10,6 +10,7 @@ describe Granite::Form::Model::Attributes::Reflections::Attribute do
10
10
 
11
11
  specify { expect(described_class.build(Class.new, Target, :field, String).type).to eq(String) }
12
12
  specify { expect(described_class.build(Class.new, Target, :field) {}.defaultizer).to be_a(Proc) }
13
+
13
14
  specify do
14
15
  described_class.build(Class.new, Target, :field)
15
16
 
@@ -12,6 +12,7 @@ describe Granite::Form::Model::Attributes::Reflections::Base do
12
12
  described_class.build(Class.new, Target, :field)
13
13
  expect(Target).not_to be_method_defined(:field)
14
14
  end
15
+
15
16
  specify { expect(described_class.build(Class.new, Target, :field).name).to eq('field') }
16
17
  end
17
18
 
@@ -4,7 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Granite::Form::Model::Attributes::Reflections::Represents::BuildTypeDefinition do
6
6
  def build_type_definition(name = :name, **options)
7
- @reflection = Granite::Form::Model::Attributes::Reflections::Represents.new(name, options.reverse_merge(of: :author))
7
+ @reflection = Granite::Form::Model::Attributes::Reflections::Represents.new(name,
8
+ options.reverse_merge(of: :author))
8
9
  described_class.new(owner, @reflection).call
9
10
  end
10
11
 
@@ -102,6 +103,7 @@ describe Granite::Form::Model::Attributes::Reflections::Represents::BuildTypeDef
102
103
  it { expect(build_type_definition(:status)).to have_type(Integer) }
103
104
  it { expect(build_type_definition(:full_name)).to have_type(String) }
104
105
  it { expect(build_type_definition(:unknown_attribute)).to have_type(Object) }
106
+
105
107
  it do
106
108
  attribute = build_type_definition(:related_ids)
107
109
  expect(attribute).to be_a(Granite::Form::Types::Collection)
@@ -23,7 +23,7 @@ describe Granite::Form::Model::Attributes::Reflections::Represents do
23
23
  end
24
24
 
25
25
  let(:instance) { Target.new attributes }
26
- let(:attributes) { {subject: Author.new} }
26
+ let(:attributes) { { subject: Author.new } }
27
27
  let!(:reflection) { build_reflection }
28
28
 
29
29
  it { expect(reflection.reference).to eq('author') }
@@ -53,7 +53,7 @@ describe Granite::Form::Model::Attributes::Reflections::Represents do
53
53
  context 'when validate_reference is false' do
54
54
  let(:reflection) { build_reflection(validate_reference: false) }
55
55
 
56
- it { expect { instance.validate }.not_to change { instance.errors.messages } }
56
+ it { expect { instance.validate }.not_to(change { instance.errors.messages }) }
57
57
  end
58
58
  end
59
59
  end
@@ -23,9 +23,9 @@ describe Granite::Form::Model::Attributes::Represents do
23
23
  describe '#initialize' do
24
24
  before { Author.attribute :name, String, default: 'Default Name' }
25
25
 
26
- let(:attributes) { {foo: 'bar'} }
26
+ let(:attributes) { { foo: 'bar' } }
27
27
 
28
- it { expect { Model.new(attributes) }.to_not change { attributes } }
28
+ it { expect { Model.new(attributes) }.not_to(change { attributes }) }
29
29
 
30
30
  it { expect(attribute.read).to eq('Default Name') }
31
31
  it { expect(attribute.read_before_type_cast).to eq('Default Name') }
@@ -37,28 +37,33 @@ describe Granite::Form::Model::Attributes do
37
37
  describe '.inspect' do
38
38
  specify { expect(stub_model.inspect).to match(/#<Class:0x\w+>\(no attributes\)/) }
39
39
  specify { expect(stub_model(:user).inspect).to eq('User(no attributes)') }
40
+
40
41
  specify do
41
42
  expect(stub_model do
42
43
  include Granite::Form::Model::Primary
43
44
  primary :count, Integer
44
45
  attribute :object, Object
45
- end.inspect).to match(/#<Class:0x\w+>\(\*count: Integer, object: Object\)/) end
46
+ end.inspect).to match(/#<Class:0x\w+>\(\*count: Integer, object: Object\)/)
47
+ end
48
+
46
49
  specify do
47
50
  expect(stub_model(:user) do
48
51
  include Granite::Form::Model::Primary
49
52
  primary :count, Integer
50
53
  attribute :object, Object
51
- end.inspect).to match('User(*count: Integer, object: Object)') end
54
+ end.inspect).to match('User(*count: Integer, object: Object)')
55
+ end
52
56
  end
53
57
 
54
58
  describe '#==' do
59
+ subject { model.new name: 'hello', count: 42 }
60
+
55
61
  let(:model) do
56
62
  stub_model do
57
63
  attribute :name, String
58
64
  attribute :count, Float, default: 0
59
65
  end
60
66
  end
61
- subject { model.new name: 'hello', count: 42 }
62
67
 
63
68
  it { is_expected.not_to eq(nil) }
64
69
  it { is_expected.not_to eq('hello') }
@@ -79,6 +84,7 @@ describe Granite::Form::Model::Attributes do
79
84
 
80
85
  describe '#attribute' do
81
86
  let(:instance) { model.new }
87
+
82
88
  specify { expect(instance.attribute(:full_name).reflection.name).to eq('full_name') }
83
89
  specify { expect(instance.attribute('full_name').reflection.name).to eq('full_name') }
84
90
  specify { expect(instance.attribute(:name).reflection.name).to eq('full_name') }
@@ -108,10 +114,12 @@ describe Granite::Form::Model::Attributes do
108
114
 
109
115
  describe '#attributes' do
110
116
  specify { expect(stub_model.new.attributes).to eq({}) }
117
+
111
118
  specify do
112
119
  expect(model.new(name: 'Name').attributes)
113
120
  .to match('id' => nil, 'full_name' => 'Name', 'author' => nil, 'projects' => nil)
114
121
  end
122
+
115
123
  specify do
116
124
  expect(model.new(name: 'Name').attributes(false))
117
125
  .to match('id' => nil, 'full_name' => 'Name')
@@ -119,13 +127,16 @@ describe Granite::Form::Model::Attributes do
119
127
  end
120
128
 
121
129
  describe '#assign_attributes' do
122
- let(:attributes) { {id: 42, full_name: 'Name', missed: 'value'} }
123
130
  subject { model.new }
124
131
 
132
+ let(:attributes) { { id: 42, full_name: 'Name', missed: 'value' } }
133
+
125
134
  specify { expect { subject.assign_attributes(attributes) }.to change { subject.id }.to(42) }
126
135
  specify { expect { subject.assign_attributes(attributes) }.to change { subject.full_name }.to('Name') }
127
136
 
128
137
  context 'features stack and assign order' do
138
+ subject { model.new }
139
+
129
140
  let(:model) do
130
141
  stub_model do
131
142
  attr_reader :logger
@@ -147,7 +158,6 @@ describe Granite::Form::Model::Attributes do
147
158
  log(:plain2)
148
159
  end
149
160
  end
150
- subject { model.new }
151
161
 
152
162
  specify do
153
163
  expect { subject.assign_attributes(plain1: 'value', plain2: 'value') }
@@ -176,18 +186,22 @@ describe Granite::Form::Model::Attributes do
176
186
  log(:assoc_plain)
177
187
 
178
188
  def assign_attributes(attrs)
179
- super attrs.merge(attrs.extract!('plain2'))
189
+ super(attrs.merge(attrs.extract!('plain2')))
180
190
  end
181
191
  end
182
192
  end
183
193
 
184
194
  specify do
185
- expect { subject.assign_attributes(assoc_plain: 'value', assoc_attributes: {}, plain1: 'value', plain2: 'value') }
195
+ expect do
196
+ subject.assign_attributes(assoc_plain: 'value', assoc_attributes: {}, plain1: 'value', plain2: 'value')
197
+ end
186
198
  .to change { subject.logger }.to(%i[plain1 assoc_attributes assoc_plain plain2])
187
199
  end
188
200
 
189
201
  specify do
190
- expect { subject.assign_attributes(plain1: 'value', plain2: 'value', assoc_plain: 'value', assoc_attributes: {}) }
202
+ expect do
203
+ subject.assign_attributes(plain1: 'value', plain2: 'value', assoc_plain: 'value', assoc_attributes: {})
204
+ end
191
205
  .to change { subject.logger }.to(%i[plain1 assoc_attributes assoc_plain plain2])
192
206
  end
193
207
  end
@@ -212,7 +226,7 @@ describe Granite::Form::Model::Attributes do
212
226
 
213
227
  let(:author) { Author.new }
214
228
  let(:model) { Model.new(attributes) }
215
- let(:attributes) { {author: author, name: 'Author Name', full_name: nil, age: 25} }
229
+ let(:attributes) { { author: author, name: 'Author Name', full_name: nil, age: 25 } }
216
230
 
217
231
  it { expect { model.sync_attributes }.to change(author, :name).to('Author Name') }
218
232
 
@@ -226,21 +240,27 @@ describe Granite::Form::Model::Attributes do
226
240
  describe '#inspect' do
227
241
  specify { expect(stub_model.new.inspect).to match(/#<#<Class:0x\w+> \(no attributes\)>/) }
228
242
  specify { expect(stub_model(:user).new.inspect).to match(/#<User \(no attributes\)>/) }
243
+
229
244
  specify do
230
245
  expect(stub_model do
231
246
  include Granite::Form::Model::Primary
232
247
  primary :count, Integer
233
248
  attribute :object, Object
234
- end.new(object: 'String').inspect).to match(/#<#<Class:0x\w+> \*count: nil, object: "String">/) end
249
+ end.new(object: 'String').inspect).to match(/#<#<Class:0x\w+> \*count: nil, object: "String">/)
250
+ end
251
+
235
252
  specify do
236
253
  expect(stub_model(:user) do
237
254
  include Granite::Form::Model::Primary
238
255
  primary :count, Integer
239
256
  attribute :object, Object
240
- end.new.inspect).to match(/#<User \*count: nil, object: nil>/) end
257
+ end.new.inspect).to match(/#<User \*count: nil, object: nil>/)
258
+ end
241
259
  end
242
260
 
243
261
  context 'attributes integration' do
262
+ subject { model.new('world') }
263
+
244
264
  let(:model) do
245
265
  stub_class do
246
266
  include Granite::Form::Util
@@ -257,9 +277,10 @@ describe Granite::Form::Model::Attributes do
257
277
  attribute :enum_with_default, Integer, enum: [1, 2, 3], default: '2'
258
278
  attribute :foo, Boolean, default: false
259
279
  collection :array, Integer, enum: [1, 2, 3], default: [2], normalizer: ->(v) { v.uniq }
260
- dictionary :dict, Integer, keys: %w[from to], enum: [1, 2, 3], default: {from: 1}, normalizer: proc { |v|
280
+ dictionary :dict, Integer, keys: %w[from to], enum: [1, 2, 3], default: { from: 1 }, normalizer: proc { |v|
261
281
  next v if v[:from].nil? || v[:to].nil? || v[:from] <= v[:to]
262
- {from: v[:to], to: v[:from]}.with_indifferent_access
282
+
283
+ { from: v[:to], to: v[:from] }.with_indifferent_access
263
284
  }
264
285
 
265
286
  def initialize(name = nil)
@@ -269,21 +290,19 @@ describe Granite::Form::Model::Attributes do
269
290
  end
270
291
  end
271
292
 
272
- subject { model.new('world') }
273
-
274
- its(:enum_values) { should == [1, 2, 3] }
275
- its(:string_default) { should == 'world' }
276
- its(:count_default) { should == '10' }
277
- its(:name) { should == 'world' }
278
- its(:hello) { should eq(nil) }
279
- its(:hello?) { should eq(false) }
280
- its(:count) { should == 10 }
281
- its(:count_before_type_cast) { should == '10' }
282
- its(:count_came_from_user?) { should eq(false) }
283
- its(:count?) { should eq(true) }
284
- its(:calc) { should == 5 }
285
- its(:enum?) { should eq(false) }
286
- its(:enum_with_default?) { should eq(true) }
293
+ its(:enum_values) { is_expected.to eq [1, 2, 3] }
294
+ its(:string_default) { is_expected.to eq 'world' }
295
+ its(:count_default) { is_expected.to eq '10' }
296
+ its(:name) { is_expected.to eq 'world' }
297
+ its(:hello) { is_expected.to eq(nil) }
298
+ its(:hello?) { is_expected.to eq(false) }
299
+ its(:count) { is_expected.to eq 10 }
300
+ its(:count_before_type_cast) { is_expected.to eq '10' }
301
+ its(:count_came_from_user?) { is_expected.to eq(false) }
302
+ its(:count?) { is_expected.to eq(true) }
303
+ its(:calc) { is_expected.to eq 5 }
304
+ its(:enum?) { is_expected.to eq(false) }
305
+ its(:enum_with_default?) { is_expected.to eq(true) }
287
306
  specify { expect { subject.hello = 'worlds' }.to change { subject.hello }.from(nil).to('worlds') }
288
307
  specify { expect { subject.count = 20 }.to change { subject.count }.from(10).to(20) }
289
308
  specify { expect { subject.calc = 15 }.to change { subject.calc }.from(5).to(15) }
@@ -294,22 +313,27 @@ describe Granite::Form::Model::Attributes do
294
313
  subject.enum = 3
295
314
  expect(subject.enum).to eq(3)
296
315
  end
316
+
297
317
  specify do
298
318
  subject.enum = '3'
299
319
  expect(subject.enum).to eq(3)
300
320
  end
321
+
301
322
  specify do
302
323
  subject.enum = 10
303
324
  expect(subject.enum).to eq(nil)
304
325
  end
326
+
305
327
  specify do
306
328
  subject.enum = 'hello'
307
329
  expect(subject.enum).to eq(nil)
308
330
  end
331
+
309
332
  specify do
310
333
  subject.enum_with_default = 3
311
334
  expect(subject.enum_with_default).to eq(3)
312
335
  end
336
+
313
337
  specify do
314
338
  subject.enum_with_default = 10
315
339
  expect(subject.enum_with_default).to be_nil
@@ -349,21 +373,37 @@ describe Granite::Form::Model::Attributes do
349
373
 
350
374
  specify do
351
375
  expect(subject).to have_attributes(
352
- dict: {from: 1},
353
- dict_before_type_cast: {from: 1},
376
+ dict: { from: 1 },
377
+ dict_before_type_cast: { from: 1 },
354
378
  dict?: true,
355
- dict_default: {from: 1},
379
+ dict_default: { from: 1 },
356
380
  dict_values: [1, 2, 3]
357
381
  )
358
382
  end
359
383
 
360
- specify { with_assigned_value(nil).to have_attributes(dict: {'from' => 1}, dict_before_type_cast: {from: 1}) }
384
+ specify { with_assigned_value(nil).to have_attributes(dict: { 'from' => 1 }, dict_before_type_cast: { from: 1 }) }
361
385
  specify { with_assigned_value([nil]).to have_attributes(dict: {}, dict_before_type_cast: [nil]) }
362
386
  specify { with_assigned_value(1).to have_attributes(dict: {}, dict_before_type_cast: 1) }
363
- specify { with_assigned_value(from: 1, to: 2).to have_attributes(dict: {'from' => 1, 'to' => 2}, dict_before_type_cast: {from: 1, to: 2}) }
364
- specify { with_assigned_value(from: 2, to: 4).to have_attributes(dict: {'from' => 2, 'to' => nil}, dict_before_type_cast: {from: 2, to: 4}) }
365
- specify { with_assigned_value(from: '1', to: '2').to have_attributes(dict: {'from' => 1, 'to' => 2}, dict_before_type_cast: {from: '1', to: '2'}) }
366
- specify { with_assigned_value(from: 3, to: 1).to have_attributes(dict: {'from' => 1, 'to' => 3}, dict_before_type_cast: {from: 3, to: 1}) }
387
+
388
+ specify do
389
+ with_assigned_value(from: 1, to: 2)
390
+ .to have_attributes(dict: { 'from' => 1, 'to' => 2 }, dict_before_type_cast: { from: 1, to: 2 })
391
+ end
392
+
393
+ specify do
394
+ with_assigned_value(from: 2, to: 4)
395
+ .to have_attributes(dict: { 'from' => 2, 'to' => nil }, dict_before_type_cast: { from: 2, to: 4 })
396
+ end
397
+
398
+ specify do
399
+ with_assigned_value(from: '1', to: '2')
400
+ .to have_attributes(dict: { 'from' => 1, 'to' => 2 }, dict_before_type_cast: { from: '1', to: '2' })
401
+ end
402
+
403
+ specify do
404
+ with_assigned_value(from: 3, to: 1)
405
+ .to have_attributes(dict: { 'from' => 1, 'to' => 3 }, dict_before_type_cast: { from: 3, to: 1 })
406
+ end
367
407
  end
368
408
 
369
409
  context 'attribute caching' do
@@ -45,16 +45,19 @@ describe Granite::Form::Model::Dirty do
45
45
  .tap { |m| m.update(author_id: author.id) }.changes)
46
46
  .to eq('author_id' => [other_author.id, author.id])
47
47
  end
48
+
48
49
  specify do
49
50
  expect(Model.instantiate(author_id: other_author.id)
50
51
  .tap { |m| m.update(author: author) }.changes)
51
52
  .to eq('author_id' => [other_author.id, author.id])
52
53
  end
54
+
53
55
  specify do
54
56
  expect(Model.instantiate(author_ids: [other_author.id])
55
57
  .tap { |m| m.update(author_ids: [author.id]) }.changes)
56
58
  .to eq('author_ids' => [[other_author.id], [author.id]])
57
59
  end
60
+
58
61
  specify do
59
62
  expect(Model.instantiate(author_ids: [other_author.id])
60
63
  .tap { |m| m.update(authors: [author]) }.changes)
@@ -19,7 +19,7 @@ describe Granite::Form::Model::Persistence do
19
19
  context do
20
20
  subject(:instance) { model.instantiate(name: 'Hello', foo: 'Bar') }
21
21
 
22
- specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
22
+ specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys) }
23
23
  end
24
24
  end
25
25
 
@@ -28,17 +28,27 @@ describe Granite::Form::Model::Persistence do
28
28
  subject(:instances) { model.instantiate_collection(name: 'Hello', foo: 'Bar') }
29
29
 
30
30
  specify { expect(subject).to be_a Array }
31
- specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
31
+
32
+ specify do
33
+ expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys)
34
+ end
32
35
  end
33
36
 
34
37
  context do
38
+ subject(:instances) { model.instantiate_collection([{ name: 'Hello', foo: 'Bar' }, { name: 'World' }]) }
39
+
35
40
  before { model.send(:include, Granite::Form::Model::Scopes) }
36
- subject(:instances) { model.instantiate_collection([{name: 'Hello', foo: 'Bar'}, {name: 'World'}]) }
37
41
 
38
42
  specify { expect(subject).to be_a Granite::Form::Model::Scopes::ScopeProxy }
39
43
  specify { expect(subject.count).to eq(2) }
40
- specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
41
- specify { expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({name: 'World'}.stringify_keys) }
44
+
45
+ specify do
46
+ expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({ name: 'Hello' }.stringify_keys)
47
+ end
48
+
49
+ specify do
50
+ expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({ name: 'World' }.stringify_keys)
51
+ end
42
52
  end
43
53
  end
44
54
  end
@@ -18,6 +18,7 @@ describe Granite::Form::Model::Primary do
18
18
 
19
19
  context do
20
20
  let(:object) { model.new(name: 'Hello') }
21
+
21
22
  specify { expect(object).not_to eq(object.clone.tap { |o| o.update(name: 'World') }) }
22
23
  specify { expect(object).not_to eql(object.clone.tap { |o| o.update(name: 'World') }) }
23
24
  end
@@ -43,6 +44,7 @@ describe Granite::Form::Model::Primary do
43
44
 
44
45
  context do
45
46
  let(:object) { model.new(name: 'Hello') }
47
+
46
48
  specify { expect(object).to eq(object.clone.tap { |o| o.update(name: 'World') }) }
47
49
  specify { expect(object).to eql(object.clone.tap { |o| o.update(name: 'World') }) }
48
50
  end
@@ -63,20 +65,33 @@ describe Granite::Form::Model::Primary do
63
65
  specify { expect(model.new.primary_attribute).to be_nil }
64
66
  specify { expect(model.new(name: 'Hello')).not_to eq(model.new(name: 'Hello')) }
65
67
  specify { expect(model.new(name: 'Hello')).not_to eql(model.new(name: 'Hello')) }
66
- specify { expect(model.new(name: 'Hello').tap { |o| o.id = 1 }).not_to eq(model.new(name: 'Hello').tap { |o| o.id = 2 }) }
67
- specify { expect(model.new(name: 'Hello').tap { |o| o.id = 1 }).not_to eql(model.new(name: 'Hello').tap { |o| o.id = 2 }) }
68
+
69
+ specify do
70
+ expect(model.new(name: 'Hello').tap { |o| o.id = 1 }).not_to eq(model.new(name: 'Hello').tap do |o|
71
+ o.id = 2
72
+ end)
73
+ end
74
+
75
+ specify do
76
+ expect(model.new(name: 'Hello').tap { |o| o.id = 1 }).not_to eql(model.new(name: 'Hello').tap do |o|
77
+ o.id = 2
78
+ end)
79
+ end
80
+
68
81
  specify { expect(model.new(id: 1).id).to be_nil }
69
82
  specify { expect(model.new.tap { |o| o.assign_attributes(id: 1) }.id).to be_nil }
70
83
  specify { expect(model.new.tap { |o| o.id = 1 }.id).to eq(1) }
71
84
 
72
85
  context do
73
86
  let(:object) { model.new(name: 'Hello').tap { |o| o.id = 1 } }
87
+
74
88
  specify { expect(object).to eq(object.clone.tap { |o| o.update(name: 'World') }) }
75
89
  specify { expect(object).to eql(object.clone.tap { |o| o.update(name: 'World') }) }
76
90
  end
77
91
 
78
92
  context do
79
93
  let(:object) { model.new(name: 'Hello') }
94
+
80
95
  specify { expect(object).to eq(object) }
81
96
  specify { expect(object).to eql(object) }
82
97
  end
@@ -11,12 +11,16 @@ describe Granite::Form::Model::Representation do
11
11
  include Granite::Form::Model::Representation
12
12
 
13
13
  attribute :author, Object
14
+ attribute :foo_container, Object
14
15
  alias_attribute :a, :author
15
16
  represents :rate, of: :a
17
+ represents :foos, of: :foo_container
16
18
  alias_attribute :r, :rate
17
19
  end
18
20
  end
21
+
19
22
  let(:author) { Author.new(rate: '42') }
23
+ let(:foos) { %w[foo bar] }
20
24
 
21
25
  specify { expect(Post.reflect_on_attribute(:rate).reference).to eq('author') }
22
26
 
@@ -30,8 +34,13 @@ describe Granite::Form::Model::Representation do
30
34
  specify { expect(Post.new.rate).to be_nil }
31
35
  specify { expect(Post.new.rate_before_type_cast).to be_nil }
32
36
 
37
+ if ActiveModel.version >= Gem::Version.new('7.0.0')
38
+ specify { expect { Post.new(foo_container: FooContainer.new, foos: foos) }.not_to raise_exception }
39
+ end
40
+
33
41
  context 'ActionController::Parameters' do
34
- let(:params) { instance_double('ActionController::Parameters', to_unsafe_hash: {rate: '33', author: author}) }
42
+ let(:params) { instance_double('ActionController::Parameters', to_unsafe_hash: { rate: '33', author: author }) }
43
+
35
44
  specify { expect { Post.new(params) }.not_to raise_error }
36
45
  end
37
46
 
@@ -64,6 +73,7 @@ describe Granite::Form::Model::Representation do
64
73
  represents :name, of: :a
65
74
  end
66
75
  end
76
+
67
77
  let!(:author) { Author.create!(name: 42) }
68
78
 
69
79
  specify { expect(Post.reflect_on_attribute(:name).reference).to eq('author') }
@@ -129,13 +139,13 @@ describe Granite::Form::Model::Representation do
129
139
  if ActiveModel.version >= Gem::Version.new('6.1.0')
130
140
  specify do
131
141
  expect { post.validate }.to change { post.errors.details }
132
- .to('author.user.email': [{error: 'is invalid'}], name: [{error: :blank}])
142
+ .to('author.user.email': [{ error: 'is invalid' }], name: [{ error: :blank }])
133
143
  end
134
144
  end
135
145
 
136
146
  context 'when using symbol in error message of represented model' do
137
147
  before do
138
- Author.validates :name, inclusion: {in: ['Author'], message: :invalid_name, allow_blank: true}
148
+ Author.validates :name, inclusion: { in: ['Author'], message: :invalid_name, allow_blank: true }
139
149
  post.author.name = 'Not Author'
140
150
  end
141
151
 
@@ -9,14 +9,14 @@ describe Granite::Form::Model::Scopes do
9
9
 
10
10
  class << self
11
11
  def except_first
12
- scope[1..-1]
12
+ scope[1..]
13
13
  end
14
14
 
15
15
  def no_mars
16
16
  scope.delete_if { |i| i.name == 'Mars' }
17
17
  end
18
18
 
19
- private
19
+ private
20
20
 
21
21
  def hidden_method() end
22
22
  end
@@ -45,7 +45,12 @@ describe Granite::Form::Model::Scopes do
45
45
  let(:scope) { model.scope([model.new(name: 'Hello'), model.new(name: 'World'), model.new(name: 'Mars')]) }
46
46
 
47
47
  specify { expect(scope).to be_instance_of model.scope_class }
48
- specify { expect { model.scope([model.new(name: 'Hello'), {}]) }.to raise_error Granite::Form::AssociationTypeMismatch }
48
+
49
+ specify do
50
+ expect do
51
+ model.scope([model.new(name: 'Hello'), {}])
52
+ end.to raise_error Granite::Form::AssociationTypeMismatch
53
+ end
49
54
 
50
55
  context 'scopes' do
51
56
  specify { expect(scope.except_first).to be_instance_of model.scope_class }
@@ -33,13 +33,16 @@ describe Granite::Form::Model::Validations::AssociatedValidator do
33
33
  end
34
34
 
35
35
  context do
36
- subject(:instance) { Main.instantiate name: 'hello', validated_one: {name: 'name'} }
36
+ subject(:instance) { Main.instantiate name: 'hello', validated_one: { name: 'name' } }
37
+
37
38
  it { is_expected.to be_valid }
38
39
  end
39
40
 
40
41
  context do
41
42
  subject(:instance) { Main.instantiate name: 'hello', validated_one: {} }
43
+
42
44
  it { is_expected.not_to be_valid }
45
+
43
46
  specify do
44
47
  expect { instance.validate }.to change { instance.errors.messages }
45
48
  .to(validated_one: ['is invalid'])
@@ -47,23 +50,28 @@ describe Granite::Form::Model::Validations::AssociatedValidator do
47
50
  end
48
51
 
49
52
  context do
50
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {name: 'name'} }
53
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: { name: 'name' } }
54
+
51
55
  it { is_expected.to be_valid }
52
56
  end
53
57
 
54
58
  context do
55
59
  subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {} }
60
+
56
61
  it { is_expected.to be_valid }
57
62
  end
58
63
 
59
64
  context do
60
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}] }
65
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }] }
66
+
61
67
  it { is_expected.to be_valid }
62
68
  end
63
69
 
64
70
  context do
65
71
  subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}] }
72
+
66
73
  it { is_expected.not_to be_valid }
74
+
67
75
  specify do
68
76
  expect { instance.validate }.to change { instance.errors.messages }
69
77
  .to('validated_many.0.name': ["can't be blank"], validated_many: ['is invalid'])
@@ -71,18 +79,22 @@ describe Granite::Form::Model::Validations::AssociatedValidator do
71
79
  end
72
80
 
73
81
  context do
74
- subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{name: 'name'}] }
82
+ subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{ name: 'name' }] }
83
+
75
84
  it { is_expected.to be_valid }
76
85
  end
77
86
 
78
87
  context do
79
88
  subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{}] }
89
+
80
90
  it { is_expected.to be_valid }
81
91
  end
82
92
 
83
93
  context do
84
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}], validated_one: {} }
94
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{ name: 'name' }], validated_one: {} }
95
+
85
96
  it { is_expected.not_to be_valid }
97
+
86
98
  specify do
87
99
  expect { instance.validate }.to change { instance.errors.messages }
88
100
  .to(validated_one: ['is invalid'])
@@ -90,8 +102,10 @@ describe Granite::Form::Model::Validations::AssociatedValidator do
90
102
  end
91
103
 
92
104
  context do
93
- subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: {name: 'name'} }
105
+ subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: { name: 'name' } }
106
+
94
107
  it { is_expected.not_to be_valid }
108
+
95
109
  specify do
96
110
  expect { instance.validate }.to change { instance.errors.messages }
97
111
  .to('validated_many.0.name': ["can't be blank"], validated_many: ['is invalid'])