# frozen_string_literal: true require "dry/core/deprecations" require "dry/types/builder" require "dry/types/result" require "dry/types/options" require "dry/types/meta" module Dry module Types # Nominal types define a primitive class and do not apply any constructors or constraints # # Use these types for annotations and the base for building more complex types on top of them. # # @api public class Nominal include Type include Options include Meta include Builder include Printable include Dry::Equalizer(:primitive, :options, :meta, inspect: false, immutable: true) # @return [Class] attr_reader :primitive # @param [Class] primitive # # @return [Type] # # @api private def self.[](primitive) if primitive == ::Array Types::Array elsif primitive == ::Hash Types::Hash else self end end ALWAYS = proc { true } # @param [Type,Class] primitive # @param [Hash] options # # @api private def initialize(primitive, **options) super @primitive = primitive freeze end # @return [String] # # @api public def name primitive.name end # @return [false] # # @api public def default? false end # @return [false] # # @api public def constrained? false end # @return [false] # # @api public def optional? false end # @param [BasicObject] input # # @return [BasicObject] # # @api private def call_unsafe(input) input end # @param [BasicObject] input # # @return [BasicObject] # # @api private def call_safe(input) input end # @param [Object] input # # @yieldparam [Failure] failure # @yieldreturn [Result] # # @return [Result,Logic::Result] when a block is not provided # @return [nil] otherwise # # @api public def try(input) success(input) end # @param (see Dry::Types::Success#initialize) # # @return [Result::Success] # # @api public def success(input) Result::Success.new(input) end # @param (see Failure#initialize) # # @return [Result::Failure] # # @api public def failure(input, error) raise ArgumentError, "error must be a CoercionError" unless error.is_a?(CoercionError) Result::Failure.new(input, error) end # Checks whether value is of a #primitive class # # @param [Object] value # # @return [Boolean] # # @api public def primitive?(value) value.is_a?(primitive) end # @api private def coerce(input, &_block) if primitive?(input) input elsif block_given? yield else raise CoercionError, "#{input.inspect} must be an instance of #{primitive}" end end # @api private def try_coerce(input) result = success(input) coerce(input) do result = failure( input, CoercionError.new("#{input.inspect} must be an instance of #{primitive}") ) end if block_given? yield(result) else result end end # Return AST representation of a type nominal # # @return [Array] # # @api public def to_ast(meta: true) [:nominal, [primitive, meta ? self.meta : EMPTY_HASH]] end # Return self. Nominal types are lax by definition # # @return [Nominal] # # @api public def lax self end # Wrap the type with a proc # # @return [Proc] # # @api public def to_proc ALWAYS end end extend Dry::Core::Deprecations[:'dry-types'] Definition = Nominal deprecate_constant(:Definition, message: "Nominal") end end require "dry/types/array" require "dry/types/hash" require "dry/types/map"