granite-form 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,100 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Attributes::Dictionary 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::Dictionary, :field, options)
9
- Dummy.new.attribute(:field)
10
- end
11
-
12
- describe '#read' do
13
- let(:field) do
14
- attribute(type: String,
15
- normalizer: ->(val) { val.delete_if { |_, v| v.nil? } },
16
- default: :world, enum: %w[hello 42])
17
- end
18
-
19
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq({}) }
20
- specify { expect(field.tap { |r| r.write({}) }.read).to eq({}) }
21
- specify { expect(field.tap { |r| r.write(a: nil) }.read).to eq({}) }
22
- specify { expect(field.tap { |r| r.write(a: '') }.read).to eq({}) }
23
- specify { expect(field.tap { |r| r.write(a: 1) }.read).to eq({}) }
24
- specify { expect(field.tap { |r| r.write(a: 42) }.read).to eq('a' => '42') }
25
- specify { expect(field.tap { |r| r.write(a: 'hello', b: '42') }.read).to eq('a' => 'hello', 'b' => '42') }
26
- specify { expect(field.tap { |r| r.write(a: 'hello', b: '1') }.read).to eq('a' => 'hello') }
27
- specify { expect(field.tap { |r| r.write(a: 'hello', x: '42') }.read).to eq('a' => 'hello', 'x' => '42') }
28
-
29
- context do
30
- let(:field) do
31
- attribute(type: String,
32
- normalizer: ->(val) { val.delete_if { |_, v| v.nil? } },
33
- default: :world)
34
- end
35
-
36
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq({}) }
37
- specify { expect(field.tap { |r| r.write({}) }.read).to eq({}) }
38
- specify { expect(field.tap { |r| r.write(a: 1) }.read).to eq('a' => '1') }
39
- specify { expect(field.tap { |r| r.write(a: nil, b: nil) }.read).to eq('a' => 'world', 'b' => 'world') }
40
- specify { expect(field.tap { |r| r.write(a: '') }.read).to eq('a' => '') }
41
- end
42
-
43
- context 'with :keys' do
44
- let(:field) { attribute(type: String, keys: ['a', :b]) }
45
-
46
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq({}) }
47
- specify { expect(field.tap { |r| r.write({}) }.read).to eq({}) }
48
- specify { expect(field.tap { |r| r.write(a: 1, 'b' => 2, c: 3, 'd' => 4) }.read).to eq('a' => '1', 'b' => '2') }
49
- specify { expect(field.tap { |r| r.write(a: 1, c: 3, 'd' => 4) }.read).to eq('a' => '1') }
50
- end
51
- end
52
-
53
- describe '#read_before_type_cast' do
54
- let(:field) { attribute(type: String, default: :world, enum: %w[hello 42]) }
55
-
56
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq({}) }
57
- specify { expect(field.tap { |r| r.write({}) }.read_before_type_cast).to eq({}) }
58
- specify { expect(field.tap { |r| r.write(a: 1) }.read_before_type_cast).to eq('a' => 1) }
59
- specify { expect(field.tap { |r| r.write(a: nil) }.read_before_type_cast).to eq('a' => :world) }
60
- specify { expect(field.tap { |r| r.write(a: '') }.read_before_type_cast).to eq('a' => '') }
61
- specify { expect(field.tap { |r| r.write(a: 42) }.read_before_type_cast).to eq('a' => 42) }
62
- specify { expect(field.tap { |r| r.write(a: 'hello', b: '42') }.read_before_type_cast).to eq('a' => 'hello', 'b' => '42') }
63
- specify { expect(field.tap { |r| r.write(a: 'hello', b: '1') }.read_before_type_cast).to eq('a' => 'hello', 'b' => '1') }
64
- specify { expect(field.tap { |r| r.write(a: 'hello', x: '42') }.read_before_type_cast).to eq('a' => 'hello', 'x' => '42') }
65
-
66
- context do
67
- let(:field) { attribute(type: String, default: :world) }
68
-
69
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq({}) }
70
- specify { expect(field.tap { |r| r.write({}) }.read_before_type_cast).to eq({}) }
71
- specify { expect(field.tap { |r| r.write(a: 1) }.read_before_type_cast).to eq('a' => 1) }
72
- specify { expect(field.tap { |r| r.write(a: nil, b: nil) }.read_before_type_cast).to eq('a' => :world, 'b' => :world) }
73
- specify { expect(field.tap { |r| r.write(a: '') }.read_before_type_cast).to eq('a' => '') }
74
- end
75
-
76
- context 'with :keys' do
77
- let(:field) { attribute(type: String, keys: ['a', :b]) }
78
-
79
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq({}) }
80
- specify { expect(field.tap { |r| r.write({}) }.read_before_type_cast).to eq({}) }
81
- specify do
82
- expect(field.tap { |r| r.write(a: 1, 'b' => 2, c: 3, 'd' => 4) }.read_before_type_cast)
83
- .to eq('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4)
84
- end
85
- end
86
- end
87
-
88
- context 'integration' do
89
- before do
90
- stub_model(:post) do
91
- dictionary :options, type: String
92
- end
93
- end
94
-
95
- specify { expect(Post.new(options: {a: 'hello', b: 42}).options).to eq('a' => 'hello', 'b' => '42') }
96
- specify { expect(Post.new(options: {a: 'hello', b: 42}).options_before_type_cast).to eq('a' => 'hello', 'b' => 42) }
97
- specify { expect(Post.new.options?).to eq(false) }
98
- specify { expect(Post.new(options: {a: 'hello', b: 42}).options?).to eq(true) }
99
- end
100
- end
@@ -1,103 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Attributes::Localized 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::Localized, :field, options)
9
- Dummy.new.attribute(:field)
10
- end
11
-
12
- describe '#read' do
13
- let(:field) { attribute(type: String, 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(en: 'hello') }.read).to eq('en' => 'hello') }
17
- specify { expect(field.tap { |r| r.write(en: 42) }.read).to eq('en' => '42') }
18
- specify { expect(field.tap { |r| r.write(en: 43) }.read).to eq('en' => nil) }
19
- specify { expect(field.tap { |r| r.write(en: '') }.read).to eq('en' => nil) }
20
- specify { expect(field.tap { |r| r.write(en: nil) }.read).to eq('en' => nil) }
21
- specify { expect(field.tap { |r| r.write(en: 'hello', ru: 42) }.read).to eq('en' => 'hello', 'ru' => '42') }
22
-
23
- context do
24
- let(:field) { attribute(type: String, default: :world) }
25
-
26
- specify { expect(field.tap { |r| r.write(nil) }.read).to eq({}) }
27
- specify { expect(field.tap { |r| r.write(en: 'hello') }.read).to eq('en' => 'hello') }
28
- specify { expect(field.tap { |r| r.write(en: 42) }.read).to eq('en' => '42') }
29
- specify { expect(field.tap { |r| r.write(en: '') }.read).to eq('en' => '') }
30
- specify { expect(field.tap { |r| r.write(en: nil) }.read).to eq('en' => 'world') }
31
- end
32
- end
33
-
34
- describe '#read_before_type_cast' do
35
- let(:field) { attribute(type: String, default: :world, enum: %w[hello 42]) }
36
-
37
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq({}) }
38
- specify { expect(field.tap { |r| r.write(en: 'hello') }.read_before_type_cast).to eq('en' => 'hello') }
39
- specify { expect(field.tap { |r| r.write(en: 42) }.read_before_type_cast).to eq('en' => 42) }
40
- specify { expect(field.tap { |r| r.write(en: 43) }.read_before_type_cast).to eq('en' => 43) }
41
- specify { expect(field.tap { |r| r.write(en: '') }.read_before_type_cast).to eq('en' => '') }
42
- specify { expect(field.tap { |r| r.write(en: nil) }.read_before_type_cast).to eq('en' => :world) }
43
- specify { expect(field.tap { |r| r.write(en: 'hello', ru: 42) }.read_before_type_cast).to eq('en' => 'hello', 'ru' => 42) }
44
-
45
- context do
46
- let(:field) { attribute(type: String, default: :world) }
47
-
48
- specify { expect(field.tap { |r| r.write(nil) }.read_before_type_cast).to eq({}) }
49
- specify { expect(field.tap { |r| r.write(en: 'hello') }.read_before_type_cast).to eq('en' => 'hello') }
50
- specify { expect(field.tap { |r| r.write(en: 42) }.read_before_type_cast).to eq('en' => 42) }
51
- specify { expect(field.tap { |r| r.write(en: '') }.read_before_type_cast).to eq('en' => '') }
52
- specify { expect(field.tap { |r| r.write(en: nil) }.read_before_type_cast).to eq('en' => :world) }
53
- end
54
- end
55
-
56
- context 'integration' do
57
- let(:klass) do
58
- Class.new do
59
- include Granite::Form::Model
60
- include Granite::Form::Model::Localization
61
-
62
- localized :name, type: String
63
- end
64
- end
65
- let(:translations) { {en: 'Hello', ru: 'Привет'} }
66
- before { I18n.locale = :en }
67
-
68
- describe '#name_translations' do
69
- subject { klass.new name_translations: translations }
70
- its(:name_translations) { should == translations.stringify_keys }
71
- its(:name) { should == translations[:en] }
72
- end
73
-
74
- describe '#name' do
75
- subject { klass.new name: 'Hello' }
76
- its(:name_translations) { should == {'en' => 'Hello'} }
77
- its(:name) { should == 'Hello' }
78
- end
79
-
80
- describe '#name_before_type_cast' do
81
- let(:object) { Object.new }
82
- subject { klass.new name: object }
83
- its(:name_before_type_cast) { should == object }
84
- end
85
-
86
- context 'fallbacks' do
87
- subject { klass.new name_translations: {ru: 'Привет'} }
88
- context do
89
- its(:name) { should be_nil }
90
- end
91
-
92
- context do
93
- before do
94
- require 'i18n/backend/fallbacks'
95
- I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
96
- I18n.fallbacks[:en] = [:ru]
97
- end
98
- after { I18n.fallbacks = false }
99
- its(:name) { should == 'Привет' }
100
- end
101
- end
102
- end
103
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Attributes::Reflections::Localized do
4
- def reflection(options = {})
5
- described_class.new(:field, options)
6
- end
7
-
8
- describe '.build' do
9
- before { stub_class(:target) }
10
-
11
- specify do
12
- described_class.build(Class.new, Target, :field)
13
-
14
- expect(Target).to be_method_defined(:field_translations)
15
- expect(Target).to be_method_defined(:field_translations=)
16
- expect(Target).to be_method_defined(:field)
17
- expect(Target).to be_method_defined(:field=)
18
- expect(Target).to be_method_defined(:field?)
19
- expect(Target).to be_method_defined(:field_before_type_cast)
20
- end
21
- end
22
-
23
- describe '#generate_methods' do
24
- before { stub_class(:target) }
25
-
26
- specify do
27
- described_class.generate_methods(:field_alias, Target)
28
-
29
- expect(Target).to be_method_defined(:field_alias_translations)
30
- expect(Target).to be_method_defined(:field_alias_translations=)
31
- expect(Target).to be_method_defined(:field_alias)
32
- expect(Target).to be_method_defined(:field_alias=)
33
- expect(Target).to be_method_defined(:field_alias?)
34
- expect(Target).to be_method_defined(:field_alias_before_type_cast)
35
- end
36
- end
37
- end