Macros

Defining rules using blocks is very flexible and powerful; however, in most common cases repeatedly defining the same rules leads to boilerplate code. That’s why dry-schema‘s DSL provides convenient macros to reduce that boilerplate. Every macro can be expanded to its block-based equivalent.

This document describes available built-in macros.

value

Use it to quickly provide a list of all predicates that will be AND-ed automatically:

Dry::Schema.Params do
  # expands to `required(:age) { int? & gt?(18) }`
  required(:age).value(:integer, gt?: 18)
end

filled

Use it when a value is expected to be filled. “filled” means that the value is non-nil and, in the case of a String, Hash, or Array value, that the value is not .empty?.

Dry::Schema.Params do
  # expands to `required(:age) { int? & filled? }`
  required(:age).filled(:integer)
end
Dry::Schema.Params do
  # expands to `required(:age) { array? & filled? }`
  required(:tags).filled(:array)
end

maybe

Use it when a value can be nil.

Notice: do not confuse maybe with the optional method, which allows a key to be omitted in the input, whereas maybe is for checking the value

Dry::Schema.Params do
  # expands to `required(:age) { !nil?.then(int?) }`
  required(:age).maybe(:integer)
end

hash

Use it when a value is expected to be a hash:

Dry::Schema.Params do
  # expands to: `required(:tags) { hash? & filled? & schema { required(:name).filled(:string) } } }`
  required(:tags).hash do
    required(:name).filled(:string)
  end
end

schema

This works like hash but does not prepend hash? predicate. It’s a simpler building block for checking nested hashes. Use it when you want to provide base checks prior applying rules to values.

Dry::Schema.Params do
  # expands to: `required(:tags) { hash? & filled? & schema { required(:name).filled(:string) } } }`
  required(:tags).filled(:hash).schema do
    required(:name).filled(:string)
  end
end

array

Use it to apply predicates to every element in a value that is expected to be an array.

Dry::Schema.Params do
  # expands to: `required(:tags) { array? & each { str? } } }`
  required(:tags).array(:str?)
end

You can also define an array where elements are hashes:

Dry::Schema.Params do
  # expands to: `required(:tags) { array? & each { hash { required(:name).filled(:string) } } } }`
  required(:tags).array(:hash) do
    required(:name).filled(:string)
  end
end

each

This works like array but does not prepend array? predicate. It’s a simpler building block for checking each element of an array. Use it when you want to provide base checks prior applying rules to elements.

Dry::Schema.Params do
  # expands to: `required(:tags) { array? & each { str? } } }`
  required(:tags).value(:array, min_size?: 2).each(:str?)
end

Learn more