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 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