Skip to content

Commit

Permalink
Merge pull request #673 from moofkit/rule_error_with_args
Browse files Browse the repository at this point in the history
adds support of explict argument for #rule_error? method

[changelog]

added: "You can now pass a key name or path to `rule_error?` predicate (issue #658 closed via #673) (@moofkit)"
  • Loading branch information
solnic authored Nov 11, 2020
2 parents f28256f + 63449fd commit 658bc27
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 14 deletions.
22 changes: 22 additions & 0 deletions docsite/source/rules.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,28 @@ FooContract.new.(foo: 'foo').errors.to_h
# { foo: ['failure added', 'failure added after checking'] }
```

Also it is possible for checking other rule error by passing explicit argument to `rule_error?` method

```ruby
class PersonContract < Dry::Validation::Contract
schema do
required(:email).filled(:string)
required(:name).filled(:string)
end

rule(:name) do
key.failure('name rule error')
end

rule(:email) do
key.failure('email rule error') if rule_error?(:name)
end
end

PersonContract.new.call(email: 'bar', name: 'foo').errors.to_h
# {name: ['name rule error'], email: ['email rule error']}
```

### Defining a rule for each element of an array

To check each element of an array you can simply use `Rule#each` shortcut. It works just like a normal rule, which means it's only applied when a value passed schema checks and supports setting failure messages in the standard way.
Expand Down
10 changes: 8 additions & 2 deletions lib/dry/validation/evaluator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,17 @@ def schema_error?(path)

# Check if there are any errors on the current rule
#
# @param path [Symbol, String, Array] A Path-compatible spec
#
# @return [Boolean]
#
# @api public
def rule_error?
!key(path).empty?
def rule_error?(path = nil)
if path.nil?
!key(self.path).empty?
else
result.rule_error?(path)
end
end

# @api private
Expand Down
7 changes: 7 additions & 0 deletions lib/dry/validation/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ def schema_error?(key)
schema_result.error?(key)
end

# Check if the rules includes an error for the provided key
#
# @api private
def rule_error?(key)
!schema_error?(key) && error?(key)
end

# Check if there's any error for the provided key
#
# This does not consider errors from the nested values
Expand Down
57 changes: 45 additions & 12 deletions spec/integration/contract/evaluator/errors_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,56 @@
end

describe "#rule_error?" do
let(:contract) do
Class.new(Dry::Validation::Contract) do
schema do
required(:foo).filled(:string)
end
context "without argument" do
let(:contract) do
Class.new(Dry::Validation::Contract) do
schema do
required(:foo).filled(:string)
end

rule(:foo) do
key.failure("failure added")
key.failure("failure added after checking") if rule_error?
rule(:foo) do
key.failure("failure added")
key.failure("failure added after checking") if rule_error?
end
end
end

it "checks for errors in current rule" do
expect(contract.new.(foo: "some@email.com").errors.to_h).to eql(
foo: ["failure added", "failure added after checking"]
)
end
end

it "checks for errors in current rule" do
expect(contract.new.(foo: "some@email.com").errors.to_h).to eql(
foo: ["failure added", "failure added after checking"]
)
context "with argument" do
let(:contract) do
Class.new(Dry::Validation::Contract) do
schema do
required(:name).filled(:string)
required(:email).filled(:string)
end

rule(:name) do
key.failure("expected")
end

rule(:email) do
key.failure("also expected") if rule_error?(:name)
end
end
end

it "checks for error in rule with name provided in argument" do
expect(contract.new.(name: "John", email: "some@email.com").errors.to_h).to eql(
{name: ["expected"], email: ["also expected"]}
)
end

it "does not evaluate if schema with provided key is falling down" do
expect(contract.new.(name: nil, email: "some@email.com").errors.to_h).to eql(
{name: ["must be a string"]}
)
end
end
end
end

0 comments on commit 658bc27

Please sign in to comment.