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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b6d048d5a1bc4790a7852753a5bb79b74ddcef73e88603692fc0c580a28247c
4
- data.tar.gz: 62091b8494eee0cd2d90b64fb9540067e0b98446403af42e21ddb45df2891f9c
3
+ metadata.gz: 965fd20ed2231b6cb6a86c1849e11138cb694a77e05cb24e0091674964bbbd51
4
+ data.tar.gz: b86949412bf7a60d767fa27dec8b0092f0c0b053afb11bd50a5a5f09f83dc921
5
5
  SHA512:
6
- metadata.gz: bf7ba20068a6d5aee70730136d891d1bc4ce94d49ec8d7558805e3c6e017ba8560943581c31a99760890572a5b8d4121ec4ec8c8d639c3a29878505d56f09221
7
- data.tar.gz: 12a9fb539e434435065fde8671905b34fa742e4ebe5b030992b2d0ed58c17040cbaa9b2125a7a391311bd64659aa24416aa6c2d2b3ab151cadde018be1ff86fb
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::Base#initialize)
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 ActiveInteraction::Inputs.reserved?(name)
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
- inputs = normalize_inputs!(inputs)
168
- process_inputs(inputs.symbolize_keys)
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
- key_or_index = key_or_index.to_sym
243
- filter_level = filter_level.filters[key_or_index]
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
- break false unless input_level.key?(key_or_index) || input_level.key?(key_or_index.to_s)
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[key_or_index] || input_level[key_or_index.to_s]
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 key_or_index.between?(-input_level.size, input_level.size - 1)
256
+ break false unless index.between?(-input_level.size, input_level.size - 1)
254
257
 
255
- input_level = input_level[key_or_index]
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 = ActiveInteraction::Inputs.new
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
@@ -12,6 +12,10 @@ module ActiveInteraction
12
12
  self.class.slug
13
13
  end
14
14
 
15
+ def accepts_grouped_inputs?
16
+ true
17
+ end
18
+
15
19
  private
16
20
 
17
21
  def klasses
@@ -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.stringify_keys.sort.each_with_object({}) do |(k, v), h|
33
- next if reserved?(k)
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
- if (group = GROUPED_INPUT_PATTERN.match(k))
36
- assign_to_grouped_input!(h, group[:key], group[:index], v)
37
- else
38
- h[k.to_sym] = v
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
@@ -4,5 +4,5 @@ module ActiveInteraction
4
4
  # The version number.
5
5
  #
6
6
  # @return [Gem::Version]
7
- VERSION = Gem::Version.new('4.0.2')
7
+ VERSION = Gem::Version.new('4.0.3')
8
8
  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.2
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-22 00:00:00.000000000 Z
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: '1.8'
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: '1.8'
145
+ version: 1.17.0
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: rubocop-rake
148
148
  requirement: !ruby/object:Gem::Requirement