Validating against a regex match *and* a regex failure?

Let’s say I have this existing regex-based “name” validation. In this scenario, a name must

  • begin with an alphabetic letter
  • end with a word character ([a-zA-Z0-9_])
  • contain at least 4 characters between the begin and end characters that may be word characters, full stop, hyphen, or space
  • not have any sequence of two or more whitespace characters

is_valid = name.match(/\A([[:alpha:]][\.\- \w]{4,}\w)\z/) && !name.match(/\s{2,}/

What would be the preferred way to code that using dry-validation?

If you want to use this with dry-validation then you may want to check out a less-known feature - negating a predicate (I probably never documented it anywhere, oops). So here it goes:

Dry::Validation.Schema do
  required(:name).filled {
    str? & format?(/some-regex/) & format?(/other-regex/).not
  }
end

This should work just fine, but it hasn’t been tested a lot, but feel free to try this out and lemme know if it’s what you need.

1 Like

Piotr, negation is exactly what I was looking for, thanks a lot. Things now work as expected:

$ pry
[1] pry(main)> require 'dry-types'; require 'dry-validation'
true
[2] pry(main)> class Member < Dry::Types::Value
[2] pry(main)*   attribute :name, Types::Strict::String.constrained(min_size: 6)  
[2] pry(main)* end  
Member < Dry::Types::Value
[3] pry(main)> foo = Member.new name: '  John  '
{
    :name => "  John  "
}
[4] pry(main)> MemberSchema = Dry::Validation.Schema do
[4] pry(main)*   required(:name).filled do  
[4] pry(main)*     str? & format?(/\A([[:alpha:]][\.\- \w]{4,}\w)\z/) & format?(/\s{2,}/).not    
[4] pry(main)*   end    
[4] pry(main)* end;  
[5] pry(main)> MemberSchema.call(foo.to_h).inspect
"#<Dry::Validation::Result output={:name=>\"  John  \"} messages={:name=>[\"is in invalid format\"]}>"
[6] pry(main)> q = MemberSchema.call(foo.to_h)
{
    :name => "  John  "
}
[7] pry(main)> q.messages
{
    :name => [
        [0] "is in invalid format"
    ]
}
[8] pry(main)> exit

$

Now, if I may ask a bonus question: after having read through the doc for error messages, it’s not clear to me if and how one can tell which constraint was violated. For instance, in the example I’d been poking along with, would I be able to have separate error messages for “not long enough or invalid characters” (not matching the first regex) separately from “redundant spaces” (invalidly matching the second)?

Thanks again!

Unfortunately there’s no support for negated rules in error messages. You gotta provide custom messages in the yaml file and that should work for now. Just define a custom predicate name and add a message for it.

Right; thanks a lot.