dry-validation
dry-validation copied to clipboard
Support for pattern-matched rules
In order to make defining rules that depend on additional conditions nicer, we can have something like this:
params do
optional(:per_page).value(:integer)
end
rule(:per_page).if(:key?).validate(gt?: 0, lteq?: 20)
See the original conversation: https://github.com/dry-rb/dry-validation/issues/540#issuecomment-744022950
Above code won't work. For optional
, we will need :key?
. What is going to check for maybe
? Unlike optional
which is related to key
, maybe
is related to its value
.
@musaffa right, thanks - just updated the example. The actual part that needs to be implemented is the if
method. The underlying predicates (like key?
) will be available OOTB, so we can add value?
like you suggested in a separate PR, because essentially it's going to be a separate, new feature as well 🙂
@solnic Hi, Is there any update about this feature?
@musaffa hey there, no, nobody has had the time to work on this yet. There's a lot of more important things to do in validation/schema so this needs to wait.
@solnic I can help with implementing this feature. For that, I'll need some guidance from you.
@musaffa that's cool! Feel free to grab this issue. I don't really have any specific idea how to implement this so you need to experiment a bit. Rules are captured via Contract.rule
so I think something similar can be done as we have in case of Rule#each
. The trick is that each
overrides rule's block, and with this if
method it should most likely create a rule-like object that would just serve as a guard. Maybe something like this:
# inside rule.rb
def if(*args)
Guard.new(self, args: args)
end
This Guard
thingie would have to quack like a rule, using a decorator should work better than inheriting from Rule. You also need to figure out how to replace the rule with the guard because Contract.rule
adds rule instances to the internal rules
array. This can be a bit difficult though so...another option is to use a different top-level DSL method for this, like guard(:key?).rule(:foo).validate(:good?)
.
Yeah...this needs some experimentation to see what makes more sense 🙂
Thanks. I'll look into it.
@musaffa I'd start with this additional top-level method, actually 🙂
Noted.
Any news on this? would this also be covering rules that has more than one key?
rule(:key1, :key2) do
...
end