active_interaction 3.8.3 → 4.0.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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -0
  3. data/README.md +93 -107
  4. data/lib/active_interaction.rb +1 -7
  5. data/lib/active_interaction/base.rb +23 -26
  6. data/lib/active_interaction/concerns/active_modelable.rb +1 -3
  7. data/lib/active_interaction/concerns/active_recordable.rb +1 -6
  8. data/lib/active_interaction/concerns/hashable.rb +0 -1
  9. data/lib/active_interaction/concerns/missable.rb +0 -1
  10. data/lib/active_interaction/concerns/runnable.rb +6 -12
  11. data/lib/active_interaction/errors.rb +3 -6
  12. data/lib/active_interaction/filter.rb +51 -37
  13. data/lib/active_interaction/filter_column.rb +0 -3
  14. data/lib/active_interaction/filters/abstract_date_time_filter.rb +34 -36
  15. data/lib/active_interaction/filters/abstract_numeric_filter.rb +27 -17
  16. data/lib/active_interaction/filters/array_filter.rb +57 -36
  17. data/lib/active_interaction/filters/boolean_filter.rb +26 -12
  18. data/lib/active_interaction/filters/date_filter.rb +1 -2
  19. data/lib/active_interaction/filters/date_time_filter.rb +1 -2
  20. data/lib/active_interaction/filters/decimal_filter.rb +10 -28
  21. data/lib/active_interaction/filters/file_filter.rb +6 -5
  22. data/lib/active_interaction/filters/float_filter.rb +1 -2
  23. data/lib/active_interaction/filters/hash_filter.rb +37 -27
  24. data/lib/active_interaction/filters/integer_filter.rb +7 -8
  25. data/lib/active_interaction/filters/interface_filter.rb +48 -14
  26. data/lib/active_interaction/filters/object_filter.rb +23 -50
  27. data/lib/active_interaction/filters/record_filter.rb +10 -35
  28. data/lib/active_interaction/filters/string_filter.rb +21 -12
  29. data/lib/active_interaction/filters/symbol_filter.rb +13 -7
  30. data/lib/active_interaction/filters/time_filter.rb +19 -22
  31. data/lib/active_interaction/grouped_input.rb +0 -3
  32. data/lib/active_interaction/inputs.rb +89 -0
  33. data/lib/active_interaction/modules/input_processor.rb +1 -4
  34. data/lib/active_interaction/modules/validation.rb +9 -12
  35. data/lib/active_interaction/version.rb +1 -3
  36. data/spec/active_interaction/base_spec.rb +13 -41
  37. data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -2
  38. data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -2
  39. data/spec/active_interaction/concerns/hashable_spec.rb +1 -3
  40. data/spec/active_interaction/concerns/missable_spec.rb +0 -2
  41. data/spec/active_interaction/concerns/runnable_spec.rb +9 -13
  42. data/spec/active_interaction/errors_spec.rb +4 -25
  43. data/spec/active_interaction/filter_column_spec.rb +0 -2
  44. data/spec/active_interaction/filter_spec.rb +0 -2
  45. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -3
  46. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -3
  47. data/spec/active_interaction/filters/array_filter_spec.rb +41 -15
  48. data/spec/active_interaction/filters/boolean_filter_spec.rb +58 -4
  49. data/spec/active_interaction/filters/date_filter_spec.rb +43 -3
  50. data/spec/active_interaction/filters/date_time_filter_spec.rb +43 -3
  51. data/spec/active_interaction/filters/decimal_filter_spec.rb +57 -3
  52. data/spec/active_interaction/filters/file_filter_spec.rb +1 -3
  53. data/spec/active_interaction/filters/float_filter_spec.rb +60 -4
  54. data/spec/active_interaction/filters/hash_filter_spec.rb +19 -9
  55. data/spec/active_interaction/filters/integer_filter_spec.rb +49 -7
  56. data/spec/active_interaction/filters/interface_filter_spec.rb +397 -24
  57. data/spec/active_interaction/filters/object_filter_spec.rb +23 -59
  58. data/spec/active_interaction/filters/record_filter_spec.rb +23 -49
  59. data/spec/active_interaction/filters/string_filter_spec.rb +15 -3
  60. data/spec/active_interaction/filters/symbol_filter_spec.rb +15 -3
  61. data/spec/active_interaction/filters/time_filter_spec.rb +65 -3
  62. data/spec/active_interaction/grouped_input_spec.rb +0 -2
  63. data/spec/active_interaction/i18n_spec.rb +3 -7
  64. data/spec/active_interaction/{modules/input_processor_spec.rb → inputs_spec.rb} +3 -5
  65. data/spec/active_interaction/integration/array_interaction_spec.rb +18 -22
  66. data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -2
  67. data/spec/active_interaction/integration/date_interaction_spec.rb +0 -2
  68. data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -2
  69. data/spec/active_interaction/integration/file_interaction_spec.rb +0 -2
  70. data/spec/active_interaction/integration/float_interaction_spec.rb +0 -2
  71. data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -2
  72. data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -2
  73. data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -3
  74. data/spec/active_interaction/integration/object_interaction_spec.rb +0 -2
  75. data/spec/active_interaction/integration/string_interaction_spec.rb +0 -2
  76. data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -2
  77. data/spec/active_interaction/integration/time_interaction_spec.rb +14 -18
  78. data/spec/active_interaction/modules/validation_spec.rb +1 -3
  79. data/spec/spec_helper.rb +2 -6
  80. data/spec/support/concerns.rb +0 -2
  81. data/spec/support/filters.rb +13 -9
  82. data/spec/support/interactions.rb +22 -14
  83. metadata +77 -52
  84. data/lib/active_interaction/backports.rb +0 -59
  85. data/lib/active_interaction/filters/abstract_filter.rb +0 -19
  86. data/spec/active_interaction/filters/abstract_filter_spec.rb +0 -8
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
  require 'active_record'
