dry-validation icon indicating copy to clipboard operation
dry-validation copied to clipboard

Support for pattern-matched rules

Open solnic opened this issue 3 years ago • 10 comments

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

solnic avatar Dec 16 '20 06:12 solnic

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 avatar Dec 16 '20 15:12 musaffa

@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 avatar Dec 17 '20 05:12 solnic

@solnic Hi, Is there any update about this feature?

musaffa avatar Apr 25 '21 18:04 musaffa

@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 avatar Apr 26 '21 04:04 solnic

@solnic I can help with implementing this feature. For that, I'll need some guidance from you.

musaffa avatar Apr 26 '21 10:04 musaffa

@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 🙂

solnic avatar Apr 27 '21 04:04 solnic

Thanks. I'll look into it.

musaffa avatar Apr 27 '21 16:04 musaffa

@musaffa I'd start with this additional top-level method, actually 🙂

solnic avatar Apr 28 '21 07:04 solnic

Noted.

musaffa avatar Apr 28 '21 12:04 musaffa

Any news on this? would this also be covering rules that has more than one key?

rule(:key1, :key2) do
    ...
 end

ssoulless avatar Mar 29 '23 19:03 ssoulless