granite-form 0.3.0 → 0.4.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +6 -13
  5. data/lib/granite/form/model/associations/nested_attributes.rb +2 -2
  6. data/lib/granite/form/model/associations/reflections/embeds_many.rb +1 -1
  7. data/lib/granite/form/model/associations/reflections/embeds_one.rb +11 -1
  8. data/lib/granite/form/model/associations/reflections/references_one.rb +2 -0
  9. data/lib/granite/form/model/associations/reflections/singular.rb +0 -14
  10. data/lib/granite/form/model/attributes/attribute.rb +3 -21
  11. data/lib/granite/form/model/attributes/base.rb +5 -23
  12. data/lib/granite/form/model/attributes/reference_many.rb +1 -1
  13. data/lib/granite/form/model/attributes/reference_one.rb +1 -1
  14. data/lib/granite/form/model/attributes/reflections/attribute.rb +4 -4
  15. data/lib/granite/form/model/attributes/reflections/base/build_type_definition.rb +38 -0
  16. data/lib/granite/form/model/attributes/reflections/base.rb +12 -10
  17. data/lib/granite/form/model/attributes/reflections/collection/build_type_definition.rb +19 -0
  18. data/lib/granite/form/model/attributes/reflections/dictionary/build_type_definition.rb +19 -0
  19. data/lib/granite/form/model/attributes/reflections/dictionary.rb +0 -3
  20. data/lib/granite/form/model/attributes/reflections/represents/build_type_definition.rb +73 -0
  21. data/lib/granite/form/model/attributes/reflections/represents.rb +10 -2
  22. data/lib/granite/form/model/attributes/represents.rb +22 -37
  23. data/lib/granite/form/model/attributes.rb +10 -2
  24. data/lib/granite/form/model/representation.rb +1 -0
  25. data/lib/granite/form/model/validations.rb +6 -0
  26. data/lib/granite/form/model.rb +1 -1
  27. data/lib/granite/form/types/active_support/time_zone.rb +2 -0
  28. data/lib/granite/form/types/array.rb +2 -0
  29. data/lib/granite/form/types/big_decimal.rb +2 -0
  30. data/lib/granite/form/types/boolean.rb +2 -0
  31. data/lib/granite/form/types/collection.rb +11 -0
  32. data/lib/granite/form/types/date.rb +2 -0
  33. data/lib/granite/form/types/date_time.rb +2 -0
  34. data/lib/granite/form/types/dictionary.rb +23 -0
  35. data/lib/granite/form/types/float.rb +2 -0
  36. data/lib/granite/form/types/has_subtype.rb +18 -0
  37. data/lib/granite/form/types/hash_with_action_controller_parameters.rb +2 -0
  38. data/lib/granite/form/types/integer.rb +2 -0
  39. data/lib/granite/form/types/object.rb +28 -0
  40. data/lib/granite/form/types/string.rb +2 -0
  41. data/lib/granite/form/types/time.rb +2 -0
  42. data/lib/granite/form/types/uuid.rb +2 -0
  43. data/lib/granite/form/types.rb +3 -0
  44. data/lib/granite/form/util.rb +55 -0
  45. data/lib/granite/form/version.rb +1 -1
  46. data/lib/granite/form.rb +1 -0
  47. data/spec/granite/form/model/associations/references_many_spec.rb +1 -1
  48. data/spec/granite/form/model/associations/references_one_spec.rb +4 -4
  49. data/spec/granite/form/model/attributes/attribute_spec.rb +0 -29
  50. data/spec/granite/form/model/attributes/reflections/attribute_spec.rb +0 -9
  51. data/spec/granite/form/model/attributes/reflections/base/build_type_definition_spec.rb +27 -0
  52. data/spec/granite/form/model/attributes/reflections/base_spec.rb +16 -10
  53. data/spec/granite/form/model/attributes/reflections/collection/build_type_definition_spec.rb +24 -0
  54. data/spec/granite/form/model/attributes/reflections/dictionary/build_type_definition_spec.rb +24 -0
  55. data/spec/granite/form/model/attributes/reflections/dictionary_spec.rb +0 -6
  56. data/spec/granite/form/model/attributes/reflections/represents/build_type_definition_spec.rb +129 -0
  57. data/spec/granite/form/model/attributes/reflections/represents_spec.rb +43 -20
  58. data/spec/granite/form/model/attributes/represents_spec.rb +78 -55
  59. data/spec/granite/form/model/attributes_spec.rb +84 -23
  60. data/spec/granite/form/model/dirty_spec.rb +0 -6
  61. data/spec/granite/form/model/representation_spec.rb +4 -7
  62. data/spec/granite/form/model/validations_spec.rb +28 -1
  63. data/spec/granite/form/types/collection_spec.rb +22 -0
  64. data/spec/granite/form/types/dictionary_spec.rb +32 -0
  65. data/spec/granite/form/types/has_subtype_spec.rb +20 -0
  66. data/spec/granite/form/types/object_spec.rb +50 -4
  67. data/spec/granite/form/util_spec.rb +108 -0
  68. data/spec/support/active_record.rb +3 -0
  69. metadata +26 -15
  70. data/lib/granite/form/model/attributes/collection.rb +0 -19
  71. data/lib/granite/form/model/attributes/dictionary.rb +0 -28
  72. data/lib/granite/form/model/attributes/localized.rb +0 -44
  73. data/lib/granite/form/model/attributes/reflections/localized.rb +0 -45
  74. data/lib/granite/form/model/localization.rb +0 -26
  75. data/spec/granite/form/model/attributes/collection_spec.rb +0 -72
  76. data/spec/granite/form/model/attributes/dictionary_spec.rb +0 -100
  77. data/spec/granite/form/model/attributes/localized_spec.rb +0 -103
  78. data/spec/granite/form/model/attributes/reflections/localized_spec.rb +0 -37
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Granite::Form::Types::Collection do
4
+ subject(:type) { described_class.new(subtype_definition) }
5
+ let(:element_type) { Dummy }
6
+ let(:subtype_definition) { Granite::Form::Types::Object.new(element_type, reflection, nil) }
7
+ let(:reflection) { Granite::Form::Model::Attributes::Reflections::Base.new(:field) }
8
+ let(:dummy_object) { Dummy.new }
9
+
10
+ before { stub_class :dummy }
11
+
12
+ describe '#prepare' do
13
+ specify { expect(subject.prepare([dummy_object, Object.new])).to eq([dummy_object, nil]) }
14
+ specify { expect(subject.prepare(dummy_object)).to eq([dummy_object]) }
15
+
16
+ context 'with Hash collection' do
17
+ let(:element_type) { Hash }
18
+
19
+ specify { expect(subject.prepare([{key: 'value'}])).to eq([{key: 'value'}]) }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Granite::Form::Types::Dictionary do
6
+ subject(:type) { described_class.new(subtype_definition) }
7
+ let(:element_type) { Dummy }
8
+ let(:subtype_definition) { Granite::Form::Types::Object.new(element_type, reflection, nil) }
9
+ let(:reflection) { build_reflection }
10
+ let(:dummy) { Dummy.new }
11
+ let(:dummy2) { Dummy.new }
12
+
13
+ def build_reflection(**options)
14
+ Granite::Form::Model::Attributes::Reflections::Dictionary.new(:field, options)
15
+ end
16
+
17
+ before { stub_class :dummy }
18
+
19
+ describe '#prepare' do
20
+ specify { expect(subject.prepare(one: dummy, two: Object.new)).to eq('one' => dummy, 'two' => nil) }
21
+ specify { expect(subject.prepare(three: dummy)).to eq('three' => dummy) }
22
+ specify { expect(subject.prepare([['one', dummy]])).to eq('one' => dummy) }
23
+ specify { expect(subject.prepare(nil)).to eq({}) }
24
+
25
+ context 'when keys are set' do
26
+ let(:reflection) { build_reflection keys: %w[one two] }
27
+
28
+ specify { expect(subject.prepare(three: dummy)).to eq({}) }
29
+ specify { expect(subject.prepare(nil)).to eq({}) }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Granite::Form::Types::HasSubtype do
6
+ subject(:type) { described_class.new(subtype_definition) }
7
+ let(:subtype_definition) { Granite::Form::Types::Object.new(Dummy, reflection, nil) }
8
+ let(:reflection) { Granite::Form::Model::Attributes::Reflections::Base.new(:field) }
9
+ let(:dummy_object) { Dummy.new }
10
+
11
+ before { stub_class :dummy }
12
+
13
+ describe '#build_duplicate' do
14
+ subject { type.build_duplicate(new_reflection, new_model) }
15
+ let(:new_model) { double('new_model') }
16
+ let(:new_reflection) { double('new_reflection') }
17
+
18
+ it { is_expected.to have_attributes(subtype_definition: have_attributes(type: Dummy, reflection: new_reflection, owner: new_model)) }
19
+ end
20
+ end
@@ -3,12 +3,32 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Granite::Form::Types::Object do
6
- subject(:type) { described_class.new(String, reflection, model.new) }
7
- let(:model) { stub_model }
8
- let(:reflection) { Granite::Form::Model::Attributes::Reflections::Base.new(:field) }
6
+ subject(:type) { build_type(reflection: reflection) }
7
+ let(:model) { Model.new }
8
+ let(:reflection) { build_reflection }
9
+
10
+ before do
11
+ stub_model :model
12
+ end
13
+
14
+ def build_reflection(name: :field, **options)
15
+ Granite::Form::Model::Attributes::Reflections::Base.new(name, options)
16
+ end
17
+
18
+ def build_type(type: String, reflection: nil, **options)
19
+ described_class.new(type, reflection || build_reflection(**options), model)
20
+ end
9
21
 
