active_interaction 3.8.3 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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