module Dry::Validation::Contract::ClassInterface

Contract's class interface

@see Contract

@api public

Public Instance Methods

__schema__() click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 130
def __schema__
  @__schema__ if defined?(@__schema__)
end
build(options = EMPTY_HASH, &block) click to toggle source

A shortcut that can be used to define contracts that won't be reused or inherited

@example

my_contract = Dry::Validation::Contract.build do
  params do
    required(:name).filled(:string)
  end
end

my_contract.call(name: "Jane")

@return [Contract]

@api public

# File lib/dry/validation/contract/class_interface.rb, line 125
def build(options = EMPTY_HASH, &block)
  Class.new(self, &block).new(**options)
end
config() click to toggle source

Configuration

@example

class MyContract < Dry::Validation::Contract
  config.messages.backend = :i18n
end

@return [Config]

@api public

# File lib/dry/validation/contract/class_interface.rb, line 39
def config
  @config ||= Validation::Config.new
end
inherited(klass) click to toggle source

@api private

Calls superclass method
# File lib/dry/validation/contract/class_interface.rb, line 24
def inherited(klass)
  super
  klass.instance_variable_set("@config", config.dup)
end
json(*external_schemas, &block) click to toggle source

Define a JSON schema for your contract

This type of schema is suitable for JSON data

@return [Dry::Schema::JSON,NilClass] @see dry-rb.org/gems/dry-schema/json/

@api public

# File lib/dry/validation/contract/class_interface.rb, line 72
def json(*external_schemas, &block)
  define(:JSON, external_schemas, &block)
end
macros() click to toggle source

Return macros registered for this class

@return [Macros::Container]

@api public

# File lib/dry/validation/contract/class_interface.rb, line 48
def macros
  config.macros
end
messages() click to toggle source

Return messages configured for this class

@return [Dry::Schema::Messages]

@api private

# File lib/dry/validation/contract/class_interface.rb, line 150
def messages
  @messages ||= Schema::Messages.setup(config.messages)
end
params(*external_schemas, &block) click to toggle source

Define a params schema for your contract

This type of schema is suitable for HTTP parameters

@return [Dry::Schema::Params,NilClass] @see dry-rb.org/gems/dry-schema/params/

@api public

# File lib/dry/validation/contract/class_interface.rb, line 60
def params(*external_schemas, &block)
  define(:Params, external_schemas, &block)
end
rule(*keys, &block) click to toggle source

Define a rule for your contract

@example using a symbol

rule(:age) do
  failure('must be at least 18') if values[:age] < 18
end

@example using a path to a value and a custom predicate

rule('address.street') do
  failure('please provide a valid street address') if valid_street?(values[:street])
end

@return [Rule]

@api public

# File lib/dry/validation/contract/class_interface.rb, line 103
def rule(*keys, &block)
  ensure_valid_keys(*keys) if __schema__

  Rule.new(keys: keys, block: block).tap do |rule|
    rules << rule
  end
end
rules() click to toggle source

Return rules defined in this class

@return [Array<Rule>]

@api private

# File lib/dry/validation/contract/class_interface.rb, line 139
def rules
  @rules ||= EMPTY_ARRAY
    .dup
    .concat(superclass.respond_to?(:rules) ? superclass.rules : EMPTY_ARRAY)
end
schema(*external_schemas, &block) click to toggle source

Define a plain schema for your contract

This type of schema does not offer coercion out of the box

@return [Dry::Schema::Processor,NilClass] @see dry-rb.org/gems/dry-schema/

@api public

# File lib/dry/validation/contract/class_interface.rb, line 84
def schema(*external_schemas, &block)
  define(:schema, external_schemas, &block)
end

Private Instance Methods

core_schema_opts() click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 204
def core_schema_opts
  {parent: superclass&.__schema__, config: config}
end
define(method_name, external_schemas, &block) click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 209
def define(method_name, external_schemas, &block)
  return __schema__ if external_schemas.empty? && block.nil?

  unless __schema__.nil?
    raise ::Dry::Validation::DuplicateSchemaError, "Schema has already been defined"
  end

  schema_opts = core_schema_opts

  schema_opts.update(parent: external_schemas) if external_schemas.any?

  case method_name
  when :schema
    @__schema__ = Schema.define(**schema_opts, &block)
  when :Params
    @__schema__ = Schema.Params(**schema_opts, &block)
  when :JSON
    @__schema__ = Schema.JSON(**schema_opts, &block)
  end
end
ensure_valid_keys(*keys) click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 157
        def ensure_valid_keys(*keys)
          valid_paths = key_map.to_dot_notation
          key_paths = key_paths(keys)

          invalid_keys = key_paths.filter_map { |(key, path)|
            if valid_paths.none? { |vp|
                 vp == path || vp.start_with?("#{path}.", "#{path}[]")
               }
              key
            end
          }.uniq

          return if invalid_keys.empty?

          raise InvalidKeysError, <<~STR.strip
            #{name}.rule specifies keys that are not defined by the schema: #{invalid_keys.inspect}
          STR
        end
key_map() click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 199
def key_map
  __schema__.key_map
end
key_paths(keys) click to toggle source

@api private

# File lib/dry/validation/contract/class_interface.rb, line 177
def key_paths(keys)
  keys.map { |key|
    case key
    when Hash
      path = Schema::Path[key]
      if path.multi_value?
        *head, tail = Array(path)
        [key].product(
          tail.map { |el| [*head, *el] }.map { |parts| parts.join(DOT) }
        )
      else
        [[key, path.to_a.join(DOT)]]
      end
    when Array
      [[key, Schema::Path[key].to_a.join(DOT)]]
    else
      [[key, key.to_s]]
    end
  }.flatten(1)
end