active_interaction 3.8.1 → 4.0.2
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 +190 -0
- data/CONTRIBUTING.md +1 -1
- data/README.md +93 -107
- data/lib/active_interaction.rb +1 -7
- data/lib/active_interaction/base.rb +31 -35
- 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 +12 -24
- data/lib/active_interaction/errors.rb +6 -19
- data/lib/active_interaction/filter.rb +51 -37
- data/lib/active_interaction/filter_column.rb +0 -3
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +34 -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 +95 -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 +22 -70
- 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} +3 -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,4 +1,3 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require 'active_support/core_ext/hash/indifferent_access'
|
|
@@ -28,7 +27,7 @@ module ActiveInteraction
|
|
|
28
27
|
# else
|
|
29
28
|
# outcome.errors
|
|
30
29
|
# end
|
|
31
|
-
class Base
|
|
30
|
+
class Base
|
|
32
31
|
include ActiveModelable
|
|
33
32
|
include ActiveRecordable
|
|
34
33
|
include Runnable
|
|
@@ -74,9 +73,7 @@ module ActiveInteraction
|
|
|
74
73
|
# @return [String, nil] The description.
|
|
75
74
|
def desc(desc = nil)
|
|
76
75
|
if desc.nil?
|
|
77
|
-
unless instance_variable_defined?(:@_interaction_desc)
|
|
78
|
-
@_interaction_desc = nil
|
|
79
|
-
end
|
|
76
|
+
@_interaction_desc = nil unless instance_variable_defined?(:@_interaction_desc)
|
|
80
77
|
else
|
|
81
78
|
@_interaction_desc = desc
|
|
82
79
|
end
|
|
@@ -88,17 +85,21 @@ module ActiveInteraction
|
|
|
88
85
|
#
|
|
89
86
|
# @return [Hash{Symbol => Filter}]
|
|
90
87
|
def filters
|
|
88
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
|
91
89
|
@_interaction_filters ||= {}
|
|
90
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
|
92
91
|
end
|
|
93
92
|
|
|
94
93
|
# @private
|
|
95
|
-
|
|
94
|
+
# rubocop:disable Style/MissingRespondToMissing
|
|
95
|
+
def method_missing(*args, &block)
|
|
96
96
|
super do |klass, names, options|
|
|
97
97
|
raise InvalidFilterError, 'missing attribute name' if names.empty?
|
|
98
98
|
|
|
99
99
|
names.each { |name| add_filter(klass, name, options, &block) }
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
|
+
# rubocop:enable Style/MissingRespondToMissing
|
|
102
103
|
|
|
103
104
|
private
|
|
104
105
|
|
|
@@ -106,9 +107,7 @@ module ActiveInteraction
|
|
|
106
107
|
# @param name [Symbol]
|
|
107
108
|
# @param options [Hash]
|
|
108
109
|
def add_filter(klass, name, options, &block)
|
|
109
|
-
if
|
|
110
|
-
raise InvalidFilterError, %("#{name}" is a reserved name)
|
|
111
|
-
end
|
|
110
|
+
raise InvalidFilterError, %("#{name}" is a reserved name) if ActiveInteraction::Inputs.reserved?(name)
|
|
112
111
|
|
|
113
112
|
initialize_filter(klass.new(name, options, &block))
|
|
114
113
|
end
|
|
@@ -133,7 +132,7 @@ module ActiveInteraction
|
|
|
133
132
|
other_filters.select! { |k, _| [*only].include?(k) } if only
|
|
134
133
|
other_filters.reject! { |k, _| [*except].include?(k) } if except
|
|
135
134
|
|
|
136
|
-
other_filters.
|
|
135
|
+
other_filters.each_value { |filter| initialize_filter(filter) }
|
|
137
136
|
end
|
|
138
137
|
|
|
139
138
|
# @param klass [Class]
|
|
@@ -146,13 +145,10 @@ module ActiveInteraction
|
|
|
146
145
|
# @param filter [Filter]
|
|
147
146
|
def initialize_filter(filter)
|
|
148
147
|
attribute = filter.name
|
|
149
|
-
if filters.key?(attribute)
|
|
150
|
-
warn "WARNING: Redefining #{name}##{attribute} filter"
|
|
151
|
-
end
|
|
148
|
+
warn "WARNING: Redefining #{name}##{attribute} filter" if filters.key?(attribute)
|
|
152
149
|
filters[attribute] = filter
|
|
153
150
|
|
|
154
151
|
attr_accessor attribute
|
|
155
|
-
define_method("#{attribute}?") { !public_send(attribute).nil? }
|
|
156
152
|
|
|
157
153
|
eagerly_evaluate_default(filter)
|
|
158
154
|
end
|
|
@@ -195,9 +191,7 @@ module ActiveInteraction
|
|
|
195
191
|
#
|
|
196
192
|
# @return [Hash{Symbol => Object}] All inputs passed to {.run} or {.run!}.
|
|
197
193
|
def inputs
|
|
198
|
-
|
|
199
|
-
h[name] = public_send(name)
|
|
200
|
-
end
|
|
194
|
+
@_interaction_inputs
|
|
201
195
|
end
|
|
202
196
|
|
|
203
197
|
# Returns `true` if the given key was in the hash passed to {.run}.
|
|
@@ -241,7 +235,7 @@ module ActiveInteraction
|
|
|
241
235
|
# rubocop:disable all
|
|
242
236
|
def given?(input, *rest)
|
|
243
237
|
filter_level = self.class
|
|
244
|
-
input_level = @
|
|
238
|
+
input_level = @_interaction_raw_inputs
|
|
245
239
|
|
|
246
240
|
[input, *rest].each do |key_or_index|
|
|
247
241
|
if key_or_index.is_a?(Symbol) || key_or_index.is_a?(String)
|
|
@@ -291,33 +285,35 @@ module ActiveInteraction
|
|
|
291
285
|
|
|
292
286
|
# @param inputs [Hash{Symbol => Object}]
|
|
293
287
|
def process_inputs(inputs)
|
|
294
|
-
@
|
|
295
|
-
|
|
296
|
-
inputs.each do |key, value|
|
|
297
|
-
populate_reader(key, value) unless InputProcessor.reserved?(key)
|
|
298
|
-
end
|
|
288
|
+
@_interaction_raw_inputs = inputs
|
|
299
289
|
|
|
300
|
-
|
|
290
|
+
populate_filters_and_inputs(ActiveInteraction::Inputs.process(inputs))
|
|
301
291
|
end
|
|
302
292
|
|
|
303
|
-
def
|
|
304
|
-
|
|
305
|
-
end
|
|
293
|
+
def populate_filters_and_inputs(inputs)
|
|
294
|
+
@_interaction_inputs = ActiveInteraction::Inputs.new
|
|
306
295
|
|
|
307
|
-
def populate_filters(inputs)
|
|
308
296
|
self.class.filters.each do |name, filter|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
297
|
+
value =
|
|
298
|
+
begin
|
|
299
|
+
filter.clean(inputs[name], self)
|
|
300
|
+
rescue InvalidValueError, MissingValueError, NoDefaultError
|
|
301
|
+
# #type_check will add errors if appropriate.
|
|
302
|
+
# We'll get the original value for the error.
|
|
303
|
+
inputs[name]
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
@_interaction_inputs[name] = value
|
|
307
|
+
public_send("#{name}=", value)
|
|
314
308
|
end
|
|
309
|
+
|
|
310
|
+
@_interaction_inputs.freeze
|
|
315
311
|
end
|
|
316
312
|
|
|
317
313
|
def type_check
|
|
318
314
|
run_callbacks(:type_check) do
|
|
319
|
-
Validation.validate(self, self.class.filters, inputs).each do |
|
|
320
|
-
errors.add(
|
|
315
|
+
Validation.validate(self, self.class.filters, inputs).each do |attr, type, kwargs = {}|
|
|
316
|
+
errors.add(attr, type, **kwargs)
|
|
321
317
|
end
|
|
322
318
|
end
|
|
323
319
|
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
|
|
@@ -71,24 +68,15 @@ module ActiveInteraction
|
|
|
71
68
|
|
|
72
69
|
# @return (see #result=)
|
|
73
70
|
# @return [nil]
|
|
74
|
-
def run
|
|
75
|
-
self.result =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
if result_or_errors.is_a?(ActiveInteraction::Errors)
|
|
86
|
-
errors.merge!(result_or_errors)
|
|
87
|
-
else
|
|
88
|
-
result_or_errors
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
71
|
+
def run
|
|
72
|
+
return self.result = nil unless valid?
|
|
73
|
+
|
|
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)
|
|
79
|
+
end
|
|
92
80
|
end
|
|
93
81
|
|
|
94
82
|
# @return [Object]
|
|
@@ -101,11 +89,11 @@ module ActiveInteraction
|
|
|
101
89
|
|
|
102
90
|
e = InvalidInteractionError.new(errors.full_messages.join(', '))
|
|
103
91
|
e.interaction = self
|
|
92
|
+
e.set_backtrace(errors.backtrace) if errors.backtrace
|
|
104
93
|
raise e
|
|
105
94
|
end
|
|
106
95
|
|
|
107
|
-
#
|
|
108
|
-
module ClassMethods
|
|
96
|
+
module ClassMethods # rubocop:disable Style/Documentation
|
|
109
97
|
def new(*)
|
|
110
98
|
super.tap do |instance|
|
|
111
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
|
#
|
|
@@ -92,17 +90,15 @@ module ActiveInteraction
|
|
|
92
90
|
|
|
93
91
|
# An extension that provides the ability to merge other errors into itself.
|
|
94
92
|
class Errors < ActiveModel::Errors
|
|
93
|
+
attr_accessor :backtrace
|
|
94
|
+
|
|
95
95
|
# Merge other errors into this one.
|
|
96
96
|
#
|
|
97
97
|
# @param other [Errors]
|
|
98
98
|
#
|
|
99
99
|
# @return [Errors]
|
|
100
100
|
def merge!(other)
|
|
101
|
-
|
|
102
|
-
merge_details!(other)
|
|
103
|
-
else
|
|
104
|
-
merge_messages!(other)
|
|
105
|
-
end
|
|
101
|
+
merge_details!(other)
|
|
106
102
|
|
|
107
103
|
self
|
|
108
104
|
end
|
|
@@ -117,14 +113,6 @@ module ActiveInteraction
|
|
|
117
113
|
detail[:error].is_a?(Symbol)
|
|
118
114
|
end
|
|
119
115
|
|
|
120
|
-
def merge_messages!(other)
|
|
121
|
-
other.messages.each do |attribute, messages|
|
|
122
|
-
messages.each do |message|
|
|
123
|
-
merge_message!(attribute, message)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
|
|
128
116
|
def merge_message!(attribute, message)
|
|
129
117
|
unless attribute?(attribute)
|
|
130
118
|
message = full_message(attribute, message)
|
|
@@ -149,9 +137,8 @@ module ActiveInteraction
|
|
|
149
137
|
if attribute?(attribute) || attribute == :base
|
|
150
138
|
options = detail.dup
|
|
151
139
|
error = options.delete(:error)
|
|
152
|
-
options[:message] = message
|
|
153
140
|
|
|
154
|
-
add(attribute, error, options) unless added?(attribute, error, options)
|
|
141
|
+
add(attribute, error, **options.merge(message: message)) unless added?(attribute, error, **options)
|
|
155
142
|
else
|
|
156
143
|
merge_message!(attribute, message)
|
|
157
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,59 @@ 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
|
|
|
203
181
|
private
|
|
204
182
|
|
|
205
|
-
#
|
|
206
|
-
|
|
183
|
+
# rubocop:disable Metrics/MethodLength
|
|
184
|
+
def cast(value, context, convert: true, reconstantize: true)
|
|
185
|
+
if matches?(value)
|
|
186
|
+
adjust_output(value, context)
|
|
187
|
+
# we can't use `nil?` because BasicObject doesn't have it
|
|
188
|
+
elsif value == nil # rubocop:disable Style/NilComparison
|
|
189
|
+
raise MissingValueError, name unless default?
|
|
190
|
+
|
|
191
|
+
nil
|
|
192
|
+
elsif reconstantize
|
|
193
|
+
send(__method__, value, context,
|
|
194
|
+
convert: convert,
|
|
195
|
+
reconstantize: false
|
|
196
|
+
)
|
|
197
|
+
elsif convert
|
|
198
|
+
send(__method__, convert(value), context,
|
|
199
|
+
convert: false,
|
|
200
|
+
reconstantize: reconstantize
|
|
201
|
+
)
|
|
202
|
+
else
|
|
203
|
+
raise InvalidValueError, "#{name}: #{describe(value)}"
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
# rubocop:enable Metrics/MethodLength
|
|
207
|
+
|
|
208
|
+
def matches?(_value)
|
|
209
|
+
false
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def adjust_output(value, _context)
|
|
213
|
+
value
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def convert(value)
|
|
217
|
+
value
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def klass
|
|
221
|
+
@klass ||= Object.const_get(self.class.slug.to_s.camelize, false)
|
|
222
|
+
end
|
|
223
|
+
|
|
207
224
|
def describe(value)
|
|
208
225
|
value.inspect
|
|
209
226
|
rescue NoMethodError
|
|
210
227
|
"(Object doesn't support #inspect)"
|
|
211
228
|
end
|
|
212
229
|
|
|
213
|
-
# @param context [Base, nil]
|
|
214
|
-
#
|
|
215
|
-
# @return [Object]
|
|
216
230
|
def raw_default(context)
|
|
217
231
|
value = options.fetch(:default)
|
|
218
232
|
return value unless value.is_a?(Proc)
|