active_interaction 3.7.1 → 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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +190 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +96 -90
  5. data/lib/active_interaction.rb +1 -7
  6. data/lib/active_interaction/base.rb +48 -33
  7. data/lib/active_interaction/concerns/active_modelable.rb +1 -3
  8. data/lib/active_interaction/concerns/active_recordable.rb +1 -6
  9. data/lib/active_interaction/concerns/hashable.rb +0 -1
  10. data/lib/active_interaction/concerns/missable.rb +0 -1
  11. data/lib/active_interaction/concerns/runnable.rb +16 -28
  12. data/lib/active_interaction/errors.rb +8 -7
  13. data/lib/active_interaction/filter.rb +51 -37
  14. data/lib/active_interaction/filter_column.rb +0 -3
  15. data/lib/active_interaction/filters/abstract_date_time_filter.rb +34 -36
  16. data/lib/active_interaction/filters/abstract_numeric_filter.rb +27 -17
  17. data/lib/active_interaction/filters/array_filter.rb +57 -36
  18. data/lib/active_interaction/filters/boolean_filter.rb +26 -12
  19. data/lib/active_interaction/filters/date_filter.rb +1 -2
  20. data/lib/active_interaction/filters/date_time_filter.rb +1 -2
  21. data/lib/active_interaction/filters/decimal_filter.rb +10 -28
  22. data/lib/active_interaction/filters/file_filter.rb +6 -5
  23. data/lib/active_interaction/filters/float_filter.rb +1 -2
  24. data/lib/active_interaction/filters/hash_filter.rb +37 -27
  25. data/lib/active_interaction/filters/integer_filter.rb +7 -8
  26. data/lib/active_interaction/filters/interface_filter.rb +48 -14
  27. data/lib/active_interaction/filters/object_filter.rb +23 -50
  28. data/lib/active_interaction/filters/record_filter.rb +10 -35
  29. data/lib/active_interaction/filters/string_filter.rb +21 -12
  30. data/lib/active_interaction/filters/symbol_filter.rb +13 -7
  31. data/lib/active_interaction/filters/time_filter.rb +19 -22
  32. data/lib/active_interaction/grouped_input.rb +0 -3
  33. data/lib/active_interaction/inputs.rb +89 -0
  34. data/lib/active_interaction/locale/ja.yml +24 -0
  35. data/lib/active_interaction/modules/input_processor.rb +9 -6
  36. data/lib/active_interaction/modules/validation.rb +9 -12
  37. data/lib/active_interaction/version.rb +1 -3
  38. data/spec/active_interaction/base_spec.rb +95 -35
  39. data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -2
  40. data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -2
  41. data/spec/active_interaction/concerns/hashable_spec.rb +1 -3
  42. data/spec/active_interaction/concerns/missable_spec.rb +0 -2
  43. data/spec/active_interaction/concerns/runnable_spec.rb +32 -12
  44. data/spec/active_interaction/errors_spec.rb +49 -22
  45. data/spec/active_interaction/filter_column_spec.rb +0 -2
  46. data/spec/active_interaction/filter_spec.rb +0 -2
  47. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -3
  48. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -3
  49. data/spec/active_interaction/filters/array_filter_spec.rb +41 -15
  50. data/spec/active_interaction/filters/boolean_filter_spec.rb +58 -4
  51. data/spec/active_interaction/filters/date_filter_spec.rb +43 -3
  52. data/spec/active_interaction/filters/date_time_filter_spec.rb +43 -3
  53. data/spec/active_interaction/filters/decimal_filter_spec.rb +57 -3
  54. data/spec/active_interaction/filters/file_filter_spec.rb +1 -3
  55. data/spec/active_interaction/filters/float_filter_spec.rb +60 -4
  56. data/spec/active_interaction/filters/hash_filter_spec.rb +19 -9
  57. data/spec/active_interaction/filters/integer_filter_spec.rb +49 -7
  58. data/spec/active_interaction/filters/interface_filter_spec.rb +397 -24
  59. data/spec/active_interaction/filters/object_filter_spec.rb +23 -59
  60. data/spec/active_interaction/filters/record_filter_spec.rb +23 -49
  61. data/spec/active_interaction/filters/string_filter_spec.rb +15 -3
  62. data/spec/active_interaction/filters/symbol_filter_spec.rb +15 -3
  63. data/spec/active_interaction/filters/time_filter_spec.rb +65 -3
  64. data/spec/active_interaction/grouped_input_spec.rb +0 -2
  65. data/spec/active_interaction/i18n_spec.rb +3 -7
  66. data/spec/active_interaction/{modules/input_processor_spec.rb → inputs_spec.rb} +5 -5
  67. data/spec/active_interaction/integration/array_interaction_spec.rb +23 -12
  68. data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -2
  69. data/spec/active_interaction/integration/date_interaction_spec.rb +0 -2
  70. data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -2
  71. data/spec/active_interaction/integration/file_interaction_spec.rb +0 -2
  72. data/spec/active_interaction/integration/float_interaction_spec.rb +0 -2
  73. data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -2
  74. data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -2
  75. data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -3
  76. data/spec/active_interaction/integration/object_interaction_spec.rb +0 -2
  77. data/spec/active_interaction/integration/string_interaction_spec.rb +0 -2
  78. data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -2
  79. data/spec/active_interaction/integration/time_interaction_spec.rb +14 -18
  80. data/spec/active_interaction/modules/validation_spec.rb +1 -3
  81. data/spec/spec_helper.rb +2 -6
  82. data/spec/support/concerns.rb +0 -2
  83. data/spec/support/filters.rb +13 -9
  84. data/spec/support/interactions.rb +22 -14
  85. metadata +106 -52
  86. data/lib/active_interaction/backports.rb +0 -59
  87. data/lib/active_interaction/filters/abstract_filter.rb +0 -19
  88. data/spec/active_interaction/filters/abstract_filter_spec.rb +0 -8