5
3
  unless defined?(JRUBY_VERSION) # rubocop:disable Style/IfUnlessModifier
@@ -28,25 +26,6 @@ describe ActiveInteraction::Errors do
28
26
 
29
27
  subject(:errors) { described_class.new(klass.new) }
30
28
 
31
- context 'backports' do
32
- describe '#delete' do
33
- it 'deletes the detailed error' do
34
- errors.add(:attribute)
35
- errors.delete(:attribute)
36
- expect(errors.details).to_not have_key :attribute
37
- end
38
- end
39
-
40
- describe '#initialize_dup' do
41
- it 'duplicates the detailed errors' do
42
- errors.add(:attribute)
43
- other = errors.dup
44
- expect(other.details).to eql errors.details
45
- expect(other.details).to_not be errors.details
46
- end
47
- end
48
- end
49
-
50
29
  describe '#merge!' do
51
30
  let(:other) { described_class.new(klass.new) }
52
31
 
@@ -128,7 +107,7 @@ describe ActiveInteraction::Errors do
128
107
  klass.name => {
129
108
  attributes: {
130
109
  attribute: {
131
- invalid_type: 'is not a valid %{type}'
110
+ invalid_type: 'is not a valid %<type>s'
132
111
  }
133
112
  }
134
113
  }
@@ -173,12 +152,12 @@ describe ActiveInteraction::Errors do
173
152
  end
174
153
  end
175
154
 
176
- class A < ActiveRecord::Base
155
+ class A < ActiveRecord::Base # rubocop:disable Lint/ConstantDefinitionInBlock
177
156
  has_one :b
178
157
  accepts_nested_attributes_for :b
179
158
  end
180
159
 
181
- class B < ActiveRecord::Base
160
+ class B < ActiveRecord::Base # rubocop:disable Lint/ConstantDefinitionInBlock
182
161
  belongs_to :a
183
162
 
184
163
  validates :name, presence: true
@@ -189,7 +168,7 @@ describe ActiveInteraction::Errors do
189
168
 
190
169
  it 'merges the nested errors' do
191
170
  a.valid?
