# frozen_string_literal: true require "dry/core/equalizer" 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, immutable: true) 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) case input when ::Dry::Monads::Maybe input when Undefined None() else Maybe(type.call_safe(input) { |output = input| return yield(output) }) end end # @param [Object] input # # @return [Result::Success] # # @api public def try(input = Undefined) result = type.try(input) if result.success? Result::Success.new(Maybe(result.input)) else result end 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["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[name.to_s].maybe) end # Register coercible maybe types COERCIBLE.each_key do |name| register("maybe.coercible.#{name}", self["coercible.#{name}"].maybe) end end end