active_interaction 3.8.2 → 4.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|