192
- expect(a.errors.messages).to eql(:'b.name' => ["can't be blank"])
171
+ expect(a.errors.messages).to eq('b.name': ["can't be blank"])
193
172
  expect(a.errors.size).to eql 1
194
173
  expect { errors.merge!(a.errors) }.to_not raise_error
195
174
  expect(errors.size).to eql 1
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::FilterColumn do
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::Filter, :filter do
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::AbstractDateTimeFilter, :filter do
@@ -9,7 +7,7 @@ describe ActiveInteraction::AbstractDateTimeFilter, :filter do
9
7
  let(:value) { nil }
10
8
 
11
9
  it 'raises an error' do
12
- expect { filter.cast(value, nil) }.to raise_error NameError
10
+ expect { filter.send(:cast, value, nil) }.to raise_error NameError
13
11
  end
14
12
  end
15
13
  end
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::AbstractNumericFilter, :filter do
@@ -9,7 +7,7 @@ describe ActiveInteraction::AbstractNumericFilter, :filter do
9
7
  let(:value) { nil }
10
8
 
11
9
  it 'raises an error' do
12
- expect { filter.cast(value, nil) }.to raise_error NameError
10
+ expect { filter.send(:cast, value, nil) }.to raise_error NameError
13
11
  end
14
12
  end
15
13
  end
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::ArrayFilter, :filter do
@@ -36,7 +34,7 @@ describe ActiveInteraction::ArrayFilter, :filter do
36
34
  end
37
35
 
38
36
  describe '#cast' do
39
- let(:result) { filter.cast(value, nil) }
37
+ let(:result) { filter.send(:cast, value, nil) }
40
38
 
41
39
  context 'with an Array' do
42
40
  let(:value) { [] }
@@ -46,6 +44,20 @@ describe ActiveInteraction::ArrayFilter, :filter do
46
44
  end
47
45
  end
48
46
 
47
+ context 'with an implicit Array' do
48
+ let(:value) do
49
+ Class.new do
50
+ def to_ary
51
+ [1, 2, 3]
52
+ end
53
+ end.new
54
+ end
55
+
56
+ it 'returns the Array' do
57
+ expect(result).to eql value.to_ary
58
+ end
59
+ end
60
+
49
61
  context 'with a heterogenous Array' do
50
62
  let(:value) { [[], false, 0.0, {}, 0, '', :''] }
51
63
 
@@ -84,21 +96,35 @@ describe ActiveInteraction::ArrayFilter, :filter do
84
96
  end
85
97
  end
86
98
 
87
- context 'with a nested object filter' do
88
- let(:block) { proc { object } }
89
- let(:name) { :objects }
90
- let(:value) { [Object.new] }
99
+ [
100
+ %i[object class],
101
+ %i[record class],
102
+ %i[interface from]
103
+ ].each do |(type, option)|
104
+ context "with a nested #{type} filter" do
105
+ let(:block) { proc { public_send(type) } }
106
+ let(:name) { :objects }
107
+ let(:value) { [''] }
108
+
109
+ it 'does not raise an error' do
110
+ expect { result }.to_not raise_error
111
+ end
91
112
 
92
- it 'does not raise an error' do
93
- expect { result }.to_not raise_error
94
- end
113
+ it 'has a filter with the right key' do
114
+ expect(filter.filters).to have_key(:'0')
115
+ end
95
116
 
96
- it 'has a filter with the right key' do
97
- expect(filter.filters).to have_key(:object)
98
- end
117
+ it 'has a filter with the right option' do
118
+ expect(filter.filters[:'0'].options).to have_key(option)
119
+ end
120
+
121
+ context 'with a class set' do
122
+ let(:block) { proc { public_send(type, "#{option}": String) } }
99
123
 
100
- it 'has a filter with the right name' do
101
- expect(filter.filters[:object].name).to eql(:object)
124
+ it "does not override the #{option}" do
125
+ expect(filter.filters[:'0'].options[option]).to eql String
126
+ end
127
+ end
102
128
  end
103
129
  end
