# 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 Schema::Key # @api private def maybe __new__(type.maybe) 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