active_interaction 5.3.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +2 -2
  4. data/lib/active_interaction/errors.rb +1 -1
  5. data/lib/active_interaction/version.rb +1 -1
  6. metadata +26 -112
  7. data/spec/active_interaction/array_input_spec.rb +0 -164
  8. data/spec/active_interaction/base_spec.rb +0 -536
  9. data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -43
  10. data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -47
  11. data/spec/active_interaction/concerns/hashable_spec.rb +0 -44
  12. data/spec/active_interaction/concerns/missable_spec.rb +0 -97
  13. data/spec/active_interaction/concerns/runnable_spec.rb +0 -395
  14. data/spec/active_interaction/errors_spec.rb +0 -223
  15. data/spec/active_interaction/filter/column_spec.rb +0 -85
  16. data/spec/active_interaction/filter_spec.rb +0 -58
  17. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +0 -11
  18. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +0 -11
  19. data/spec/active_interaction/filters/array_filter_spec.rb +0 -248
  20. data/spec/active_interaction/filters/boolean_filter_spec.rb +0 -85
  21. data/spec/active_interaction/filters/date_filter_spec.rb +0 -176
  22. data/spec/active_interaction/filters/date_time_filter_spec.rb +0 -187
  23. data/spec/active_interaction/filters/decimal_filter_spec.rb +0 -124
  24. data/spec/active_interaction/filters/file_filter_spec.rb +0 -38
  25. data/spec/active_interaction/filters/float_filter_spec.rb +0 -109
  26. data/spec/active_interaction/filters/hash_filter_spec.rb +0 -127
  27. data/spec/active_interaction/filters/integer_filter_spec.rb +0 -102
  28. data/spec/active_interaction/filters/interface_filter_spec.rb +0 -459
  29. data/spec/active_interaction/filters/object_filter_spec.rb +0 -235
  30. data/spec/active_interaction/filters/record_filter_spec.rb +0 -204
  31. data/spec/active_interaction/filters/string_filter_spec.rb +0 -58
  32. data/spec/active_interaction/filters/symbol_filter_spec.rb +0 -44
  33. data/spec/active_interaction/filters/time_filter_spec.rb +0 -249
  34. data/spec/active_interaction/grouped_input_spec.rb +0 -15
  35. data/spec/active_interaction/hash_input_spec.rb +0 -56
  36. data/spec/active_interaction/i18n_spec.rb +0 -111
  37. data/spec/active_interaction/inputs_spec.rb +0 -264
  38. data/spec/active_interaction/integration/array_interaction_spec.rb +0 -87
  39. data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -11
  40. data/spec/active_interaction/integration/date_interaction_spec.rb +0 -3
  41. data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -3
  42. data/spec/active_interaction/integration/file_interaction_spec.rb +0 -17
  43. data/spec/active_interaction/integration/float_interaction_spec.rb +0 -3
  44. data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -106
  45. data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -3
  46. data/spec/active_interaction/integration/interface_interaction_spec.rb +0 -18
  47. data/spec/active_interaction/integration/object_interaction_spec.rb +0 -12
  48. data/spec/active_interaction/integration/record_integration_spec.rb +0 -3
  49. data/spec/active_interaction/integration/string_interaction_spec.rb +0 -3
  50. data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -3
  51. data/spec/active_interaction/integration/time_interaction_spec.rb +0 -86
  52. data/spec/active_interaction/modules/validation_spec.rb +0 -55
  53. data/spec/spec_helper.rb +0 -22
  54. data/spec/support/concerns.rb +0 -13
  55. data/spec/support/filters.rb +0 -227
  56. data/spec/support/interactions.rb +0 -124