104
130
  end
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::BooleanFilter, :filter do
@@ -10,7 +8,21 @@ describe ActiveInteraction::BooleanFilter, :filter do
10
8
  context 'falsey' do
11
9
  [false, '0', 'false', 'FALSE', 'off', 'OFF'].each do |value|
12
10
  it "returns false for #{value.inspect}" do
13
- expect(filter.cast(value, nil)).to be_falsey
11
+ expect(filter.send(:cast, value, nil)).to be_falsey
12
+ end
13
+ end
14
+
15
+ context 'with an implicit string' do
16
+ let(:value) do
17
+ Class.new do
18
+ def to_str
19
+ 'false'
20
+ end
21
+ end.new
22
+ end
23
+
24
+ it 'returns false' do
25
+ expect(filter.send(:cast, value, nil)).to be_falsey
14
26
  end
15
27
  end
16
28
  end
@@ -18,7 +30,49 @@ describe ActiveInteraction::BooleanFilter, :filter do
18
30
  context 'truthy' do
19
31
  [true, '1', 'true', 'TRUE', 'on', 'ON'].each do |value|
20
32
  it "returns true for #{value.inspect}" do
21
- expect(filter.cast(value, nil)).to be_truthy
33
+ expect(filter.send(:cast, value, nil)).to be_truthy
34
+ end
35
+ end
36
+
37
+ context 'with an implicit string' do
38
+ let(:value) do
39
+ Class.new do
40
+ def to_str
41
+ 'true'
42
+ end
43
+ end.new
44
+ end
45
+
46
+ it 'returns true' do
47
+ expect(filter.send(:cast, value, nil)).to be_truthy
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'with a blank String' do
53
+ let(:value) do
54
+ Class.new do
55
+ def to_str
56
+ ' '
57
+ end
58
+ end.new
59
+ end
60
+
61
+ context 'optional' do
62
+ include_context 'optional'
63
+
64
+ it 'returns the default' do
65
+ expect(filter.send(:cast, value, nil)).to eql options[:default]
66
+ end
67
+ end
68
+
69
+ context 'required' do
70
+ include_context 'required'
71
+
72
+ it 'raises an error' do
73
+ expect do
74
+ filter.send(:cast, value, nil)
75
+ end.to raise_error ActiveInteraction::MissingValueError
22
76
  end
23
77
  end
24
78
  end
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::DateFilter, :filter do
@@ -15,7 +13,7 @@ describe ActiveInteraction::DateFilter, :filter do
15
13
  end
16
14
 
17
15
  describe '#cast' do
18
- let(:result) { filter.cast(value, nil) }
16
+ let(:result) { filter.send(:cast, value, nil) }
19
17
 
20
18
  context 'with a Date' do
21
19
  let(:value) { Date.new }
@@ -63,6 +61,48 @@ describe ActiveInteraction::DateFilter, :filter do
63
61
  end
64
62
  end
65
63
 
64
+ context 'with an implicit String' do
65
+ let(:value) do
66
+ Class.new do
67
+ def to_str
68
+ '2011-12-13'
69
+ end
70
+ end.new
71
+ end
72
+
73
+ it 'returns a Date' do
74
+ expect(result).to eql Date.parse(value)
75
+ end
76
+ end
77
+
78
+ context 'with a blank String' do
79
+ let(:value) do
80
+ Class.new do
81
+ def to_str
82
+ ' '
83
+ end
84
+ end.new
85
+ end
86
+
87
+ context 'optional' do
88
+ include_context 'optional'
89
+
90
+ it 'returns the default' do
91
+ expect(result).to eql options[:default]
92
+ end
93
+ end
94
+
95
+ context 'required' do
96
+ include_context 'required'
97
+
98
+ it 'raises an error' do
99
+ expect do
100
+ result
101
+ end.to raise_error ActiveInteraction::MissingValueError
102
+ end
103
+ end
104
+ end
105
+
66
106
  context 'with a GroupedInput' do
67
107
  let(:year) { 2012 }
68
108
  let(:month) { 1 }
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::DateTimeFilter, :filter do
@@ -15,7 +13,7 @@ describe ActiveInteraction::DateTimeFilter, :filter do
15
13
  end