@@ -1,47 +1,420 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
- require 'json'
5
- require 'yaml'
2
+
3
+ module InterfaceModule; end
4
+
5
+ class InterfaceClass; end # rubocop:disable Lint/EmptyClass
6
6
 
7
7
  describe ActiveInteraction::InterfaceFilter, :filter do
8
8
  include_context 'filters'
9
- it_behaves_like 'a filter'
10
-
11
- before { options[:methods] = %i[dump load] }
9
+ it_behaves_like 'a filter' do
10
+ let(:name) { :interface_module }
11
+ end
12
12
 
13
13
  describe '#cast' do
14
- let(:result) { filter.cast(value, nil) }
14
+ let(:result) { filter.send(:cast, value, nil) }
15
15
 
16
- context 'with a BasicObject' do
17
- let(:value) { BasicObject.new }
16
+ context 'with an implicit constant name' do
17
+ context 'passed an instance' do
18
+ context 'with the module included' do
19
+ let(:name) { :interface_module }
20
+ let(:value) do
21
+ Class.new do
22
+ include InterfaceModule
23
+ end.new
24
+ end
18
25
 
19
- it 'raises an error' do
20
- expect { result }.to raise_error ActiveInteraction::InvalidValueError
26
+ it 'returns a the value' do
27
+ expect(result).to eql value
28
+ end
29
+ end
30
+
31
+ context 'with the class inherited from' do
32
+ let(:name) { :interface_class }
33
+ let(:value) do
34
+ Class.new(InterfaceClass) {}.new # rubocop:disable Lint/EmptyBlock
35
+ end
36
+
37
+ it 'returns a the value' do
38
+ expect(result).to eql value
39
+ end
40
+ end
41
+
42
+ context 'that is extended by the ancestor' do
43
+ let(:name) { :interface_module }
44
+ let(:value) do
45
+ Class.new {}.new.extend(InterfaceModule) # rubocop:disable Lint/EmptyBlock
46
+ end
47
+
48
+ it 'returns a the value' do
49
+ expect(result).to eql value
50
+ end
51
+ end
52
+
53
+ context 'that does not match' do
54
+ let(:name) { :interface_module }
55
+ let(:value) { Class.new }
56
+
57
+ it 'raises an error' do
58
+ expect do
59
+ result
60
+ end.to raise_error ActiveInteraction::InvalidValueError
61
+ end
62
+ end
63
+
64
+ context 'with the class itself' do
65
+ let(:name) { :interface_class }
66
+ let(:value) do
67
+ InterfaceClass.new
68
+ end
69
+
70
+ it 'raises an error' do
71
+ expect do
72
+ result
73
+ end.to raise_error ActiveInteraction::InvalidValueError
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'passed a class' do
79
+ context 'with the class inherited from' do
80
+ let(:name) { :interface_class }
81
+ let(:value) do
82
+ Class.new(InterfaceClass) {} # rubocop:disable Lint/EmptyBlock
83
+ end
84
+
85
+ it 'returns a the value' do
86
+ expect(result).to eql value
87
+ end
88
+ end
89
+
90
+ context 'that is extended by the ancestor' do
91
+ let(:name) { :interface_module }
92
+ let(:value) do
93
+ Class.new do
94
+ extend InterfaceModule
95
+ end
96
+ end
97
+
98
+ it 'returns a the value' do
99
+ expect(result).to eql value
100
+ end
101
+ end
102
+
103
+ context 'that does not match' do
104
+ let(:name) { :interface_class }
105
+ let(:value) { Class }
106
+
107
+ it 'raises an error' do
108
+ expect do
109
+ result
110
+ end.to raise_error ActiveInteraction::InvalidValueError
111
+ end
112
+ end
113
+
114
+ context 'with the class itself' do
115
+ let(:name) { :interface_class }
116
+ let(:value) { InterfaceClass }
117
+
118
+ it 'raises an error' do
119
+ expect do
120
+ result
121
+ end.to raise_error ActiveInteraction::InvalidValueError
122
+ end
123
+ end
124
+ end
125
+
126
+ context 'passed a module' do
127
+ context 'that is extended by the ancestor' do
128
+ let(:name) { :interface_module }
129
+ let(:value) do
130
+ Module.new do
131
+ extend InterfaceModule
132
+ end
133
+ end
134
+
135
+ it 'returns a the value' do
136
+ expect(result).to eql value
137
+ end
138
+ end
139
+
140
+ context 'that does not match' do
141
+ let(:name) { :interface_module }
142
+ let(:value) { Module.new }
143
+
144
+ it 'raises an error' do
145
+ expect do
146
+ result
147
+ end.to raise_error ActiveInteraction::InvalidValueError
148
+ end
149
+ end
150
+
151
+ context 'with the module itself' do
152
+ let(:name) { :interface_module }
153
+ let(:value) { InterfaceModule }
154
+
155
+ it 'raises an error' do
156
+ expect do
157
+ result
158
+ end.to raise_error ActiveInteraction::InvalidValueError
159
+ end
160
+ end
161
+ end
162
+
163
+ context 'given an invalid name' do
164
+ let(:name) { :invalid }
165
+ let(:value) { Object }
166
+
167
+ it 'raises an error' do
168
+ expect do
169
+ result
170
+ end.to raise_error ActiveInteraction::InvalidNameError
171
+ end
21
172
  end
