How can I perform custom validation without monkeypatching?

Hello!

Thanks for an awesome set of libraries.

The problem

I want to make sure the object I’m building isn’t broken.

It should either have both :text and :path_name as being filled OR neither key should be present.

My solution

module Dry::Logic::Predicates::Methods
  def all_keys_filled_or_missing?(keys, object)
    keys.all? { |key| object[key].present? } || keys.all? { |key| object[key].nil? }
  end
end

module Features
  module Values
    class Link < Dry::Struct
      schema schema.constrained(all_keys_filled_or_missing: [:text, :path_name])
      
      attribute :text?, Dry.Types::String
      attribute :path_name?, Dry.Types::String
    end
  end
end

I’ve studied the dry logic docs here: dry-rb - dry-logic v1.2 - Custom predicates

But no matter what I did I couldn’t get this to integrate with Dry::Struct

Does anyone know a cleaner more modular way of doing this?

Thanks in advance for the library and for the help!

dry-structs are meant to be valid by construction. They do have type checks but more complex rules are handled either by dry-validation or custom code. There’re no and will not be APIs for complex cross-attribute predicates. dry-struct here is an important layer of abstraction. For example, you can build structs for use in tests. There’s no point in applying complex rules there since these objects are special-purposed.

1 Like

I think it’s also worth mentioning that schema => struct converted has been on our “list of things we’d like to build” for a while now :sweat_smile:

1 Like