class Dry::Types::Module

Export types registered in a container as module constants. @example

module Types
  include Dry::Types(:strict, :coercible, :nominal, default: :strict)
end

Types.constants
# => [:Class, :Strict, :Symbol, :Integer, :Float, :String, :Array, :Hash,
#     :Decimal, :Nil, :True, :False, :Bool, :Date, :Nominal, :DateTime, :Range,
#     :Coercible, :Time]

@api public

Public Class Methods

new(registry, *args, **kwargs) click to toggle source
Calls superclass method
# File lib/dry/types/module.rb, line 21
def initialize(registry, *args, **kwargs)
  @registry = registry
  check_parameters(*args, **kwargs)
  constants = type_constants(*args, **kwargs)
  define_constants(constants)
  extend(BuilderMethods)

  if constants.key?(:Nominal)
    singleton_class.send(:define_method, :included) do |base|
      super(base)
      base.instance_exec(const_get(:Nominal, false)) do |nominal|
        extend Dry::Core::Deprecations[:'dry-types']
        const_set(:Definition, nominal)
        deprecate_constant(:Definition, message: "Nominal")
      end
    end
  end
end

Public Instance Methods

registry_tree() click to toggle source

@api private

# File lib/dry/types/module.rb, line 69
def registry_tree
  @registry_tree ||= @registry.keys.each_with_object({}) { |key, tree|
    type = @registry[key]
    *modules, const_name = key.split(".").map { |part|
      Inflector.camelize(part).to_sym
    }
    next if modules.empty?

    modules.reduce(tree) { |br, name| br[name] ||= {} }[const_name] = type
  }.freeze
end
type_constants(*namespaces, default: Undefined, **aliases) click to toggle source

@api private

# File lib/dry/types/module.rb, line 41
def type_constants(*namespaces, default: Undefined, **aliases)
  if namespaces.empty? && aliases.empty? && Undefined.equal?(default)
    default_ns = :Strict
  elsif Undefined.equal?(default)
    default_ns = Undefined
  else
    default_ns = Inflector.camelize(default).to_sym
  end

  tree = registry_tree

  if namespaces.empty? && aliases.empty?
    modules = tree.select { |_, v| v.is_a?(::Hash) }.map(&:first)
  else
    modules = (namespaces + aliases.keys).map { |n| Inflector.camelize(n).to_sym }
  end

  tree.each_with_object({}) do |(key, value), constants|
    if modules.include?(key)
      name = aliases.fetch(Inflector.underscore(key).to_sym, key)
      constants[name] = value
    end

    constants.update(value) if key == default_ns
  end
end

Private Instance Methods

check_parameters(*namespaces, default: Undefined, **aliases) click to toggle source

@api private

# File lib/dry/types/module.rb, line 84
def check_parameters(*namespaces, default: Undefined, **aliases)
  referenced = namespaces.dup
  referenced << default unless false.equal?(default) || Undefined.equal?(default)
  referenced.concat(aliases.keys)

  known = @registry.keys.map { |k|
    ns, *path = k.split(".")
    ns.to_sym unless path.empty?
  }.compact.uniq

  (referenced.uniq - known).each do |name|
    raise ArgumentError,
          "#{name.inspect} is not a known type namespace. "\
          "Supported options are #{known.map(&:inspect).join(", ")}"
  end
end
define_constants(constants, mod = self) click to toggle source

@api private

# File lib/dry/types/module.rb, line 102
def define_constants(constants, mod = self)
  constants.each do |name, value|
    case value
    when ::Hash
      if mod.const_defined?(name, false)
        define_constants(value, mod.const_get(name, false))
      else
        m = ::Module.new
        mod.const_set(name, m)
        define_constants(value, m)
      end
    else
      mod.const_set(name, value)
    end
  end
end