22
173
  end
23
174
 
24
- context 'with an Object' do
25
- let(:value) { Object.new }
175
+ context 'with a constant given' do
176
+ context 'passed an instance' do
177
+ context 'with the module included' do
178
+ before { options.merge!(from: :interface_module) }
179
+ let(:value) do
180
+ Class.new do
181
+ include InterfaceModule
182
+ end.new
183
+ end
26
184
 
27
- it 'raises an error' do
28
- expect { result }.to raise_error ActiveInteraction::InvalidValueError
185
+ it 'returns a the value' do
186
+ expect(result).to eql value
187
+ end
188
+ end
189
+
190
+ context 'with the class inherited from' do
191
+ before { options.merge!(from: :interface_class) }
192
+ let(:value) do
193
+ Class.new(InterfaceClass) {}.new # rubocop:disable Lint/EmptyBlock
194
+ end
195
+
196
+ it 'returns a the value' do
197
+ expect(result).to eql value
198
+ end
199
+ end
200
+
201
+ context 'that is extended by the ancestor' do
202
+ before { options.merge!(from: :interface_module) }
203
+ let(:value) do
204
+ Class.new {}.new.extend(InterfaceModule) # rubocop:disable Lint/EmptyBlock
205
+ end
206
+
207
+ it 'returns a the value' do
208
+ expect(result).to eql value
209
+ end
210
+ end
211
+
212
+ context 'that does not match' do
213
+ let(:name) { :interface_class }
214
+ let(:value) { Class.new }
215
+
216
+ it 'raises an error' do
217
+ expect do
218
+ result
219
+ end.to raise_error ActiveInteraction::InvalidValueError
220
+ end
221
+ end
222
+
223
+ context 'with the class itself' do
224
+ let(:name) { :interface_class }
225
+ let(:value) { InterfaceClass.new }
226
+
227
+ it 'raises an error' do
228
+ expect do
229
+ result
230
+ end.to raise_error ActiveInteraction::InvalidValueError
231
+ end
232
+ end
233
+ end
234
+
235
+ context 'passed a class' do
236
+ context 'with the class inherited from' do
237
+ before { options.merge!(from: :interface_class) }
238
+ let(:value) do
239
+ Class.new(InterfaceClass) {} # rubocop:disable Lint/EmptyBlock
240
+ end
241
+
242
+ it 'returns a the value' do
243
+ expect(result).to eql value
244
+ end
245
+ end
246
+
247
+ context 'that is extended by the ancestor' do
248
+ before { options.merge!(from: :interface_module) }
249
+ let(:value) do
250
+ Class.new do
251
+ extend InterfaceModule
252
+ end
253
+ end
254
+
255
+ it 'returns a the value' do
256
+ expect(result).to eql value
257
+ end
258
+ end
259
+
260
+ context 'that does not match' do
261
+ let(:name) { :interface_class }
262
+ let(:value) { Class }
263
+
264
+ it 'raises an error' do
265
+ expect do
266
+ result
267
+ end.to raise_error ActiveInteraction::InvalidValueError
268
+ end
269
+ end
270
+
271
+ context 'with the class itself' do
272
+ let(:name) { :interface_class }
273
+ let(:value) { InterfaceClass }
274
+
275
+ it 'raises an error' do
276
+ expect do
277
+ result
278
+ end.to raise_error ActiveInteraction::InvalidValueError
279
+ end
280
+ end
281
+ end
282
+
283
+ context 'passed a module' do
284
+ context 'that is extended by the ancestor' do
285
+ before { options.merge!(from: :interface_module) }
286
+ let(:value) do
287
+ Module.new do
288
+ extend InterfaceModule
289
+ end
290
+ end
291
+
292
+ it 'returns a the value' do
293
+ expect(result).to eql value
294
+ end
295
+ end
296
+
297
+ context 'that does not match' do
298
+ let(:name) { :interface_module }
299
+ let(:value) { Module.new }
300
+
301
+ it 'raises an error' do
302
+ expect do
303
+ result
304
+ end.to raise_error ActiveInteraction::InvalidValueError
305
+ end
306
+ end
307
+
308
+ context 'with the module itself' do
309
+ let(:name) { :interface_module }
310
+ let(:value) { InterfaceModule }
311
+
312
+ it 'raises an error' do
313
+ expect do
314
+ result
315
+ end.to raise_error ActiveInteraction::InvalidValueError
316
+ end
317
+ end
318
+ end
319
+
320
+ context 'given an invalid name' do
321
+ before { options.merge!(from: :invalid) }
322
+ let(:value) { Object }
323
+
324
+ it 'raises an error' do
325
+ expect do
326
+ result
327
+ end.to raise_error ActiveInteraction::InvalidNameError
328
+ end
29
329
  end
