# 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'