10
22
  describe '#initialize' do
11
- it { is_expected.to have_attributes(type: String, reflection: reflection, owner: an_instance_of(model)) }
23
+ it { is_expected.to have_attributes(type: String, reflection: reflection, owner: model) }
24
+ end
25
+
26
+ describe '#build_duplicate' do
27
+ subject { type.build_duplicate(new_reflection, new_model) }
28
+ let(:new_model) { double('new_model') }
29
+ let(:new_reflection) { Granite::Form::Model::Attributes::Reflections::Base.new(:new_field) }
30
+
31
+ it { is_expected.to have_attributes(type: String, reflection: new_reflection, owner: new_model) }
12
32
  end
13
33
 
14
34
  describe 'typecasting' do
@@ -37,4 +57,30 @@ RSpec.describe Granite::Form::Types::Object do
37
57
  specify { expect(typecast(nil)).to be_nil }
38
58
  end
39
59
  end
60
+
61
+ describe '#enum' do
62
+ before { allow(model).to receive_messages(value: 1..5) }
63
+
64
+ specify { expect(build_type.enum).to eq([].to_set) }
65
+ specify { expect(build_type(enum: []).enum).to eq([].to_set) }
66
+ specify { expect(build_type(enum: 'hello').enum).to eq(['hello'].to_set) }
67
+ specify { expect(build_type(enum: %w[hello world]).enum).to eq(%w[hello world].to_set) }
68
+ specify { expect(build_type(enum: [1..5]).enum).to eq([1..5].to_set) }
69
+ specify { expect(build_type(enum: 1..5).enum).to eq((1..5).to_a.to_set) }
70
+ specify { expect(build_type(enum: -> { 1..5 }).enum).to eq((1..5).to_a.to_set) }
71
+ specify { expect(build_type(enum: -> { 'hello' }).enum).to eq(['hello'].to_set) }
72
+ specify { expect(build_type(enum: -> { ['hello', 42] }).enum).to eq(['hello', 42].to_set) }
73
+ specify { expect(build_type(enum: -> { value }).enum).to eq((1..5).to_a.to_set) }
74
+ end
75
+
76
+ describe '#prepare' do
77
+ specify { expect(build_type.prepare('anything')).to eq('anything') }
78
+ specify { expect(build_type(enum: %w[hello 42]).prepare('hello')).to eq('hello') }
79
+ specify { expect(build_type(enum: %w[hello 42]).prepare('world')).to eq(nil) }
80
+ specify { expect(build_type(enum: %w[hello 42]).prepare('42')).to eq('42') }
81
+ specify { expect(build_type(enum: %w[hello 42]).prepare(42)).to eq(nil) }
82
+ specify { expect(build_type(enum: -> { 'hello' }).prepare('hello')).to eq('hello') }
83
+ specify { expect(build_type(type: Integer, enum: -> { 1..5 }).prepare(2)).to eq(2) }
84
+ specify { expect(build_type(type: Integer, enum: -> { 1..5 }).prepare(42)).to eq(nil) }
85
+ end
40
86
  end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Granite::Form::Util do