30
330
  end
31
331
 
32
- context 'with JSON' do
33
- let(:value) { JSON }
332
+ context 'with methods passed' do
333
+ before { options[:methods] = %i[dump load] }
334
+
335
+ context 'passed an valid instance' do
336
+ let(:value) do
337
+ Class.new do
338
+ def dump; end
34
339
 
35
- it 'returns an Array' do
36
- expect(result).to eql value
340
+ def load; end
341
+ end.new
342
+ end
343
+
344
+ it 'returns a the value' do
345
+ expect(result).to eql value
346
+ end
347
+ end
348
+
349
+ context 'passed an invalid instance' do
350
+ let(:value) { Class.new }
351
+
352
+ it 'raises an error' do
353
+ expect do
354
+ result
355
+ end.to raise_error ActiveInteraction::InvalidValueError
356
+ end
357
+ end
358
+
359
+ context 'passed a class' do
360
+ let(:value) do
361
+ Class.new do
362
+ def self.dump; end
363
+
364
+ def self.load; end
365
+ end
366
+ end
367
+
368
+ it 'returns a the value' do
369
+ expect(result).to eql value
370
+ end
371
+ end
372
+
373
+ context 'passed an invalid class' do
374
+ let(:value) { Class }
375
+
376
+ it 'raises an error' do
377
+ expect do
378
+ result
379
+ end.to raise_error ActiveInteraction::InvalidValueError
380
+ end
381
+ end
382
+
383
+ context 'passed a module' do
384
+ let(:value) do
385
+ Module.new do
386
+ def self.dump; end
387
+
388
+ def self.load; end
389
+ end
390
+ end
391
+
392
+ it 'returns a the value' do
393
+ expect(result).to eql value
394
+ end
395
+ end
396
+
397
+ context 'passed an invalid module' do
398
+ let(:value) { Module.new }
399
+
400
+ it 'raises an error' do
401
+ expect do
402
+ result
403
+ end.to raise_error ActiveInteraction::InvalidValueError
404
+ end
37
405
  end
