1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
# 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'
|