@@ -1,111 +0,0 @@
1
- RSpec.describe ActiveInteraction do
2
- context 'I18n.load_path' do
3
- it 'contains localization file paths' do
4
- expect(I18n.load_path)
5
- .to include a_string_ending_with('active_interaction/locale/en.yml')
6
- end
7
- end
8
- end
9
-
10
- I18nInteraction = Class.new(TestInteraction) do
11
- hash :a do
12
- hash :x
13
- end
14
- end
15
-
16
- TYPES = ActiveInteraction::Filter
17
- .const_get(:CLASSES)
18
- .keys
19
- .map(&:to_s)
20
-
21
- RSpec.describe I18nInteraction do
22
- include_context 'interactions'
23
-
24
- shared_examples 'translation' do |locale|
25
- around do |example|
26
- old_locale = I18n.locale
27
- I18n.locale = locale
28
-
29
- example.run
30
-
31
- I18n.locale = old_locale
32
- end
33
-
34
- context 'types' do
35
- TYPES.each do |type|
36
- it "has a translation for #{type}" do
37
- key = "#{described_class.i18n_scope}.types.#{type}"
38
- expect { I18n.translate(key, raise: true) }.to_not raise_error
39
- end
40
- end
41
- end
42
-
43
- context 'error messages' do
44
- let(:translation) { I18n.translate(key, type: type, raise: true) }
45
- let(:type) { I18n.translate("#{described_class.i18n_scope}.types.hash") }
46
-
47
- shared_examples 'translations' do |key, value|
48
- context key.inspect do
49
- let(:key) { "#{described_class.i18n_scope}.errors.messages.#{key}" }
50
-
51
- before { inputs[:a] = value }
52
-
53
- it 'has a translation' do
54
- expect { translation }.to_not raise_error
55
- end
56
-
57
- it 'returns the translation' do
58
- expect(outcome.errors[:a]).to include translation
59
- end
60
- end
61
- end
62
-
63
- include_examples 'translations', :invalid_type, Object.new
64
- include_examples 'translations', :missing, nil
65
- end
66
- end
67
-
68
- context 'english' do
69
- include_examples 'translation', :en
70
- end
71
-
72
- context 'brazilian portuguese' do
73
- include_examples 'translation', :'pt-BR'
74
- end
75
-
76
- context 'french' do
77
- include_examples 'translation', :fr
78
- end
79
-
80
- context 'italian' do
81
- include_examples 'translation', :it
82
- end
83
-
84
- context 'hsilgne' do
85
- # This must appear before including the translation examples so that the
86
- # locale is available before it is assigned.
87
- around do |example|
88
- old_locals = I18n.config.available_locales
89
- I18n.config.available_locales += [:hsilgne]
90
-
91
- I18n.backend.store_translations('hsilgne',
92
- active_interaction: {
93
- errors: {
94
- messages: {
95
- invalid: 'is invalid'.reverse,
96
- invalid_type: "%<type>s} #{'is not a valid'.reverse}",
97
- missing: 'missing'.reverse
98
- }
99
- },
100
- types: TYPES.each_with_object({}) { |e, a| a[e] = e.reverse }
101
- }
102
- )
103
-
104
- example.run
105
-
106
- I18n.config.available_locales = old_locals
107
- end
108
-
109
- include_examples 'translation', :hsilgne
110
- end
111
- end
@@ -1,264 +0,0 @@
1
- RSpec.describe ActiveInteraction::Inputs do
2
- subject(:inputs) { described_class.new(args, base_class.new) }
3
-
4
- let(:args) { {} }
5
- let(:base_class) { ActiveInteraction::Base }
6
-
7
- describe '.reserved?(name)' do
8
- it 'returns true for anything starting with "_interaction_"' do
9
- expect(described_class).to be_reserved('_interaction_')
10
- end
11
-
12
- it 'returns true for existing instance methods' do
13
- (
14
- (ActiveInteraction::Base.instance_methods - Object.instance_methods) +
15
- (ActiveInteraction::Base.private_instance_methods - Object.private_instance_methods)
16
- ).each do |method|
17
- expect(described_class).to be_reserved(method)
18
- end
19
- end
20
-
21
- it 'returns false for anything else' do
22
- expect(described_class).to_not be_reserved(SecureRandom.hex)
23
- end
24
- end
25
-
26
- describe '#normalized' do
27
- let(:result) { inputs.normalized }
28
-
29
- context 'with invalid inputs' do
30
- let(:args) { nil }
31
-
32
- it 'raises an error' do
33
- expect { result }.to raise_error ArgumentError
34
- end
35
- end
36
-
37
- context 'with non-hash inputs' do
38
- let(:args) { [%i[k v]] }
39
-
40
- it 'raises an error' do
41
- expect { result }.to raise_error ArgumentError
42
- end
43
- end
44
-
45
- context 'with ActiveInteraction::Inputs inputs' do
46
- let(:args) { described_class.new({ key: :value }, base_class.new) }
47
-
48
- it 'does not raise an error' do
49
- expect { result }.to_not raise_error
50
- end
51
- end
52
-
53
- context 'with ActionController::Parameters inputs' do
54
- let(:args) { ::ActionController::Parameters.new }
55
-
56
- it 'does not raise an error' do
57
- expect { result }.to_not raise_error
58
- end
59
- end
60
-
61
- context 'with simple inputs' do
62
- before { args[:key] = :value }
63
-
64
- it 'sends them straight through' do
65
- expect(result).to eql args
66
- end
67
- end
68
-
69
- context 'with groupable inputs' do
70
- context 'without a matching simple input' do
71
- before do
72
- args.merge!(
73
- 'key(1i)' => :value1,
74
- 'key(2i)' => :value2
75
- )
76
- end
77
-
78
- it 'groups the inputs into a GroupedInput' do
79
- expect(result).to eq(
80
- key: ActiveInteraction::GroupedInput.new(
81
- '1' => :value1,
82
- '2' => :value2
83
- )
84
- )
85
- end
86
- end
87
-
88
- context 'with a matching simple input' do
89
- before do
90
- args.merge!(
91
- 'key(1i)' => :value1,
92
- key: :value2
93
- )
94
- end
95
-
96
- it 'groups the inputs into a GroupedInput' do
97
- expect(result).to eq(
98
- key: ActiveInteraction::GroupedInput.new(
99
- '1' => :value1
100
- )
101
- )
102
- end
103
- end
104
- end
105
-
106
- context 'with a reserved name' do
107
- before { args[:_interaction_key] = :value }
108
-
109
- it 'skips the input' do
110
- expect(result).to_not have_key(:_interaction_key)
111
- end
112
- end
113
- end
114
-
115
- describe '#given?' do
116
- let(:base_class) do
117
- Class.new(ActiveInteraction::Base) do
118
- float :x,
119
- default: nil
120
-
121
- def execute; end
122
- end
123
- end
124
-
125
- it 'is false when the input is not given' do
126
- expect(inputs.given?(:x)).to be false
127
- end
128
-
129
- it 'is true when the input is nil' do
130
- args[:x] = nil
131
- expect(inputs.given?(:x)).to be true
132
- end
133
-
134
- it 'is true when the input is given' do
135
- args[:x] = rand
136
- expect(inputs.given?(:x)).to be true
137
- end
138
-
139
- it 'symbolizes its argument' do
140
- args[:x] = rand
141
- expect(inputs.given?('x')).to be true
142
- end
143
-
144
- it 'only tracks inputs with filters' do
145
- args[:y] = rand
146
- expect(inputs.given?(:y)).to be false
147
- end
148
-
149
- context 'nested hash values' do
150
- let(:base_class) do
151
- Class.new(ActiveInteraction::Base) do
152
- hash :x, default: {} do
153
- boolean :y,
154
- default: true
155
- end
156
-
157
- def execute; end
158
- end
159
- end
160
-
161
- it 'is true when the nested inputs symbols are given' do
162
- described_class.class_exec do
163
- def execute
164
- given?(:x, :y)
165
- end
166
- end
167
-
168
- args[:x] = { y: false }
169
- expect(inputs.given?(:x, :y)).to be true
170
- end
171
-
172
- it 'is true when the nested inputs strings are given' do
173
- args['x'] = { 'y' => false }
174
- expect(inputs.given?(:x, :y)).to be true
175
- end
176
-
177
- it 'is false when the nested input is not given' do
178
- args[:x] = {}
179
- expect(inputs.given?(:x, :y)).to be false
180
- end
181
-
182
- it 'is false when the first input is not given' do
183
- expect(inputs.given?(:x, :y)).to be false
184
- end
185
-
186
- it 'is false when the first input is nil' do
187
- args[:x] = nil
188
- expect(inputs.given?(:x, :y)).to be false
189
- end
190
-
191
- it 'returns false if you go too far' do
192
- args[:x] = { y: true }
193
- expect(inputs.given?(:x, :y, :z)).to be false
194
- end
195
- end
196
-
197
- context 'nested array values' do
198
- let(:base_class) do
199
- Class.new(ActiveInteraction::Base) do
200
- array :x do
201
- hash do
202
- boolean :y, default: true
203
- end
204
- end
205
-
206
- def execute; end
207
- end
208
- end
209
-
210
- context 'has a positive index' do
211
- it 'returns true if found' do
212
- args[:x] = [{ y: true }]
213
- expect(inputs.given?(:x, 0, :y)).to be true
214
- end
215
-
216
- it 'returns false if not found' do
217
- args[:x] = []
218
- expect(inputs.given?(:x, 0, :y)).to be false
219
- end
220
- end
221
-
222
- context 'has a negative index' do
223
- it 'returns true if found' do
224
- args[:x] = [{ y: true }]
225
- expect(inputs.given?(:x, -1, :y)).to be true
226
- end
227
-
228
- it 'returns false if not found' do
229
- args[:x] = []
230
- expect(inputs.given?(:x, -1, :y)).to be false
231
- end
232
- end
233
-
234
- it 'returns false if you go too far' do
235
- args[:x] = [{}]
236
- expect(inputs.given?(:x, 10, :y)).to be false
237
- end
238
- end
239
-
240
- context 'multi-part date values' do
241
- let(:base_class) do
242
- Class.new(ActiveInteraction::Base) do
243
- date :thing,
244
- default: nil
245
-
246
- def execute; end
247
- end
248
- end
249
-
250
- it 'returns true when the input is given' do
251
- args.merge!(
252
- 'thing(1i)' => '2020',
253
- 'thing(2i)' => '12',
254
- 'thing(3i)' => '31'
255
- )
256
- expect(inputs.given?(:thing)).to be true
257
- end
258
-
259
- it 'returns false if not found' do
260
- expect(inputs.given?(:thing)).to be false
261
- end
262
- end
263
- end
264
- end
@@ -1,87 +0,0 @@
1
- require 'active_record'
2
- require 'sqlite3'
3
-
4
- ActiveRecord::Base.establish_connection(
5
- adapter: 'sqlite3',
6
- database: ':memory:'
7
- )
8
-
9
- ActiveRecord::Schema.define do
10
- create_table(:lists)
11
- create_table(:elements) { |t| t.column(:list_id, :integer) }
12
- end
13
-
14
- class List < ActiveRecord::Base
15
- has_many :elements
16
- end
17
-
18
- class Element < ActiveRecord::Base
19
- belongs_to :list
20
- end
21
-
22
- ArrayInteraction = Class.new(TestInteraction) do
23
- array :a do
24
- array
25
- end
26
- array :b, default: [[]] do
27
- array
28
- end
29
- end
30
-
31
- RSpec.describe ArrayInteraction do
32
- include_context 'interactions'
33
- it_behaves_like 'an interaction', :array, -> { [] }
34
- it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }, ->(result) { result.to_a }
35
- it_behaves_like 'an interaction', :array, -> { List.create!.elements }, ->(result) { result.to_a }
36
-
37
- context 'with inputs[:a]' do
38
- let(:a) { [[]] }
39
-
40
- before { inputs[:a] = a }
41
-
42
- it 'returns the correct value for :a' do
43
- expect(result[:a]).to eql a
44
- end
45
-
46
- it 'returns the correct value for :b' do
47
- expect(result[:b]).to eql [[]]
48
- end
49
-
50
- it 'does not raise an error with an invalid nested value' do
51
- inputs[:a] = [false]
52
- expect { outcome }.to_not raise_error
53
- end
54
- end
55
-
56
- context 'with an invalid default' do
57
- it 'raises an error' do
58
- expect do
59
- Class.new(ActiveInteraction::Base) do
60
- array :a, default: Object.new
61
- end
62
- end.to raise_error ActiveInteraction::InvalidDefaultError
63
- end
64
- end
65
-
66
- context 'with an invalid default as a proc' do
67
- it 'does not raise an error' do
68
- expect do
69
- Class.new(ActiveInteraction::Base) do
70
- array :a, default: -> { Object.new }
71
- end
72
- end.to_not raise_error
73
- end
74
- end
75
-
76
- context 'with an invalid nested default' do
77
- it 'raises an error' do
78
- expect do
79
- Class.new(ActiveInteraction::Base) do
80
- array :a, default: [Object.new] do
81
- array
82
- end
83
- end
84
- end.to raise_error ActiveInteraction::InvalidDefaultError
85
- end
86
- end
87
- end
@@ -1,11 +0,0 @@
1
- BooleanInteraction = Class.new(TestInteraction) do
2
- boolean :x
3
- end
4
-
5
- RSpec.describe BooleanInteraction do
6
- it_behaves_like 'an interaction', :boolean, -> { [false, true].sample }
7
-
8
- it 'responds to #x?' do
9
- expect(described_class.new).to respond_to(:x?)
10
- end
11
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'DateInteraction' do
2
- it_behaves_like 'an interaction', :date, -> { Date.today }
3
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'DateTimeInteraction' do
2
- it_behaves_like 'an interaction', :date_time, -> { DateTime.now }
3
- end
@@ -1,17 +0,0 @@
1
- require 'action_dispatch'
2
-
3
- FileInteraction = Class.new(TestInteraction) do
4
- file :a
5
- end
6
-
7
- RSpec.describe FileInteraction do
8
- include_context 'interactions'
9
- it_behaves_like 'an interaction', :file, -> { File.open(__FILE__) }
10
-
11
- it 'works with an uploaded file' do
12
- file = File.open(__FILE__)
13
- uploaded_file = ActionDispatch::Http::UploadedFile.new(tempfile: file)
14
- inputs[:a] = uploaded_file
15
- expect(outcome).to be_valid
16
- end
17
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'FloatInteraction' do
2
- it_behaves_like 'an interaction', :float, -> { rand }
3
- end
@@ -1,106 +0,0 @@
1
- HashInteraction = Class.new(TestInteraction) do
2
- hash :a do
3
- hash :x
4
- end
5
- hash :b, default: {} do
6
- hash :x, default: {}
7
- end
8
- end
9
-
10
- RSpec.describe HashInteraction do
11
- include_context 'interactions'
12
- it_behaves_like 'an interaction', :hash, -> { {} }
13
-
14
- context 'with inputs[:a]' do
15
- let(:a) { { x: {} } }
16
-
17
- before { inputs[:a] = a }
18
-
19
- it 'returns the correct value for :a' do
20
- expect(result[:a]).to eql ActiveSupport::HashWithIndifferentAccess.new(a)
21
- end
22
-
23
- it 'returns the correct value for :b' do
24
- expect(result[:b]).to eql('x' => {})
25
- end
26
-
27
- it 'does not raise an error with an invalid nested value' do
28
- inputs[:a] = { x: false }
29
- expect { outcome }.to_not raise_error
30
- end
31
- end
32
-
33
- context 'with an invalid default' do
34
- it 'raises an error' do
35
- expect do
36
- Class.new(ActiveInteraction::Base) do
37
- hash :a, default: Object.new
38
- end
39
- end.to raise_error ActiveInteraction::InvalidDefaultError
40
- end
41
- end
42
-
43
- context 'with an invalid default as a proc' do
44
- it 'does not raise an error' do
45
- expect do
46
- Class.new(ActiveInteraction::Base) do
47
- array :a, default: -> { Object.new }
48
- end
49
- end.to_not raise_error
50
- end
51
- end
52
-
53
- context 'with an invalid nested default' do
54
- it 'raises an error with a non-empty hash' do
55
- expect do
56
- Class.new(ActiveInteraction::Base) do
57
- hash :a, default: { x: Object.new } do
58
- hash :x
59
- end
60
- end
61
- end.to raise_error ActiveInteraction::InvalidDefaultError
62
- end
63
-
64
- it 'raises an error' do
65
- expect do
66
- Class.new(ActiveInteraction::Base) do
67
- hash :a, default: {} do
68
- hash :x
69
- end
70
- end
71
- end.to raise_error ActiveInteraction::InvalidDefaultError
72
- end
73
- end
74
-
75
- context 'with a default' do
76
- context 'with a lazy nested default' do
77
- it 'raises an error' do
78
- expect do
79
- Class.new(ActiveInteraction::Base) do
80
- hash :b, default: {} do
81
- hash :x, default: -> { {} }
82
- end
83
- end
84
- end.to raise_error ActiveInteraction::InvalidDefaultError
85
- end
86
- end
87
- end
88
-
89
- context 'with a lazy default' do
90
- context 'with a lazy nested default' do
91
- it 'returns the correct value' do
92
- klass = Class.new(ActiveInteraction::Base) do
93
- hash :b, default: -> { {} } do
94
- hash :x, default: -> { {} }
95
- end
96
-
97
- def execute
98
- b
99
- end
100
- end
101
-
102
- expect(klass.run!).to eql('x' => {})
103
- end
104
- end
105
- end
106
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'IntegerInteraction' do
2
- it_behaves_like 'an interaction', :integer, -> { rand(1 << 16) }
3
- end
@@ -1,18 +0,0 @@
1
- require 'json'
2
- require 'yaml'
3
-
4
- InterfaceInteraction = Class.new(TestInteraction) do
5
- interface :anything, methods: []
6
- end
7
-
8
- RSpec.describe InterfaceInteraction do
9
- include_context 'interactions'
10
- it_behaves_like 'an interaction',
11
- :interface,
12
- -> { [JSON, YAML].sample },
13
- methods: %i[dump load]
14
-
15
- it 'succeeds when given nil' do
16
- expect { result }.to_not raise_error
17
- end
18
- end
@@ -1,12 +0,0 @@
1
- ObjectInteraction = Class.new(TestInteraction) do
2
- object :object
3
- end
4
-
5
- RSpec.describe ObjectInteraction do
6
- include_context 'interactions'
7
- it_behaves_like 'an interaction', :object, -> { // }, class: Regexp
8
-
9
- it 'succeeds when given nil' do
10
- expect { result }.to_not raise_error
11
- end
12
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'RecordIntegration' do
2
- it_behaves_like 'an interaction', :record, -> { Encoding::US_ASCII }, class: Encoding
3
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'StringInteraction' do
2
- it_behaves_like 'an interaction', :string, -> { SecureRandom.hex }
3
- end
@@ -1,3 +0,0 @@
1
- RSpec.describe 'SymbolInteraction' do
2
- it_behaves_like 'an interaction', :symbol, -> { SecureRandom.hex.to_sym }
3
- end