38
406
  end
39
407
 
40
- context 'with YAML' do
41
- let(:value) { YAML }
408
+ context 'with from and methods passed' do
409
+ before do
410
+ options[:from] = :module
411
+ options[:methods] = %i[dump load]
412
+ end
42
413
 
43
- it 'returns an Hash' do
44
- expect(result).to eql value
414
+ it 'raises an error' do
415
+ expect do
416
+ filter
417
+ end.to raise_error ActiveInteraction::InvalidFilterError
45
418
  end
46
419
  end
47
420
  end
@@ -1,5 +1,3 @@
1
- # coding: utf-8
2
-
3
1
  require 'spec_helper'
4
2
 
5
3
  class ObjectThing
@@ -11,7 +9,8 @@ class ObjectThing
11
9
  raise 'error'
12
10
  end
13
11
  end
14
- class ObjectThings; end
12
+
13
+ class ObjectThings; end # rubocop:disable Lint/EmptyClass
15
14
  BackupObjectThing = ObjectThing
16
15
 
17
16
  describe ActiveInteraction::ObjectFilter, :filter do
@@ -24,86 +23,51 @@ describe ActiveInteraction::ObjectFilter, :filter do
24
23
 
25
24
  describe '#cast' do
26
25
  let(:value) { ObjectThing.new }
27
- let(:result) { filter.cast(value, nil) }
26
+ let(:result) { filter.send(:cast, value, nil) }
28
27
 
29
- context 'with class as a Class' do
28
+ context 'with an instance of the class' do
30
29
  it 'returns the instance' do
31
30
  expect(result).to eql value
32
31
  end
33
32
 
33
+ context 'with an instance that is a subclass' do
34
+ let(:subclass) { Class.new(ObjectThing) }
35
+ let(:value) { subclass.new }
36
+
37
+ it 'returns the instance' do
38
+ expect(result).to eql value
39
+ end
40
+ end
41
+
34
42
  it 'handles reconstantizing' do
35
43
  expect(result).to eql value
36
44
 
