141 lines
3.4 KiB
Ruby
141 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'dry/core/deprecations'
|
|
|
|
module Dry
|
|
module Types
|
|
# Common API for building types and composition
|
|
#
|
|
# @api public
|
|
module Builder
|
|
include Dry::Core::Constants
|
|
|
|
# @return [Class]
|
|
#
|
|
# @api private
|
|
def constrained_type
|
|
Constrained
|
|
end
|
|
|
|
# @return [Class]
|
|
#
|
|
# @api private
|
|
def constructor_type
|
|
Constructor
|
|
end
|
|
|
|
# Compose two types into a Sum type
|
|
#
|
|
# @param [Type] other
|
|
#
|
|
# @return [Sum, Sum::Constrained]
|
|
#
|
|
# @api private
|
|
def |(other)
|
|
klass = constrained? && other.constrained? ? Sum::Constrained : Sum
|
|
klass.new(self, other)
|
|
end
|
|
|
|
# Turn a type into an optional type
|
|
#
|
|
# @return [Sum]
|
|
#
|
|
# @api public
|
|
def optional
|
|
Types['strict.nil'] | self
|
|
end
|
|
|
|
# Turn a type into a constrained type
|
|
#
|
|
# @param [Hash] options constraining rule (see {Types.Rule})
|
|
#
|
|
# @return [Constrained]
|
|
#
|
|
# @api public
|
|
def constrained(options)
|
|
constrained_type.new(self, rule: Types.Rule(options))
|
|
end
|
|
|
|
# Turn a type into a type with a default value
|
|
#
|
|
# @param [Object] input
|
|
# @param [Hash] options
|
|
# @param [#call,nil] block
|
|
#
|
|
# @raise [ConstraintError]
|
|
#
|
|
# @return [Default]
|
|
#
|
|
# @api public
|
|
def default(input = Undefined, options = EMPTY_HASH, &block)
|
|
unless input.frozen? || options[:shared]
|
|
where = Dry::Core::Deprecations::STACK.()
|
|
Dry::Core::Deprecations.warn(
|
|
"#{input.inspect} is mutable."\
|
|
' Be careful: types will return the same instance of the default'\
|
|
' value every time. Call `.freeze` when setting the default'\
|
|
' or pass `shared: true` to discard this warning.'\
|
|
"\n#{ where }",
|
|
tag: :'dry-types'
|
|
)
|
|
end
|
|
|
|
value = input.equal?(Undefined) ? block : input
|
|
|
|
if value.respond_to?(:call) || valid?(value)
|
|
Default[value].new(self, value)
|
|
else
|
|
raise ConstraintError.new("default value #{value.inspect} violates constraints", value)
|
|
end
|
|
end
|
|
|
|
# Define an enum on top of the existing type
|
|
#
|
|
# @param [Array] values
|
|
#
|
|
# @return [Enum]
|
|
#
|
|
# @api public
|
|
def enum(*values)
|
|
mapping =
|
|
if values.length == 1 && values[0].is_a?(::Hash)
|
|
values[0]
|
|
else
|
|
::Hash[values.zip(values)]
|
|
end
|
|
|
|
Enum.new(constrained(included_in: mapping.keys), mapping: mapping)
|
|
end
|
|
|
|
# Turn a type into a lax type that will rescue from type-errors and
|
|
# return the original input
|
|
#
|
|
# @return [Lax]
|
|
#
|
|
# @api public
|
|
def lax
|
|
Lax.new(self)
|
|
end
|
|
|
|
# Define a constructor for the type
|
|
#
|
|
# @param [#call,nil] constructor
|
|
# @param [Hash] options
|
|
# @param [#call,nil] block
|
|
#
|
|
# @return [Constructor]
|
|
#
|
|
# @api public
|
|
def constructor(constructor = nil, **options, &block)
|
|
constructor_type.new(with(options), fn: constructor || block)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
require 'dry/types/default'
|
|
require 'dry/types/constrained'
|
|
require 'dry/types/enum'
|
|
require 'dry/types/lax'
|
|
require 'dry/types/sum'
|