active_interaction 4.0.2 → 4.0.6

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: 8ea0d31fc8d2cf65540edb64cc51b1b3a31205a5f4a179fd56ecdb1606d84c9f
4
+ data.tar.gz: fd79ef266a8357bad053b282068b0fe5bfb3cf677f778b97ebe373b7c9c9a216
5
5
  SHA512:
6
- metadata.gz: bf7ba20068a6d5aee70730136d891d1bc4ce94d49ec8d7558805e3c6e017ba8560943581c31a99760890572a5b8d4121ec4ec8c8d639c3a29878505d56f09221
7
- data.tar.gz: 12a9fb539e434435065fde8671905b34fa742e4ebe5b030992b2d0ed58c17040cbaa9b2125a7a391311bd64659aa24416aa6c2d2b3ab151cadde018be1ff86fb
6
+ metadata.gz: d4070194c1bcf654043c65e340abf6a1be0977282c214636511cb5188cace08a81a34ef811f9d3a369b7dc10a8ce8fcdda6a563c69fe34435fef6618c67dc5b7
7
+ data.tar.gz: 446e6ccc7f28132c70808817b3db99b5852486f1c097212aea861db4235da1df676c1cd3751019425a34f84b6590b9c06e954b31ae3c8dc32cf0843ea3c7d326
data/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ # [4.0.6][] (2021-10-13)
2
+
3
+ ## Fix
4
+
5
+ - [#515][] - Filters nested in arrays should accept default values as indicated in the documentation.
6
+
7
+ # [4.0.5][] (2021-07-11)
8
+
9
+ ## Fix
10
+
11
+ - [#480][] - Interfaces used inside hashes failed to recognize `nil` as a non-value.
12
+
13
+ # [4.0.4][] (2021-07-03)
14
+
15
+ ## Fix
16
+
17
+ - [#510][] - Hash parameters failed when working outside of Rails.
18
+ - [#511][] - Nested filters with options but no `:class` failed to have `:class` automatically added.
19
+
20
+ # [4.0.3][] (2021-06-24)
21
+
22
+ ## Fix
23
+
24
+ - [#499][] - `given?` now recognizes multi-part date inputs by their primary key name
25
+ - [#493][] - `compose` now properly accepts `Inputs`
26
+
1
27
  # [4.0.2][] (2021-06-22)
2
28
 
3
29
  ## Fix
@@ -70,7 +96,7 @@ class Example < ActiveInteraction::Base
70
96
 
71
97
  validates :first_name,
72
98
  presence: true,
73
- unless: 'first_name.nil?'
99
+ unless: -> { first_name.nil? }
74
100
 
75
101
  def execute
76
102
  # ...
@@ -169,13 +195,13 @@ has a particular module included, you'll need to use the newly expanded
169
195
 
170
196
  ## Fixed
171
197
 
172
- - [486][] `valid?` returns true if block not called and error added in execute around callback.
198
+ - [#486][] `valid?` returns true if block not called and error added in execute around callback.
173
199
 
174
200
  # [3.8.2][] (2020-04-22)
175
201
 
176
202
  ## Fixed
177
203
 
178
- - [479][] Composed interactions that throw errors now show a complete backtrace instead of ending at the `run!` of the outermost interaction.
204
+ - [#479][] Composed interactions that throw errors now show a complete backtrace instead of ending at the `run!` of the outermost interaction.
179
205
 
180
206
  # [3.8.1][] (2020-04-04)
181
207
 
@@ -944,6 +970,10 @@ Example.run
944
970
 
945
971
  - Initial release.
946
972
 
973
+ [4.0.6]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.5...v4.0.6
974
+ [4.0.5]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.4...v4.0.5
975
+ [4.0.4]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.3...v4.0.4
976
+ [4.0.3]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.2...v4.0.3
947
977
  [4.0.2]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.1...v4.0.2
948
978
  [4.0.1]: https://github.com/AaronLasseigne/active_interaction/compare/v4.0.0...v4.0.1
949
979
  [4.0.0]: https://github.com/AaronLasseigne/active_interaction/compare/v3.8.3...v4.0.0
@@ -1153,3 +1183,10 @@ Example.run
1153
1183
  [#398]: https://github.com/AaronLasseigne/active_interaction/issues/398
1154
1184
  [#495]: https://github.com/AaronLasseigne/active_interaction/issues/495
1155
1185
  [#505]: https://github.com/AaronLasseigne/active_interaction/issues/505
1186
+ [#499]: https://github.com/AaronLasseigne/active_interaction/issues/499
1187
+ [#493]: https://github.com/AaronLasseigne/active_interaction/issues/493
1188
+ [#510]: https://github.com/AaronLasseigne/active_interaction/issues/510
1189
+ [#511]: https://github.com/AaronLasseigne/active_interaction/issues/511
1190
+ [#412]: https://github.com/AaronLasseigne/active_interaction/issues/412
1191
+ [#480]: https://github.com/AaronLasseigne/active_interaction/issues/480
1192
+ [#515]: https://github.com/AaronLasseigne/active_interaction/issues/515
data/README.md CHANGED
@@ -5,7 +5,6 @@ It's an implementation of the command pattern in Ruby.
5
5
 
6
6
  [![Version](https://img.shields.io/gem/v/active_interaction.svg?style=flat-square)](https://rubygems.org/gems/active_interaction)
7
7
  [![Test](https://img.shields.io/github/workflow/status/AaronLasseigne/active_interaction/Test?label=Test&style=flat-square)](https://github.com/AaronLasseigne/active_interaction/actions?query=workflow%3ATest)
8
- [![Coverage](https://img.shields.io/coveralls/github/AaronLasseigne/active_interaction.svg?style=flat-square)](https://coveralls.io/r/orgsync/active_interaction)
9
8
  [![Climate](https://img.shields.io/codeclimate/maintainability/orgsync/active_interaction.svg?style=flat-square)](https://codeclimate.com/github/orgsync/active_interaction)
10
9
 
11
10
  ---
@@ -58,7 +57,7 @@ handles your verbs.
58
57
  - [Translations](#translations)
59
58
  - [Credits](#credits)
60
59
 
61
- [Full Documentation][]
60
+ [API Documentation][]
62
61
 
63
62
  ## Installation
64
63
 
@@ -977,10 +976,10 @@ class UpdateAccount < ActiveInteraction::Base
977
976
 
978
977
  validates :first_name,
979
978
  presence: true,
980
- unless: 'first_name.nil?'
979
+ unless: -> { first_name.nil? }
981
980
  validates :last_name,
982
981
  presence: true,
983
- unless: 'last_name.nil?'
982
+ unless: -> { last_name.nil? }
984
983
 
985
984
  def execute
986
985
  account.first_name = first_name if first_name.present?
@@ -1448,8 +1447,8 @@ I18nInteraction.run(name: false).errors.messages[:name]
1448
1447
 
1449
1448
  ## Credits
1450
1449
 
1451
- ActiveInteraction is brought to you by [Aaron Lasseigne][] and
1452
- [Taylor Fausak][] and was originally built at [OrgSync][].
1450
+ ActiveInteraction is brought to you by [Aaron Lasseigne][].
1451
+ Along with Aaron, [Taylor Fausak][] helped create and maintain ActiveInteraction but has since moved on.
1453
1452
 
1454
1453
  If you want to contribute to ActiveInteraction, please read
1455
1454
  [our contribution guidelines][]. A [complete list of contributors][] is
@@ -1458,14 +1457,11 @@ available on GitHub.
1458
1457
  ActiveInteraction is licensed under [the MIT License][].
1459
1458
 
1460
1459
  [activeinteraction]: https://github.com/AaronLasseigne/active_interaction
1461
- [Full Documentation]: http://rubydoc.info/github/orgsync/active_interaction
1460
+ [API Documentation]: http://rubydoc.info/github/AaronLasseigne/active_interaction
1462
1461
  [semantic versioning]: http://semver.org/spec/v2.0.0.html
1463
1462
  [GitHub releases]: https://github.com/AaronLasseigne/active_interaction/releases
1464
- [the announcement post]: http://devblog.orgsync.com/2015/05/06/announcing-active-interaction-2/
1465
- [active_model-errors_details]: https://github.com/cowbell/active_model-errors_details
1466
1463
  [aaron lasseigne]: https://github.com/AaronLasseigne
1467
1464
  [taylor fausak]: https://github.com/tfausak
1468
- [orgsync]: https://github.com/orgsync
1469
1465
  [our contribution guidelines]: CONTRIBUTING.md
1470
1466
  [complete list of contributors]: https://github.com/AaronLasseigne/active_interaction/graphs/contributors
1471
1467
  [the mit license]: LICENSE.md
@@ -1474,5 +1470,4 @@ ActiveInteraction is licensed under [the MIT License][].
1474
1470
  [the filters section]: #filters
1475
1471
  [the errors section]: #errors
1476
1472
  [the optional inputs section]: #optional-inputs
1477
- [aire]: example
1478
1473
  [`with_options`]: http://api.rubyonrails.org/classes/Object.html#method-i-with_options
@@ -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
@@ -73,7 +73,7 @@ module ActiveInteraction
73
73
  end
74
74
 
75
75
  def add_option_in_place_of_name(klass, options)
76
- if (keys = FILTER_NAME_OR_OPTION[klass.to_s]) && (keys && options.keys).empty?
76
+ if (keys = FILTER_NAME_OR_OPTION[klass.to_s]) && (keys & options.keys).empty?
77
77
  options.merge(
78
78
  "#{keys.first}": name.to_s.singularize.camelize.to_sym
79
79
  )
@@ -91,7 +91,7 @@ module ActiveInteraction
91
91
 
92
92
  filters[filters.size.to_s.to_sym] = filter
93
93
 
94
- validate!(filter, names)
94
+ validate!(names)
95
95
  end
96
96
  end
97
97
  # rubocop:enable Style/MissingRespondToMissing
@@ -100,13 +100,11 @@ module ActiveInteraction
100
100
  # @param names [Array<Symbol>]
101
101
  #
102
102
  # @raise [InvalidFilterError]
103
- def validate!(filter, names)
103
+ def validate!(names)
104
104
  raise InvalidFilterError, 'multiple filters in array block' if filters.size > 1
105
105
 
106
106
  raise InvalidFilterError, 'attribute names in array block' unless names.empty?
107
107
 
108
- raise InvalidDefaultError, 'default values in array block' if filter.default?
109
-
110
108
  nil
111
109
  end
112
110
  end
@@ -44,7 +44,7 @@ module ActiveInteraction
44
44
  end
45
45
 
46
46
  def adjust_output(value, context)
47
- value = value.to_hash.with_indifferent_access
47
+ value = ActiveSupport::HashWithIndifferentAccess.new(value.to_hash)
48
48
 
49
49
  initial = strip? ? ActiveSupport::HashWithIndifferentAccess.new : value
50
50
 
@@ -48,6 +48,7 @@ module ActiveInteraction
48
48
  end
49
49
 
50
50
  def matches?(object)
51
+ return false if object.nil?
51
52
  return matches_methods?(object) if options.key?(:methods)
52
53
 
53
54
  const = from
@@ -61,7 +62,7 @@ module ActiveInteraction
61
62
  end
62
63
 
63
64
  def matches_methods?(object)
64
- options.fetch(:methods, []).all? { |method| object.respond_to?(method) }
65
+ options[:methods].all? { |method| object.respond_to?(method) }
65
66
  end
66
67
 
67
68
  def checking_class_inheritance?(object, from)
@@ -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
 
@@ -50,46 +73,8 @@ module ActiveInteraction
50
73
  end
51
74
  end
52
75
 
53
- def initialize
54
- @groups = {}
55
- @groups.default_proc = ->(hash, key) { hash[key] = [] }
56
-
57
- super(@inputs = {})
58
- end
59
-
60
- # Associates the `value` with the `key`. Allows the `key`/`value` pair to
61
- # be associated with one or more groups.
62
- #
63
- # @example
64
- # inputs.store(:key, :value)
65
- # # => :value
66
- # inputs.store(:key, :value, %i[a b])
67
- # # => :value
68
- #
69
- # @param key [Object] The key to store the value under.
70
- # @param value [Object] The value to store.
71
- # @param groups [Array<Object>] The groups to store the pair under.
72
- #
73
- # @return [Object] value
74
- def store(key, value, groups = [])
75
- groups.each do |group|
76
- @groups[group] << key
77
- end
78
-
79
- super(key, value)
80
- end
81
-
82
- # Returns inputs from the group name given.
83
- #
84
- # @example
85
- # inputs.group(:a)
86
- # # => {key: :value}
87
- #
88
- # @param name [Object] Name of the group to return.
89
- #
90
- # @return [Hash] Inputs from the group name given.
91
- def group(name)
92
- @inputs.select { |k, _| @groups[name].include?(k) }
76
+ def initialize(inputs = {})
77
+ super(inputs)
93
78
  end
94
79
  end
95
80
  end
@@ -14,26 +14,17 @@ module ActiveInteraction
14
14
  filter.clean(inputs[name], context)
15
15
  rescue NoDefaultError
16
16
  nil
17
- rescue InvalidNestedValueError,
18
- InvalidValueError,
19
- MissingValueError => e
20
- errors << error_args(filter, e)
17
+ rescue InvalidNestedValueError => e
18
+ errors << [filter.name, :invalid_nested, { name: e.filter_name.inspect, value: e.input_value.inspect }]
19
+ rescue InvalidValueError
20
+ errors << [filter.name, :invalid_type, { type: type(filter) }]
21
+ rescue MissingValueError
22
+ errors << [filter.name, :missing]
21
23
  end
22
24
  end
23
25
 
24
26
  private
25
27
 
26
- def error_args(filter, error)
27
- case error
28
- when InvalidNestedValueError
29
- [filter.name, :invalid_nested, { name: error.filter_name.inspect, value: error.input_value.inspect }]
30
- when InvalidValueError
31
- [filter.name, :invalid_type, { type: type(filter) }]
32
- when MissingValueError
33
- [filter.name, :missing]
34
- end
35
- end
36
-
37
28
  # @param filter [Filter]
38
29
  def type(filter)
39
30
  I18n.translate("#{Base.i18n_scope}.types.#{filter.class.slug}")
@@ -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.6')
8
8
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_model'
4
+ require 'active_support/hash_with_indifferent_access'
4
5
 
5
6
  # Manage application specific business logic.
6
7
  #
@@ -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
@@ -25,14 +25,6 @@ describe ActiveInteraction::ArrayFilter, :filter do
25
25
  end
26
26
  end
27
27
 
28
- context 'with a nested default' do
29
- let(:block) { proc { array default: nil } }
30
-
31
- it 'raises an error' do
32
- expect { filter }.to raise_error ActiveInteraction::InvalidDefaultError
33
- end
34
- end
35
-
36
28
  describe '#cast' do
37
29
  let(:result) { filter.send(:cast, value, nil) }
38
30
 
@@ -137,6 +129,18 @@ describe ActiveInteraction::ArrayFilter, :filter do
137
129
  expect(filter.filters[:'0'].options[:methods]).to eql %i[to_s]
138
130
  end
139
131
  end
132
+
133
+ context 'with another option set' do
134
+ let(:block) { proc { public_send(:object, converter: :new) } }
135
+ let(:name) { :objects }
136
+
137
+ it 'has a filter with the right options' do
138
+ expect(filter.filters[:'0'].options).to have_key(:class)
139
+ expect(filter.filters[:'0'].options[:class]).to eql :Object
140
+ expect(filter.filters[:'0'].options).to have_key(:converter)
141
+ expect(filter.filters[:'0'].options[:converter]).to eql :new
142
+ end
143
+ end
140
144
  end
141
145
  end
142
146
 
@@ -61,6 +61,17 @@ describe ActiveInteraction::InterfaceFilter, :filter do
61
61
  end
62
62
  end
63
63
 
64
+ context 'that is nil' do
65
+ let(:name) { :interface_module }
66
+ let(:value) { nil }
67
+
68
+ it 'raises an error' do
69
+ expect do
70
+ result
71
+ end.to raise_error ActiveInteraction::MissingValueError
72
+ end
73
+ end
74
+
64
75
  context 'with the class itself' do
65
76
  let(:name) { :interface_class }
66
77
  let(:value) 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
 
@@ -19,7 +19,7 @@ describe HashInteraction do
19
19
  before { inputs[:a] = a }
20
20
 
21
21
  it 'returns the correct value for :a' do
22
- expect(result[:a]).to eql a.with_indifferent_access
22
+ expect(result[:a]).to eql ActiveSupport::HashWithIndifferentAccess.new(a)
23
23
  end
24
24
 
25
25
  it 'returns the correct value for :b' do
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,3 @@
1
- # Disable code coverage for JRuby because it always reports 0% coverage.
2
- if RUBY_ENGINE != 'jruby'
3
- require 'coveralls'
4
- Coveralls.wear!
5
- end
6
-
7
1
  require 'i18n'
8
2
  I18n.config.enforce_available_locales = true if I18n.config.respond_to?(:enforce_available_locales)
9
3
 
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.6
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-10-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -32,21 +32,27 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: '7'
34
34
  - !ruby/object:Gem::Dependency
35
- name: actionpack
35
+ name: activesupport
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
41
- type: :development
40
+ version: '5'
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '7'
44
+ type: :runtime
42
45
  prerelease: false
43
46
  version_requirements: !ruby/object:Gem::Requirement
44
47
  requirements:
45
48
  - - ">="
46
49
  - !ruby/object:Gem::Version
47
- version: '0'
50
+ version: '5'
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '7'
48
54
  - !ruby/object:Gem::Dependency
49
- name: activerecord
55
+ name: actionpack
50
56
  requirement: !ruby/object:Gem::Requirement
51
57
  requirements:
52
58
  - - ">="
@@ -60,33 +66,33 @@ dependencies:
60
66
  - !ruby/object:Gem::Version
61
67
  version: '0'
62
68
  - !ruby/object:Gem::Dependency
63
- name: benchmark-ips
69
+ name: activerecord
64
70
  requirement: !ruby/object:Gem::Requirement
65
71
  requirements:
66
- - - "~>"
72
+ - - ">="
67
73
  - !ruby/object:Gem::Version
68
- version: '2.7'
74
+ version: '0'
69
75
  type: :development
70
76
  prerelease: false
71
77
  version_requirements: !ruby/object:Gem::Requirement
72
78
  requirements:
73
- - - "~>"
79
+ - - ">="
74
80
  - !ruby/object:Gem::Version
75
- version: '2.7'
81
+ version: '0'
76
82
  - !ruby/object:Gem::Dependency
77
- name: coveralls
83
+ name: benchmark-ips
78
84
  requirement: !ruby/object:Gem::Requirement
79
85
  requirements:
80
86
  - - "~>"
81
87
  - !ruby/object:Gem::Version
82
- version: '0.8'
88
+ version: '2.7'
83
89
  type: :development
84
90
  prerelease: false
85
91
  version_requirements: !ruby/object:Gem::Requirement
86
92
  requirements:
87
93
  - - "~>"
88
94
  - !ruby/object:Gem::Version
89
- version: '0.8'
95
+ version: '2.7'
90
96
  - !ruby/object:Gem::Dependency
91
97
  name: kramdown
92
98
  requirement: !ruby/object:Gem::Requirement
@@ -135,14 +141,14 @@ dependencies:
135
141
  requirements:
136
142
  - - "~>"
137
143
  - !ruby/object:Gem::Version
138
- version: '1.8'
144
+ version: 1.17.0
139
145
  type: :development
140
146
  prerelease: false
141
147
  version_requirements: !ruby/object:Gem::Requirement
142
148
  requirements:
143
149
  - - "~>"
144
150
  - !ruby/object:Gem::Version
145
- version: '1.8'
151
+ version: 1.17.0
146
152
  - !ruby/object:Gem::Dependency
147
153
  name: rubocop-rake
148
154
  requirement: !ruby/object:Gem::Requirement
@@ -318,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
318
324
  - !ruby/object:Gem::Version
319
325
  version: '0'
320
326
  requirements: []
321
- rubygems_version: 3.2.3
327
+ rubygems_version: 3.2.15
322
328
  signing_key:
323
329
  specification_version: 4
324
330
  summary: Manage application specific business logic.