37
45
  Object.send(:remove_const, :ObjectThing)
38
- ObjectThing = BackupObjectThing
46
+ ObjectThing = BackupObjectThing # rubocop:disable Lint/ConstantDefinitionInBlock
39
47
  value = ObjectThing.new
40
48
 
41
- expect(filter.cast(value, nil)).to eql value
49
+ expect(filter.send(:cast, value, nil)).to eql value
42
50
  end
43
51
 
44
52
  it 'handles reconstantizing subclasses' do
45
53
  filter
46
54
 
47
55
  Object.send(:remove_const, :ObjectThing)
48
- ObjectThing = BackupObjectThing
49
- class SubObjectThing < ObjectThing; end
56
+ ObjectThing = BackupObjectThing # rubocop:disable Lint/ConstantDefinitionInBlock
57
+ class SubObjectThing < ObjectThing; end # rubocop:disable Lint/ConstantDefinitionInBlock
50
58
  value = SubObjectThing.new
51
59
 
52
- expect(filter.cast(value, nil)).to eql value
60
+ expect(filter.send(:cast, value, nil)).to eql value
53
61
  end
54
62
 
55
63
  context 'without the class available' do
56
64
  before { Object.send(:remove_const, :ObjectThing) }
57
- after { ObjectThing = BackupObjectThing }
65
+ after { ObjectThing = BackupObjectThing } # rubocop:disable Lint/ConstantDefinitionInBlock
58
66
 
59
67
  it 'does not raise an error on initialization' do
60
68
  expect { filter }.to_not raise_error
61
69
  end
62
70
  end
63
-
64
- context 'with bidirectional class comparisons' do
65
- let(:case_equality) { false }
66
- let(:class_equality) { false }
67
-
68
- before do
69
- allow(ObjectThing).to receive(:===).and_return(case_equality)
70
- allow(value).to receive(:is_a?).and_return(class_equality)
71
- end
72
-
73
- context 'without case or class equality' do
74
- it 'raises an error' do
75
- expect do
76
- result
77
- end.to raise_error ActiveInteraction::InvalidValueError
78
- end
79
- end
80
-
81
- context 'with case equality' do
82
- let(:case_equality) { true }
83
-
84
- it 'returns the instance' do
85
- expect(result).to eql value
86
- end
87
- end
88
-
89
- context 'with class equality' do
90
- let(:class_equality) { true }
91
-
92
- it 'returns the instance' do
93
- expect(result).to eql value
94
- end
95
- end
96
- end
97
- end
98
-
99
- context 'with class as a superclass' do
100
- before do
101
- options[:class] = ObjectThing.superclass
102
- end
103
-
104
- it 'returns the instance' do
105
- expect(result).to eql value
106
- end
107
71
  end
108
72
 
109
73
  context 'with class as a String' do
@@ -134,7 +98,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
134
98
  it 'raises an error' do
135
99
  expect do
136
100
  result
137
- end.to raise_error ActiveInteraction::InvalidClassError
101
+ end.to raise_error ActiveInteraction::InvalidNameError
138
102
  end
139
103
  end
140
104
 
@@ -161,7 +125,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
161
125
  end
162
126
  end
163
127
 
164
- context 'with a object of the correct class' do
128
+ context 'with an object of the correct class' do
165
129
  let(:value) { ObjectThing.new }
166
130
 
167
131
  it 'does not call the converter' do
@@ -170,7 +134,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
170
134
  end
171
135
  end
172
136
 
173
- context 'with a object is a subclass' do
137
+ context 'with an object that is a subclass' do
174
138
  let(:subclass) { Class.new(ObjectThing) }
175
139
  let(:value) { subclass.new }
176
140
 
@@ -223,7 +187,7 @@ describe ActiveInteraction::ObjectFilter, :filter do
223
187
 
224
188
  before do
225
189
  options[:default] = ObjectThing.new
226
- options[:converter] = ->(_) { nil }
190
+ options[:converter] = ->(_) {}
227
191
  end
228
192
 
229
193
  it 'raises an error' do