dry-types/lib/dry/types/extensions/maybe.rb

123 lines
2.6 KiB
Ruby

# frozen_string_literal: true
require 'dry/monads/maybe'
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)
include Decorator
include Builder
include Printable
include Dry::Monads::Maybe::Mixin
# @param [Dry::Monads::Maybe, Object] input
#
# @return [Dry::Monads::Maybe]
#
# @api private
def call_unsafe(input = Undefined)
case input
when Dry::Monads::Maybe
input
when Undefined
None()
else
Maybe(type.call_unsafe(input))
end
end
# @param [Dry::Monads::Maybe, Object] input
#
# @return [Dry::Monads::Maybe]
#
# @api private
def call_safe(input = Undefined, &block)
case input
when Dry::Monads::Maybe
input
when Undefined
None()
else
Maybe(type.call_safe(input, &block))
end
end
# @param [Object] input
#
# @return [Result::Success]
#
# @api public
def try(input = Undefined)
res = if input.equal?(Undefined)
None()
else
Maybe(type[input])
end
Result::Success.new(res)
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"
else
super
end
end
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}>"
end
end
end
# Register non-coercible maybe types
NON_NIL.each_key do |name|
register("maybe.strict.#{name}", self["strict.#{name}"].maybe)
end
# Register coercible maybe types
COERCIBLE.each_key do |name|
register("maybe.coercible.#{name}", self["coercible.#{name}"].maybe)
end
end
end