4
+ subject(:dummy) { Dummy.new('John') }
5
+
6
+ before do
7
+ stub_class(:dummy, Object) do
8
+ attr_accessor :name
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ end
13
+
14
+ def full_name(last_name)
15
+ [name, last_name].join(' ')
16
+ end
17
+ end
18
+
19
+ Dummy.include described_class
20
+ end
21
+
22
+ describe '#evaluate' do
23
+ subject { dummy.evaluate(target) }
24
+ let(:target) { 'Peter' }
25
+
26
+ it { is_expected.to eq('Peter') }
27
+
28
+ context 'when symbol is passed' do
29
+ let(:target) { :name }
30
+
31
+ it { is_expected.to eq('John') }
32
+ end
33
+
34
+ context 'when lambda is passed' do
35
+ let(:target) { -> { name } }
36
+
37
+ it { is_expected.to eq('John') }
38
+ end
39
+
40
+ context 'with extra arguments' do
41
+ subject { dummy.evaluate(target, 'Doe') }
42
+
43
+ context 'when symbol is passed' do
44
+ let(:target) { :full_name }
45
+
46
+ it { is_expected.to eq('John Doe') }
47
+ end
48
+
49
+ context 'when lambda is passed' do
50
+ let(:target) { ->(last_name) { ['John', last_name].join(' ') } }
51
+
52
+ it { is_expected.to eq('John Doe') }
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#evaluate_if_proc' do
58
+ subject { dummy.evaluate(target) }
59
+ let(:target) { 'Peter' }
60
+
61
+ it { is_expected.to eq('Peter') }
62
+
63
+ context 'when lambda is passed' do
64
+ let(:target) { -> { name } }
65
+
66
+ it { is_expected.to eq('John') }
67
+ end
68
+
69
+ context 'with extra arguments' do
70
+ subject { dummy.evaluate(target, 'Doe') }
71
+
72
+ let(:target) { ->(last_name) { ['John', last_name].join(' ') } }
73
+
74
+ it { is_expected.to eq('John Doe') }
75
+ end
76
+ end
77
+
78
+ describe '#conditions_satisfied?' do
79
+ subject { dummy.conditions_satisfied?(**conditions) }
80
+ let(:conditions) { {if: -> { name == 'John' }} }
81
+
82
+ it { is_expected.to be_truthy }
83
+
84
+ context 'when if condition is satisfied' do
85
+ before { dummy.name = 'Peter' }
86
+
87
+ it { is_expected.to be_falsey }
88
+ end
89
+
90
+ context 'when unless condition is passed' do
91
+ let(:conditions) { {unless: :name} }
92
+
93
+ it { is_expected.to be_falsey }
94
+ end
95
+
96
+ context 'when no condition is passed' do
97
+ let(:conditions) { {} }
98
+
99
+ it { is_expected.to be_truthy }
100
+ end
101
+
102
+ context 'when both if & unless are passed' do
103
+ let(:conditions) { {if: :name, unless: :name} }
104
+
105
+ it { expect { subject }.to raise_error(ArgumentError) }
106
+ end
107
+ end
108
+ end
@@ -16,5 +16,8 @@ ActiveRecord::Schema.define do
16
16
 
17
17
  create_table :authors, force: :cascade do |t|
18
18
  t.column :name, :string
19
+ t.column :status, :integer
20
+ t.column :related_ids, :integer, array: true
21
+ t.column :data, :text
19
22
  end
20
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: granite-form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toptal Engineering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-22 00:00:00.000000000 Z
11
+ date: 2023-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -268,23 +268,22 @@ files:
268
268
  - lib/granite/form/model/attributes.rb
269
269
  - lib/granite/form/model/attributes/attribute.rb
270
270
  - lib/granite/form/model/attributes/base.rb
271
- - lib/granite/form/model/attributes/collection.rb
272
- - lib/granite/form/model/attributes/dictionary.rb
273
- - lib/granite/form/model/attributes/localized.rb
274
271
  - lib/granite/form/model/attributes/reference_many.rb
275
272
  - lib/granite/form/model/attributes/reference_one.rb
276
273
  - lib/granite/form/model/attributes/reflections/attribute.rb
277
274
  - lib/granite/form/model/attributes/reflections/base.rb
275
+ - lib/granite/form/model/attributes/reflections/base/build_type_definition.rb
278
276
  - lib/granite/form/model/attributes/reflections/collection.rb
277
+ - lib/granite/form/model/attributes/reflections/collection/build_type_definition.rb
279
278
  - lib/granite/form/model/attributes/reflections/dictionary.rb
280
- - lib/granite/form/model/attributes/reflections/localized.rb
279
+ - lib/granite/form/model/attributes/reflections/dictionary/build_type_definition.rb
281
280
  - lib/granite/form/model/attributes/reflections/reference_many.rb
282
281
  - lib/granite/form/model/attributes/reflections/reference_one.rb
283
282
  - lib/granite/form/model/attributes/reflections/represents.rb
283
+ - lib/granite/form/model/attributes/reflections/represents/build_type_definition.rb
284
284
  - lib/granite/form/model/attributes/represents.rb
285
285
  - lib/granite/form/model/conventions.rb
286
286
  - lib/granite/form/model/dirty.rb
287
- - lib/granite/form/model/localization.rb
288
287
  - lib/granite/form/model/persistence.rb
289
288
  - lib/granite/form/model/primary.rb
290
289
  - lib/granite/form/model/representation.rb
@@ -298,9 +297,12 @@ files:
298
297
  - lib/granite/form/types/array.rb
299
298
  - lib/granite/form/types/big_decimal.rb
300
299
  - lib/granite/form/types/boolean.rb
300
+ - lib/granite/form/types/collection.rb
301
301
  - lib/granite/form/types/date.rb
302
302
  - lib/granite/form/types/date_time.rb
303
+ - lib/granite/form/types/dictionary.rb
303
304
  - lib/granite/form/types/float.rb
305
+ - lib/granite/form/types/has_subtype.rb
304
306
  - lib/granite/form/types/hash_with_action_controller_parameters.rb
305
307
  - lib/granite/form/types/integer.rb
306
308
  - lib/granite/form/types/object.rb
@@ -308,6 +310,7 @@ files:
308
310
  - lib/granite/form/types/time.rb
309
311
  - lib/granite/form/types/uuid.rb
310
312
  - lib/granite/form/undefined_class.rb
313
+ - lib/granite/form/util.rb
311
314
  - lib/granite/form/version.rb
312
315
  - spec/granite/form/active_record/associations_spec.rb
313
316
  - spec/granite/form/active_record/nested_attributes_spec.rb
@@ -328,14 +331,14 @@ files:
328
331
  - spec/granite/form/model/associations_spec.rb
329
332
  - spec/granite/form/model/attributes/attribute_spec.rb
330
333
  - spec/granite/form/model/attributes/base_spec.rb
331
- - spec/granite/form/model/attributes/collection_spec.rb
332
- - spec/granite/form/model/attributes/dictionary_spec.rb
333
- - spec/granite/form/model/attributes/localized_spec.rb
334
334
  - spec/granite/form/model/attributes/reflections/attribute_spec.rb
335
+ - spec/granite/form/model/attributes/reflections/base/build_type_definition_spec.rb
335
336
  - spec/granite/form/model/attributes/reflections/base_spec.rb
337
+ - spec/granite/form/model/attributes/reflections/collection/build_type_definition_spec.rb
336
338
  - spec/granite/form/model/attributes/reflections/collection_spec.rb
339
+ - spec/granite/form/model/attributes/reflections/dictionary/build_type_definition_spec.rb
337
340
  - spec/granite/form/model/attributes/reflections/dictionary_spec.rb
338
- - spec/granite/form/model/attributes/reflections/localized_spec.rb
341
+ - spec/granite/form/model/attributes/reflections/represents/build_type_definition_spec.rb
339
342
  - spec/granite/form/model/attributes/reflections/represents_spec.rb
340
343
  - spec/granite/form/model/attributes/represents_spec.rb