16
14
 
17
15
  describe '#cast' do
18
- let(:result) { filter.cast(value, nil) }
16
+ let(:result) { filter.send(:cast, value, nil) }
19
17
 
20
18
  context 'with a Datetime' do
21
19
  let(:value) { DateTime.new }
@@ -63,6 +61,48 @@ describe ActiveInteraction::DateTimeFilter, :filter do
63
61
  end
64
62
  end
65
63
 
64
+ context 'with an implicit String' do
65
+ let(:value) do
66
+ Class.new do
67
+ def to_str
68
+ '2011-12-13T14:15:16+17:18'
69
+ end
70
+ end.new
71
+ end
72
+
73
+ it 'returns a DateTime' do
74
+ expect(result).to eql DateTime.parse(value)
75
+ end
76
+ end
77
+
78
+ context 'with a blank String' do
79
+ let(:value) do
80
+ Class.new do
81
+ def to_str
82
+ ' '
83
+ end
84
+ end.new
85
+ end
86
+
87
+ context 'optional' do
88
+ include_context 'optional'
89
+
90
+ it 'returns the default' do
91
+ expect(result).to eql options[:default]
92
+ end
93
+ end
94
+
95
+ context 'required' do
96
+ include_context 'required'
97
+
98
+ it 'raises an error' do
99
+ expect do
100
+ result
101
+ end.to raise_error ActiveInteraction::MissingValueError
102
+ end
103
+ end
104
+ end
105
+
66
106
  context 'with a GroupedInput' do
67
107
  let(:year) { 2012 }
68
108
  let(:month) { 1 }
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  describe ActiveInteraction::DecimalFilter, :filter do
@@ -15,7 +13,7 @@ describe ActiveInteraction::DecimalFilter, :filter do
15
13
  end
16
14
 
17
15
  describe '#cast' do
18
- let(:result) { filter.cast(value, nil) }
16
+ let(:result) { filter.send(:cast, value, nil) }
19
17
 
20
18
  context 'with a Float' do
21
19
  let(:value) { rand }
@@ -35,6 +33,20 @@ describe ActiveInteraction::DecimalFilter, :filter do
35
33
  end
36
34
  end
37
35
 
36
+ context 'with an implicit Integer' do
37
+ let(:value) do
38
+ Class.new do
39
+ def to_int
40
+ @to_int ||= rand(1 << 16)
41
+ end
42
+ end.new
43
+ end
44
+
45
+ it 'returns a BigDecimal' do
46
+ expect(result).to eql BigDecimal(value.to_int)
47
+ end
48
+ end
49
+
38
50
  context 'with a Numeric' do
39
51
  let(:value) { rand(1 << 16) }
40
52
 
@@ -60,6 +72,48 @@ describe ActiveInteraction::DecimalFilter, :filter do
60
72
  end.to raise_error ActiveInteraction::InvalidValueError
61
73
  end
62
74
  end
75
+
76
+ context 'with an implicit String' do
77
+ let(:value) do
78
+ Class.new do
79
+ def to_str
80
+ '1.1'
81
+ end
82
+ end.new
83
+ end
84
+
85
+ it 'returns a BigDecimal' do
86
+ expect(result).to eql BigDecimal(value)
87
+ end
88
+ end
89
+
90
+ context 'with a blank String' do
91
+ let(:value) do
92
+ Class.new do
93
+ def to_str
94
+ ' '
95
+ end
96
+ end.new
97
+ end
98
+
99
+ context 'optional' do
100
+ include_context 'optional'
101
+
102
+ it 'returns the default' do
103
+ expect(result).to eql options[:default]
104
+ end
105
+ end
106
+
107
+ context 'required' do
108
+ include_context 'required'
109
+
110
+ it 'raises an error' do
111
+ expect do
112
+ result
113
+ end.to raise_error ActiveInteraction::MissingValueError
114
+ end
115
+ end
116
+ end
63
117
  end
64
118
 
65
119
  describe '#database_column_type' do