active_interaction 4.0.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 +10 -0
- data/lib/active_interaction/base.rb +18 -37
- data/lib/active_interaction/filter.rb +15 -0
- data/lib/active_interaction/filters/abstract_date_time_filter.rb +4 -0
- data/lib/active_interaction/inputs.rb +32 -7
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/base_spec.rb +26 -24
- data/spec/active_interaction/inputs_spec.rb +32 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 965fd20ed2231b6cb6a86c1849e11138cb694a77e05cb24e0091674964bbbd51
|
4
|
+
data.tar.gz: b86949412bf7a60d767fa27dec8b0092f0c0b053afb11bd50a5a5f09f83dc921
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31878456f6b33fb902254fd44cc532d411a97db32ff347ca8bc8164166897d54cd0eae31e0add30f4f130f4e744a16cdb8970859d8bf79a842258b4c0ec38c0f
|
7
|
+
data.tar.gz: 17addfece52ce88fe5757eae06e14930508d209747caba20bd3e1d9b1aff140d2525e9548ec4a19dd1388dc7ef7e780706e35850351e8b487cda36c3f5b10bd9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# [4.0.3][] (2021-06-24)
|
2
|
+
|
3
|
+
## Fix
|
4
|
+
|
5
|
+
- [#499][] - `given?` now recognizes multi-part date inputs by their primary key name
|
6
|
+
- [#493][] - `compose` now properly accepts `Inputs`
|
7
|
+
|
1
8
|
# [4.0.2][] (2021-06-22)
|
2
9
|
|
3
10
|
## Fix
|
@@ -944,6 +951,7 @@ Example.run
|
|
944
951
|
|
945
952
|
- Initial release.
|
946
953
|
|
954
|
+
[4.0.2]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.2...v4.0.3
|
947
955
|
[4.0.2]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.1...v4.0.2
|
948
956
|
[4.0.1]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.0...v4.0.1
|
949
957
|
[4.0.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.3...v4.0.0
|
@@ -1153,3 +1161,5 @@ Example.run
|
|
1153
1161
|
[#398]: https://github.com/AaronLasseigne/active_interaction/issues/398
|
1154
1162
|
[#495]: https://github.com/AaronLasseigne/active_interaction/issues/495
|
1155
1163
|
[#505]: https://github.com/AaronLasseigne/active_interaction/issues/505
|
1164
|
+
[#499]: https://github.com/AaronLasseigne/active_interaction/issues/499
|
1165
|
+
[#493]: https://github.com/AaronLasseigne/active_interaction/issues/493
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
4
|
-
|
5
3
|
module ActiveInteraction
|
6
4
|
# @abstract Subclass and override {#execute} to implement a custom
|
7
5
|
# ActiveInteraction::Base class.
|
@@ -45,7 +43,7 @@ module ActiveInteraction
|
|
45
43
|
#
|
46
44
|
# Runs validations and if there are no errors it will call {#execute}.
|
47
45
|
#
|
48
|
-
# @param (see ActiveInteraction::
|
46
|
+
# @param (see ActiveInteraction::Inputs.process)
|
49
47
|
#
|
50
48
|
# @return [Base]
|
51
49
|
|
@@ -107,7 +105,7 @@ module ActiveInteraction
|
|
107
105
|
# @param name [Symbol]
|
108
106
|
# @param options [Hash]
|
109
107
|
def add_filter(klass, name, options, &block)
|
110
|
-
raise InvalidFilterError, %("#{name}" is a reserved name) if
|
108
|
+
raise InvalidFilterError, %("#{name}" is a reserved name) if Inputs.reserved?(name)
|
111
109
|
|
112
110
|
initialize_filter(klass.new(name, options, &block))
|
113
111
|
end
|
@@ -160,12 +158,11 @@ module ActiveInteraction
|
|
160
158
|
end
|
161
159
|
end
|
162
160
|
|
163
|
-
# @param inputs [Hash{Symbol => Object}] Attribute values to set.
|
164
|
-
#
|
165
161
|
# @private
|
166
162
|
def initialize(inputs = {})
|
167
|
-
|
168
|
-
|
163
|
+
@_interaction_raw_inputs = inputs
|
164
|
+
|
165
|
+
populate_filters_and_inputs(Inputs.process(inputs))
|
169
166
|
end
|
170
167
|
|
171
168
|
# @!method compose(other, inputs = {})
|
@@ -239,20 +236,26 @@ module ActiveInteraction
|
|
239
236
|
|
240
237
|
[input, *rest].each do |key_or_index|
|
241
238
|
if key_or_index.is_a?(Symbol) || key_or_index.is_a?(String)
|
242
|
-
|
243
|
-
|
239
|
+
key = key_or_index.to_sym
|
240
|
+
key_to_s = key_or_index.to_s
|
241
|
+
filter_level = filter_level.filters[key]
|
244
242
|
|
245
243
|
break false if filter_level.nil? || input_level.nil?
|
246
|
-
|
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
|
247
249
|
|
248
|
-
input_level = input_level[
|
250
|
+
input_level = input_level[key] || input_level[key_to_s]
|
249
251
|
else
|
252
|
+
index = key_or_index
|
250
253
|
filter_level = filter_level.filters.first.last
|
251
254
|
|
252
255
|
break false if filter_level.nil? || input_level.nil?
|
253
|
-
break false unless
|
256
|
+
break false unless index.between?(-input_level.size, input_level.size - 1)
|
254
257
|
|
255
|
-
input_level = input_level[
|
258
|
+
input_level = input_level[index]
|
256
259
|
end
|
257
260
|
end && true
|
258
261
|
end
|
@@ -268,30 +271,8 @@ module ActiveInteraction
|
|
268
271
|
|
269
272
|
private
|
270
273
|
|
271
|
-
# We want to allow both `Hash` objects and `ActionController::Parameters`
|
272
|
-
# objects. In Rails < 5, parameters are a subclass of hash and calling
|
273
|
-
# `#symbolize_keys` returns the entire hash, not just permitted values. In
|
274
|
-
# Rails >= 5, parameters are not a subclass of hash but calling
|
275
|
-
# `#to_unsafe_h` returns the entire hash.
|
276
|
-
def normalize_inputs!(inputs)
|
277
|
-
return inputs if inputs.is_a?(Hash)
|
278
|
-
|
279
|
-
parameters = 'ActionController::Parameters'
|
280
|
-
klass = parameters.safe_constantize
|
281
|
-
return inputs.to_unsafe_h if klass && inputs.is_a?(klass)
|
282
|
-
|
283
|
-
raise ArgumentError, "inputs must be a hash or #{parameters}"
|
284
|
-
end
|
285
|
-
|
286
|
-
# @param inputs [Hash{Symbol => Object}]
|
287
|
-
def process_inputs(inputs)
|
288
|
-
@_interaction_raw_inputs = inputs
|
289
|
-
|
290
|
-
populate_filters_and_inputs(ActiveInteraction::Inputs.process(inputs))
|
291
|
-
end
|
292
|
-
|
293
274
|
def populate_filters_and_inputs(inputs)
|
294
|
-
@_interaction_inputs =
|
275
|
+
@_interaction_inputs = Inputs.new
|
295
276
|
|
296
277
|
self.class.filters.each do |name, filter|
|
297
278
|
value =
|
@@ -178,6 +178,21 @@ module ActiveInteraction
|
|
178
178
|
:string
|
179
179
|
end
|
180
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
|
+
|
181
196
|
private
|
182
197
|
|
183
198
|
# rubocop:disable Metrics/MethodLength
|
@@ -13,8 +13,15 @@ module ActiveInteraction
|
|
13
13
|
/x.freeze
|
14
14
|
private_constant :GROUPED_INPUT_PATTERN
|
15
15
|
|
16
|
+
# @private
|
17
|
+
def keys_for_group?(keys, group_key)
|
18
|
+
search_key = /\A#{group_key}\(\d+i\)\z/
|
19
|
+
keys.any? { |key| search_key.match?(key) }
|
20
|
+
end
|
21
|
+
|
16
22
|
# Checking `syscall` is the result of what appears to be a bug in Ruby.
|
17
23
|
# https://bugs.ruby-lang.org/issues/15597
|
24
|
+
# @private
|
18
25
|
def reserved?(name)
|
19
26
|
name.to_s.start_with?('_interaction_') ||
|
20
27
|
name == :syscall ||
|
@@ -28,20 +35,36 @@ module ActiveInteraction
|
|
28
35
|
)
|
29
36
|
end
|
30
37
|
|
38
|
+
# @param inputs [Hash, ActionController::Parameters, ActiveInteraction::Inputs] Attribute values to set.
|
39
|
+
#
|
40
|
+
# @private
|
31
41
|
def process(inputs)
|
32
|
-
inputs
|
33
|
-
|
42
|
+
normalize_inputs!(inputs)
|
43
|
+
.stringify_keys
|
44
|
+
.sort
|
45
|
+
.each_with_object({}) do |(k, v), h|
|
46
|
+
next if reserved?(k)
|
34
47
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
48
|
+
if (group = GROUPED_INPUT_PATTERN.match(k))
|
49
|
+
assign_to_grouped_input!(h, group[:key], group[:index], v)
|
50
|
+
else
|
51
|
+
h[k.to_sym] = v
|
52
|
+
end
|
39
53
|
end
|
40
|
-
end
|
41
54
|
end
|
42
55
|
|
43
56
|
private
|
44
57
|
|
58
|
+
def normalize_inputs!(inputs)
|
59
|
+
return inputs if inputs.is_a?(Hash) || inputs.is_a?(Inputs)
|
60
|
+
|
61
|
+
parameters = 'ActionController::Parameters'
|
62
|
+
klass = parameters.safe_constantize
|
63
|
+
return inputs.to_unsafe_h if klass && inputs.is_a?(klass)
|
64
|
+
|
65
|
+
raise ArgumentError, "inputs must be a hash or #{parameters}"
|
66
|
+
end
|
67
|
+
|
45
68
|
def assign_to_grouped_input!(inputs, key, index, value)
|
46
69
|
key = key.to_sym
|
47
70
|
|
@@ -71,6 +94,7 @@ module ActiveInteraction
|
|
71
94
|
# @param groups [Array<Object>] The groups to store the pair under.
|
72
95
|
#
|
73
96
|
# @return [Object] value
|
97
|
+
# @private
|
74
98
|
def store(key, value, groups = [])
|
75
99
|
groups.each do |group|
|
76
100
|
@groups[group] << key
|
@@ -88,6 +112,7 @@ module ActiveInteraction
|
|
88
112
|
# @param name [Object] Name of the group to return.
|
89
113
|
#
|
90
114
|
# @return [Hash] Inputs from the group name given.
|
115
|
+
# @private
|
91
116
|
def group(name)
|
92
117
|
@inputs.select { |k, _| @groups[name].include?(k) }
|
93
118
|
end
|
@@ -46,30 +46,6 @@ describe ActiveInteraction::Base do
|
|
46
46
|
expect(interaction.instance_variable_defined?(:"@#{key}")).to be false
|
47
47
|
end
|
48
48
|
|
49
|
-
context 'with invalid inputs' do
|
50
|
-
let(:inputs) { nil }
|
51
|
-
|
52
|
-
it 'raises an error' do
|
53
|
-
expect { interaction }.to raise_error ArgumentError
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'with non-hash inputs' do
|
58
|
-
let(:inputs) { [%i[k v]] }
|
59
|
-
|
60
|
-
it 'raises an error' do
|
61
|
-
expect { interaction }.to raise_error ArgumentError
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'with ActionController::Parameters inputs' do
|
66
|
-
let(:inputs) { ActionController::Parameters.new }
|
67
|
-
|
68
|
-
it 'does not raise an error' do
|
69
|
-
expect { interaction }.to_not raise_error
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
49
|
context 'with a filter' do
|
74
50
|
let(:described_class) { InteractionWithFilter }
|
75
51
|
|
@@ -554,6 +530,32 @@ describe ActiveInteraction::Base do
|
|
554
530
|
expect(result).to be false
|
555
531
|
end
|
556
532
|
end
|
533
|
+
|
534
|
+
context 'multi-part date values' do
|
535
|
+
let(:described_class) do
|
536
|
+
Class.new(TestInteraction) do
|
537
|
+
date :thing,
|
538
|
+
default: nil
|
539
|
+
|
540
|
+
def execute
|
541
|
+
given?(:thing)
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'returns true when the input is given' do
|
547
|
+
inputs.merge!(
|
548
|
+
'thing(1i)' => '2020',
|
549
|
+
'thing(2i)' => '12',
|
550
|
+
'thing(3i)' => '31'
|
551
|
+
)
|
552
|
+
expect(result).to be true
|
553
|
+
end
|
554
|
+
|
555
|
+
it 'returns false if not found' do
|
556
|
+
expect(result).to be false
|
557
|
+
end
|
558
|
+
end
|
557
559
|
end
|
558
560
|
|
559
561
|
context 'inheritance' do
|
@@ -26,6 +26,38 @@ describe ActiveInteraction::Inputs do
|
|
26
26
|
let(:inputs) { {} }
|
27
27
|
let(:result) { described_class.process(inputs) }
|
28
28
|
|
29
|
+
context 'with invalid inputs' do
|
30
|
+
let(:inputs) { nil }
|
31
|
+
|
32
|
+
it 'raises an error' do
|
33
|
+
expect { result }.to raise_error ArgumentError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with non-hash inputs' do
|
38
|
+
let(:inputs) { [%i[k v]] }
|
39
|
+
|
40
|
+
it 'raises an error' do
|
41
|
+
expect { result }.to raise_error ArgumentError
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with ActionController::Parameters inputs' do
|
46
|
+
let(:inputs) { ActionController::Parameters.new }
|
47
|
+
|
48
|
+
it 'does not raise an error' do
|
49
|
+
expect { result }.to_not raise_error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with Inputs inputs' do
|
54
|
+
let(:inputs) { ActiveInteraction::Inputs.new }
|
55
|
+
|
56
|
+
it 'does not raise an error' do
|
57
|
+
expect { result }.to_not raise_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
29
61
|
context 'with simple inputs' do
|
30
62
|
before { inputs[:key] = :value }
|
31
63
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_interaction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Lasseigne
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-06-
|
12
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -135,14 +135,14 @@ dependencies:
|
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 1.17.0
|
139
139
|
type: :development
|
140
140
|
prerelease: false
|
141
141
|
version_requirements: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: 1.17.0
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: rubocop-rake
|
148
148
|
requirement: !ruby/object:Gem::Requirement
|