active_interaction 3.8.2 → 4.0.3
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 +192 -0
- data/README.md +93 -107
- data/lib/active_interaction.rb +1 -7
- data/lib/active_interaction/base.rb +44 -67
- data/lib/active_interaction/concerns/active_modelable.rb +1 -3
- data/lib/active_interaction/concerns/active_recordable.rb +1 -6
- data/lib/active_interaction/concerns/hashable.rb +0 -1
- data/lib/active_interaction/concerns/missable.rb +0 -1
- data/lib/active_interaction/concerns/runnable.rb +7 -14
- data/lib/active_interaction/errors.rb +4 -19
- data/lib/active_interaction/filter.rb +66 -37
- data/lib/active_interaction/filter_column.rb +0 -3
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +38 -36
- data/lib/active_interaction/filters/abstract_numeric_filter.rb +27 -17
- data/lib/active_interaction/filters/array_filter.rb +59 -36
- data/lib/active_interaction/filters/boolean_filter.rb +26 -12
- data/lib/active_interaction/filters/date_filter.rb +1 -2
- data/lib/active_interaction/filters/date_time_filter.rb +1 -2
- data/lib/active_interaction/filters/decimal_filter.rb +10 -28
- data/lib/active_interaction/filters/file_filter.rb +6 -5
- data/lib/active_interaction/filters/float_filter.rb +1 -2
- data/lib/active_interaction/filters/hash_filter.rb +37 -27
- data/lib/active_interaction/filters/integer_filter.rb +7 -8
- data/lib/active_interaction/filters/interface_filter.rb +48 -14
- data/lib/active_interaction/filters/object_filter.rb +23 -50
- data/lib/active_interaction/filters/record_filter.rb +10 -35
- data/lib/active_interaction/filters/string_filter.rb +21 -12
- data/lib/active_interaction/filters/symbol_filter.rb +13 -7
- data/lib/active_interaction/filters/time_filter.rb +24 -19
- data/lib/active_interaction/grouped_input.rb +0 -3
- data/lib/active_interaction/inputs.rb +120 -0
- data/lib/active_interaction/modules/validation.rb +9 -12
- data/lib/active_interaction/version.rb +1 -3
- data/spec/active_interaction/base_spec.rb +38 -99
- data/spec/active_interaction/concerns/active_modelable_spec.rb +0 -2
- data/spec/active_interaction/concerns/active_recordable_spec.rb +0 -2
- data/spec/active_interaction/concerns/hashable_spec.rb +0 -2
- data/spec/active_interaction/concerns/missable_spec.rb +0 -2
- data/spec/active_interaction/concerns/runnable_spec.rb +26 -12
- data/spec/active_interaction/errors_spec.rb +4 -25
- data/spec/active_interaction/filter_column_spec.rb +0 -2
- data/spec/active_interaction/filter_spec.rb +0 -2
- data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/array_filter_spec.rb +51 -14
- data/spec/active_interaction/filters/boolean_filter_spec.rb +58 -4
- data/spec/active_interaction/filters/date_filter_spec.rb +43 -3
- data/spec/active_interaction/filters/date_time_filter_spec.rb +43 -3
- data/spec/active_interaction/filters/decimal_filter_spec.rb +57 -3
- data/spec/active_interaction/filters/file_filter_spec.rb +1 -3
- data/spec/active_interaction/filters/float_filter_spec.rb +60 -4
- data/spec/active_interaction/filters/hash_filter_spec.rb +19 -9
- data/spec/active_interaction/filters/integer_filter_spec.rb +49 -7
- data/spec/active_interaction/filters/interface_filter_spec.rb +397 -24
- data/spec/active_interaction/filters/object_filter_spec.rb +23 -59
- data/spec/active_interaction/filters/record_filter_spec.rb +23 -49
- data/spec/active_interaction/filters/string_filter_spec.rb +15 -3
- data/spec/active_interaction/filters/symbol_filter_spec.rb +15 -3
- data/spec/active_interaction/filters/time_filter_spec.rb +65 -3
- data/spec/active_interaction/grouped_input_spec.rb +0 -2
- data/spec/active_interaction/i18n_spec.rb +3 -7
- data/spec/active_interaction/{modules/input_processor_spec.rb → inputs_spec.rb} +35 -5
- data/spec/active_interaction/integration/array_interaction_spec.rb +18 -22
- data/spec/active_interaction/integration/boolean_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/date_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/date_time_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/file_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/float_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/hash_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/integer_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/interface_interaction_spec.rb +1 -3
- data/spec/active_interaction/integration/object_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/string_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/symbol_interaction_spec.rb +0 -2
- data/spec/active_interaction/integration/time_interaction_spec.rb +14 -18
- data/spec/active_interaction/modules/validation_spec.rb +1 -3
- data/spec/spec_helper.rb +2 -6
- data/spec/support/concerns.rb +0 -2
- data/spec/support/filters.rb +13 -9
- data/spec/support/interactions.rb +22 -14
- metadata +81 -57
- data/lib/active_interaction/backports.rb +0 -59
- data/lib/active_interaction/filters/abstract_filter.rb +0 -19
- data/lib/active_interaction/modules/input_processor.rb +0 -52
- data/spec/active_interaction/filters/abstract_filter_spec.rb +0 -8
data/lib/active_interaction.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require 'active_model'
|
@@ -7,8 +6,6 @@ require 'active_model'
|
|
7
6
|
#
|
8
7
|
# @author Aaron Lasseigne <aaron.lasseigne@gmail.com>
|
9
8
|
# @author Taylor Fausak <taylor@fausak.me>
|
10
|
-
#
|
11
|
-
# @since 1.0.0
|
12
9
|
module ActiveInteraction
|
13
10
|
end
|
14
11
|
|
@@ -22,13 +19,12 @@ require 'active_interaction/concerns/missable'
|
|
22
19
|
require 'active_interaction/concerns/runnable'
|
23
20
|
|
24
21
|
require 'active_interaction/grouped_input'
|
22
|
+
require 'active_interaction/inputs'
|
25
23
|
|
26
|
-
require 'active_interaction/modules/input_processor'
|
27
24
|
require 'active_interaction/modules/validation'
|
28
25
|
|
29
26
|
require 'active_interaction/filter_column'
|
30
27
|
require 'active_interaction/filter'
|
31
|
-
require 'active_interaction/filters/abstract_filter'
|
32
28
|
require 'active_interaction/filters/interface_filter'
|
33
29
|
require 'active_interaction/filters/abstract_date_time_filter'
|
34
30
|
require 'active_interaction/filters/abstract_numeric_filter'
|
@@ -49,8 +45,6 @@ require 'active_interaction/filters/time_filter'
|
|
49
45
|
|
50
46
|
require 'active_interaction/base'
|
51
47
|
|
52
|
-
require 'active_interaction/backports'
|
53
|
-
|
54
48
|
I18n.load_path.unshift(
|
55
49
|
*Dir.glob(
|
56
50
|
File.expand_path(
|
@@ -1,8 +1,5 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
5
|
-
|
6
3
|
module ActiveInteraction
|
7
4
|
# @abstract Subclass and override {#execute} to implement a custom
|
8
5
|
# ActiveInteraction::Base class.
|
@@ -28,7 +25,7 @@ module ActiveInteraction
|
|
28
25
|
# else
|
29
26
|
# outcome.errors
|
30
27
|
# end
|
31
|
-
class Base
|
28
|
+
class Base
|
32
29
|
include ActiveModelable
|
33
30
|
include ActiveRecordable
|
34
31
|
include Runnable
|
@@ -46,7 +43,7 @@ module ActiveInteraction
|
|
46
43
|
#
|
47
44
|
# Runs validations and if there are no errors it will call {#execute}.
|
48
45
|
#
|
49
|
-
# @param (see ActiveInteraction::
|
46
|
+
# @param (see ActiveInteraction::Inputs.process)
|
50
47
|
#
|
51
48
|
# @return [Base]
|
52
49
|
|
@@ -74,9 +71,7 @@ module ActiveInteraction
|
|
74
71
|
# @return [String, nil] The description.
|
75
72
|
def desc(desc = nil)
|
76
73
|
if desc.nil?
|
77
|
-
unless instance_variable_defined?(:@_interaction_desc)
|
78
|
-
@_interaction_desc = nil
|
79
|
-
end
|
74
|
+
@_interaction_desc = nil unless instance_variable_defined?(:@_interaction_desc)
|
80
75
|
else
|
81
76
|
@_interaction_desc = desc
|
82
77
|
end
|
@@ -88,17 +83,21 @@ module ActiveInteraction
|
|
88
83
|
#
|
89
84
|
# @return [Hash{Symbol => Filter}]
|
90
85
|
def filters
|
86
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
91
87
|
@_interaction_filters ||= {}
|
88
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
92
89
|
end
|
93
90
|
|
94
91
|
# @private
|
95
|
-
|
92
|
+
# rubocop:disable Style/MissingRespondToMissing
|
93
|
+
def method_missing(*args, &block)
|
96
94
|
super do |klass, names, options|
|
97
95
|
raise InvalidFilterError, 'missing attribute name' if names.empty?
|
98
96
|
|
99
97
|
names.each { |name| add_filter(klass, name, options, &block) }
|
100
98
|
end
|
101
99
|
end
|
100
|
+
# rubocop:enable Style/MissingRespondToMissing
|
102
101
|
|
103
102
|
private
|
104
103
|
|
@@ -106,9 +105,7 @@ module ActiveInteraction
|
|
106
105
|
# @param name [Symbol]
|
107
106
|
# @param options [Hash]
|
108
107
|
def add_filter(klass, name, options, &block)
|
109
|
-
if
|
110
|
-
raise InvalidFilterError, %("#{name}" is a reserved name)
|
111
|
-
end
|
108
|
+
raise InvalidFilterError, %("#{name}" is a reserved name) if Inputs.reserved?(name)
|
112
109
|
|
113
110
|
initialize_filter(klass.new(name, options, &block))
|
114
111
|
end
|
@@ -133,7 +130,7 @@ module ActiveInteraction
|
|
133
130
|
other_filters.select! { |k, _| [*only].include?(k) } if only
|
134
131
|
other_filters.reject! { |k, _| [*except].include?(k) } if except
|
135
132
|
|
136
|
-
other_filters.
|
133
|
+
other_filters.each_value { |filter| initialize_filter(filter) }
|
137
134
|
end
|
138
135
|
|
139
136
|
# @param klass [Class]
|
@@ -146,13 +143,10 @@ module ActiveInteraction
|
|
146
143
|
# @param filter [Filter]
|
147
144
|
def initialize_filter(filter)
|
148
145
|
attribute = filter.name
|
149
|
-
if filters.key?(attribute)
|
150
|
-
warn "WARNING: Redefining #{name}##{attribute} filter"
|
151
|
-
end
|
146
|
+
warn "WARNING: Redefining #{name}##{attribute} filter" if filters.key?(attribute)
|
152
147
|
filters[attribute] = filter
|
153
148
|
|
154
149
|
attr_accessor attribute
|
155
|
-
define_method("#{attribute}?") { !public_send(attribute).nil? }
|
156
150
|
|
157
151
|
eagerly_evaluate_default(filter)
|
158
152
|
end
|
@@ -164,12 +158,11 @@ module ActiveInteraction
|
|
164
158
|
end
|
165
159
|
end
|
166
160
|
|
167
|
-
# @param inputs [Hash{Symbol => Object}] Attribute values to set.
|
168
|
-
#
|
169
161
|
# @private
|
170
162
|
def initialize(inputs = {})
|
171
|
-
|
172
|
-
|
163
|
+
@_interaction_raw_inputs = inputs
|
164
|
+
|
165
|
+
populate_filters_and_inputs(Inputs.process(inputs))
|
173
166
|
end
|
174
167
|
|
175
168
|
# @!method compose(other, inputs = {})
|
@@ -195,9 +188,7 @@ module ActiveInteraction
|
|
195
188
|
#
|
196
189
|
# @return [Hash{Symbol => Object}] All inputs passed to {.run} or {.run!}.
|
197
190
|
def inputs
|
198
|
-
|
199
|
-
h[name] = public_send(name)
|
200
|
-
end
|
191
|
+
@_interaction_inputs
|
201
192
|
end
|
202
193
|
|
203
194
|
# Returns `true` if the given key was in the hash passed to {.run}.
|
@@ -241,24 +232,30 @@ module ActiveInteraction
|
|
241
232
|
# rubocop:disable all
|
242
233
|
def given?(input, *rest)
|
243
234
|
filter_level = self.class
|
244
|
-
input_level = @
|
235
|
+
input_level = @_interaction_raw_inputs
|
245
236
|
|
246
237
|
[input, *rest].each do |key_or_index|
|
247
238
|
if key_or_index.is_a?(Symbol) || key_or_index.is_a?(String)
|
248
|
-
|
249
|
-
|
239
|
+
key = key_or_index.to_sym
|
240
|
+
key_to_s = key_or_index.to_s
|
241
|
+
filter_level = filter_level.filters[key]
|
250
242
|
|
251
243
|
break false if filter_level.nil? || input_level.nil?
|
252
|
-
|
244
|
+
if filter_level.accepts_grouped_inputs?
|
245
|
+
break false unless input_level.key?(key) || input_level.key?(key_to_s) || Inputs.keys_for_group?(input_level.keys, key)
|
246
|
+
else
|
247
|
+
break false unless input_level.key?(key) || input_level.key?(key_to_s)
|
248
|
+
end
|
253
249
|
|
254
|
-
input_level = input_level[
|
250
|
+
input_level = input_level[key] || input_level[key_to_s]
|
255
251
|
else
|
252
|
+
index = key_or_index
|
256
253
|
filter_level = filter_level.filters.first.last
|
257
254
|
|
258
255
|
break false if filter_level.nil? || input_level.nil?
|
259
|
-
break false unless
|
256
|
+
break false unless index.between?(-input_level.size, input_level.size - 1)
|
260
257
|
|
261
|
-
input_level = input_level[
|
258
|
+
input_level = input_level[index]
|
262
259
|
end
|
263
260
|
end && true
|
264
261
|
end
|
@@ -274,50 +271,30 @@ module ActiveInteraction
|
|
274
271
|
|
275
272
|
private
|
276
273
|
|
277
|
-
|
278
|
-
|
279
|
-
# `#symbolize_keys` returns the entire hash, not just permitted values. In
|
280
|
-
# Rails >= 5, parameters are not a subclass of hash but calling
|
281
|
-
# `#to_unsafe_h` returns the entire hash.
|
282
|
-
def normalize_inputs!(inputs)
|
283
|
-
return inputs if inputs.is_a?(Hash)
|
284
|
-
|
285
|
-
parameters = 'ActionController::Parameters'
|
286
|
-
klass = parameters.safe_constantize
|
287
|
-
return inputs.to_unsafe_h if klass && inputs.is_a?(klass)
|
288
|
-
|
289
|
-
raise ArgumentError, "inputs must be a hash or #{parameters}"
|
290
|
-
end
|
274
|
+
def populate_filters_and_inputs(inputs)
|
275
|
+
@_interaction_inputs = Inputs.new
|
291
276
|
|
292
|
-
|
293
|
-
|
294
|
-
|
277
|
+
self.class.filters.each do |name, filter|
|
278
|
+
value =
|
279
|
+
begin
|
280
|
+
filter.clean(inputs[name], self)
|
281
|
+
rescue InvalidValueError, MissingValueError, NoDefaultError
|
282
|
+
# #type_check will add errors if appropriate.
|
283
|
+
# We'll get the original value for the error.
|
284
|
+
inputs[name]
|
285
|
+
end
|
295
286
|
|
296
|
-
|
297
|
-
|
287
|
+
@_interaction_inputs[name] = value
|
288
|
+
public_send("#{name}=", value)
|
298
289
|
end
|
299
290
|
|
300
|
-
|
301
|
-
end
|
302
|
-
|
303
|
-
def populate_reader(key, value)
|
304
|
-
instance_variable_set("@#{key}", value) if respond_to?(key)
|
305
|
-
end
|
306
|
-
|
307
|
-
def populate_filters(inputs)
|
308
|
-
self.class.filters.each do |name, filter|
|
309
|
-
begin
|
310
|
-
public_send("#{name}=", filter.clean(inputs[name], self))
|
311
|
-
rescue InvalidValueError, MissingValueError, NoDefaultError
|
312
|
-
nil # #type_check will add errors if appropriate.
|
313
|
-
end
|
314
|
-
end
|
291
|
+
@_interaction_inputs.freeze
|
315
292
|
end
|
316
293
|
|
317
294
|
def type_check
|
318
295
|
run_callbacks(:type_check) do
|
319
|
-
Validation.validate(self, self.class.filters, inputs).each do |
|
320
|
-
errors.add(
|
296
|
+
Validation.validate(self, self.class.filters, inputs).each do |attr, type, kwargs = {}|
|
297
|
+
errors.add(attr, type, **kwargs)
|
321
298
|
end
|
322
299
|
end
|
323
300
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ActiveInteraction
|
@@ -34,8 +33,7 @@ module ActiveInteraction
|
|
34
33
|
false
|
35
34
|
end
|
36
35
|
|
37
|
-
#
|
38
|
-
module ClassMethods
|
36
|
+
module ClassMethods # rubocop:disable Style/Documentation
|
39
37
|
# @return [Symbol]
|
40
38
|
#
|
41
39
|
# @see ActiveModel::Translation#i18n_scope
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ActiveInteraction
|
@@ -24,8 +23,6 @@ module ActiveInteraction
|
|
24
23
|
# # => nil
|
25
24
|
#
|
26
25
|
# @return [FilterColumn, nil]
|
27
|
-
#
|
28
|
-
# @since 1.2.0
|
29
26
|
def column_for_attribute(name)
|
30
27
|
filter = self.class.filters[name]
|
31
28
|
FilterColumn.intern(filter.database_column_type) if filter
|
@@ -49,9 +46,7 @@ module ActiveInteraction
|
|
49
46
|
# # => false
|
50
47
|
#
|
51
48
|
# @return [Boolean]
|
52
|
-
#
|
53
|
-
# @since 1.5.0
|
54
|
-
def has_attribute?(name) # rubocop:disable Style/PredicateName
|
49
|
+
def has_attribute?(name) # rubocop:disable Naming/PredicateName
|
55
50
|
self.class.filters.key?(name.to_sym)
|
56
51
|
end
|
57
52
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module ActiveInteraction
|
@@ -46,9 +45,7 @@ module ActiveInteraction
|
|
46
45
|
|
47
46
|
# @return [Boolean]
|
48
47
|
def valid?(*)
|
49
|
-
if instance_variable_defined?(:@_interaction_valid)
|
50
|
-
return @_interaction_valid
|
51
|
-
end
|
48
|
+
return @_interaction_valid if instance_variable_defined?(:@_interaction_valid)
|
52
49
|
|
53
50
|
super
|
54
51
|
end
|
@@ -74,14 +71,11 @@ module ActiveInteraction
|
|
74
71
|
def run
|
75
72
|
return self.result = nil unless valid?
|
76
73
|
|
77
|
-
run_callbacks(:execute) do
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
errors.backtrace = interrupt.errors.backtrace || interrupt.backtrace
|
83
|
-
errors.merge!(interrupt.errors)
|
84
|
-
end
|
74
|
+
self.result = run_callbacks(:execute) do
|
75
|
+
execute
|
76
|
+
rescue Interrupt => e
|
77
|
+
errors.backtrace = e.errors.backtrace || e.backtrace
|
78
|
+
errors.merge!(e.errors)
|
85
79
|
end
|
86
80
|
end
|
87
81
|
|
@@ -99,8 +93,7 @@ module ActiveInteraction
|
|
99
93
|
raise e
|
100
94
|
end
|
101
95
|
|
102
|
-
#
|
103
|
-
module ClassMethods
|
96
|
+
module ClassMethods # rubocop:disable Style/Documentation
|
104
97
|
def new(*)
|
105
98
|
super.tap do |instance|
|
106
99
|
{
|
@@ -1,17 +1,15 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
#
|
5
3
|
module ActiveInteraction
|
6
4
|
# Top-level error class. All other errors subclass this.
|
7
5
|
#
|
8
6
|
# @return [Class]
|
9
7
|
Error = Class.new(StandardError)
|
10
8
|
|
11
|
-
# Raised if a
|
9
|
+
# Raised if a constant name is invalid.
|
12
10
|
#
|
13
11
|
# @return [Class]
|
14
|
-
|
12
|
+
InvalidNameError = Class.new(Error)
|
15
13
|
|
16
14
|
# Raised if a converter is invalid.
|
17
15
|
#
|
@@ -100,11 +98,7 @@ module ActiveInteraction
|
|
100
98
|
#
|
101
99
|
# @return [Errors]
|
102
100
|
def merge!(other)
|
103
|
-
|
104
|
-
merge_details!(other)
|
105
|
-
else
|
106
|
-
merge_messages!(other)
|
107
|
-
end
|
101
|
+
merge_details!(other)
|
108
102
|
|
109
103
|
self
|
110
104
|
end
|
@@ -119,14 +113,6 @@ module ActiveInteraction
|
|
119
113
|
detail[:error].is_a?(Symbol)
|
120
114
|
end
|
121
115
|
|
122
|
-
def merge_messages!(other)
|
123
|
-
other.messages.each do |attribute, messages|
|
124
|
-
messages.each do |message|
|
125
|
-
merge_message!(attribute, message)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
116
|
def merge_message!(attribute, message)
|
131
117
|
unless attribute?(attribute)
|
132
118
|
message = full_message(attribute, message)
|
@@ -151,9 +137,8 @@ module ActiveInteraction
|
|
151
137
|
if attribute?(attribute) || attribute == :base
|
152
138
|
options = detail.dup
|
153
139
|
error = options.delete(:error)
|
154
|
-
options[:message] = message
|
155
140
|
|
156
|
-
add(attribute, error, options) unless added?(attribute, error, options)
|
141
|
+
add(attribute, error, **options.merge(message: message)) unless added?(attribute, error, **options)
|
157
142
|
else
|
158
143
|
merge_message!(attribute, message)
|
159
144
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require 'active_support/inflector'
|
@@ -78,16 +77,16 @@ module ActiveInteraction
|
|
78
77
|
# to the default value.
|
79
78
|
#
|
80
79
|
# @example
|
81
|
-
# ActiveInteraction::Filter.new(:example).clean(nil)
|
80
|
+
# ActiveInteraction::Filter.new(:example).clean(nil, nil)
|
82
81
|
# # => ActiveInteraction::MissingValueError: example
|
83
82
|
# @example
|
84
|
-
# ActiveInteraction::Filter.new(:example).clean(0)
|
83
|
+
# ActiveInteraction::Filter.new(:example).clean(0, nil)
|
85
84
|
# # => ActiveInteraction::InvalidValueError: example: 0
|
86
85
|
# @example
|
87
|
-
# ActiveInteraction::Filter.new(:example, default: nil).clean(nil)
|
86
|
+
# ActiveInteraction::Filter.new(:example, default: nil).clean(nil, nil)
|
88
87
|
# # => nil
|
89
88
|
# @example
|
90
|
-
# ActiveInteraction::Filter.new(:example, default: 0).clean(nil)
|
89
|
+
# ActiveInteraction::Filter.new(:example, default: 0).clean(nil, nil)
|
91
90
|
# # => ActiveInteraction::InvalidDefaultError: example: 0
|
92
91
|
#
|
93
92
|
# @param value [Object]
|
@@ -95,7 +94,9 @@ module ActiveInteraction
|
|
95
94
|
#
|
96
95
|
# @return [Object]
|
97
96
|
#
|
98
|
-
# @raise
|
97
|
+
# @raise [MissingValueError] If the value is missing and there is no
|
98
|
+
# default.
|
99
|
+
# @raise [InvalidValueError] If the value is invalid.
|
99
100
|
# @raise (see #default)
|
100
101
|
def clean(value, context)
|
101
102
|
value = cast(value, context)
|
@@ -120,7 +121,7 @@ module ActiveInteraction
|
|
120
121
|
#
|
121
122
|
# @param context [Base, nil]
|
122
123
|
#
|
123
|
-
# @return
|
124
|
+
# @return [Object]
|
124
125
|
#
|
125
126
|
# @raise [NoDefaultError] If the default is missing.
|
126
127
|
# @raise [InvalidDefaultError] If the default is invalid.
|
@@ -131,8 +132,8 @@ module ActiveInteraction
|
|
131
132
|
raise InvalidValueError if value.is_a?(GroupedInput)
|
132
133
|
|
133
134
|
cast(value, context)
|
134
|
-
rescue InvalidNestedValueError =>
|
135
|
-
raise InvalidDefaultError, "#{name}: #{value.inspect} (#{
|
135
|
+
rescue InvalidNestedValueError => e
|
136
|
+
raise InvalidDefaultError, "#{name}: #{value.inspect} (#{e})"
|
136
137
|
rescue InvalidValueError, MissingValueError
|
137
138
|
raise InvalidDefaultError, "#{name}: #{value.inspect}"
|
138
139
|
end
|
@@ -162,27 +163,6 @@ module ActiveInteraction
|
|
162
163
|
options.key?(:default)
|
163
164
|
end
|
164
165
|
|
165
|
-
# @param value [Object]
|
166
|
-
# @param _interaction [Base, nil]
|
167
|
-
#
|
168
|
-
# @return [Object]
|
169
|
-
#
|
170
|
-
# @raise [MissingValueError] If the value is missing and there is no
|
171
|
-
# default.
|
172
|
-
# @raise [InvalidValueError] If the value is invalid.
|
173
|
-
#
|
174
|
-
# @private
|
175
|
-
def cast(value, _interaction)
|
176
|
-
case value
|
177
|
-
when NilClass
|
178
|
-
raise MissingValueError, name unless default?
|
179
|
-
|
180
|
-
nil
|
181
|
-
else
|
182
|
-
raise InvalidValueError, "#{name}: #{describe(value)}"
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
166
|
# Gets the type of database column that would represent the filter data.
|
187
167
|
#
|
188
168
|
# @example
|
@@ -194,25 +174,74 @@ module ActiveInteraction
|
|
194
174
|
#
|
195
175
|
# @return [Symbol] A database column type. If no sensible mapping exists,
|
196
176
|
# returns `:string`.
|
197
|
-
#
|
198
|
-
# @since 1.2.0
|
199
177
|
def database_column_type
|
200
178
|
:string
|
201
179
|
end
|
202
180
|
|
181
|
+
# Tells whether or not the filter accepts a group of parameters to form a
|
182
|
+
# single input.
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
# ActiveInteraction::TimeFilter.new(Time.now).accepts_grouped_inputs?
|
186
|
+
# # => true
|
187
|
+
# @example
|
188
|
+
# ActiveInteraction::Filter.new(:example).accepts_grouped_inputs?
|
189
|
+
# # => false
|
190
|
+
#
|
191
|
+
# @return [Boolean]
|
192
|
+
def accepts_grouped_inputs?
|
193
|
+
false
|
194
|
+
end
|
195
|
+
|
203
196
|
private
|
204
197
|
|
205
|
-
#
|
206
|
-
|
198
|
+
# rubocop:disable Metrics/MethodLength
|
199
|
+
def cast(value, context, convert: true, reconstantize: true)
|
200
|
+
if matches?(value)
|
201
|
+
adjust_output(value, context)
|
202
|
+
# we can't use `nil?` because BasicObject doesn't have it
|
203
|
+
elsif value == nil # rubocop:disable Style/NilComparison
|
204
|
+
raise MissingValueError, name unless default?
|
205
|
+
|
206
|
+
nil
|
207
|
+
elsif reconstantize
|
208
|
+
send(__method__, value, context,
|
209
|
+
convert: convert,
|
210
|
+
reconstantize: false
|
211
|
+
)
|
212
|
+
elsif convert
|
213
|
+
send(__method__, convert(value), context,
|
214
|
+
convert: false,
|
215
|
+
reconstantize: reconstantize
|
216
|
+
)
|
217
|
+
else
|
218
|
+
raise InvalidValueError, "#{name}: #{describe(value)}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
# rubocop:enable Metrics/MethodLength
|
222
|
+
|
223
|
+
def matches?(_value)
|
224
|
+
false
|
225
|
+
end
|
226
|
+
|
227
|
+
def adjust_output(value, _context)
|
228
|
+
value
|
229
|
+
end
|
230
|
+
|
231
|
+
def convert(value)
|
232
|
+
value
|
233
|
+
end
|
234
|
+
|
235
|
+
def klass
|
236
|
+
@klass ||= Object.const_get(self.class.slug.to_s.camelize, false)
|
237
|
+
end
|
238
|
+
|
207
239
|
def describe(value)
|
208
240
|
value.inspect
|
209
241
|
rescue NoMethodError
|
210
242
|
"(Object doesn't support #inspect)"
|
211
243
|
end
|
212
244
|
|
213
|
-
# @param context [Base, nil]
|
214
|
-
#
|
215
|
-
# @return [Object]
|
216
245
|
def raw_default(context)
|
217
246
|
value = options.fetch(:default)
|
218
247
|
return value unless value.is_a?(Proc)
|