active_interaction 4.0.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 +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
|