class Dry::Types::Hash::Schema

@see Dry::Types::Default::Callable#evaluate
@see Dry::Types::Default#evaluate
(see {Schema#resolve_missing_value})
Basic {Schema} evaluates default values for keys missing in input hash
hashes with explicit schemas and coercible values using the built-in types.
The built-in Hash type has constructors that you can use to define

def call(hash)

Returns:
  • (Hash{Symbol => Object}) -

Parameters:
  • hash (Hash) --
def call(hash)
  coerce(hash)
end

def coerce(hash)

Returns:
  • (Hash{Symbol => Object}) -

Parameters:
  • hash (Hash) --
def coerce(hash)
  resolve(hash) do |type, key, value|
    begin
      type.call(value)
    rescue ConstraintError => e
      raise SchemaError.new(key, value, e.result)
    rescue TypeError, ArgumentError => e
      raise SchemaError.new(key, value, e.message)
    end
  end
end

def initialize(_primitive, **options)

Options Hash: (**options)
  • :key_transform_fn (String) --
  • :member_types (Hash{Symbol => Definition}) --

Parameters:
  • options (Hash) --
  • _primitive (Class) --
def initialize(_primitive, **options)
  @member_types = options.fetch(:member_types)
  meta = options[:meta] || EMPTY_HASH
  key_fn = meta.fetch(:key_transform_fn, NO_TRANSFORM)
  @transform_key = Dry::Types::FnContainer[key_fn]
  super
end

def resolve(hash)

def resolve(hash)
  result = {}
  hash.each do |key, value|
    k = transform_key.(key)
    if member_types.key?(k)
      result[k] = yield(member_types[k], k, value)
    elsif strict?
      raise UnknownKeysError.new(*unexpected_keys(hash.keys))
    end
  end
  if result.size < member_types.size
    resolve_missing_keys(result, &Proc.new)
  end
  result
end

def resolve_missing_keys(result)

def resolve_missing_keys(result)
  member_types.each do |k, type|
    next if result.key?(k)
    if type.default?
      result[k] = yield(type, k, Undefined)
    elsif !type.meta[:omittable]
      raise MissingKeyError, k
    end
  end
end

def schema(type_map)

Returns:
  • (Schema) -

Parameters:
  • type_map ({Symbol => Definition}) --
def schema(type_map)
  member_types = self.member_types.merge(transform_types(type_map))
  Schema.new(primitive, **options, member_types: member_types, meta: meta)
end

def strict

Returns:
  • (Schema) -
def strict
  meta(strict: true)
end

def strict?

Returns:
  • (Boolean) -
def strict?
  meta.fetch(:strict, false)
end

def to_ast(meta: true)

Returns:
  • (Array) - An AST representation

Parameters:
  • meta (Boolean) -- Whether to dump the meta to the AST
def to_ast(meta: true)
  [
    :hash_schema,
    [
      member_types.map { |name, member| [:member, [name, member.to_ast(meta: meta)]] },
      meta ? self.meta : EMPTY_HASH
    ]
  ]
end

def try(hash)

Returns:
  • (Object) - if coercion fails and a block is given
  • (Logic::Result) -

Other tags:
    Yieldreturn: -

Other tags:
    Yieldparam: failure -

Parameters:
  • hash (Hash) --
def try(hash)
  if hash.is_a?(::Hash)
    success = true
    output  = {}
    begin
      result = try_coerce(hash) do |key, member_result|
        success &&= member_result.success?
        output[key] = member_result.input
        member_result
      end
    rescue ConstraintError, UnknownKeysError, SchemaError, MissingKeyError => e
      success = false
      result = e
    end
  else
    success = false
    output = hash
    result = "#{hash} must be a hash"
  end
  if success
    success(output)
  else
    failure = failure(output, result)
    block_given? ? yield(failure) : failure
  end
end

def try_coerce(hash)

Returns:
  • (Hash{Symbol => Object}) -

Parameters:
  • hash (Hash) --
def try_coerce(hash)
  resolve(hash) do |type, key, value|
    yield(key, type.try(value))
  end
end

def unexpected_keys(keys)

Returns:
  • (Array) -

Parameters:
  • keys (Array) --
def unexpected_keys(keys)
  keys.map(&transform_key) - member_types.keys
end

def valid?(hash)

Returns:
  • (Boolean) -

Parameters:
  • hash (Hash) --
def valid?(hash)
  result = try(hash)
  result.success?
end

def with_key_transform(proc = nil, &block)

Returns:
  • (Schema) -

Parameters:
  • block (#call, nil) --
  • proc (#call, nil) --
def with_key_transform(proc = nil, &block)
  fn = proc || block
  if fn.nil?
    raise ArgumentError, "a block or callable argument is required"
  end
  handle = Dry::Types::FnContainer.register(fn)
  meta(key_transform_fn: handle)
end