### Usage Example: Validating Unexpected Keys - Dry-Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/unexpected-keys.html.md This example demonstrates how to define a schema with key validation enabled and how it reports unexpected keys in the input. Ensure `config.validate_keys = true` is set for the schema. ```ruby require 'dry/schema' UserSchema = Dry::Schema.Params do config.validate_keys = true required(:name).filled(:string) required(:address).hash do required(:city).filled(:string) required(:zipcode).filled(:string) end required(:roles).array(:hash) do required(:name).filled(:string) end end input = { foo: 'unexpected', name: 'Jane', address: { bar: 'unexpected', city: 'NYC', zipcode: '1234' }, roles: [{ name: 'admin' }, { name: 'editor', foo: 'unexpected' }] } UserSchema.(input).errors.to_h # { # :foo=>["is not allowed"], # :address=>{:bar=>["is not allowed"]}, # :roles=>{1=>{:foo=>["is not allowed"]}} # } ``` -------------------------------- ### Iterating Over Key Map with Enumerable Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/key-maps.html.md Key maps are enumerable, allowing you to use methods like `each` and `detect`. This example shows how to iterate and find a specific key. ```ruby schema.key_map.each { |key| puts key.inspect } # #> # #> schema.key_map.detect { |key| key.name.eql?("email") } # => #> ``` -------------------------------- ### AST Compiler Example Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/rule-ast.html.md A simple AST compiler class (`DocCompiler`) demonstrates how to traverse and interpret the AST nodes to generate documentation metadata. It requires `dry/schema` to be required. ```ruby require 'dry/schema' class DocCompiler def visit(node) meth, rest = node public_send(வையில்_"visit_#{meth}", rest) end def visit_set(nodes) nodes.map { |node| visit(node) }.flatten(1) end def visit_and(node) left, right = node [visit(left), visit(right)].compact end def visit_key(node) name, rest = node predicates = visit(rest).flatten(1).reduce(:merge) validations = predicates.map { |name, args| predicate_description(name, args) }.compact { key: name, validations: validations } end def visit_implication(node) _, right = node.map(&method(:visit)) right.merge(optional: true) end def visit_predicate(node) name, args = node return if name.equal?(:key?) { name => args.map(&:last).reject { |v| v.equal?(Dry::Schema::Undefined) } } end def predicate_description(name, args) case name when :str? then "must be a string" when :filled? then "must be filled" when :int? then "must be an integer" when :gt? then "must be greater than #{args[0]}" else raise NotImplementedError, "#{name} not supported yet" end end end ``` -------------------------------- ### Get Full Hints with Options Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/hints.html.md Access hints with the `full: true` option to include the attribute name in the hint message. This provides more context for the validation failure. ```ruby result.hints(full: true) # {:age=>['age must be greater than 18']} ``` -------------------------------- ### Validate Array Size and Elements Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/nested-data.html.md Combine array predicates like `min_size?` with element validation using `each`. This example ensures the array is not empty and contains valid hashes. ```ruby schema = Dry::Schema.Params do required(:people).value(:array, min_size?: 1).each do hash do required(:name).filled(:string) required(:age).filled(:integer, gteq?: 18) end end end errors = schema.call(people: []).errors puts errors.to_h.inspect # => { # :people=>["size cannot be less than 1"] # } ``` -------------------------------- ### Define array of hashes using array macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md This example defines a 'tags' field that must be an array where each element is a hash containing a required 'name' field, which must be a filled string. ```ruby 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 ``` -------------------------------- ### Define array with minimum size and string elements using each macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md The `each` macro applies rules to each element of an array without prepending the `array?` predicate. This example defines a 'tags' field that must be an array with a minimum size of 2, and each element must be a string. ```ruby Dry::Schema.Params do # expands to: `required(:tags) { array? & each { str? } } }` required(:tags).value(:array, min_size?: 2).each(:str?) end ``` -------------------------------- ### Define required filled array using filled macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md This example uses the `filled` macro to ensure that the 'tags' field is a non-empty array. ```ruby Dry::Schema.Params do # expands to `required(:tags) { array? & filled? }` required(:tags).filled(:array) end ``` -------------------------------- ### Define a Basic User Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/index.html.md Use Dry::Schema.Params to define a schema for form parameters. This example shows required string fields, an optional integer field, and a nested hash for the address. ```ruby require 'dry/schema' UserSchema = Dry::Schema.Params do required(:name).filled(:string) required(:email).filled(:string) required(:age).maybe(:integer) required(:address).hash do required(:street).filled(:string) required(:city).filled(:string) required(:zipcode).filled(:string) end end UserSchema.( name: 'Jane', email: 'jane@doe.org', address: { street: 'Street 1', city: 'NYC', zipcode: '1234' } ).inspect # #"Jane", :email=>"jane@doe.org", :address=>{:street=>"Street 1", :city=>"NYC", :zipcode=>"1234"}} errors={:age=>["age is missing"]}> ``` -------------------------------- ### Define array with optional strings using maybe macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md When using `maybe` with `each`, use this syntax to correctly handle optional elements within an array. This example defines a 'list' that can be an array containing optional strings. ```ruby Dry::Schema.Params do required(:list).maybe(array[:string]) # or required(:list).maybe(:array) do nil? | each(:string) end end ``` -------------------------------- ### YAML Error Message Structure Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Example structure of a YAML file for defining custom error messages. This format is compatible with I18n. ```yaml en: dry_schema: errors: size?: arg: default: "size must be %{num}" range: "size must be within %{left} - %{right}" value: string: arg: default: "length must be %{num}" range: "length must be within %{left} - %{right}" filled?: "must be filled" included_in?: "must be one of %{list}" excluded_from?: "must not be one of: %{list}" rules: email: filled?: "the email is missing" user: filled?: "name cannot be blank" rules: address: filled?: "You gotta tell us where you live" ``` -------------------------------- ### Define optional integer using maybe macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md Use the `maybe` macro when a value is permitted to be nil. This example allows the 'age' field to be nil or an integer. ```ruby Dry::Schema.Params do # expands to `required(:age) { !nil?.then(int?) }` required(:age).maybe(:integer) end ``` -------------------------------- ### Validate Array of Strings Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/nested-data.html.md Use the `array` macro to validate that a key holds an array of strings. This example also shows how to handle non-array input and arrays with invalid elements. ```ruby schema = Dry::Schema.Params do required(:phone_numbers).array(:str?) end errors = schema.call(phone_numbers: '').messages puts errors.to_h.inspect # { :phone_numbers => ["must be an array"] } errors = schema.call(phone_numbers: ['123456789', 123456789]).messages puts errors.to_h.inspect # { # :phone_numbers => { # 1 => ["must be a string"] # } # } ``` -------------------------------- ### Define array of strings using array macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md The `array` macro applies predicates to each element of an array. This example defines a 'tags' field that must be an array where each element is a string. ```ruby Dry::Schema.Params do # expands to: `required(:tags) { array? & each { str? } } }` required(:tags).array(:str?) end ``` -------------------------------- ### Combine Errors and Hints with Messages Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/hints.html.md Use `result.messages.to_h` to get a combined output of both validation errors and hints. This provides a comprehensive view of all validation outcomes. ```ruby result = schema.call(email: 'jane@doe.org', age: '') result.messages.to_h # {:age=>["must be filled", "must be greater than 18"]} ``` -------------------------------- ### Add Callback Before Value Coercer in Dry-Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/processor-steps.html.md Use the `before` callback to execute custom logic before the value coercion step. This example removes keys with nil values. ```ruby schema = Dry::Schema.Params do required(:name).value(:string) optional(:age).value(:integer) before(:value_coercer) do |result| result.to_h.compact end end ``` -------------------------------- ### Validate Array of Hashes Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/nested-data.html.md Validate an array where each element is expected to be a hash with specific keys and types. This example validates an array of people with name and age. ```ruby schema = Dry::Schema.Params do required(:people).array(:hash) do required(:name).filled(:string) required(:age).filled(:integer, gteq?: 18) end end errors = schema.call(people: [{ name: 'Alice', age: 19 }, { name: 'Bob', age: 17 }]).errors puts errors.to_h.inspect # => { # :people=>{ # 1=>{ # :age=>["must be greater than or equal to 18"] # } # } # } ``` -------------------------------- ### Define and Validate a JSON Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/json.html.md Use `Dry::Schema.JSON` to define a schema for JSON data. The example shows required fields with type and value constraints. Validation errors are returned as a hash. ```ruby schema = Dry::Schema.JSON do required(:email).filled(:string) required(:age).value(:integer, gt?: 18) end errors = schema.call('email' => '', 'age' => 18).errors.to_h puts errors.inspect # { # :email => ["must be filled"], # :age => ["must be greater than 18"] # } ``` -------------------------------- ### Validate Nested Array (Matrix) Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/nested-data.html.md Define validation for a matrix-like structure (an array of arrays) by nesting `value(:array).each` macros. This example validates a matrix of non-negative integers. ```ruby schema = Dry::Schema.Params do config.validate_keys = true required(:matrix).value(:array).each do value(:array).each do value(:integer, gteq?: 0) end end end errors = schema.call(matrix: [[1, 2, 3], [4, -5, 6]]).errors puts errors.to_h.inspect # => {:matrix=>{1=>{1=>["must be greater than or equal to 0"]}}} ``` -------------------------------- ### Define nested schema with required name field using schema macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md The `schema` macro is similar to `hash` but does not prepend the `hash?` predicate, making it a simpler building block for nested hashes. This example defines a 'tags' field that must be a filled hash containing a required 'name' field, which must be a filled string. ```ruby 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 ``` -------------------------------- ### Validate Nested Hash Structure Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/nested-data.html.md Define validation rules for a nested hash by using the DSL on a specific key. This example shows validation for an address hash with nested country details. ```ruby schema = Dry::Schema.Params do required(:address).hash do required(:city).filled(:string, min_size?: 3) required(:street).filled(:string) required(:country).hash do required(:name).filled(:string) required(:code).filled(:string) end end end errors = schema.call({}).errors puts errors.to_h.inspect # { :address => ["is missing"] } errors = schema.call(address: { city: 'NYC' }).errors puts errors.to_h.inspect # { # :address => [ # { :street => ["is missing"] }, # { :country => ["is missing"] } # ] # } ``` -------------------------------- ### Define required integer with greater than 18 rule using value macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md Use the `value` macro to specify multiple predicates that will be automatically AND-ed. This example defines a required 'age' field that must be an integer and greater than 18. ```ruby Dry::Schema.Params do # expands to `required(:age) { int? & gt?(18) }` required(:age).value(:integer, gt?: 18) end ``` -------------------------------- ### Define required ID with string or integer rule using value macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md When predicates are passed as an array to the `value` macro, they are automatically OR-ed. This example defines a required 'id' field that can be either a string or an integer. ```ruby Dry::Schema.Params do # expands to `required(:id) { str? | int? }` required(:id).value([:string, :integer]) end ``` -------------------------------- ### Basic Params Validation Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/params.html.md Use `Dry::Schema.Params` for validating HTTP parameters. It automatically symbolizes stringified keys and coerces values. This example shows validation of email and age, with errors reported for empty or out-of-range values. ```ruby schema = Dry::Schema.Params do required(:email).filled(:string) required(:age).filled(:integer, gt?: 18) end errors = schema.call('email' => '', 'age' => '18').errors puts errors.to_h.inspect # { # :email => ["must be filled"], # :age => ["must be greater than 18"] # } ``` -------------------------------- ### Define required filled integer using filled macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md The `filled` macro ensures that a value is not nil and, for strings, hashes, or arrays, that it is not empty. This example requires the 'age' field to be a non-empty integer. ```ruby Dry::Schema.Params do # expands to `required(:age) { int? & filled? }` required(:age).filled(:integer) end ``` -------------------------------- ### Define nested hash with required name field using hash macro Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/macros.html.md The `hash` macro is used to define a nested hash structure with its own rules. This example defines a 'tags' field that must be a hash containing a required 'name' field, which must be a filled string. ```ruby 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 ``` -------------------------------- ### Define and Call a Schema - Ruby Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/working-with-schemas.html.md Defines a schema with required email and age fields, then calls it with sample data. Accesses the validation output and checks for success. ```ruby schema = Dry::Schema.Params do required(:email).filled(:string) required(:age).filled(:integer) end result = schema.call(email: 'jane@doe.org', age: 21) # access validation output data result.to_h # => {:email=>'jane@doe.org', :age=>21} # check if all rules passed result.success? # => true # check if any of the rules failed result.failure? # => false ``` -------------------------------- ### Compiling AST to Documentation Metadata Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/rule-ast.html.md After defining a compiler, you can use it to transform the schema's AST into a structured list of hashes, providing a clear overview of keys and their associated validations. ```ruby compiler = DocCompiler.new compiler.visit(schema.to_ast) # [ # {:key=>:email, :validations=>["must be filled", "must be a string"]}, # {:key=>:age, :validations=>["must be filled", "must be an integer", "must be greater than 18"], :optional=>true} # ] ``` -------------------------------- ### Enable and Use Hints in Dry Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/hints.html.md Enable the hints extension and call a schema with invalid data to see the generated hints. Hints show un-evaluated predicates. ```ruby # enable :hints Dry::Schema.load_extensions(:hints) schema = Dry::Schema.Params do required(:email).filled(:string) required(:age).filled(:integer, gt?: 18) end result = schema.call(email: 'jane@doe.org', age: '') result.hints.to_h # {:age=>['must be greater than 18']} ``` -------------------------------- ### Compare Errors and Hints Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/hints.html.md Call a schema with invalid data to observe both the errors (failed checks) and hints (skipped checks). Hints are available even when errors are present. ```ruby result = schema.call(email: 'jane@doe.org', age: '') result.errors.to_h # {:age=>['must be filled']} result.hints.to_h # {:age=>['must be greater than 18']} ``` -------------------------------- ### Custom Type Namespaces for Schema Processors Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/custom-types.html.md Understand the different namespaces used for registering custom types with various schema processors. Use 'params.' for Dry::Schema::Params, 'nominal.' for Dry::Schema::Processor, and 'json.' for Dry::Schema::JSON. ```ruby TypeContainer.register('params.my_type', MyType) ``` ```ruby TypeContainer.register('nominal.my_type', MyType) ``` ```ruby TypeContainer.register('json.my_type', MyType) ``` -------------------------------- ### Use Dry::Schema with Monads and Pattern Matching Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/monads.html.md Integrate dry-schema and dry-monads with Ruby's pattern matching for elegant handling of success and failure cases. Ensure both libraries are required and the monads extension is loaded. ```ruby require 'dry/schema' require 'dry/monads' Dry::Schema.load_extensions(:monads) class Example include Dry::Monads[:result] Schema = Dry::Schema.Params { required(:name).filled(:string, size?: 2..4) } def call(input) case schema.(input).to_monad in Success(name:) "Hello #{name}" # name is captured from result in Failure(name:) "#{name} is not a valid name" end end end run = Example.new run.('name' => 'Jane') # => "Hello Jane" run.('name' => 'Albert') # => "Albert is not a valid name" ``` -------------------------------- ### Create Basic HTTP Params Schema with Dry::Schema.Params Source: https://context7.com/dry-rb/dry-schema/llms.txt Use Dry::Schema.Params to create schemas for HTTP parameters. It automatically symbolizes string keys and coerces values. Use `filled` to ensure values are present and non-empty, and specify types with predicates like `gt?`. ```ruby require 'dry/schema' schema = Dry::Schema.Params do required(:email).filled(:string) required(:age).filled(:integer, gt?: 18) end # Valid input - string keys and values are automatically coerced result = schema.call('email' => 'jane@doe.org', 'age' => '21') result.success? # => true result.to_h # => {:email=>"jane@doe.org", :age=>21} # Invalid input - validation errors with human-readable messages result = schema.call('email' => '', 'age' => '17') result.failure? # => true result.errors.to_h # => {:email=>["must be filled"], :age=>["must be greater than 18"]} # Full error messages with field names result.errors(full: true).to_h # => {:email=>["email must be filled"], :age=>["age must be greater than 18"]} ``` -------------------------------- ### Define and Reuse Schemas with Nesting Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/reusing-schemas.html.md Define a base schema for an address and then nest it within a user schema. This approach promotes modularity and reusability of schema components. Ensure all required fields are filled to avoid validation errors. ```ruby AddressSchema = Dry::Schema.Params do required(:street).filled(:string) required(:city).filled(:string) required(:zipcode).filled(:string) end UserSchema = Dry::Schema.Params do required(:email).filled(:string) required(:name).filled(:string) required(:address).hash(AddressSchema) end UserSchema.( email: 'jane@doe', name: 'Jane', address: { street: nil, city: 'NYC', zipcode: '123' } ).errors.to_h ``` -------------------------------- ### Define Array with Integer Members and Size Constraint Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/type-specs.html.md Use the `array` shortcut with a member type spec (e.g., `[:integer]`) to define arrays. Constraints like `size?` can be applied. ```ruby UserSchema = Dry::Schema.Params do # expands to: `array? & each { int? } & size?(3)` required(:nums).value(array[:integer], size?: 3) end ``` -------------------------------- ### Apply Schema with Nil Value Filtering Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/processor-steps.html.md Demonstrates applying a schema that has a `before(:value_coercer)` callback to remove nil values. The `age` key with a nil value is removed from the output. ```ruby schema.(name: "Jane", age: nil) # => #"jane"} errors={}> ``` -------------------------------- ### Check for value equality with `eql?` Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `eql?: value` to verify that a key's value is strictly equal to a specified value. This is useful for validating against a fixed set of allowed values. ```ruby describe 'eql?' do let(:schema) do Dry::Schema.Params do required(:sample).value(eql?: 1234) end end let(:input) { {sample: 1234} } it 'as regular ruby' do assert input[:sample] == 1234 end it 'with dry-schema' do assert schema.call(input).success? end end ``` -------------------------------- ### Define Required and Optional Keys with `required` and `optional` Source: https://context7.com/dry-rb/dry-schema/llms.txt Use `required` to enforce the presence of a key and `optional` to allow it to be omitted. When an optional key is provided, its associated validation rules still apply. `maybe` allows `nil` values. ```ruby require 'dry/schema' schema = Dry::Schema.Params do required(:email).filled(:string) optional(:age).filled(:integer, gt?: 18) optional(:nickname).maybe(:string) end # Key is optional - no error when omitted result = schema.call(email: 'jane@doe.org') result.success? # => true result.errors.to_h # => {} # When optional key is provided, rules still apply result = schema.call(email: 'jane@doe.org', age: 17) result.errors.to_h # => {:age=>["must be greater than 18"]} # maybe allows nil values result = schema.call(email: 'jane@doe.org', nickname: nil) result.success? # => true ``` -------------------------------- ### Enable and Use :info Extension in Dry Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/info.html.md Enable the :info extension to add the `#info` method to schema types. This method returns a data structure with information about keys and their types. Note: The info data structure is not stable and may change before 2.0.0. ```ruby require 'dry/schema' Dry::Schema.load_extensions(:info) UserSchema = Dry::Schema.JSON do required(:email).filled(:string) optional(:age).filled(:integer) optional(:address).hash do required(:street).filled(:string) required(:zipcode).filled(:string) required(:city).filled(:string) end end UserSchema.info ``` ```json { :keys=> { :email=>{ :required=>true, :type=>"string" }, :age=>{ :required=>false, :type=>"integer" }, :address=>{ :type=>"hash", :required=>false, :keys=>{ :street=>{ :required=>true, :type=>"string" }, :zipcode=>{ :required=>true, :type=>"string" }, :city=>{ :required=>true, :type=>"string" } } } } } ``` -------------------------------- ### Accessing and Using Schema Key Map Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/key-maps.html.md Access the schema's key map using `Schema#key_map`. The key map can be used to rebuild the original input hash by rejecting unknown keys. ```ruby schema = Dry::Schema.Params do required(:email).filled(:string) optional(:age).filled(:integer, gt?: 18) end schema.key_map # => # schema.key_map.write("email" => "jane@doe.org", "age" => 21, "something_unexpected" => "oops") # => {:email=>"jane@doe.org", :age=>21} ``` -------------------------------- ### Load Monads Extension for Dry::Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/monads.html.md Require the dry-schema library and load the monads extension to enable monad compatibility. ```ruby require 'dry/schema' Dry::Schema.load_extensions(:monads) ``` -------------------------------- ### Configure Custom Error Message Paths Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Add custom error message paths to the schema configuration. Ensure the specified YAML file exists and is correctly formatted. ```ruby schema = Dry::Schema.Params do config.messages.load_paths << '/path/to/my/errors.yml' end ``` -------------------------------- ### Accessing Schema Rule AST Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/rule-ast.html.md Use the `Schema#to_ast` method to retrieve the Abstract Syntax Tree (AST) representation of schema rules. This AST is built using simple data structures from `dry-logic`. ```ruby schema = Dry::Schema.Params do required(:email).filled(:string) optional(:age).filled(:integer, gt?: 18) end schema.to_ast # => [:set, # [[:and, # [[:predicate, [:key?, [[:name, :email], [:input, Undefined]]]], # [:key, [:email, [:and, [[:predicate, [:str?, [[:input, Undefined]]]], [:predicate, [:filled?, [[:input, Undefined]]]]]]]]]], # [:implication, # [[:predicate, [:key?, [[:name, :age], [:input, Undefined]]]], # [:key, # [:age, # [:and, # [[:and, [[:predicate, [:int?, [[:input, Undefined]]]], [:predicate, [:filled?, [[:input, Undefined]]]]]], # [:predicate, [:gt?, [[:num, 18], [:input, Undefined]]]]]]]]]]]] ``` -------------------------------- ### Integrate with I18n for Multilingual Messages Source: https://context7.com/dry-rb/dry-schema/llms.txt Set the message backend to :i18n to utilize the I18n gem for translations. Errors can be retrieved for specific locales. ```ruby require 'i18n' require 'dry/schema' schema = Dry::Schema.Params do config.messages.backend = :i18n required(:email).filled(:string) end result = schema.call(email: '') result.errors.to_h # => {:email=>["must be filled"]} result.errors(locale: :pl).to_h # => {:email=>["musi byc wypelniony"]} result.errors(full: true).to_h # => {:email=>["email must be filled"]} ``` -------------------------------- ### Define and Validate Basic Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics.html.md Use this to define required fields with type and value constraints. The schema automatically handles key coercion to symbols, value coercion based on type specs, and validation against defined rules. ```ruby require 'dry-schema' schema = Dry::Schema.Params do required(:email).filled(:string) required(:age).filled(:integer, gt?: 18) end schema.call(email: 'jane@doe.org', age: 19) # #"jane@doe.org", :age=>19} errors={}> schema.call("email" => "", "age" => "19") # #"", :age=>19} errors={:email=>["must be filled"]}> ``` -------------------------------- ### Check minimum string bytesize with min_bytesize? Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `min_bytesize?` to ensure a string's bytesize meets a minimum threshold. This is important for handling multi-byte character sets correctly. ```ruby describe 'min_binsize?' do let(:schema) do Dry::Schema.Params do required(:sample).value(min_bytesize?: 3) end end it 'with regular ruby' do assert 'こ'.byte >= 3 end it 'with dry-schema' do assert schema.call(sample: 'こ').success? end end ``` -------------------------------- ### Configure Schema to Use I18n Messages Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Set the message backend to :i18n for the schema. This requires the 'i18n' gem to be loaded beforehand. ```ruby require 'i18n' require 'dry-schema' schema = Dry::Schema.Params do config.messages.backend = :i18n required(:email).filled(:string) end ``` -------------------------------- ### Validate string format with format? Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `format?` to check if a string matches a given regular expression. This is essential for validating string patterns. ```ruby describe 'format?' do let(:schema) do Dry::Schema.Params do required(:sample).value(format?: /^a/) end end it 'with regular ruby' do assert /^a/ =~ "aa" end it 'with dry-schema' do assert schema.call(sample: "aa").success? end end ``` -------------------------------- ### Generate JSON Schema from Dry::Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/extensions/json_schema.html.md Use the `:json_schema` extension to define a schema and then call `.json_schema` to generate its JSON Schema representation. Ensure the extension is loaded before defining the schema. ```ruby Dry::Schema.load_extensions(:json_schema) UserSchema = Dry::Schema.JSON do required(:email).filled(:str?, min_size?: 8) optional(:favorite_color).filled(:str?, included_in?: %w[red green blue pink]) optional(:age).filled(:int?) end UserSchema.json_schema ``` ```json { "type": "object", "properties": { "email": { "type": "string", "minLength": 8 }, "favorite_color": { "type": "string", "enum": ["red", "green", "blue", "pink"] }, "age": { "type": "integer" } }, "required": ["email"] } ``` -------------------------------- ### Check minimum array/string size with min_size? Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `min_size?` to ensure an array or string meets a minimum size requirement. It can be applied directly within `Dry::Schema.Params`. ```ruby describe 'min_size?' do let(:schema) do Dry::Schema.Params do required(:sample).value(min_size?: 3) end end it 'with regular ruby' do assert [1, 2, 3].size >= 3 assert 'foo'.size >= 3 end it 'with dry-schema' do assert schema.call(sample: [1, 2, 3]).success? assert schema.call(sample: 'foo').success? end end ``` -------------------------------- ### Work with Error Messages - Ruby Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/working-with-schemas.html.md Demonstrates how to retrieve and format error messages from a schema result. Supports default, full, and locale-specific error formats. ```ruby result = schema.call(email: nil, age: 21) # get default errors result.errors.to_h # => {:email=>['must be filled']} # get full errors result.errors(full: true).to_h # => {:email=>['email must be filled']} # get errors in another language result.errors(locale: :pl).to_h # => {:email=>['musi być wypełniony']} ``` -------------------------------- ### Define Inheritable Base Schema Class Source: https://context7.com/dry-rb/dry-schema/llms.txt Create a base schema class to share common configurations like message backends and load paths across multiple schemas. This promotes application-wide consistency. ```ruby require 'dry/schema' class AppSchema < Dry::Schema::Params define do config.messages.backend = :i18n config.messages.load_paths << '/app/config/locales/validations.yml' config.validate_keys = true end end class UserSchema < AppSchema define do required(:email).filled(:string) required(:name).filled(:string, min_size?: 2) end end class ProductSchema < AppSchema define do required(:title).filled(:string) required(:price).filled(:decimal, gt?: 0) optional(:description).maybe(:string) end end user_schema = UserSchema.new result = user_schema.call(email: 'jane@doe.org', name: 'Jane') result.success? # => true product_schema = ProductSchema.new result = product_schema.call(title: 'Widget', price: '19.99') result.success? # => true ``` -------------------------------- ### Define a Base Schema Class - Ruby Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/working-with-schemas.html.md Establishes a base schema class 'AppSchema' that configures message loading paths and backend. Other schemas can inherit from this base. ```ruby class AppSchema < Dry::Schema::Params define do config.messages.load_paths << '/my/app/config/locales/en.yml' config.messages.backend = :i18n # define common rules, if any end end # now you can build other schemas on top of the base one: class MySchema < AppSchema # define your rules end my_schema = MySchema.new ``` -------------------------------- ### Check for less than or equal to with `lteq?` Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `lteq?: value` to validate that a numerical value is less than or equal to the specified value. This is useful for maximum boundary conditions. ```ruby describe 'lteq?' do let(:schema) do Dry::Schema.Params do required(:sample).value(lteq?: 1) end end it 'with regular ruby' do assert 1 <= 1 end it 'with dry-schema' do assert schema.call(sample: 1).success? end end ``` -------------------------------- ### Check for greater than or equal to with `gteq?` Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `gteq?: value` to validate that a numerical value is greater than or equal to the specified value. This is useful for minimum boundary conditions. ```ruby describe 'gteq?' do let(:schema) do Dry::Schema.Params do required(:sample).value(gteq?: 1) end end it 'with regular ruby' do assert 1 >= 1 end it 'with dry-schema' do assert schema.call(sample: 1).success? end end ``` -------------------------------- ### Define Optional Values with `maybe` Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/optional-keys-and-values.html.md Use `maybe` for keys whose values are allowed to be `nil`. If the value is not `nil`, it must conform to the specified type and constraints. ```ruby schema = Dry::Schema.Params do required(:email).filled(:string) optional(:age).maybe(:integer, gt?: 18) end errors = schema.call(email: 'jane@doe.org', age: nil).errors puts errors.to_h.inspect # {} errors = schema.call(email: 'jane@doe.org', age: 19).errors puts errors.to_h.inspect # {} errors = schema.call(email: 'jane@doe.org', age: 17).errors puts errors.to_h.inspect # { :age => ["must be greater than 18"] } ``` -------------------------------- ### Configure Schema-Specific Message Namespace Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Set a default namespace for messages within a specific schema. This helps organize messages for different parts of your application. ```ruby schema = Dry::Schema.Params do config.messages.namespace = :user end ``` -------------------------------- ### Check exact string bytesize with bytesize? Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `bytesize?` to validate that a string has an exact bytesize. This is useful when specific byte representations are required. ```ruby describe 'bytesize?' do let(:schema) do Dry::Schema.Params do required(:sample).value(bytesize?: 3) end end it 'with regular ruby' do assert 'こ'.byte == 3 end it 'with dry-schema' do assert schema.call(sample: 'こ').success? end end ``` -------------------------------- ### Configure Top-Level Message Namespace Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Change the default top-level namespace for all validation schema messages. This is useful for global message organization. ```ruby schema = Dry::Schema.Params do config.messages.top_namespace = :validation_schema end ``` -------------------------------- ### Conjunction (AND) Rule Composition Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/predicate-logic.html.md Use the `&` operator to combine predicates. The rule succeeds only if all combined predicates return true. This is useful for ensuring multiple conditions are met simultaneously. ```ruby Dry::Schema.Params do required(:age) { int? & gt?(18) } end ``` -------------------------------- ### Load and Query Custom Error Messages Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Load custom error messages from a YAML file and query them using predicate and rule information. This demonstrates how to access specific error messages. ```ruby messages = Dry::Schema::Messages::YAML.load(%w(/path/to/our/errors.yml)) ``` ```ruby # matching arg type for size? predicate messages[:size?, rule: :name, arg_type: Fixnum] # => "size must be %{num}" messages[:size?, rule: :name, arg_type: Range] # => "size must be within %{left} - %{right}" ``` ```ruby # matching val type for size? predicate messages[:size?, rule: :name, val_type: String] # => "length must be %{num}" ``` ```ruby # matching predicate messages[:filled?, rule: :age] # => "must be filled" messages[:filled?, rule: :address] # => "must be filled" ``` ```ruby # matching predicate for a specific rule messages[:filled?, rule: :email] # => "the email is missing" ``` ```ruby # with namespaced messages user_messages = messages.namespaced(:user) user_messages[:filled?, rule: :age] # "cannot be blank" user_messages[:filled?, rule: :address] # "You gotta tell us where you live" ``` -------------------------------- ### Call Schema with I18n Locale Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/error-messages.html.md Call the schema and specify a locale for error messages. This allows for multi-language support. ```ruby # return default translations schema.call(email: '').errors.to_h # { :email => ["must be filled"] } ``` ```ruby # return other translations (assuming you have it :)) puts schema.call(email: '').errors(locale: :pl).to_h # { :email => ["musi być wypełniony"] } ``` -------------------------------- ### Enable Key Validation Globally - Dry-Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/unexpected-keys.html.md Enable strict key validation for all schemas by setting `Dry::Schema.config.validate_keys` to `true`. This affects all subsequent schema definitions. ```ruby Dry::Schema.config.validate_keys = true ``` -------------------------------- ### Check for nil value with `nil?` Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `nil?` to ensure a key's value is nil. This predicate is useful for optional fields that should explicitly be null. ```ruby describe 'nil?' do let(:schema) do Dry::Schema.Params do required(:sample).value(:nil?) end end let(:input) { {sample: nil} } it 'as regular ruby' do assert input[:sample].nil? end it 'with dry-schema' do assert schema.call(input).success? end end ``` -------------------------------- ### Define Custom Predicates Module Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/custom-predicates.html.md Create a module that includes default Dry::Logic::Predicates and defines your custom predicate functions. This module will house your reusable validation logic. ```ruby module MyPredicates include Dry::Logic::Predicates def self.future_date?(date) date > Date.today end end ``` -------------------------------- ### Define and Use a Custom StrippedString Type Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/custom-types.html.md Define a custom string type that automatically strips leading and trailing whitespace. Use this type directly in your schema definition. ```ruby StrippedString = Types::String.constructor(&:strip) Schema = Dry::Schema.Params do required(:some_number).filled(:integer) required(:my_string).filled(StrippedString) end ``` -------------------------------- ### Compose Schemas with AND (&) Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/composing-schemas.html.md Use the '&' operator to ensure both schemas pass. The right schema is only evaluated if the left schema passes. ```ruby Role = Dry::Schema.JSON do required(:id).filled(:string) end Expirable = Dry::Schema.JSON do required(:expires_on).value(:date) end User = Dry::Schema.JSON do required(:name).filled(:string) required(:role).hash(Role & Expirable) end puts User.(name: "Jane", role: { id: "admin", expires_on: "2020-05-01" }).errors.to_h.inspect # {} puts User.(name: "Jane", role: { id: "", expires_on: "2020-05-01" }).errors.to_h.inspect # {role: {id: ["must be filled"]}} puts User.(name: "Jane", role: { id: "admin", expires_on: "oops" }).errors.to_h.inspect # {role: {expires_on: ["must be a date"]}} ``` -------------------------------- ### Load Custom YAML Messages Source: https://context7.com/dry-rb/dry-schema/llms.txt Configure dry-schema to load custom error messages from YAML files. Ensure the YAML file is structured correctly with namespaces for rules. ```ruby schema = Dry::Schema.Params do config.messages.load_paths << '/path/to/my/errors.yml' config.messages.namespace = :user required(:email).filled(:string) required(:age).filled(:integer, gt?: 18) end ``` -------------------------------- ### Check exact array/string size with size? Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/built-in-predicates.html.md Use `size?` to validate that an array or string has an exact size. This validator accepts an integer for the exact size. ```ruby describe 'size?' do let(:schema) do Dry::Schema.Params do required(:sample).value(size?: 3) end end it 'with regular ruby' do assert [1, 2, 3].size == 3 assert 'foo'.size == 3 end it 'with dry-schema' do assert schema.call(sample: [1, 2, 3]).success? assert schema.call(sample: 'foo').success? end end ``` -------------------------------- ### Define Schema with Custom String Type and Min Size Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/basics/type-specs.html.md Incorporate custom `Dry::Types::Type` objects, such as a `StrippedString`, into schema definitions. Predicates like `min_size?` can be applied to these custom types. ```ruby module Types include Dry::Types() StrippedString = Types::String.constructor(&:strip) end UserSchema = Dry::Schema.Params do # expands to: `str? & min_size?(10)` required(:login_time).value(Types::StrippedString, min_size?: 10) end ``` -------------------------------- ### Enable Key Validation Per Schema - Dry-Schema Source: https://github.com/dry-rb/dry-schema/blob/main/docsite/source/advanced/unexpected-keys.html.md Enable strict key validation for a specific schema by setting `config.validate_keys = true` within the schema definition block. This allows for more granular control. ```ruby Dry::Schema.Params do config.validate_keys = true # ... end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.