341
344
  - spec/granite/form/model/attributes_spec.rb
@@ -353,15 +356,19 @@ files:
353
356
  - spec/granite/form/types/array_spec.rb
354
357
  - spec/granite/form/types/big_decimal_spec.rb
355
358
  - spec/granite/form/types/boolean_spec.rb
359
+ - spec/granite/form/types/collection_spec.rb
356
360
  - spec/granite/form/types/date_spec.rb
357
361
  - spec/granite/form/types/date_time_spec.rb
362
+ - spec/granite/form/types/dictionary_spec.rb
358
363
  - spec/granite/form/types/float_spec.rb
364
+ - spec/granite/form/types/has_subtype_spec.rb
359
365
  - spec/granite/form/types/hash_with_action_controller_parameters_spec.rb
360
366
  - spec/granite/form/types/integer_spec.rb
361
367
  - spec/granite/form/types/object_spec.rb
362
368
  - spec/granite/form/types/string_spec.rb
363
369
  - spec/granite/form/types/time_spec.rb
364
370
  - spec/granite/form/types/uuid_spec.rb
371
+ - spec/granite/form/util_spec.rb
365
372
  - spec/granite/form_spec.rb
366
373
  - spec/spec_helper.rb
367
374
  - spec/support/active_record.rb
@@ -412,14 +419,14 @@ test_files:
412
419
  - spec/granite/form/model/associations_spec.rb
413
420
  - spec/granite/form/model/attributes/attribute_spec.rb
414
421
  - spec/granite/form/model/attributes/base_spec.rb
415
- - spec/granite/form/model/attributes/collection_spec.rb
416
- - spec/granite/form/model/attributes/dictionary_spec.rb
417
- - spec/granite/form/model/attributes/localized_spec.rb
418
422
  - spec/granite/form/model/attributes/reflections/attribute_spec.rb
423
+ - spec/granite/form/model/attributes/reflections/base/build_type_definition_spec.rb
419
424
  - spec/granite/form/model/attributes/reflections/base_spec.rb
425
+ - spec/granite/form/model/attributes/reflections/collection/build_type_definition_spec.rb
420
426
  - spec/granite/form/model/attributes/reflections/collection_spec.rb
427
+ - spec/granite/form/model/attributes/reflections/dictionary/build_type_definition_spec.rb
421
428
  - spec/granite/form/model/attributes/reflections/dictionary_spec.rb
422
- - spec/granite/form/model/attributes/reflections/localized_spec.rb
429
+ - spec/granite/form/model/attributes/reflections/represents/build_type_definition_spec.rb
423
430
  - spec/granite/form/model/attributes/reflections/represents_spec.rb
424
431
  - spec/granite/form/model/attributes/represents_spec.rb
425
432
  - spec/granite/form/model/attributes_spec.rb
@@ -437,15 +444,19 @@ test_files:
437
444
  - spec/granite/form/types/array_spec.rb
438
445
  - spec/granite/form/types/big_decimal_spec.rb
439
446
  - spec/granite/form/types/boolean_spec.rb
447
+ - spec/granite/form/types/collection_spec.rb
440
448
  - spec/granite/form/types/date_spec.rb
441
449
  - spec/granite/form/types/date_time_spec.rb
450
+ - spec/granite/form/types/dictionary_spec.rb
442
451
  - spec/granite/form/types/float_spec.rb
452
+ - spec/granite/form/types/has_subtype_spec.rb
443
453
  - spec/granite/form/types/hash_with_action_controller_parameters_spec.rb
444
454
  - spec/granite/form/types/integer_spec.rb
445
455
  - spec/granite/form/types/object_spec.rb
446
456
  - spec/granite/form/types/string_spec.rb
447
457
  - spec/granite/form/types/time_spec.rb
448
458
  - spec/granite/form/types/uuid_spec.rb
459
+ - spec/granite/form/util_spec.rb
449
460
  - spec/granite/form_spec.rb
450
461
  - spec/spec_helper.rb
451
462
  - spec/support/active_record.rb
