diff --git a/lib/dry/validation/rule.rb b/lib/dry/validation/rule.rb index bc052675..f51dceed 100644 --- a/lib/dry/validation/rule.rb +++ b/lib/dry/validation/rule.rb @@ -82,7 +82,7 @@ def each(*macros, &block) @keys = [] @block = proc do - unless result.base_error?(root) || !values.key?(root) + unless result.base_error?(root) || !values.key?(root) || values[root].nil? values[root].each_with_index do |_, idx| path = [*Schema::Path[root].to_a, idx] diff --git a/lib/dry/validation/values.rb b/lib/dry/validation/values.rb index 272745f4..588f6db4 100644 --- a/lib/dry/validation/values.rb +++ b/lib/dry/validation/values.rb @@ -65,7 +65,6 @@ def [](*args) def key?(key, hash = data) return hash.key?(key) if key.is_a?(Symbol) - # rubocop: disable Lint/DuplicateBranch Schema::Path[key].reduce(hash) do |a, e| if e.is_a?(Array) result = e.all? { |k| key?(k, a) } @@ -81,8 +80,6 @@ def key?(key, hash = data) end a[e] end - # rubocop: enable Lint/DuplicateBranch - true end # rubocop: enable Metrics/PerceivedComplexity diff --git a/spec/unit/rule_spec.rb b/spec/unit/rule_spec.rb index e91b1853..1aa2e363 100644 --- a/spec/unit/rule_spec.rb +++ b/spec/unit/rule_spec.rb @@ -50,4 +50,24 @@ end end end + + context "with an optional value" do + let(:contract_class) do + Class.new(Dry::Validation::Contract) do + schema do + required(:tags).maybe(:array) + end + end + end + + context "when using .each macro" do + it "does not fail when input is nil" do + contract_class.rule(:tags).each do + key.failure("should not be called") + end + + expect(contract.(tags: nil).errors.to_h).to eq({}) + end + end + end end