active_interaction 5.2.0 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +11 -12
- data/lib/active_interaction/base.rb +2 -0
- data/lib/active_interaction/errors.rb +16 -16
- data/lib/active_interaction/filters/hash_filter.rb +5 -1
- data/lib/active_interaction/version.rb +1 -1
- metadata +26 -112
- data/spec/active_interaction/array_input_spec.rb +0 -166
- data/spec/active_interaction/base_spec.rb +0 -537
- data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -45
- data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -49
- data/spec/active_interaction/concerns/hashable_spec.rb +0 -46
- data/spec/active_interaction/concerns/missable_spec.rb +0 -99
- data/spec/active_interaction/concerns/runnable_spec.rb +0 -397
- data/spec/active_interaction/errors_spec.rb +0 -196
- data/spec/active_interaction/filter/column_spec.rb +0 -87
- data/spec/active_interaction/filter_spec.rb +0 -60
- data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +0 -13
- data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +0 -13
- data/spec/active_interaction/filters/array_filter_spec.rb +0 -250
- data/spec/active_interaction/filters/boolean_filter_spec.rb +0 -87
- data/spec/active_interaction/filters/date_filter_spec.rb +0 -178
- data/spec/active_interaction/filters/date_time_filter_spec.rb +0 -189
- data/spec/active_interaction/filters/decimal_filter_spec.rb +0 -126
- data/spec/active_interaction/filters/file_filter_spec.rb +0 -40
- data/spec/active_interaction/filters/float_filter_spec.rb +0 -110
- data/spec/active_interaction/filters/hash_filter_spec.rb +0 -129
- data/spec/active_interaction/filters/integer_filter_spec.rb +0 -104
- data/spec/active_interaction/filters/interface_filter_spec.rb +0 -461
- data/spec/active_interaction/filters/object_filter_spec.rb +0 -237
- data/spec/active_interaction/filters/record_filter_spec.rb +0 -206
- data/spec/active_interaction/filters/string_filter_spec.rb +0 -60
- data/spec/active_interaction/filters/symbol_filter_spec.rb +0 -46
- data/spec/active_interaction/filters/time_filter_spec.rb +0 -251
- data/spec/active_interaction/grouped_input_spec.rb +0 -17
- data/spec/active_interaction/hash_input_spec.rb +0 -58
- data/spec/active_interaction/i18n_spec.rb +0 -113
- data/spec/active_interaction/inputs_spec.rb +0 -266
- data/spec/active_interaction/integration/array_interaction_spec.rb +0 -88
- data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/date_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/file_interaction_spec.rb +0 -18
- data/spec/active_interaction/integration/float_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -76
- data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/interface_interaction_spec.rb +0 -19
- data/spec/active_interaction/integration/object_interaction_spec.rb +0 -14
- data/spec/active_interaction/integration/record_integration_spec.rb +0 -5
- data/spec/active_interaction/integration/string_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -5
- data/spec/active_interaction/integration/time_interaction_spec.rb +0 -88
- data/spec/active_interaction/modules/validation_spec.rb +0 -57
- data/spec/spec_helper.rb +0 -20
- data/spec/support/concerns.rb +0 -13
- data/spec/support/filters.rb +0 -227
- data/spec/support/interactions.rb +0 -124
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
TimeWithZone = Class.new do
|
4
|
-
attr_reader :time
|
5
|
-
|
6
|
-
def initialize(time)
|
7
|
-
@time = time
|
8
|
-
end
|
9
|
-
|
10
|
-
def ==(other)
|
11
|
-
!other.nil? && time == other.time
|
12
|
-
end
|
13
|
-
|
14
|
-
def at(*args)
|
15
|
-
TimeWithZone.new(Time.at(*args) + 1)
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse(*args)
|
19
|
-
TimeWithZone.new(Time.parse(*args) + 1)
|
20
|
-
rescue ArgumentError
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
TimeInteraction = Class.new(TestInteraction) do
|
26
|
-
time :a
|
27
|
-
end
|
28
|
-
|
29
|
-
describe TimeInteraction do
|
30
|
-
include_context 'interactions'
|
31
|
-
it_behaves_like 'an interaction', :time, -> { Time.now }
|
32
|
-
|
33
|
-
context 'with a time zone' do
|
34
|
-
let(:a) { nil }
|
35
|
-
|
36
|
-
before do
|
37
|
-
inputs[:a] = a
|
38
|
-
|
39
|
-
allow(Time).to receive(:zone).and_return(TimeWithZone.new(0))
|
40
|
-
end
|
41
|
-
|
42
|
-
context 'with an integer' do
|
43
|
-
let(:a) { rand(1 << 16) }
|
44
|
-
|
45
|
-
it 'returns the correct value' do
|
46
|
-
expect(result[:a]).to eq TimeWithZone.new(0).at(a)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'with a string' do
|
51
|
-
let(:a) { '2011-12-13T14:15:16Z' }
|
52
|
-
|
53
|
-
it 'returns the correct value' do
|
54
|
-
expect(result[:a]).to eq TimeWithZone.new(0).parse(a)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'with an invalid String' do
|
59
|
-
let(:a) { 'invalid' }
|
60
|
-
|
61
|
-
it 'is invalid' do
|
62
|
-
expect(outcome).to be_invalid
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'with a Time' do
|
67
|
-
let(:a) { Time.now }
|
68
|
-
|
69
|
-
it 'returns the correct value' do
|
70
|
-
expect(result[:a]).to eql a
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
context 'with a TimeZone' do
|
75
|
-
let(:a) { TimeWithZone.new(Time.now) }
|
76
|
-
|
77
|
-
it 'returns the correct value' do
|
78
|
-
expect(result[:a]).to eql a
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'handles time zone changes' do
|
82
|
-
outcome
|
83
|
-
allow(Time).to receive(:zone).and_return(nil)
|
84
|
-
expect(described_class.run(inputs)).to be_invalid
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ActiveInteraction::Validation do
|
4
|
-
describe '.validate(context, filters, inputs)' do
|
5
|
-
let(:inputs) { {} }
|
6
|
-
let(:filter) { ActiveInteraction::Filter.new(:name, {}) }
|
7
|
-
let(:interaction) do
|
8
|
-
name = filter.name
|
9
|
-
klass = Class.new(ActiveInteraction::Base) { attr_writer(name) }
|
10
|
-
klass.filters[name] = filter
|
11
|
-
klass.new
|
12
|
-
end
|
13
|
-
let(:result) do
|
14
|
-
described_class.validate(interaction, interaction.class.filters, inputs)
|
15
|
-
end
|
16
|
-
|
17
|
-
context 'no filters are given' do
|
18
|
-
let(:interaction) { Class.new(ActiveInteraction::Base).new }
|
19
|
-
|
20
|
-
it 'returns no errors' do
|
21
|
-
expect(result).to eql []
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'filter returns no errors' do
|
26
|
-
let(:inputs) { { name: 1 } }
|
27
|
-
|
28
|
-
before do
|
29
|
-
allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, value: 1))
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'returns no errors' do
|
33
|
-
expect(result).to eql []
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'filter returns with errors' do
|
38
|
-
before do
|
39
|
-
allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, error: exception))
|
40
|
-
end
|
41
|
-
|
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) }
|
46
|
-
|
47
|
-
it 'returns an :invalid_type error' do
|
48
|
-
type = I18n.translate(
|
49
|
-
"#{ActiveInteraction::Base.i18n_scope}.types.#{filter.class.slug}"
|
50
|
-
)
|
51
|
-
|
52
|
-
expect(result).to eql [[filter.name, :invalid_type, { type: type }]]
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'i18n'
|
2
|
-
I18n.config.enforce_available_locales = true if I18n.config.respond_to?(:enforce_available_locales)
|
3
|
-
|
4
|
-
require 'active_interaction'
|
5
|
-
require 'active_record'
|
6
|
-
|
7
|
-
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
8
|
-
|
9
|
-
RSpec.configure do |config|
|
10
|
-
config.run_all_when_everything_filtered = true
|
11
|
-
config.filter_run_including :focus
|
12
|
-
|
13
|
-
config.before(:suite) do
|
14
|
-
if ActiveRecord.respond_to?(:index_nested_attribute_errors)
|
15
|
-
ActiveRecord.index_nested_attribute_errors = false
|
16
|
-
else
|
17
|
-
ActiveRecord::Base.index_nested_attribute_errors = false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/spec/support/concerns.rb
DELETED
data/spec/support/filters.rb
DELETED
@@ -1,227 +0,0 @@
|
|
1
|
-
shared_context 'filters' do
|
2
|
-
subject(:filter) { described_class.new(name, options, &block) }
|
3
|
-
|
4
|
-
let(:block) { nil }
|
5
|
-
let(:name) { SecureRandom.hex.to_sym }
|
6
|
-
let(:options) { {} }
|
7
|
-
|
8
|
-
shared_context 'optional' do
|
9
|
-
before do
|
10
|
-
options[:default] = nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
shared_context 'required' do
|
15
|
-
before do
|
16
|
-
options.delete(:default)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
shared_examples_for 'a filter' do
|
22
|
-
include_context 'filters'
|
23
|
-
|
24
|
-
describe '.factory' do
|
25
|
-
context 'with an invalid slug' do
|
26
|
-
it 'raises an error' do
|
27
|
-
expect do
|
28
|
-
described_class.factory(:invalid)
|
29
|
-
end.to raise_error ActiveInteraction::MissingFilterError
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'with a valid slug' do
|
34
|
-
it 'returns a Filter' do
|
35
|
-
expect(
|
36
|
-
described_class.factory(described_class.slug)
|
37
|
-
).to eql described_class
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '.slug' do
|
43
|
-
it 'returns a symbol' do
|
44
|
-
expect(described_class.slug).to be_a Symbol
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe '#process' do
|
49
|
-
let(:value) { nil }
|
50
|
-
|
51
|
-
context 'optional' do
|
52
|
-
include_context 'optional'
|
53
|
-
|
54
|
-
it 'returns the default' do
|
55
|
-
expect(filter.process(value, nil).value).to eql options[:default]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'required' do
|
60
|
-
include_context 'required'
|
61
|
-
|
62
|
-
it 'indicates an error' do
|
63
|
-
error = filter.process(value, nil).errors.first
|
64
|
-
|
65
|
-
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
66
|
-
expect(error.type).to be :missing
|
67
|
-
end
|
68
|
-
|
69
|
-
context 'with an invalid value' do
|
70
|
-
let(:value) { Object.new }
|
71
|
-
|
72
|
-
it 'indicates an error' do
|
73
|
-
error = filter.process(value, nil).errors.first
|
74
|
-
|
75
|
-
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
76
|
-
expect(error.type).to be :invalid_type
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'with an invalid default' do
|
82
|
-
before do
|
83
|
-
options[:default] = Object.new
|
84
|
-
end
|
85
|
-
|
86
|
-
it 'raises an error' do
|
87
|
-
expect do
|
88
|
-
filter.process(value, nil)
|
89
|
-
end.to raise_error ActiveInteraction::InvalidDefaultError
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# BasicObject is missing a lot of methods
|
94
|
-
context 'with a BasicObject' do
|
95
|
-
let(:value) { BasicObject.new }
|
96
|
-
|
97
|
-
it 'indicates an error' do
|
98
|
-
error = filter.process(value, nil).errors.first
|
99
|
-
|
100
|
-
expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
|
101
|
-
expect(error.type).to be :invalid_type
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
describe '#default' do
|
107
|
-
context 'optional' do
|
108
|
-
include_context 'optional'
|
109
|
-
|
110
|
-
it 'returns the default' do
|
111
|
-
expect(filter.default(nil)).to eql options[:default]
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context 'required' do
|
116
|
-
include_context 'required'
|
117
|
-
|
118
|
-
it 'raises an error' do
|
119
|
-
expect do
|
120
|
-
filter.default(nil)
|
121
|
-
end.to raise_error ActiveInteraction::NoDefaultError
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context 'with an invalid default' do
|
126
|
-
before do
|
127
|
-
options[:default] = Object.new
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'raises an error' do
|
131
|
-
expect do
|
132
|
-
filter.default(nil)
|
133
|
-
end.to raise_error ActiveInteraction::InvalidDefaultError
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
context 'with a callable default' do
|
138
|
-
include_context 'optional'
|
139
|
-
|
140
|
-
before do
|
141
|
-
default = options[:default]
|
142
|
-
options[:default] = -> { default }
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'returns the default' do
|
146
|
-
expect(filter.default(nil)).to eql options[:default].call
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
context 'with a callable default that takes an argument' do
|
151
|
-
include_context 'optional'
|
152
|
-
|
153
|
-
it 'returns the default' do
|
154
|
-
default = options[:default]
|
155
|
-
|
156
|
-
spec = self
|
157
|
-
filter # Necessary to bring into scope for lambda.
|
158
|
-
options[:default] = lambda do |this|
|
159
|
-
spec.expect(this).to be filter
|
160
|
-
default
|
161
|
-
end
|
162
|
-
|
163
|
-
expect(filter.default(nil)).to be default
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
describe '#desc' do
|
169
|
-
it 'returns nil' do
|
170
|
-
expect(filter.desc).to be_nil
|
171
|
-
end
|
172
|
-
|
173
|
-
context 'with a description' do
|
174
|
-
let(:desc) { SecureRandom.hex }
|
175
|
-
|
176
|
-
before do
|
177
|
-
options[:desc] = desc
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'returns the description' do
|
181
|
-
expect(filter.desc).to eql desc
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe '#filters' do
|
187
|
-
it 'returns Hash' do
|
188
|
-
expect(filter.filters).to be_a Hash
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
describe '#default?' do
|
193
|
-
context 'optional' do
|
194
|
-
include_context 'optional'
|
195
|
-
|
196
|
-
it 'returns true' do
|
197
|
-
expect(filter).to be_default
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
context 'required' do
|
202
|
-
include_context 'required'
|
203
|
-
|
204
|
-
it 'returns false' do
|
205
|
-
expect(filter).to_not be_default
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
describe '#name' do
|
211
|
-
it 'returns the name' do
|
212
|
-
expect(filter.name).to eql name
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
describe '#options' do
|
217
|
-
it 'returns the options' do
|
218
|
-
expect(filter.options).to eql options
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
describe '#database_column_type' do
|
223
|
-
it 'returns a symbol' do
|
224
|
-
expect(filter.database_column_type).to be_a Symbol
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
@@ -1,124 +0,0 @@
|
|
1
|
-
TestInteraction = Class.new(ActiveInteraction::Base) do
|
2
|
-
def self.name
|
3
|
-
SecureRandom.hex
|
4
|
-
end
|
5
|
-
|
6
|
-
def execute
|
7
|
-
inputs
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
shared_context 'interactions' do
|
12
|
-
let(:inputs) { {} }
|
13
|
-
let(:outcome) { described_class.run(inputs) }
|
14
|
-
let(:result) { outcome.result }
|
15
|
-
end
|
16
|
-
|
17
|
-
shared_examples_for 'an interaction' do |type, generator, adjust_output = nil, **filter_options|
|
18
|
-
include_context 'interactions'
|
19
|
-
|
20
|
-
let(:described_class) do
|
21
|
-
Class.new(TestInteraction) do
|
22
|
-
public_send(type, :required, filter_options)
|
23
|
-
public_send(type, :optional,
|
24
|
-
filter_options.merge(
|
25
|
-
default: nil
|
26
|
-
)
|
27
|
-
)
|
28
|
-
public_send(type, :default,
|
29
|
-
filter_options.merge(
|
30
|
-
default: generator.call
|
31
|
-
)
|
32
|
-
)
|
33
|
-
public_send(type, :defaults1, :defaults2,
|
34
|
-
filter_options.merge(
|
35
|
-
default: generator.call
|
36
|
-
)
|
37
|
-
)
|
38
|
-
public_send(type, :defaults3,
|
39
|
-
filter_options.merge(
|
40
|
-
default: -> { required }
|
41
|
-
)
|
42
|
-
)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'with an invalid lazy default' do
|
47
|
-
let(:described_class) do
|
48
|
-
Class.new(TestInteraction) do
|
49
|
-
public_send(type, :default,
|
50
|
-
filter_options.merge(default: -> { Object.new })
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'raises an error' do
|
56
|
-
expect { outcome }.to raise_error ActiveInteraction::InvalidDefaultError
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'without required inputs' do
|
61
|
-
it 'is invalid' do
|
62
|
-
expect(outcome).to be_invalid
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'with inputs[:required]' do
|
67
|
-
let(:required) { generator.call }
|
68
|
-
|
69
|
-
before { inputs[:required] = required }
|
70
|
-
|
71
|
-
it 'is valid' do
|
72
|
-
expect(outcome).to be_valid
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'returns the correct value for :required' do
|
76
|
-
expect(result[:required]).to eql(adjust_output ? adjust_output.call(required) : required)
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'returns nil for :optional' do
|
80
|
-
expect(result[:optional]).to be_nil
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'does not return nil for :default' do
|
84
|
-
expect(result[:default]).to_not be_nil
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'does not return nil for :default when given nil' do
|
88
|
-
inputs[:default] = nil
|
89
|
-
expect(result[:default]).to_not be_nil
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'does not return nil for :defaults1' do
|
93
|
-
expect(result[:defaults1]).to_not be_nil
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'does not return nil for :defaults2' do
|
97
|
-
expect(result[:defaults2]).to_not be_nil
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'evaluates :defaults3 in the interaction binding' do
|
101
|
-
expect(result[:defaults3]).to eql result[:required]
|
102
|
-
end
|
103
|
-
|
104
|
-
context 'with inputs[:optional]' do
|
105
|
-
let(:optional) { generator.call }
|
106
|
-
|
107
|
-
before { inputs[:optional] = optional }
|
108
|
-
|
109
|
-
it 'returns the correct value for :optional' do
|
110
|
-
expect(result[:optional]).to eql(adjust_output ? adjust_output.call(optional) : optional)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context 'with inputs[:default]' do
|
115
|
-
let(:default) { generator.call }
|
116
|
-
|
117
|
-
before { inputs[:default] = default }
|
118
|
-
|
119
|
-
it 'returns the correct value for :default' do
|
120
|
-
expect(result[:default]).to eql(adjust_output ? adjust_output.call(default) : default)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|