@@ -1,19 +0,0 @@
1
- module Granite
2
- module Form
3
- module Model
4
- module Attributes
5
- class Collection < Attribute
6
- def read
7
- @value ||= normalize(read_before_type_cast.map do |value|
8
- enumerize(type_definition.ensure_type(value))
9
- end)
10
- end
11
-
12
- def read_before_type_cast
13
- @value_before_type_cast ||= Array.wrap(@value_cache).map { |value| defaultize(value) }
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
@@ -1,28 +0,0 @@
1
- module Granite
2
- module Form
3
- module Model
4
- module Attributes
5
- class Dictionary < Attribute
6
- delegate :keys, to: :reflection
7
-
8
- def read
9
- @value ||= begin
10
- hash = read_before_type_cast
11
- hash = hash.stringify_keys.slice(*keys) if keys.present?
12
-
13
- normalize(Hash[hash.map do |key, value|
14
- [key, enumerize(type_definition.ensure_type(value))]
15
- end].with_indifferent_access).with_indifferent_access
16
- end
17
- end
18
-
19
- def read_before_type_cast
20
- @value_before_type_cast ||= Hash[(@value_cache.presence || {}).map do |key, value|
21
- [key, defaultize(value)]
22
- end].with_indifferent_access
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,44 +0,0 @@
1
- module Granite
2
- module Form
3
- module Model
4
- module Attributes
5
- class Localized < Attribute
6
- def read
7
- @value ||= Hash[read_before_type_cast.map do |locale, value|
8
- [locale.to_s, normalize(enumerize(type_definition.ensure_type(value)))]
9
- end]
10
- end
11
-
12
- def read_before_type_cast
13
- @value_before_type_cast ||= Hash[(@value_cache.presence || {}).map do |locale, value|
14
- [locale.to_s, defaultize(value)]
15
- end]
16
- end
17
-
18
- def write_locale(value, locale)
19
- pollute do
20
- write(read.merge(locale.to_s => value))
21
- end
22
- end
23
-
24
- def read_locale(locale)
25
- read[owner.class.fallbacks(locale).detect do |fallback|
26
- read[fallback.to_s]
27
- end.to_s]
28
- end
29
-
30
- def read_locale_before_type_cast(locale)
31
- read_before_type_cast[owner.class.fallbacks(locale).detect do |fallback|
32
- read_before_type_cast[fallback.to_s]
33
- end.to_s]
34
- end
35
-
36
- def locale_query(locale)
37
- value = read_locale(locale)
38
- !(value.respond_to?(:zero?) ? value.zero? : value.blank?)
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,45 +0,0 @@
1
- module Granite
2
- module Form
3
- module Model
4
- module Attributes
5
- module Reflections
6
- class Localized < Attribute
7
- def self.build(target, generated_methods, name, *args, &block)
8
- attribute = super(target, generated_methods, name, *args, &block)
9
- generate_methods name, generated_methods
10
- attribute
11
- end
12
-
13
- def self.generate_methods(name, target)
14
- target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
- def #{name}_translations
16
- attribute('#{name}').read
17
- end
18
-
19
- def #{name}_translations= value
20
- attribute('#{name}').write(value)
21
- end
22
-
23
- def #{name}
24
- attribute('#{name}').read_locale(self.class.locale)
25
- end
26
-
27
- def #{name}= value
28
- attribute('#{name}').write_locale(value, self.class.locale)
29
- end
30
-
31
- def #{name}?
32
- attribute('#{name}').locale_query(self.class.locale)
33
- end
34
-
35
- def #{name}_before_type_cast
36
- attribute('#{name}').read_locale_before_type_cast(self.class.locale)
37
- end
38
- RUBY
39
- end
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,26 +0,0 @@
1
- require 'granite/form/model/attributes/reflections/localized'
2
- require 'granite/form/model/attributes/localized'
3
-
4
- module Granite
5
- module Form
6
- module Model
7
- module Localization
8
- extend ActiveSupport::Concern
9
-
10
- module ClassMethods
11
- def localized(*args, &block)
12
- add_attribute(Granite::Form::Model::Attributes::Reflections::Localized, *args, &block)
13
- end
14
-
15
- def fallbacks(locale)
16
- ::I18n.respond_to?(:fallbacks) ? ::I18n.fallbacks[locale] : [locale]
17
- end
18
-
19
- def locale
20
- I18n.locale
21
- end
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,72 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Attributes::Collection do
4
- before { stub_model(:dummy) }
5
-
6
- def attribute(*args)
7
- options = args.extract_options!
8
- Dummy.add_attribute(Granite::Form::Model::Attributes::Reflections::Collection, :field, options)
9
- Dummy.new.attribute(:field)
10
- end
11
-
12
- describe '#read' do
13
- let(:field) { attribute(type: String, normalizer: ->(v) { v.uniq }, default: :world, enum: %w[hello 42]) }
14
-
15
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq([]) }
16
- specify { expect(field.tap { |r| r.write([nil]) }.read).to eq([nil]) }
17
- specify { expect(field.tap { |r| r.write('hello') }.read).to eq(['hello']) }
18
- specify { expect(field.tap { |r| r.write([42]) }.read).to eq(['42']) }
19
- specify { expect(field.tap { |r| r.write([43]) }.read).to eq([nil]) }
20
- specify { expect(field.tap { |r| r.write([43, 44]) }.read).to eq([nil]) }
21
- specify { expect(field.tap { |r| r.write(['']) }.read).to eq([nil]) }
22
- specify { expect(field.tap { |r| r.write(['hello', 42]) }.read).to eq(%w[hello 42]) }
23
- specify { expect(field.tap { |r| r.write(['hello', false]) }.read).to eq(['hello', nil]) }
24
-
25
- context do
26
- let(:field) { attribute(type: String, normalizer: ->(v) { v.uniq }, default: :world) }
27
-
28
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq([]) }
29
- specify { expect(field.tap { |r| r.write([nil, nil]) }.read).to eq(['world']) }
30
- specify { expect(field.tap { |r| r.write('hello') }.read).to eq(['hello']) }
31
- specify { expect(field.tap { |r| r.write([42]) }.read).to eq(['42']) }
32
- specify { expect(field.tap { |r| r.write(['']) }.read).to eq(['']) }
33
- end
34
- end
35
-
36
- describe '#read_before_type_cast' do
37
- let(:field) { attribute(type: String, default: :world, enum: %w[hello 42]) }
38
-
39
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq([]) }
40
- specify { expect(field.tap { |r| r.write([nil]) }.read_before_type_cast).to eq([:world]) }
41
- specify { expect(field.tap { |r| r.write('hello') }.read_before_type_cast).to eq(['hello']) }
42
- specify { expect(field.tap { |r| r.write([42]) }.read_before_type_cast).to eq([42]) }
43
- specify { expect(field.tap { |r| r.write([43]) }.read_before_type_cast).to eq([43]) }
44
- specify { expect(field.tap { |r| r.write([43, 44]) }.read_before_type_cast).to eq([43, 44]) }
45
- specify { expect(field.tap { |r| r.write(['']) }.read_before_type_cast).to eq(['']) }
46
- specify { expect(field.tap { |r| r.write(['hello', 42]) }.read_before_type_cast).to eq(['hello', 42]) }
47
- specify { expect(field.tap { |r| r.write(['hello', false]) }.read_before_type_cast).to eq(['hello', false]) }
48
-
49
- context do
50
- let(:field) { attribute(type: String, default: :world) }
51
-
52
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq([]) }
53
- specify { expect(field.tap { |r| r.write([nil, nil]) }.read_before_type_cast).to eq(%i[world world]) }
54
- specify { expect(field.tap { |r| r.write('hello') }.read_before_type_cast).to eq(['hello']) }
55
- specify { expect(field.tap { |r| r.write([42]) }.read_before_type_cast).to eq([42]) }
56
- specify { expect(field.tap { |r| r.write(['']) }.read_before_type_cast).to eq(['']) }
57
- end
58
- end
59
-
60
- context 'integration' do
61
- before do
62
- stub_model(:post) do
63
- collection :tags, String
64
- end
65
- end
66
-
67
- specify { expect(Post.new(tags: ['hello', 42]).tags).to eq(%w[hello 42]) }
68
- specify { expect(Post.new(tags: ['hello', 42]).tags_before_type_cast).to eq(['hello', 42]) }
69
- specify { expect(Post.new.tags?).to eq(false) }
70
- specify { expect(Post.new(tags: ['hello', 42]).tags?).to eq(true) }
71
- end
72
- end