Update YARD docs [ci skip]
This commit is contained in:
parent
1924074c05
commit
09170b68a8
|
@ -1,8 +1,8 @@
|
|||
--title 'dry-types'
|
||||
--query '@api.text != "private"'
|
||||
--embed-mixins
|
||||
-o doc
|
||||
-r README.md
|
||||
--output doc
|
||||
--readme README.md
|
||||
--files CHANGELOG.md
|
||||
--markup markdown
|
||||
--markup-provider=redcarpet
|
||||
|
|
|
@ -24,6 +24,9 @@ require 'dry/types/module'
|
|||
require 'dry/types/errors'
|
||||
|
||||
module Dry
|
||||
# Main library namespace
|
||||
#
|
||||
# @api public
|
||||
module Types
|
||||
extend Dry::Core::Extensions
|
||||
extend Dry::Core::ClassAttributes
|
||||
|
@ -45,20 +48,32 @@ module Dry
|
|||
raise RuntimeError, "Import Dry.Types, not Dry::Types"
|
||||
end
|
||||
|
||||
# Return container with registered built-in type objects
|
||||
#
|
||||
# @return [Container{String => Nominal}]
|
||||
#
|
||||
# @api private
|
||||
def self.container
|
||||
@container ||= Container.new
|
||||
end
|
||||
|
||||
# Check if a give type is registered
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def self.registered?(class_or_identifier)
|
||||
container.key?(identifier(class_or_identifier))
|
||||
end
|
||||
|
||||
# Register a new built-in type
|
||||
#
|
||||
# @param [String] name
|
||||
# @param [Type] type
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @return [Container{String => Nominal}]
|
||||
#
|
||||
# @api private
|
||||
def self.register(name, type = nil, &block)
|
||||
container.register(name, type || block.call)
|
||||
|
@ -67,7 +82,10 @@ module Dry
|
|||
# Get a built-in type by its name
|
||||
#
|
||||
# @param [String,Class] name
|
||||
#
|
||||
# @return [Type,Class]
|
||||
#
|
||||
# @api public
|
||||
def self.[](name)
|
||||
type_map.fetch_or_store(name) do
|
||||
case name
|
||||
|
@ -92,19 +110,29 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# Infer a type identifier from the provided class
|
||||
#
|
||||
# @param [#to_s] klass
|
||||
#
|
||||
# @return [String]
|
||||
def self.identifier(klass)
|
||||
Inflector.underscore(klass).tr('/', '.')
|
||||
end
|
||||
|
||||
# Cached type map
|
||||
#
|
||||
# @return [Concurrent::Map]
|
||||
#
|
||||
# @api private
|
||||
def self.type_map
|
||||
@type_map ||= Concurrent::Map.new
|
||||
end
|
||||
|
||||
# List of type keys defined in {Dry::Types.container}
|
||||
# @return [<String>]
|
||||
# List of type keys defined in {Dry::Types.container}
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
def self.type_keys
|
||||
container.keys
|
||||
end
|
||||
|
@ -166,12 +194,18 @@ module Dry
|
|||
# @param [Array<Symbol>] namespaces List of type namespaces to export
|
||||
# @param [Symbol] default Default namespace to export
|
||||
# @param [Hash{Symbol => Symbol}] aliases Optional renamings, like strict: :Draconian
|
||||
#
|
||||
# @return [Dry::Types::Module]
|
||||
#
|
||||
# @see Dry::types::Module
|
||||
# @see Dry::Types::Module
|
||||
#
|
||||
# @api public
|
||||
#
|
||||
# rubocop:disable Naming/MethodName
|
||||
def self.Types(*namespaces, default: Types::Undefined, **aliases)
|
||||
Types::Module.new(Types.container, *namespaces, default: default, **aliases)
|
||||
end
|
||||
# rubocop:enable Naming/MethodName
|
||||
end
|
||||
|
||||
require 'dry/types/core' # load built-in types
|
||||
|
|
|
@ -2,27 +2,41 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Any is a nominal type that defines Object as the primitive class
|
||||
#
|
||||
# This type is useful in places where you can't be specific about the type
|
||||
# and anything is acceptable.
|
||||
#
|
||||
# @api public
|
||||
class AnyClass < Nominal
|
||||
def self.name
|
||||
'Any'
|
||||
end
|
||||
|
||||
# @api private
|
||||
def initialize(**options)
|
||||
super(::Object, options)
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
def name
|
||||
'Any'
|
||||
end
|
||||
|
||||
# @param [Hash] new_options
|
||||
#
|
||||
# @return [Type]
|
||||
#
|
||||
# @api public
|
||||
def with(new_options)
|
||||
self.class.new(**options, meta: @meta, **new_options)
|
||||
end
|
||||
|
||||
# @return [Array]
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:any, meta ? self.meta : EMPTY_HASH]
|
||||
end
|
||||
|
|
|
@ -4,9 +4,17 @@ require 'dry/types/array/member'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Array type can be used to define an array with optional member type
|
||||
#
|
||||
# @api public
|
||||
class Array < Nominal
|
||||
# @param [Type] type
|
||||
# Build an array type with a member type
|
||||
#
|
||||
# @param [Type,#call] type
|
||||
#
|
||||
# @return [Array::Member]
|
||||
#
|
||||
# @api public
|
||||
def of(type)
|
||||
member =
|
||||
case type
|
||||
|
|
|
@ -3,22 +3,29 @@
|
|||
module Dry
|
||||
module Types
|
||||
class Array < Nominal
|
||||
# Member arrays define their member type that is applied to each element
|
||||
#
|
||||
# @api public
|
||||
class Member < Array
|
||||
# @return [Type]
|
||||
attr_reader :member
|
||||
|
||||
# @param [Class] primitive
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @option options [Type] :member
|
||||
#
|
||||
# @api private
|
||||
def initialize(primitive, options = {})
|
||||
@member = options.fetch(:member)
|
||||
super
|
||||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
if primitive?(input)
|
||||
input.each_with_object([]) do |el, output|
|
||||
|
@ -31,10 +38,10 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Object] input
|
||||
# @return [Array]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input)
|
||||
if primitive?(input)
|
||||
failed = false
|
||||
|
@ -56,9 +63,13 @@ module Dry
|
|||
|
||||
# @param [Array, Object] input
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @yieldparam [Failure] failure
|
||||
# @yieldreturn [Result]
|
||||
#
|
||||
# @return [Result,Logic::Result]
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
if primitive?(input)
|
||||
output = []
|
||||
|
@ -84,11 +95,15 @@ module Dry
|
|||
# Build a lax type
|
||||
#
|
||||
# @return [Lax]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
Lax.new(Member.new(primitive, { **options, member: member.lax }))
|
||||
end
|
||||
|
||||
# @see Nominal#to_ast
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
if member.respond_to?(:to_ast)
|
||||
[:array, [member.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
||||
|
|
|
@ -4,42 +4,69 @@ 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.()
|
||||
|
@ -62,8 +89,13 @@ module Dry
|
|||
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)
|
||||
|
@ -75,15 +107,25 @@ module Dry
|
|||
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
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Common API for building type objects in a convenient way
|
||||
#
|
||||
# rubocop:disable Naming/MethodName
|
||||
#
|
||||
# @api public
|
||||
module BuilderMethods
|
||||
# @api private
|
||||
def included(base)
|
||||
|
@ -10,7 +15,8 @@ module Dry
|
|||
end
|
||||
|
||||
# Build an array type.
|
||||
# It is a shortcut for Array.of
|
||||
#
|
||||
# Shortcut for Array#of.
|
||||
#
|
||||
# @example
|
||||
# Types::Strings = Types.Array(Types::String)
|
||||
|
|
|
@ -2,12 +2,19 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Common coercion functions used by the built-in `Params` and `JSON` types
|
||||
#
|
||||
# @api public
|
||||
module Coercions
|
||||
include Dry::Core::Constants
|
||||
|
||||
# @param [String, Object] input
|
||||
# @return [nil] if the input is an empty string
|
||||
# @return [Object] otherwise the input object is returned
|
||||
#
|
||||
# @return [nil] if the input is an empty string or nil
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def to_nil(input, &_block)
|
||||
if input.nil? || empty_str?(input)
|
||||
nil
|
||||
|
@ -19,8 +26,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_str, Object] input
|
||||
#
|
||||
# @return [Date, Object]
|
||||
#
|
||||
# @see Date.parse
|
||||
#
|
||||
# @api public
|
||||
def to_date(input, &block)
|
||||
if input.respond_to?(:to_str)
|
||||
begin
|
||||
|
@ -36,8 +47,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_str, Object] input
|
||||
#
|
||||
# @return [DateTime, Object]
|
||||
#
|
||||
# @see DateTime.parse
|
||||
#
|
||||
# @api public
|
||||
def to_date_time(input, &block)
|
||||
if input.respond_to?(:to_str)
|
||||
begin
|
||||
|
@ -53,8 +68,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_str, Object] input
|
||||
#
|
||||
# @return [Time, Object]
|
||||
#
|
||||
# @see Time.parse
|
||||
#
|
||||
# @api public
|
||||
def to_time(input, &block)
|
||||
if input.respond_to?(:to_str)
|
||||
begin
|
||||
|
@ -72,8 +91,12 @@ module Dry
|
|||
private
|
||||
|
||||
# Checks whether String is empty
|
||||
#
|
||||
# @param [String, Object] value
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def empty_str?(value)
|
||||
EMPTY_STRING.eql?(value)
|
||||
end
|
||||
|
|
|
@ -8,11 +8,19 @@ require 'time'
|
|||
module Dry
|
||||
module Types
|
||||
module Coercions
|
||||
# JSON-specific coercions
|
||||
#
|
||||
# @api public
|
||||
module JSON
|
||||
extend Coercions
|
||||
|
||||
# @param [#to_d, Object] input
|
||||
#
|
||||
# @return [BigDecimal,nil]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_decimal(input, &block)
|
||||
if input.is_a?(::Float)
|
||||
input.to_d
|
||||
|
|
|
@ -6,6 +6,9 @@ require 'bigdecimal/util'
|
|||
module Dry
|
||||
module Types
|
||||
module Coercions
|
||||
# Params-specific coercions
|
||||
#
|
||||
# @api public
|
||||
module Params
|
||||
TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
|
||||
FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
|
||||
|
@ -16,9 +19,15 @@ module Dry
|
|||
extend Coercions
|
||||
|
||||
# @param [String, Object] input
|
||||
#
|
||||
# @return [Boolean,Object]
|
||||
#
|
||||
# @see TRUE_VALUES
|
||||
# @see FALSE_VALUES
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_true(input, &_block)
|
||||
BOOLEAN_MAP.fetch(input.to_s) do
|
||||
if block_given?
|
||||
|
@ -30,9 +39,15 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [String, Object] input
|
||||
#
|
||||
# @return [Boolean,Object]
|
||||
#
|
||||
# @see TRUE_VALUES
|
||||
# @see FALSE_VALUES
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_false(input, &_block)
|
||||
BOOLEAN_MAP.fetch(input.to_s) do
|
||||
if block_given?
|
||||
|
@ -44,7 +59,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_int, #to_i, Object] input
|
||||
#
|
||||
# @return [Integer, nil, Object]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_int(input, &block)
|
||||
if input.is_a? String
|
||||
Integer(input, 10)
|
||||
|
@ -56,7 +76,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_f, Object] input
|
||||
#
|
||||
# @return [Float, nil, Object]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_float(input, &block)
|
||||
Float(input)
|
||||
rescue ArgumentError, TypeError => error
|
||||
|
@ -64,7 +89,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [#to_d, Object] input
|
||||
#
|
||||
# @return [BigDecimal, nil, Object]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_decimal(input, &block)
|
||||
to_float(input) do
|
||||
if block_given?
|
||||
|
@ -78,7 +108,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Array, String, Object] input
|
||||
#
|
||||
# @return [Array, Object]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_ary(input, &_block)
|
||||
if empty_str?(input)
|
||||
[]
|
||||
|
@ -92,7 +127,12 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Hash, String, Object] input
|
||||
#
|
||||
# @return [Hash, Object]
|
||||
#
|
||||
# @raise CoercionError
|
||||
#
|
||||
# @api public
|
||||
def self.to_hash(input, &_block)
|
||||
if empty_str?(input)
|
||||
{}
|
||||
|
|
|
@ -6,6 +6,9 @@ require 'dry/types/constrained/coercible'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Constrained types apply rules to the input
|
||||
#
|
||||
# @api public
|
||||
class Constrained
|
||||
include Type
|
||||
include Decorator
|
||||
|
@ -17,14 +20,20 @@ module Dry
|
|||
attr_reader :rule
|
||||
|
||||
# @param [Type] type
|
||||
#
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @api public
|
||||
def initialize(type, options)
|
||||
super
|
||||
@rule = options.fetch(:rule)
|
||||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api public
|
||||
def call_unsafe(input)
|
||||
result = rule.(input)
|
||||
|
||||
|
@ -36,7 +45,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api public
|
||||
def call_safe(input, &block)
|
||||
if rule[input]
|
||||
type.call_safe(input, &block)
|
||||
|
@ -59,6 +71,7 @@ module Dry
|
|||
# @yieldreturn [Object]
|
||||
# @return [Object]
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
result = rule.(input)
|
||||
|
||||
|
@ -73,19 +86,28 @@ module Dry
|
|||
# @param [Hash] options
|
||||
# The options hash provided to {Types.Rule} and combined
|
||||
# using {&} with previous {#rule}
|
||||
#
|
||||
# @return [Constrained]
|
||||
#
|
||||
# @see Dry::Logic::Operators#and
|
||||
#
|
||||
# @api public
|
||||
def constrained(options)
|
||||
with(rule: rule & Types.Rule(options))
|
||||
end
|
||||
|
||||
# @return [true]
|
||||
#
|
||||
# @api public
|
||||
def constrained?
|
||||
true
|
||||
end
|
||||
|
||||
# @param [Object] value
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def ===(value)
|
||||
valid?(value)
|
||||
end
|
||||
|
@ -93,11 +115,13 @@ module Dry
|
|||
# Build lax type. Constraints are not applicable to lax types hence unwrapping
|
||||
#
|
||||
# @return [Lax]
|
||||
# @api public
|
||||
def lax
|
||||
type.lax
|
||||
end
|
||||
|
||||
# @see Nominal#to_ast
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:constrained, [type.to_ast(meta: meta), rule.to_ast]]
|
||||
end
|
||||
|
@ -105,7 +129,10 @@ module Dry
|
|||
private
|
||||
|
||||
# @param [Object] response
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def decorate?(response)
|
||||
super || response.is_a?(Constructor)
|
||||
end
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
module Dry
|
||||
module Types
|
||||
class Constrained
|
||||
# Common coercion-related API for constrained types
|
||||
#
|
||||
# @api public
|
||||
class Coercible < Constrained
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
coerced = type.call_unsafe(input)
|
||||
result = rule.(coerced)
|
||||
|
@ -17,8 +21,9 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input)
|
||||
coerced = type.call_safe(input) { return yield }
|
||||
|
||||
|
@ -30,6 +35,8 @@ module Dry
|
|||
end
|
||||
|
||||
# @see Dry::Types::Constrained#try
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
result = type.try(input)
|
||||
|
||||
|
|
|
@ -5,9 +5,15 @@ require 'dry/logic/predicates'
|
|||
require 'dry/logic/rule/predicate'
|
||||
|
||||
module Dry
|
||||
# Helper methods for constraint types
|
||||
#
|
||||
# @api public
|
||||
module Types
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @return [Dry::Logic::Rule]
|
||||
#
|
||||
# @api public
|
||||
def self.Rule(options)
|
||||
rule_compiler.(
|
||||
options.map { |key, val|
|
||||
|
@ -19,6 +25,8 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [Dry::Logic::RuleCompiler]
|
||||
#
|
||||
# @api private
|
||||
def self.rule_compiler
|
||||
@rule_compiler ||= Logic::RuleCompiler.new(Logic::Predicates)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@ require 'dry/types/constructor/function'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Constructor types apply a function to the input that is supposed to return
|
||||
# a new value. Coercion is a common use case for constructor types.
|
||||
#
|
||||
# @api public
|
||||
class Constructor < Nominal
|
||||
include Dry::Equalizer(:type, :options, inspect: false)
|
||||
|
||||
|
@ -21,14 +25,20 @@ module Dry
|
|||
# @param [Builder, Object] input
|
||||
# @param [Hash] options
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @api public
|
||||
def self.new(input, **options, &block)
|
||||
type = input.is_a?(Builder) ? input : Nominal.new(input)
|
||||
super(type, **options, fn: Function[options.fetch(:fn, block)])
|
||||
end
|
||||
|
||||
# Instantiate a new constructor type instance
|
||||
#
|
||||
# @param [Type] type
|
||||
# @param [Function] fn
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @api private
|
||||
def initialize(type, fn: nil, **options)
|
||||
@type = type
|
||||
@fn = fn
|
||||
|
@ -36,38 +46,53 @@ module Dry
|
|||
super(type, **options, fn: fn)
|
||||
end
|
||||
|
||||
# Return the inner type's primitive
|
||||
#
|
||||
# @return [Class]
|
||||
#
|
||||
# @api public
|
||||
def primitive
|
||||
type.primitive
|
||||
end
|
||||
|
||||
# Return the inner type's name
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
def name
|
||||
type.name
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def default?
|
||||
type.default?
|
||||
end
|
||||
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input)
|
||||
coerced = fn.(input) { return yield }
|
||||
type.call_safe(coerced) { |output = coerced| yield(output) }
|
||||
end
|
||||
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
type.call_unsafe(fn.(input))
|
||||
end
|
||||
|
||||
# @param [Object] input
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @return [Logic::Result, Types::Result]
|
||||
# @return [Object] if block given and try fails
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
value = fn.(input)
|
||||
rescue CoercionError => error
|
||||
|
@ -82,7 +107,10 @@ module Dry
|
|||
# @param [#call, nil] new_fn
|
||||
# @param [Hash] options
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @return [Constructor]
|
||||
#
|
||||
# @api public
|
||||
def constructor(new_fn = nil, **options, &block)
|
||||
with({**options, fn: fn >> (new_fn || block)})
|
||||
end
|
||||
|
@ -90,11 +118,15 @@ module Dry
|
|||
alias_method :>>, :constructor
|
||||
|
||||
# @return [Class]
|
||||
#
|
||||
# @api private
|
||||
def constrained_type
|
||||
Constrained::Coercible
|
||||
end
|
||||
|
||||
# @see Nominal#to_ast
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:constructor, [type.to_ast(meta: meta), fn.to_ast]]
|
||||
end
|
||||
|
@ -104,7 +136,10 @@ module Dry
|
|||
# @param [#call, nil] new_fn
|
||||
# @param [Hash] options
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @return [Constructor]
|
||||
#
|
||||
# @api public
|
||||
def prepend(new_fn = nil, **options, &block)
|
||||
with({**options, fn: fn << (new_fn || block)})
|
||||
end
|
||||
|
@ -113,6 +148,7 @@ module Dry
|
|||
# Build a lax type
|
||||
#
|
||||
# @return [Lax]
|
||||
# @api public
|
||||
def lax
|
||||
Lax.new(Constructor.new(type.lax, options))
|
||||
end
|
||||
|
@ -120,28 +156,30 @@ module Dry
|
|||
# Wrap the type with a proc
|
||||
#
|
||||
# @return [Proc]
|
||||
#
|
||||
# @api public
|
||||
def to_proc
|
||||
proc { |value| self.(value) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Symbol] meth
|
||||
# @param [Boolean] include_private
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def respond_to_missing?(meth, include_private = false)
|
||||
super || type.respond_to?(meth)
|
||||
end
|
||||
|
||||
# Delegates missing methods to {#type}
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Symbol] method
|
||||
# @param [Array] args
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @api private
|
||||
def method_missing(method, *args, &block)
|
||||
if type.respond_to?(method)
|
||||
response = type.__send__(method, *args, &block)
|
||||
|
|
|
@ -6,9 +6,10 @@ require 'concurrent/map'
|
|||
module Dry
|
||||
module Types
|
||||
class Constructor < Nominal
|
||||
# Function is used internally by Constructor types
|
||||
#
|
||||
# @api private
|
||||
class Function
|
||||
|
||||
# Wrapper for unsafe coercion functions
|
||||
#
|
||||
# @api private
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/container'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Internal container for the built-in types
|
||||
#
|
||||
# @api private
|
||||
class Container
|
||||
include Dry::Container::Mixin
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/types/options'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Common API for types
|
||||
#
|
||||
# @api public
|
||||
module Decorator
|
||||
include Options
|
||||
|
||||
|
@ -18,30 +21,42 @@ module Dry
|
|||
|
||||
# @param [Object] input
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @return [Result,Logic::Result]
|
||||
# @return [Object] if block given and try fails
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
type.try(input, &block)
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def default?
|
||||
type.default?
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def constrained?
|
||||
type.constrained?
|
||||
end
|
||||
|
||||
# @return [Sum]
|
||||
#
|
||||
# @api public
|
||||
def optional
|
||||
Types['strict.nil'] | self
|
||||
end
|
||||
|
||||
# @param [Symbol] meth
|
||||
# @param [Boolean] include_private
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def respond_to_missing?(meth, include_private = false)
|
||||
super || type.respond_to?(meth)
|
||||
end
|
||||
|
@ -49,6 +64,8 @@ module Dry
|
|||
# Wrap the type with a proc
|
||||
#
|
||||
# @return [Proc]
|
||||
#
|
||||
# @api public
|
||||
def to_proc
|
||||
proc { |value| self.(value) }
|
||||
end
|
||||
|
@ -56,15 +73,21 @@ module Dry
|
|||
private
|
||||
|
||||
# @param [Object] response
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def decorate?(response)
|
||||
response.is_a?(type.class)
|
||||
end
|
||||
|
||||
# Delegates missing methods to {#type}
|
||||
#
|
||||
# @param [Symbol] meth
|
||||
# @param [Array] args
|
||||
# @param [#call, nil] block
|
||||
#
|
||||
# @api private
|
||||
def method_missing(meth, *args, &block)
|
||||
if type.respond_to?(meth)
|
||||
response = type.__send__(meth, *args, &block)
|
||||
|
@ -80,6 +103,8 @@ module Dry
|
|||
end
|
||||
|
||||
# Replace underlying type
|
||||
#
|
||||
# @api private
|
||||
def __new__(type)
|
||||
self.class.new(type, *@__args__[1..-1], **@options)
|
||||
end
|
||||
|
|
|
@ -4,7 +4,11 @@ require 'dry/types/decorator'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Default types are useful when a missing value should be replaced by a default one
|
||||
#
|
||||
# @api public
|
||||
class Default
|
||||
# @api private
|
||||
class Callable < Default
|
||||
include Dry::Equalizer(:type, inspect: false)
|
||||
|
||||
|
@ -27,7 +31,10 @@ module Dry
|
|||
alias_method :evaluate, :value
|
||||
|
||||
# @param [Object, #call] value
|
||||
#
|
||||
# @return [Class] {Default} or {Default::Callable}
|
||||
#
|
||||
# @api private
|
||||
def self.[](value)
|
||||
if value.respond_to?(:call)
|
||||
Callable
|
||||
|
@ -38,37 +45,52 @@ module Dry
|
|||
|
||||
# @param [Type] type
|
||||
# @param [Object] value
|
||||
#
|
||||
# @api private
|
||||
def initialize(type, value, **options)
|
||||
super
|
||||
@value = value
|
||||
end
|
||||
|
||||
# Build a constrained type
|
||||
#
|
||||
# @param [Array] args see {Dry::Types::Builder#constrained}
|
||||
#
|
||||
# @return [Default]
|
||||
#
|
||||
# @api public
|
||||
def constrained(*args)
|
||||
type.constrained(*args).default(value)
|
||||
end
|
||||
|
||||
# @return [true]
|
||||
#
|
||||
# @api public
|
||||
def default?
|
||||
true
|
||||
end
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Result::Success]
|
||||
#
|
||||
# @api public
|
||||
def try(input)
|
||||
success(call(input))
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def valid?(value = Undefined)
|
||||
Undefined.equal?(value) || super
|
||||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object] value passed through {#type} or {#default} value
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input = Undefined)
|
||||
if input.equal?(Undefined)
|
||||
evaluate
|
||||
|
@ -77,10 +99,11 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api pribate
|
||||
#
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object] value passed through {#type} or {#default} value
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input = Undefined, &block)
|
||||
if input.equal?(Undefined)
|
||||
evaluate
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/types/decorator'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Enum types can be used to define an enum on top of an existing type
|
||||
#
|
||||
# @api public
|
||||
class Enum
|
||||
include Type
|
||||
include Dry::Equalizer(:type, :mapping, inspect: false)
|
||||
|
@ -21,6 +24,8 @@ module Dry
|
|||
# @param [Type] type
|
||||
# @param [Hash] options
|
||||
# @option options [Array] :values
|
||||
#
|
||||
# @api private
|
||||
def initialize(type, options)
|
||||
super
|
||||
@mapping = options.fetch(:mapping).freeze
|
||||
|
@ -29,23 +34,28 @@ module Dry
|
|||
freeze
|
||||
end
|
||||
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
type.call_unsafe(map_value(input))
|
||||
end
|
||||
|
||||
# @api private
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input, &block)
|
||||
type.call_safe(map_value(input), &block)
|
||||
end
|
||||
|
||||
# @see Dry::Types::Constrained#try
|
||||
#
|
||||
# @api public
|
||||
def try(input)
|
||||
super(map_value(input))
|
||||
end
|
||||
|
||||
# @api private
|
||||
def default(*)
|
||||
raise '.enum(*values).default(value) is not supported. Call '\
|
||||
'.default(value).enum(*values) instead'
|
||||
|
@ -55,11 +65,15 @@ module Dry
|
|||
alias_method :include?, :valid?
|
||||
|
||||
# @see Nominal#to_ast
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:enum, [type.to_ast(meta: meta), mapping]]
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
def to_s
|
||||
PRINTER.(self)
|
||||
end
|
||||
|
@ -69,10 +83,11 @@ module Dry
|
|||
|
||||
# Maps a value
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def map_value(input)
|
||||
if input.equal?(Undefined)
|
||||
type.call
|
||||
|
|
|
@ -5,6 +5,9 @@ require 'dry/types/decorator'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Maybe extension provides Maybe types where values are wrapped using `Either` monad
|
||||
#
|
||||
# @api public
|
||||
class Maybe
|
||||
include Type
|
||||
include Dry::Equalizer(:type, :options, inspect: false)
|
||||
|
@ -13,10 +16,11 @@ module Dry
|
|||
include Printable
|
||||
include Dry::Monads::Maybe::Mixin
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Dry::Monads::Maybe, Object] input
|
||||
#
|
||||
# @return [Dry::Monads::Maybe]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input = Undefined)
|
||||
case input
|
||||
when Dry::Monads::Maybe
|
||||
|
@ -28,10 +32,11 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
#
|
||||
# @param [Dry::Monads::Maybe, Object] input
|
||||
#
|
||||
# @return [Dry::Monads::Maybe]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input = Undefined, &block)
|
||||
case input
|
||||
when Dry::Monads::Maybe
|
||||
|
@ -44,7 +49,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Result::Success]
|
||||
#
|
||||
# @api public
|
||||
def try(input = Undefined)
|
||||
res = if input.equal?(Undefined)
|
||||
None()
|
||||
|
@ -56,13 +64,19 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [true]
|
||||
#
|
||||
# @api public
|
||||
def default?
|
||||
true
|
||||
end
|
||||
|
||||
# @param [Object] value
|
||||
#
|
||||
# @see Dry::Types::Builder#default
|
||||
#
|
||||
# @raise [ArgumentError] if nil provided as default value
|
||||
#
|
||||
# @api public
|
||||
def default(value)
|
||||
if value.nil?
|
||||
raise ArgumentError, "nil cannot be used as a default of a maybe type"
|
||||
|
@ -73,15 +87,21 @@ module Dry
|
|||
end
|
||||
|
||||
module Builder
|
||||
# Turn a type into a maybe type
|
||||
#
|
||||
# @return [Maybe]
|
||||
#
|
||||
# @api public
|
||||
def maybe
|
||||
Maybe.new(Types['strict.nil'] | self)
|
||||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
class Printer
|
||||
MAPPING[Maybe] = :visit_maybe
|
||||
|
||||
# @api private
|
||||
def visit_maybe(maybe)
|
||||
visit(maybe.type) do |type|
|
||||
yield "Maybe<#{type}>"
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/types/container'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Internal container for constructor functions used by the built-in types
|
||||
#
|
||||
# @api private
|
||||
class FnContainer
|
||||
# @api private
|
||||
def self.container
|
||||
|
|
|
@ -4,10 +4,13 @@ require 'dry/types/hash/constructor'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Hash types can be used to define maps and schemas
|
||||
#
|
||||
# @api public
|
||||
class Hash < Nominal
|
||||
NOT_REQUIRED = { required: false }.freeze
|
||||
|
||||
# @overload schmea(type_map, meta = EMPTY_HASH)
|
||||
# @overload schema(type_map, meta = EMPTY_HASH)
|
||||
# @param [{Symbol => Dry::Types::Nominal}] type_map
|
||||
# @param [Hash] meta
|
||||
# @return [Dry::Types::Schema]
|
||||
|
@ -16,6 +19,8 @@ module Dry
|
|||
# @param [Array<Dry::Types::Schema::Key>] key List of schema keys
|
||||
# @param [Hash] meta
|
||||
# @return [Dry::Types::Schema]
|
||||
#
|
||||
# @api public
|
||||
def schema(keys_or_map, meta = EMPTY_HASH)
|
||||
if keys_or_map.is_a?(::Array)
|
||||
keys = keys_or_map
|
||||
|
@ -30,7 +35,10 @@ module Dry
|
|||
#
|
||||
# @param [Type] key_type
|
||||
# @param [Type] value_type
|
||||
#
|
||||
# @return [Map]
|
||||
#
|
||||
# @api public
|
||||
def map(key_type, value_type)
|
||||
Map.new(
|
||||
primitive,
|
||||
|
@ -51,9 +59,13 @@ module Dry
|
|||
alias_method :symbolized, :weak
|
||||
|
||||
# Injects a type transformation function for building schemas
|
||||
#
|
||||
# @param [#call,nil] proc
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @return [Hash]
|
||||
#
|
||||
# @api public
|
||||
def with_type_transform(proc = nil, &block)
|
||||
fn = proc || block
|
||||
|
||||
|
@ -73,12 +85,17 @@ module Dry
|
|||
# Whether the type transforms types of schemas created by {Dry::Types::Hash#schema}
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def transform_types?
|
||||
!options[:type_transform_fn].nil?
|
||||
end
|
||||
|
||||
# @param meta [Boolean] Whether to dump the meta to the AST
|
||||
#
|
||||
# @return [Array] An AST representation
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
if RUBY_VERSION >= "2.5"
|
||||
opts = options.slice(:type_transform_fn)
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/types/constructor'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Hash type exposes additional APIs for working with schema hashes
|
||||
#
|
||||
# @api public
|
||||
class Hash < Nominal
|
||||
class Constructor < ::Dry::Types::Constructor
|
||||
# @api private
|
||||
|
@ -12,6 +15,8 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [Lax]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
type.lax.constructor(fn, meta: meta)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,9 @@ require 'dry/types/decorator'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Lax types rescue from type-related errors when constructors fail
|
||||
#
|
||||
# @api public
|
||||
class Lax
|
||||
include Type
|
||||
include Decorator
|
||||
|
@ -15,7 +18,10 @@ module Dry
|
|||
private :options, :constructor
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api public
|
||||
def call(input)
|
||||
type.call_safe(input) { |output = input| output }
|
||||
end
|
||||
|
@ -25,9 +31,13 @@ module Dry
|
|||
|
||||
# @param [Object] input
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @yieldparam [Failure] failure
|
||||
# @yieldreturn [Result]
|
||||
#
|
||||
# @return [Result,Logic::Result]
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
type.try(input, &block)
|
||||
rescue CoercionError => error
|
||||
|
@ -36,11 +46,15 @@ module Dry
|
|||
end
|
||||
|
||||
# @see Nominal#to_ast
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:lax, type.to_ast(meta: meta)]
|
||||
end
|
||||
|
||||
# @return [Lax]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
self
|
||||
end
|
||||
|
@ -48,7 +62,10 @@ module Dry
|
|||
private
|
||||
|
||||
# @param [Object, Dry::Types::Constructor] response
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def decorate?(response)
|
||||
super || response.is_a?(constructor_type)
|
||||
end
|
||||
|
|
|
@ -9,34 +9,48 @@ module Dry
|
|||
# Dry::Types['integer'].constrained(gteq: 1, lteq: 10),
|
||||
# Dry::Types['string']
|
||||
# )
|
||||
#
|
||||
# type.(1 => 'right')
|
||||
# # => {1 => 'right'}
|
||||
#
|
||||
# type.('1' => 'wrong')
|
||||
# # Dry::Types::MapError: "1" violates constraints (type?(Integer, "1") AND gteq?(1, "1") AND lteq?(10, "1") failed)
|
||||
#
|
||||
# type.(11 => 'wrong')
|
||||
# # Dry::Types::MapError: 11 violates constraints (lteq?(10, 11) failed)
|
||||
#
|
||||
# @api public
|
||||
class Map < Nominal
|
||||
def initialize(_primitive, key_type: Types['any'], value_type: Types['any'], meta: EMPTY_HASH)
|
||||
super(_primitive, key_type: key_type, value_type: value_type, meta: meta)
|
||||
end
|
||||
|
||||
# @return [Type]
|
||||
#
|
||||
# @api public
|
||||
def key_type
|
||||
options[:key_type]
|
||||
end
|
||||
|
||||
# @return [Type]
|
||||
#
|
||||
# @api public
|
||||
def value_type
|
||||
options[:value_type]
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
def name
|
||||
'Map'
|
||||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @return [Hash]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(hash)
|
||||
try(hash) { |failure|
|
||||
raise MapError, failure.error.message
|
||||
|
@ -44,13 +58,19 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @return [Hash]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(hash)
|
||||
try(hash) { return yield }.input
|
||||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @return [Result]
|
||||
#
|
||||
# @api public
|
||||
def try(hash)
|
||||
result = coerce(hash)
|
||||
return result if result.success? || !block_given?
|
||||
|
@ -58,7 +78,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @param meta [Boolean] Whether to dump the meta to the AST
|
||||
#
|
||||
# @return [Array] An AST representation
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:map,
|
||||
[key_type.to_ast(meta: true),
|
||||
|
@ -67,6 +90,8 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def constrained?
|
||||
value_type.constrained?
|
||||
end
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Storage for meta-data
|
||||
#
|
||||
# @api public
|
||||
module Meta
|
||||
def initialize(*args, meta: EMPTY_HASH, **options)
|
||||
super(*args, **options)
|
||||
|
@ -9,7 +12,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Hash] new_options
|
||||
#
|
||||
# @return [Type]
|
||||
#
|
||||
# @api public
|
||||
def with(options)
|
||||
super(meta: @meta, **options)
|
||||
end
|
||||
|
@ -20,6 +26,8 @@ module Dry
|
|||
# @overload meta(data)
|
||||
# @param [Hash] new metadata to merge into existing metadata
|
||||
# @return [Type] new type with added metadata
|
||||
#
|
||||
# @api public
|
||||
def meta(data = nil)
|
||||
if !data
|
||||
@meta
|
||||
|
@ -31,7 +39,10 @@ module Dry
|
|||
end
|
||||
|
||||
# Resets meta
|
||||
#
|
||||
# @return [Dry::Types::Type]
|
||||
#
|
||||
# @api public
|
||||
def pristine
|
||||
with(meta: EMPTY_HASH)
|
||||
end
|
||||
|
|
|
@ -10,10 +10,13 @@ module Dry
|
|||
# module Types
|
||||
# include Dry::Types(:strict, :coercible, :nominal, default: :strict)
|
||||
# end
|
||||
# # Types.constants
|
||||
#
|
||||
# Types.constants
|
||||
# # => [:Class, :Strict, :Symbol, :Integer, :Float, :String, :Array, :Hash,
|
||||
# # :Decimal, :Nil, :True, :False, :Bool, :Date, :Nominal, :DateTime, :Range,
|
||||
# # :Coercible, :Time]
|
||||
#
|
||||
# @api public
|
||||
class Module < ::Module
|
||||
def initialize(registry, *args)
|
||||
@registry = registry
|
||||
|
|
|
@ -8,6 +8,11 @@ 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
|
||||
|
@ -20,7 +25,10 @@ module Dry
|
|||
attr_reader :primitive
|
||||
|
||||
# @param [Class] primitive
|
||||
#
|
||||
# @return [Type]
|
||||
#
|
||||
# @api private
|
||||
def self.[](primitive)
|
||||
if primitive == ::Array
|
||||
Types::Array
|
||||
|
@ -35,6 +43,8 @@ module Dry
|
|||
|
||||
# @param [Type,Class] primitive
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @api private
|
||||
def initialize(primitive, **options)
|
||||
super
|
||||
@primitive = primitive
|
||||
|
@ -42,55 +52,79 @@ module Dry
|
|||
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
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @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)
|
||||
unless error.is_a?(CoercionError)
|
||||
raise ArgumentError, "error must be a CoercionError"
|
||||
|
@ -99,12 +133,17 @@ module Dry
|
|||
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
|
||||
|
@ -115,6 +154,7 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def try_coerce(input)
|
||||
result = success(input)
|
||||
|
||||
|
@ -135,6 +175,8 @@ module Dry
|
|||
# Return AST representation of a type nominal
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:nominal, [primitive, meta ? self.meta : EMPTY_HASH]]
|
||||
end
|
||||
|
@ -142,6 +184,8 @@ module Dry
|
|||
# Return self. Nominal types are lax by definition
|
||||
#
|
||||
# @return [Nominal]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
self
|
||||
end
|
||||
|
@ -149,6 +193,8 @@ module Dry
|
|||
# Wrap the type with a proc
|
||||
#
|
||||
# @return [Proc]
|
||||
#
|
||||
# @api public
|
||||
def to_proc
|
||||
ALWAYS
|
||||
end
|
||||
|
|
|
@ -2,18 +2,26 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Common API for types with options
|
||||
#
|
||||
# @api private
|
||||
module Options
|
||||
# @return [Hash]
|
||||
attr_reader :options
|
||||
|
||||
# @see Nominal#initialize
|
||||
#
|
||||
# @api private
|
||||
def initialize(*args, **options)
|
||||
@__args__ = args.freeze
|
||||
@options = options.freeze
|
||||
end
|
||||
|
||||
# @param [Hash] new_options
|
||||
#
|
||||
# @return [Type]
|
||||
#
|
||||
# @api private
|
||||
def with(**new_options)
|
||||
self.class.new(*@__args__, **options, **new_options)
|
||||
end
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# @api private
|
||||
module Printable
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
def to_s
|
||||
PRINTER.(self) { super }
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/equalizer'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Result class used by {Type#try}
|
||||
#
|
||||
# @api public
|
||||
class Result
|
||||
include Dry::Equalizer(:input, inspect: false)
|
||||
|
||||
|
@ -11,22 +14,34 @@ module Dry
|
|||
attr_reader :input
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @api private
|
||||
def initialize(input)
|
||||
@input = input
|
||||
end
|
||||
|
||||
# Success result
|
||||
#
|
||||
# @api public
|
||||
class Success < Result
|
||||
# @return [true]
|
||||
#
|
||||
# @api public
|
||||
def success?
|
||||
true
|
||||
end
|
||||
|
||||
# @return [false]
|
||||
#
|
||||
# @api public
|
||||
def failure?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Failure result
|
||||
#
|
||||
# @api public
|
||||
class Failure < Result
|
||||
include Dry::Equalizer(:input, :error, inspect: false)
|
||||
|
||||
|
@ -34,23 +49,32 @@ module Dry
|
|||
attr_reader :error
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @param [#to_s] error
|
||||
#
|
||||
# @api private
|
||||
def initialize(input, error)
|
||||
super(input)
|
||||
@error = error
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
def to_s
|
||||
error.to_s
|
||||
end
|
||||
|
||||
# @return [false]
|
||||
#
|
||||
# @api public
|
||||
def success?
|
||||
false
|
||||
end
|
||||
|
||||
# @return [true]
|
||||
#
|
||||
# @api public
|
||||
def failure?
|
||||
true
|
||||
end
|
||||
|
|
|
@ -16,6 +16,8 @@ module Dry
|
|||
# @see Dry::Types::Default::Callable#evaluate
|
||||
#
|
||||
# {Schema} implements Enumerable using its keys as collection.
|
||||
#
|
||||
# @api public
|
||||
class Schema < Hash
|
||||
NO_TRANSFORM = Dry::Types::FnContainer.register { |x| x }
|
||||
SYMBOLIZE_KEY = Dry::Types::FnContainer.register(:to_sym.to_proc)
|
||||
|
@ -33,8 +35,11 @@ module Dry
|
|||
|
||||
# @param [Class] _primitive
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @option options [Array[Dry::Types::Schema::Key]] :keys
|
||||
# @option options [String] :key_transform_fn
|
||||
#
|
||||
# @api private
|
||||
def initialize(_primitive, **options)
|
||||
@keys = options.fetch(:keys)
|
||||
@name_key_map = keys.each_with_object({}) do |key, idx|
|
||||
|
@ -49,31 +54,44 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @return [Hash{Symbol => Object}]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(hash, options = EMPTY_HASH)
|
||||
resolve_unsafe(coerce(hash), options)
|
||||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @return [Hash{Symbol => Object}]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(hash, options = EMPTY_HASH)
|
||||
resolve_safe(coerce(hash) { return yield }, options) { return yield }
|
||||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @option options [Boolean] :skip_missing If true don't raise error if on missing keys
|
||||
# @option options [Boolean] :resolve_defaults If false default value
|
||||
# won't be evaluated for missing key
|
||||
# @return [Hash{Symbol => Object}]
|
||||
#
|
||||
# @api public
|
||||
def apply(hash, options = EMPTY_HASH)
|
||||
call_unsafe(hash, options)
|
||||
end
|
||||
|
||||
# @param [Hash] hash
|
||||
#
|
||||
# @yieldparam [Failure] failure
|
||||
# @yieldreturn [Result]
|
||||
#
|
||||
# @return [Logic::Result]
|
||||
# @return [Object] if coercion fails and a block is given
|
||||
#
|
||||
# @api public
|
||||
def try(input)
|
||||
if primitive?(input)
|
||||
success = true
|
||||
|
@ -122,7 +140,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @param meta [Boolean] Whether to dump the meta to the AST
|
||||
#
|
||||
# @return [Array] An AST representation
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
if RUBY_VERSION >= "2.5"
|
||||
opts = options.slice(:key_transform_fn, :type_transform_fn, :strict)
|
||||
|
@ -141,21 +162,31 @@ module Dry
|
|||
end
|
||||
|
||||
# Whether the schema rejects unknown keys
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def strict?
|
||||
options.fetch(:strict, false)
|
||||
end
|
||||
|
||||
# Make the schema intolerant to unknown keys
|
||||
#
|
||||
# @return [Schema]
|
||||
#
|
||||
# @api public
|
||||
def strict
|
||||
with(strict: true)
|
||||
end
|
||||
|
||||
# Injects a key transformation function
|
||||
#
|
||||
# @param [#call,nil] proc
|
||||
# @param [#call,nil] block
|
||||
#
|
||||
# @return [Schema]
|
||||
#
|
||||
# @api public
|
||||
def with_key_transform(proc = nil, &block)
|
||||
fn = proc || block
|
||||
|
||||
|
@ -170,6 +201,8 @@ module Dry
|
|||
# Whether the schema transforms input keys
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def trasform_keys?
|
||||
!options[:key_transform_fn].nil?
|
||||
end
|
||||
|
@ -178,10 +211,13 @@ module Dry
|
|||
# @param [{Symbol => Dry::Types::Nominal}] type_map
|
||||
# @param [Hash] meta
|
||||
# @return [Dry::Types::Schema]
|
||||
#
|
||||
# @overload schema(keys)
|
||||
# @param [Array<Dry::Types::Schema::Key>] key List of schema keys
|
||||
# @param [Hash] meta
|
||||
# @return [Dry::Types::Schema]
|
||||
#
|
||||
# @api public
|
||||
def schema(keys_or_map)
|
||||
if keys_or_map.is_a?(::Array)
|
||||
new_keys = keys_or_map
|
||||
|
@ -196,6 +232,8 @@ module Dry
|
|||
# Iterate over each key type
|
||||
#
|
||||
# @return [Array<Dry::Types::Schema::Key>,Enumerator]
|
||||
#
|
||||
# @api public
|
||||
def each(&block)
|
||||
keys.each(&block)
|
||||
end
|
||||
|
@ -203,12 +241,16 @@ module Dry
|
|||
# Whether the schema has the given key
|
||||
#
|
||||
# @param [Symbol] name Key name
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def key?(name)
|
||||
name_key_map.key?(name)
|
||||
end
|
||||
|
||||
# Fetch key type by a key name.
|
||||
# Fetch key type by a key name
|
||||
#
|
||||
# Behaves as ::Hash#fetch
|
||||
#
|
||||
# @overload key(name, fallback = Undefined)
|
||||
|
@ -220,6 +262,8 @@ module Dry
|
|||
# @param [Symbol] name Key name
|
||||
# @param [Proc] block Fallback block, runs if key is missing
|
||||
# @return [Dry::Types::Schema::Key,Object] key type or block value if key is not in schema
|
||||
#
|
||||
# @api public
|
||||
def key(name, fallback = Undefined, &block)
|
||||
if Undefined.equal?(fallback)
|
||||
name_key_map.fetch(name, &block)
|
||||
|
@ -229,11 +273,15 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def constrained?
|
||||
true
|
||||
end
|
||||
|
||||
# @return [Lax]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
Lax.new(schema(keys.map(&:lax)))
|
||||
end
|
||||
|
@ -242,9 +290,9 @@ module Dry
|
|||
|
||||
# @param [Array<Dry::Types::Schema::Keys>] keys
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [Dry::Types::Schema]
|
||||
#
|
||||
# @api private
|
||||
def merge_keys(*keys)
|
||||
keys.
|
||||
flatten(1).
|
||||
|
@ -311,6 +359,8 @@ module Dry
|
|||
end
|
||||
|
||||
# Try to add missing keys to the hash
|
||||
#
|
||||
# @api private
|
||||
def resolve_missing_keys(hash, options)
|
||||
skip_missing = options.fetch(:skip_missing, false)
|
||||
resolve_defaults = options.fetch(:resolve_defaults, true)
|
||||
|
@ -331,13 +381,18 @@ module Dry
|
|||
end
|
||||
|
||||
# @param hash_keys [Array<Symbol>]
|
||||
#
|
||||
# @return [UnknownKeysError]
|
||||
#
|
||||
# @api private
|
||||
def unexpected_keys(hash_keys)
|
||||
extra_keys = hash_keys.map(&transform_key) - name_key_map.keys
|
||||
UnknownKeysError.new(extra_keys)
|
||||
end
|
||||
|
||||
# @return [MissingKeyError]
|
||||
#
|
||||
# @api private
|
||||
def missing_key(key)
|
||||
MissingKeyError.new(key)
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/equalizer'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Schema is a hash with explicit member types defined
|
||||
#
|
||||
# @api public
|
||||
class Schema < Hash
|
||||
# Proxy type for schema keys. Contains only key name and
|
||||
# whether it's required or not. All other calls deletaged
|
||||
|
@ -30,15 +33,19 @@ module Dry
|
|||
@name = name
|
||||
end
|
||||
|
||||
# @api private
|
||||
def call_safe(input, &block)
|
||||
type.call_safe(input, &block)
|
||||
end
|
||||
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
type.call_unsafe(input)
|
||||
end
|
||||
|
||||
# @see Dry::Types::Nominal#try
|
||||
#
|
||||
# @api public
|
||||
def try(input, &block)
|
||||
type.try(input, &block)
|
||||
end
|
||||
|
@ -46,6 +53,8 @@ module Dry
|
|||
# Whether the key is required in schema input
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def required?
|
||||
options.fetch(:required)
|
||||
end
|
||||
|
@ -60,6 +69,8 @@ module Dry
|
|||
#
|
||||
# @param [Boolean] required New value
|
||||
# @return [Dry::Types::Schema::Key]
|
||||
#
|
||||
# @api public
|
||||
def required(required = Undefined)
|
||||
if Undefined.equal?(required)
|
||||
options.fetch(:required)
|
||||
|
@ -71,6 +82,8 @@ module Dry
|
|||
# Make key not required
|
||||
#
|
||||
# @return [Dry::Types::Schema::Key]
|
||||
#
|
||||
# @api public
|
||||
def omittable
|
||||
required(false)
|
||||
end
|
||||
|
@ -78,6 +91,8 @@ module Dry
|
|||
# Turn key into a lax type. Lax types are not strict hence such keys are not required
|
||||
#
|
||||
# @return [Lax]
|
||||
#
|
||||
# @api public
|
||||
def lax
|
||||
super.required(false)
|
||||
end
|
||||
|
@ -85,6 +100,8 @@ module Dry
|
|||
# Dump to internal AST representation
|
||||
#
|
||||
# @return [Array]
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[
|
||||
:key,
|
||||
|
@ -98,6 +115,7 @@ module Dry
|
|||
|
||||
private
|
||||
|
||||
# @api private
|
||||
def decorate?(response)
|
||||
response.is_a?(Type)
|
||||
end
|
||||
|
|
|
@ -5,6 +5,9 @@ require 'dry/types/meta'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Sum type
|
||||
#
|
||||
# @api public
|
||||
class Sum
|
||||
include Type
|
||||
include Builder
|
||||
|
@ -19,6 +22,7 @@ module Dry
|
|||
# @return [Type]
|
||||
attr_reader :right
|
||||
|
||||
# @api private
|
||||
class Constrained < Sum
|
||||
# @return [Dry::Logic::Operations::Or]
|
||||
def rule
|
||||
|
@ -34,6 +38,8 @@ module Dry
|
|||
# @param [Type] left
|
||||
# @param [Type] right
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @api private
|
||||
def initialize(left, right, options = {})
|
||||
super
|
||||
@left, @right = left, right
|
||||
|
@ -41,37 +47,54 @@ module Dry
|
|||
end
|
||||
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
def name
|
||||
[left, right].map(&:name).join(' | ')
|
||||
end
|
||||
|
||||
# @return [false]
|
||||
#
|
||||
# @api public
|
||||
def default?
|
||||
false
|
||||
end
|
||||
|
||||
# @return [false]
|
||||
#
|
||||
# @api public
|
||||
def constrained?
|
||||
false
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api public
|
||||
def optional?
|
||||
primitive?(nil)
|
||||
end
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_unsafe(input)
|
||||
left.call_safe(input) { right.call_unsafe(input) }
|
||||
end
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @api private
|
||||
def call_safe(input, &block)
|
||||
left.call_safe(input) { right.call_safe(input, &block) }
|
||||
end
|
||||
|
||||
# @param [Object] input
|
||||
#
|
||||
# @api public
|
||||
def try(input)
|
||||
left.try(input) do
|
||||
right.try(input) do |failure|
|
||||
|
@ -84,6 +107,7 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def success(input)
|
||||
if left.valid?(input)
|
||||
left.success(input)
|
||||
|
@ -94,6 +118,7 @@ module Dry
|
|||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def failure(input, _error = nil)
|
||||
if !left.valid?(input)
|
||||
left.failure(input, left.try(input).error)
|
||||
|
@ -103,7 +128,10 @@ module Dry
|
|||
end
|
||||
|
||||
# @param [Object] value
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def primitive?(value)
|
||||
left.primitive?(value) || right.primitive?(value)
|
||||
end
|
||||
|
@ -112,6 +140,8 @@ module Dry
|
|||
# to the right branch
|
||||
#
|
||||
# @see [Meta#meta]
|
||||
#
|
||||
# @api public
|
||||
def meta(data = nil)
|
||||
if data.nil?
|
||||
optional? ? right.meta : super
|
||||
|
@ -123,13 +153,19 @@ module Dry
|
|||
end
|
||||
|
||||
# @see Nominal#to_ast
|
||||
#
|
||||
# @api public
|
||||
def to_ast(meta: true)
|
||||
[:sum, [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
||||
end
|
||||
|
||||
# @param [Hash] options
|
||||
#
|
||||
# @return [Constrained,Sum]
|
||||
#
|
||||
# @see Builder#constrained
|
||||
#
|
||||
# @api public
|
||||
def constrained(options)
|
||||
if optional?
|
||||
right.constrained(options).optional
|
||||
|
@ -141,6 +177,8 @@ module Dry
|
|||
# Wrap the type with a proc
|
||||
#
|
||||
# @return [Proc]
|
||||
#
|
||||
# @api public
|
||||
def to_proc
|
||||
proc { |value| self.(value) }
|
||||
end
|
||||
|
|
|
@ -4,6 +4,9 @@ require 'dry/core/deprecations'
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
# Common Type module denoting an object is a Type
|
||||
#
|
||||
# @api public
|
||||
module Type
|
||||
extend ::Dry::Core::Deprecations[:'dry-types']
|
||||
|
||||
|
@ -12,6 +15,8 @@ module Dry
|
|||
# Whether a value is a valid member of the type
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
def valid?(input = Undefined)
|
||||
call_safe(input) { return false }
|
||||
true
|
||||
|
@ -36,6 +41,7 @@ module Dry
|
|||
# @yieldparam [Object] output Partially coerced value
|
||||
# @return [Object]
|
||||
#
|
||||
# @api public
|
||||
def call(input = Undefined, &block)
|
||||
if block_given?
|
||||
call_safe(input, &block)
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
module Dry
|
||||
module Types
|
||||
VERSION = '1.0.0'.freeze
|
||||
VERSION = '1.0.0'
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue