Skip to content

Commit

Permalink
close #476 by adding support for arrays to given?
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronLasseigne committed Feb 28, 2020
1 parent bfb28c7 commit c83b3eb
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Added

- [#477][] `InvalidInteractionError` now provides access to the failing interaction by calling `interaction`.
- [#476][] Update `given?` to check for items in an array by passing an index.

# [3.7.1][] (2019-03-20)

Expand Down Expand Up @@ -954,3 +955,4 @@ Example.run
[#455]: https://github.com/AaronLasseigne/active_interaction/pull/455
[#457]: https://github.com/AaronLasseigne/active_interaction/issues/457
[#477]: https://github.com/AaronLasseigne/active_interaction/issues/477
[#476]: https://github.com/AaronLasseigne/active_interaction/issues/476
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,8 @@ whether a value was passed to `run` or the result of a filter default. In
particular, it is useful when `nil` is an acceptable value. For example, you
may optionally track your users' birthdays. You can use the `given?` predicate
to see if an input was even passed to `run`. With `given?` you can also check
the input of a hash filter by passing a series of keys to check.
the input of a hash or array filter by passing a series of keys or indexes to
check.

``` rb
class UpdateUser < ActiveInteraction::Base
Expand Down
36 changes: 27 additions & 9 deletions lib/active_interaction/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module ActiveInteraction
# else
# outcome.errors
# end
class Base
class Base # rubocop:disable Metrics/ClassLength
include ActiveModelable
include ActiveRecordable
include Runnable
Expand Down Expand Up @@ -203,7 +203,8 @@ def inputs
# Returns `true` if the given key was in the hash passed to {.run}.
# Otherwise returns `false`. Use this to figure out if an input was given,
# even if it was `nil`. Keys within nested hash filter can also be checked
# by passing them in series.
# by passing them in series. Arrays can be checked in the same manor as
# hashes by passing an index.
#
# @example
# class Example < ActiveInteraction::Base
Expand All @@ -219,32 +220,49 @@ def inputs
# hash :x, default: {} do
# integer :y, default: nil
# end
# def execute; given?(:x, :y) end
# array :a, default: [] do
# integer
# end
# def execute; given?(:x, :y) || given?(:a, 2) end
# end
# Example.run!() # => false
# Example.run!(x: nil) # => false
# Example.run!(x: {}) # => false
# Example.run!(x: { y: nil }) # => true
# Example.run!(x: { y: rand }) # => true
# Example.run!(a: [1, 2]) # => false
# Example.run!(a: [1, 2, 3]) # => true
#
# @param input [#to_sym]
#
# @return [Boolean]
#
# @since 2.1.0
def given?(input, *rest) # rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable all
def given?(input, *rest)
filter_level = self.class
input_level = @_interaction_inputs

[input, *rest].map(&:to_sym).each do |key|
filter_level = filter_level.filters[key]
[input, *rest].each do |key_or_index|
if key_or_index.is_a?(Symbol) || key_or_index.is_a?(String)
key_or_index = key_or_index.to_sym
filter_level = filter_level.filters[key_or_index]

break false if filter_level.nil? || input_level.nil?
break false unless input_level.key?(key_or_index) || input_level.key?(key_or_index.to_s)

break false if filter_level.nil? || input_level.nil?
break false unless input_level.key?(key) || input_level.key?(key.to_s)
input_level = input_level[key_or_index] || input_level[key_or_index.to_s]
else
filter_level = filter_level.filters.first.last

input_level = input_level[key] || input_level[key.to_s]
break false if filter_level.nil? || input_level.nil?
break false unless key_or_index.between?(-input_level.size, input_level.size - 1)

input_level = input_level[key_or_index]
end
end && true
end
# rubocop:enable all

protected

Expand Down
73 changes: 73 additions & 0 deletions spec/active_interaction/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,79 @@ def execute
expect(result).to be false
end
end

context 'nested array values' do
let(:described_class) do
Class.new(TestInteraction) do
array :x do
hash do
boolean :y, default: true
end
end

def execute; end
end
end

context 'has a positive index' do
it 'returns true if found' do
described_class.class_exec do
def execute
given?(:x, 0, :y)
end
end

inputs[:x] = [{ y: true }]
expect(result).to be true
end

it 'returns false if not found' do
described_class.class_exec do
def execute
given?(:x, 0, :y)
end
end

inputs[:x] = []
expect(result).to be false
end
end

context 'has a negative index' do
it 'returns true if found' do
described_class.class_exec do
def execute
given?(:x, -1, :y)
end
end

inputs[:x] = [{ y: true }]
expect(result).to be true
end

it 'returns false if not found' do
described_class.class_exec do
def execute
given?(:x, -1, :y)
end
end

inputs[:x] = []
expect(result).to be false
end
end

it 'returns false if you go too far' do
described_class.class_exec do
def execute
given?(:x, 10, :y)
end
end

inputs[:x] = [{}]
expect(result).to be false
end
end
end

context 'inheritance' do
Expand Down

0 comments on commit c83b3eb

Please sign in to comment.