active_interaction 4.1.0 → 5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -1
- data/README.md +63 -28
- data/lib/active_interaction/array_input.rb +77 -0
- data/lib/active_interaction/base.rb +14 -98
- data/lib/active_interaction/concerns/active_recordable.rb +3 -3
- data/lib/active_interaction/concerns/missable.rb +2 -2
- data/lib/active_interaction/errors.rb +6 -88
- data/lib/active_interaction/exceptions.rb +47 -0
- data/lib/active_interaction/filter/column.rb +59 -0
- data/lib/active_interaction/filter/error.rb +40 -0
- data/lib/active_interaction/filter.rb +44 -53
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +9 -6
- data/lib/active_interaction/filters/abstract_numeric_filter.rb +7 -3
- data/lib/active_interaction/filters/array_filter.rb +34 -6
- data/lib/active_interaction/filters/boolean_filter.rb +4 -3
- data/lib/active_interaction/filters/date_filter.rb +1 -1
- data/lib/active_interaction/filters/date_time_filter.rb +1 -1
- data/lib/active_interaction/filters/decimal_filter.rb +1 -1
- data/lib/active_interaction/filters/float_filter.rb +1 -1
- data/lib/active_interaction/filters/hash_filter.rb +23 -15
- data/lib/active_interaction/filters/integer_filter.rb +1 -1
- data/lib/active_interaction/filters/interface_filter.rb +12 -12
- data/lib/active_interaction/filters/object_filter.rb +9 -3
- data/lib/active_interaction/filters/record_filter.rb +21 -11
- data/lib/active_interaction/filters/string_filter.rb +1 -1
- data/lib/active_interaction/filters/symbol_filter.rb +1 -1
- data/lib/active_interaction/filters/time_filter.rb +4 -4
- data/lib/active_interaction/hash_input.rb +43 -0
- data/lib/active_interaction/input.rb +23 -0
- data/lib/active_interaction/inputs.rb +157 -46
- data/lib/active_interaction/locale/en.yml +0 -1
- data/lib/active_interaction/locale/fr.yml +0 -1
- data/lib/active_interaction/locale/it.yml +0 -1
- data/lib/active_interaction/locale/ja.yml +0 -1
- data/lib/active_interaction/locale/pt-BR.yml +0 -1
- data/lib/active_interaction/modules/validation.rb +6 -17
- data/lib/active_interaction/version.rb +1 -1
- data/lib/active_interaction.rb +43 -36
- data/spec/active_interaction/array_input_spec.rb +166 -0
- data/spec/active_interaction/base_spec.rb +15 -240
- data/spec/active_interaction/concerns/active_modelable_spec.rb +3 -3
- data/spec/active_interaction/concerns/active_recordable_spec.rb +7 -7
- data/spec/active_interaction/concerns/hashable_spec.rb +8 -8
- data/spec/active_interaction/concerns/missable_spec.rb +9 -9
- data/spec/active_interaction/concerns/runnable_spec.rb +34 -32
- data/spec/active_interaction/errors_spec.rb +60 -43
- data/spec/active_interaction/{filter_column_spec.rb → filter/column_spec.rb} +3 -10
- data/spec/active_interaction/filter_spec.rb +6 -6
- data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +2 -2
- data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +2 -2
- data/spec/active_interaction/filters/array_filter_spec.rb +99 -16
- data/spec/active_interaction/filters/boolean_filter_spec.rb +12 -11
- data/spec/active_interaction/filters/date_filter_spec.rb +32 -27
- data/spec/active_interaction/filters/date_time_filter_spec.rb +34 -29
- data/spec/active_interaction/filters/decimal_filter_spec.rb +20 -18
- data/spec/active_interaction/filters/file_filter_spec.rb +7 -7
- data/spec/active_interaction/filters/float_filter_spec.rb +19 -17
- data/spec/active_interaction/filters/hash_filter_spec.rb +16 -18
- data/spec/active_interaction/filters/integer_filter_spec.rb +24 -22
- data/spec/active_interaction/filters/interface_filter_spec.rb +105 -82
- data/spec/active_interaction/filters/object_filter_spec.rb +52 -36
- data/spec/active_interaction/filters/record_filter_spec.rb +61 -39
- data/spec/active_interaction/filters/string_filter_spec.rb +7 -7
- data/spec/active_interaction/filters/symbol_filter_spec.rb +6 -6
- data/spec/active_interaction/filters/time_filter_spec.rb +57 -34
- data/spec/active_interaction/hash_input_spec.rb +58 -0
- data/spec/active_interaction/i18n_spec.rb +22 -17
- data/spec/active_interaction/inputs_spec.rb +167 -23
- data/spec/active_interaction/integration/array_interaction_spec.rb +3 -7
- data/spec/active_interaction/modules/validation_spec.rb +8 -31
- data/spec/spec_helper.rb +8 -0
- data/spec/support/concerns.rb +2 -2
- data/spec/support/filters.rb +27 -51
- data/spec/support/interactions.rb +4 -4
- metadata +40 -91
- data/lib/active_interaction/filter_column.rb +0 -57
@@ -18,11 +18,12 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
18
18
|
|
19
19
|
context 'with a time zone' do
|
20
20
|
before do
|
21
|
-
time_zone = double
|
22
|
-
allow(Time).to receive(:zone).and_return(time_zone)
|
23
|
-
|
24
21
|
time_with_zone = double
|
22
|
+
|
23
|
+
time_zone = double
|
25
24
|
allow(time_zone).to receive(:at).and_return(time_with_zone)
|
25
|
+
|
26
|
+
allow(Time).to receive(:zone).and_return(time_zone)
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'raises an error' do
|
@@ -34,14 +35,14 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
describe '#
|
38
|
-
let(:result) { filter.
|
38
|
+
describe '#process' do
|
39
|
+
let(:result) { filter.process(value, nil) }
|
39
40
|
|
40
41
|
context 'with a Time' do
|
41
42
|
let(:value) { Time.new }
|
42
43
|
|
43
44
|
it 'returns the Time' do
|
44
|
-
expect(result).to eql value
|
45
|
+
expect(result.value).to eql value
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
@@ -49,7 +50,24 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
49
50
|
let(:value) { '2011-12-13 14:15:16 +1718' }
|
50
51
|
|
51
52
|
it 'returns a Time' do
|
52
|
-
expect(result).to eql Time.parse(value)
|
53
|
+
expect(result.value).to eql Time.parse(value)
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with a time zone' do
|
57
|
+
before do
|
58
|
+
klass = double
|
59
|
+
allow(klass).to receive(:parse).with(value).and_return(nil)
|
60
|
+
|
61
|
+
allow(filter).to receive(:matches?).and_return(false)
|
62
|
+
allow(filter).to receive(:klass).and_return(klass)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'indicates an error the string is not parsable' do
|
66
|
+
error = result.errors.first
|
67
|
+
|
68
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
69
|
+
expect(error.type).to be :invalid_type
|
70
|
+
end
|
53
71
|
end
|
54
72
|
|
55
73
|
context 'with format' do
|
@@ -58,7 +76,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
58
76
|
let(:value) { '13/12/2011 14:15:16 +1718' }
|
59
77
|
|
60
78
|
it 'returns a Time' do
|
61
|
-
expect(result).to eql Time.strptime(value, format)
|
79
|
+
expect(result.value).to eql Time.strptime(value, format)
|
62
80
|
end
|
63
81
|
end
|
64
82
|
end
|
@@ -66,19 +84,21 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
66
84
|
context 'with an invalid String' do
|
67
85
|
let(:value) { 'invalid' }
|
68
86
|
|
69
|
-
it '
|
70
|
-
|
71
|
-
|
72
|
-
|
87
|
+
it 'indicates an error' do
|
88
|
+
error = result.errors.first
|
89
|
+
|
90
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
91
|
+
expect(error.type).to be :invalid_type
|
73
92
|
end
|
74
93
|
|
75
94
|
context 'with format' do
|
76
95
|
include_context 'with format'
|
77
96
|
|
78
|
-
it do
|
79
|
-
|
80
|
-
|
81
|
-
|
97
|
+
it 'indicates an error' do
|
98
|
+
error = result.errors.first
|
99
|
+
|
100
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
101
|
+
expect(error.type).to be :invalid_type
|
82
102
|
end
|
83
103
|
end
|
84
104
|
end
|
@@ -93,7 +113,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
93
113
|
end
|
94
114
|
|
95
115
|
it 'returns a Time' do
|
96
|
-
expect(result).to eql Time.parse(value)
|
116
|
+
expect(result.value).to eql Time.parse(value)
|
97
117
|
end
|
98
118
|
end
|
99
119
|
|
@@ -110,17 +130,18 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
110
130
|
include_context 'optional'
|
111
131
|
|
112
132
|
it 'returns the default' do
|
113
|
-
expect(result).to eql options[:default]
|
133
|
+
expect(result.value).to eql options[:default]
|
114
134
|
end
|
115
135
|
end
|
116
136
|
|
117
137
|
context 'required' do
|
118
138
|
include_context 'required'
|
119
139
|
|
120
|
-
it '
|
121
|
-
|
122
|
-
|
123
|
-
|
140
|
+
it 'indicates an error' do
|
141
|
+
error = result.errors.first
|
142
|
+
|
143
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
144
|
+
expect(error.type).to be :missing
|
124
145
|
end
|
125
146
|
end
|
126
147
|
end
|
@@ -129,7 +150,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
129
150
|
let(:value) { rand(1 << 16) }
|
130
151
|
|
131
152
|
it 'returns the Time' do
|
132
|
-
expect(result).to eql Time.at(value)
|
153
|
+
expect(result.value).to eql Time.at(value)
|
133
154
|
end
|
134
155
|
end
|
135
156
|
|
@@ -143,7 +164,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
143
164
|
end
|
144
165
|
|
145
166
|
it 'returns the Time' do
|
146
|
-
expect(result).to eql Time.at(value)
|
167
|
+
expect(result.value).to eql Time.at(value)
|
147
168
|
end
|
148
169
|
end
|
149
170
|
|
@@ -167,7 +188,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
167
188
|
|
168
189
|
it 'returns a Time' do
|
169
190
|
expect(
|
170
|
-
result
|
191
|
+
result.value
|
171
192
|
).to eql Time.new(year, month, day, hour, min, sec)
|
172
193
|
end
|
173
194
|
end
|
@@ -176,10 +197,11 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
176
197
|
context 'empty' do
|
177
198
|
let(:value) { ActiveInteraction::GroupedInput.new }
|
178
199
|
|
179
|
-
it '
|
180
|
-
|
181
|
-
|
182
|
-
|
200
|
+
it 'indicates an error' do
|
201
|
+
error = result.errors.first
|
202
|
+
|
203
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
204
|
+
expect(error.type).to be :invalid_type
|
183
205
|
end
|
184
206
|
end
|
185
207
|
|
@@ -190,10 +212,11 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
190
212
|
)
|
191
213
|
end
|
192
214
|
|
193
|
-
it '
|
194
|
-
|
195
|
-
|
196
|
-
|
215
|
+
it 'indicates an error' do
|
216
|
+
error = result.errors.first
|
217
|
+
|
218
|
+
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
219
|
+
expect(error.type).to be :invalid_type
|
197
220
|
end
|
198
221
|
end
|
199
222
|
end
|
@@ -201,7 +224,7 @@ describe ActiveInteraction::TimeFilter, :filter do
|
|
201
224
|
|
202
225
|
describe '#database_column_type' do
|
203
226
|
it 'returns :datetime' do
|
204
|
-
expect(filter.database_column_type).to
|
227
|
+
expect(filter.database_column_type).to be :datetime
|
205
228
|
end
|
206
229
|
end
|
207
230
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveInteraction::HashInput do
|
4
|
+
subject(:input) do
|
5
|
+
described_class.new(filter,
|
6
|
+
value: value,
|
7
|
+
error: error,
|
8
|
+
children: children
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:filter) do
|
13
|
+
ActiveInteraction::HashFilter.new(:h, &block)
|
14
|
+
end
|
15
|
+
let(:block) { proc { integer :i } }
|
16
|
+
let(:value) { nil }
|
17
|
+
let(:error) { nil }
|
18
|
+
let(:children) { {} }
|
19
|
+
|
20
|
+
describe '#errors' do
|
21
|
+
context 'with no errors' do
|
22
|
+
it 'returns an empty array' do
|
23
|
+
expect(input.errors).to be_empty
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with an error on the hash' do
|
28
|
+
let(:error) { ActiveInteraction::Filter::Error.new(filter, :invalid_type) }
|
29
|
+
|
30
|
+
it 'returns one error in the array' do
|
31
|
+
expect(input.errors.size).to be 1
|
32
|
+
|
33
|
+
error = input.errors.first
|
34
|
+
expect(error.name).to be filter.name
|
35
|
+
expect(error.type).to be :invalid_type
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with children with errors' do
|
40
|
+
let(:child_i) do
|
41
|
+
filter = ActiveInteraction::IntegerFilter.new(:i)
|
42
|
+
ActiveInteraction::Input.new(filter,
|
43
|
+
value: nil,
|
44
|
+
error: ActiveInteraction::Filter::Error.new(filter, :missing)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
let(:children) { { i: child_i } }
|
48
|
+
|
49
|
+
it 'returns the error' do
|
50
|
+
expect(input.errors.size).to be 1
|
51
|
+
|
52
|
+
error = input.errors.first
|
53
|
+
expect(error.name).to be :"#{filter.name}.i"
|
54
|
+
expect(error.type).to be :missing
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -15,20 +15,23 @@ I18nInteraction = Class.new(TestInteraction) do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
TYPES = ActiveInteraction::Filter
|
19
|
+
.const_get(:CLASSES)
|
20
|
+
.keys
|
21
|
+
.map(&:to_s)
|
22
|
+
|
18
23
|
describe I18nInteraction do
|
19
24
|
include_context 'interactions'
|
20
25
|
|
21
|
-
TYPES = ActiveInteraction::Filter # rubocop:disable Lint/ConstantDefinitionInBlock
|
22
|
-
.const_get(:CLASSES)
|
23
|
-
.map { |slug, _| slug.to_s }
|
24
|
-
|
25
26
|
shared_examples 'translation' do |locale|
|
26
|
-
|
27
|
-
|
27
|
+
around do |example|
|
28
|
+
old_locale = I18n.locale
|
28
29
|
I18n.locale = locale
|
29
|
-
end
|
30
30
|
|
31
|
-
|
31
|
+
example.run
|
32
|
+
|
33
|
+
I18n.locale = old_locale
|
34
|
+
end
|
32
35
|
|
33
36
|
context 'types' do
|
34
37
|
TYPES.each do |type|
|
@@ -81,16 +84,12 @@ describe I18nInteraction do
|
|
81
84
|
end
|
82
85
|
|
83
86
|
context 'hsilgne' do
|
84
|
-
before
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
I18n.config.available_locales
|
89
|
-
end
|
87
|
+
# This must appear before including the translation examples so that the
|
88
|
+
# locale is available before it is assigned.
|
89
|
+
around do |example|
|
90
|
+
old_locals = I18n.config.available_locales
|
91
|
+
I18n.config.available_locales += [:hsilgne]
|
90
92
|
|
91
|
-
include_examples 'translation', :hsilgne
|
92
|
-
|
93
|
-
before do
|
94
93
|
I18n.backend.store_translations('hsilgne',
|
95
94
|
active_interaction: {
|
96
95
|
errors: {
|
@@ -103,6 +102,12 @@ describe I18nInteraction do
|
|
103
102
|
types: TYPES.each_with_object({}) { |e, a| a[e] = e.reverse }
|
104
103
|
}
|
105
104
|
)
|
105
|
+
|
106
|
+
example.run
|
107
|
+
|
108
|
+
I18n.config.available_locales = old_locals
|
106
109
|
end
|
110
|
+
|
111
|
+
include_examples 'translation', :hsilgne
|
107
112
|
end
|
108
113
|
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ActiveInteraction::Inputs do
|
4
|
-
subject(:inputs) { described_class.new }
|
4
|
+
subject(:inputs) { described_class.new(args, base_class.new) }
|
5
|
+
|
6
|
+
let(:args) { {} }
|
7
|
+
let(:base_class) { ActiveInteraction::Base }
|
5
8
|
|
6
9
|
describe '.reserved?(name)' do
|
7
10
|
it 'returns true for anything starting with "_interaction_"' do
|
8
|
-
expect(described_class.
|
11
|
+
expect(described_class).to be_reserved('_interaction_')
|
9
12
|
end
|
10
13
|
|
11
14
|
it 'returns true for existing instance methods' do
|
@@ -13,21 +16,20 @@ describe ActiveInteraction::Inputs do
|
|
13
16
|
(ActiveInteraction::Base.instance_methods - Object.instance_methods) +
|
14
17
|
(ActiveInteraction::Base.private_instance_methods - Object.private_instance_methods)
|
15
18
|
).each do |method|
|
16
|
-
expect(described_class.
|
19
|
+
expect(described_class).to be_reserved(method)
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
20
23
|
it 'returns false for anything else' do
|
21
|
-
expect(described_class.
|
24
|
+
expect(described_class).to_not be_reserved(SecureRandom.hex)
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
25
|
-
describe '
|
26
|
-
let(:
|
27
|
-
let(:result) { described_class.process(inputs) }
|
28
|
+
describe '#normalized' do
|
29
|
+
let(:result) { inputs.normalized }
|
28
30
|
|
29
31
|
context 'with invalid inputs' do
|
30
|
-
let(:
|
32
|
+
let(:args) { nil }
|
31
33
|
|
32
34
|
it 'raises an error' do
|
33
35
|
expect { result }.to raise_error ArgumentError
|
@@ -35,7 +37,7 @@ describe ActiveInteraction::Inputs do
|
|
35
37
|
end
|
36
38
|
|
37
39
|
context 'with non-hash inputs' do
|
38
|
-
let(:
|
40
|
+
let(:args) { [%i[k v]] }
|
39
41
|
|
40
42
|
it 'raises an error' do
|
41
43
|
expect { result }.to raise_error ArgumentError
|
@@ -43,15 +45,7 @@ describe ActiveInteraction::Inputs do
|
|
43
45
|
end
|
44
46
|
|
45
47
|
context 'with ActionController::Parameters inputs' do
|
46
|
-
let(:
|
47
|
-
|
48
|
-
it 'does not raise an error' do
|
49
|
-
expect { result }.to_not raise_error
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
context 'with Inputs inputs' do
|
54
|
-
let(:inputs) { ActiveInteraction::Inputs.new }
|
48
|
+
let(:args) { ::ActionController::Parameters.new }
|
55
49
|
|
56
50
|
it 'does not raise an error' do
|
57
51
|
expect { result }.to_not raise_error
|
@@ -59,17 +53,17 @@ describe ActiveInteraction::Inputs do
|
|
59
53
|
end
|
60
54
|
|
61
55
|
context 'with simple inputs' do
|
62
|
-
before {
|
56
|
+
before { args[:key] = :value }
|
63
57
|
|
64
58
|
it 'sends them straight through' do
|
65
|
-
expect(result).to eql
|
59
|
+
expect(result).to eql args
|
66
60
|
end
|
67
61
|
end
|
68
62
|
|
69
63
|
context 'with groupable inputs' do
|
70
64
|
context 'without a matching simple input' do
|
71
65
|
before do
|
72
|
-
|
66
|
+
args.merge!(
|
73
67
|
'key(1i)' => :value1,
|
74
68
|
'key(2i)' => :value2
|
75
69
|
)
|
@@ -87,7 +81,7 @@ describe ActiveInteraction::Inputs do
|
|
87
81
|
|
88
82
|
context 'with a matching simple input' do
|
89
83
|
before do
|
90
|
-
|
84
|
+
args.merge!(
|
91
85
|
'key(1i)' => :value1,
|
92
86
|
key: :value2
|
93
87
|
)
|
@@ -104,11 +98,161 @@ describe ActiveInteraction::Inputs do
|
|
104
98
|
end
|
105
99
|
|
106
100
|
context 'with a reserved name' do
|
107
|
-
before {
|
101
|
+
before { args[:_interaction_key] = :value }
|
108
102
|
|
109
103
|
it 'skips the input' do
|
110
104
|
expect(result).to_not have_key(:_interaction_key)
|
111
105
|
end
|
112
106
|
end
|
113
107
|
end
|
108
|
+
|
109
|
+
describe '#given?' do
|
110
|
+
let(:base_class) do
|
111
|
+
Class.new(ActiveInteraction::Base) do
|
112
|
+
float :x,
|
113
|
+
default: nil
|
114
|
+
|
115
|
+
def execute; end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'is false when the input is not given' do
|
120
|
+
expect(inputs.given?(:x)).to be false
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'is true when the input is nil' do
|
124
|
+
args[:x] = nil
|
125
|
+
expect(inputs.given?(:x)).to be true
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'is true when the input is given' do
|
129
|
+
args[:x] = rand
|
130
|
+
expect(inputs.given?(:x)).to be true
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'symbolizes its argument' do
|
134
|
+
args[:x] = rand
|
135
|
+
expect(inputs.given?('x')).to be true
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'only tracks inputs with filters' do
|
139
|
+
args[:y] = rand
|
140
|
+
expect(inputs.given?(:y)).to be false
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'nested hash values' do
|
144
|
+
let(:base_class) do
|
145
|
+
Class.new(ActiveInteraction::Base) do
|
146
|
+
hash :x, default: {} do
|
147
|
+
boolean :y,
|
148
|
+
default: true
|
149
|
+
end
|
150
|
+
|
151
|
+
def execute; end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'is true when the nested inputs symbols are given' do
|
156
|
+
described_class.class_exec do
|
157
|
+
def execute
|
158
|
+
given?(:x, :y)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
args[:x] = { y: false }
|
163
|
+
expect(inputs.given?(:x, :y)).to be true
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'is true when the nested inputs strings are given' do
|
167
|
+
args['x'] = { 'y' => false }
|
168
|
+
expect(inputs.given?(:x, :y)).to be true
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'is false when the nested input is not given' do
|
172
|
+
args[:x] = {}
|
173
|
+
expect(inputs.given?(:x, :y)).to be false
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'is false when the first input is not given' do
|
177
|
+
expect(inputs.given?(:x, :y)).to be false
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'is false when the first input is nil' do
|
181
|
+
args[:x] = nil
|
182
|
+
expect(inputs.given?(:x, :y)).to be false
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'returns false if you go too far' do
|
186
|
+
args[:x] = { y: true }
|
187
|
+
expect(inputs.given?(:x, :y, :z)).to be false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'nested array values' do
|
192
|
+
let(:base_class) do
|
193
|
+
Class.new(ActiveInteraction::Base) do
|
194
|
+
array :x do
|
195
|
+
hash do
|
196
|
+
boolean :y, default: true
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def execute; end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'has a positive index' do
|
205
|
+
it 'returns true if found' do
|
206
|
+
args[:x] = [{ y: true }]
|
207
|
+
expect(inputs.given?(:x, 0, :y)).to be true
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'returns false if not found' do
|
211
|
+
args[:x] = []
|
212
|
+
expect(inputs.given?(:x, 0, :y)).to be false
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'has a negative index' do
|
217
|
+
it 'returns true if found' do
|
218
|
+
args[:x] = [{ y: true }]
|
219
|
+
expect(inputs.given?(:x, -1, :y)).to be true
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'returns false if not found' do
|
223
|
+
args[:x] = []
|
224
|
+
expect(inputs.given?(:x, -1, :y)).to be false
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'returns false if you go too far' do
|
229
|
+
args[:x] = [{}]
|
230
|
+
expect(inputs.given?(:x, 10, :y)).to be false
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'multi-part date values' do
|
235
|
+
let(:base_class) do
|
236
|
+
Class.new(ActiveInteraction::Base) do
|
237
|
+
date :thing,
|
238
|
+
default: nil
|
239
|
+
|
240
|
+
def execute; end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'returns true when the input is given' do
|
245
|
+
args.merge!(
|
246
|
+
'thing(1i)' => '2020',
|
247
|
+
'thing(2i)' => '12',
|
248
|
+
'thing(3i)' => '31'
|
249
|
+
)
|
250
|
+
expect(inputs.given?(:thing)).to be true
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'returns false if not found' do
|
254
|
+
expect(inputs.given?(:thing)).to be false
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
114
258
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'active_record'
|
3
|
-
|
4
|
-
require 'activerecord-jdbcsqlite3-adapter'
|
5
|
-
else
|
6
|
-
require 'sqlite3'
|
7
|
-
end
|
3
|
+
require 'sqlite3'
|
8
4
|
|
9
5
|
ActiveRecord::Base.establish_connection(
|
10
6
|
adapter: 'sqlite3',
|
@@ -36,8 +32,8 @@ end
|
|
36
32
|
describe ArrayInteraction do
|
37
33
|
include_context 'interactions'
|
38
34
|
it_behaves_like 'an interaction', :array, -> { [] }
|
39
|
-
it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }
|
40
|
-
it_behaves_like 'an interaction', :array, -> { List.create!.elements }
|
35
|
+
it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }, ->(result) { result.to_a }
|
36
|
+
it_behaves_like 'an interaction', :array, -> { List.create!.elements }, ->(result) { result.to_a }
|
41
37
|
|
42
38
|
context 'with inputs[:a]' do
|
43
39
|
let(:a) { [[]] }
|
@@ -22,11 +22,11 @@ describe ActiveInteraction::Validation do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
context 'filter
|
25
|
+
context 'filter returns no errors' do
|
26
26
|
let(:inputs) { { name: 1 } }
|
27
27
|
|
28
28
|
before do
|
29
|
-
allow(filter).to receive(:
|
29
|
+
allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, value: 1))
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'returns no errors' do
|
@@ -34,14 +34,15 @@ describe ActiveInteraction::Validation do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
context 'filter
|
37
|
+
context 'filter returns with errors' do
|
38
38
|
before do
|
39
|
-
allow(filter).to receive(:
|
39
|
+
allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, error: exception))
|
40
40
|
end
|
41
41
|
|
42
|
-
context '
|
43
|
-
let(:
|
44
|
-
|
42
|
+
context 'Filter::Error' do
|
43
|
+
let(:filter) { ActiveInteraction::ArrayFilter.new(:name, [1.0, 'a']) { float } }
|
44
|
+
|
45
|
+
let(:exception) { ActiveInteraction::Filter::Error.new(filter, :invalid_type) }
|
45
46
|
|
46
47
|
it 'returns an :invalid_type error' do
|
47
48
|
type = I18n.translate(
|
@@ -51,30 +52,6 @@ describe ActiveInteraction::Validation do
|
|
51
52
|
expect(result).to eql [[filter.name, :invalid_type, { type: type }]]
|
52
53
|
end
|
53
54
|
end
|
54
|
-
|
55
|
-
context 'MissingValueError' do
|
56
|
-
let(:exception) { ActiveInteraction::MissingValueError }
|
57
|
-
|
58
|
-
it 'returns a :missing error' do
|
59
|
-
expect(result).to eql [[filter.name, :missing]]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context 'InvalidNestedValueError' do
|
64
|
-
let(:exception) do
|
65
|
-
ActiveInteraction::InvalidNestedValueError.new(name, value)
|
66
|
-
end
|
67
|
-
let(:name) { SecureRandom.hex.to_sym }
|
68
|
-
let(:value) { double }
|
69
|
-
|
70
|
-
it 'returns an :invalid_nested error' do
|
71
|
-
expect(result).to eql [[
|
72
|
-
filter.name,
|
73
|
-
:invalid_nested,
|
74
|
-
{ name: name.inspect, value: value.inspect }
|
75
|
-
]]
|
76
|
-
end
|
77
|
-
end
|
78
55
|
end
|
79
56
|
end
|
80
57
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,4 +8,12 @@ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
|
8
8
|
RSpec.configure do |config|
|
9
9
|
config.run_all_when_everything_filtered = true
|
10
10
|
config.filter_run_including :focus
|
11
|
+
|
12
|
+
config.before(:suite) do
|
13
|
+
if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
|
14
|
+
::ActiveRecord.index_nested_attribute_errors = false
|
15
|
+
else
|
16
|
+
::ActiveRecord::Base.index_nested_attribute_errors = false
|
17
|
+
end
|
18
|
+
end
|
11
19
|
end
|
data/spec/support/concerns.rb
CHANGED