# frozen_string_literal: true module Zx class Result class FailureError < StandardError; end def initialize @value = nil @success = true @exception = false @type = nil end attr_reader :value, :type def error @value unless type == :ok end def success? !!@success end def failure? !success? end def value! @value || raise(FailureError) end def deconstruct [type, value] end def deconstruct_keys(_) { type: type, value: value, error: error } end def on_unknown(&block) __execute__(nil, &block) end def on_success(tag = nil, &block) return self if failure? __execute__(tag, &block) self end def on_failure(tag = nil, &block) return self if success? __execute__(tag, &block) self end def on(ontype, tag = nil, &block) case ontype.to_sym when :success then on_success(tag, &block) when :failure then on_failure(tag, &block) end end alias >> on alias | on alias pipe on def then(&block) fmap(&block) end def step(&block) fmap(&block) end def fmap(&block) return self if failure? new_value = block.call @value @value = new_value self end def check(&block) return self if !!block.call(@value) failure! end def failure!(value = nil, type: :error) @type = type.to_sym @success = false @value = value self end def success!(value = nil, type: :ok) @type = type.to_sym @success = true @value = value self end def __execute__(tag = nil, &block) return block.call(@value, [@type, @success]) if tag.nil? block.call(@value, [@type, @success]) if @type == tag.to_sym end private :__execute__ def Success(value = nil, options = {}) success!(value, type: options.fetch(:type, :ok)) end def Success!(value = nil, options = {}) success!(value, type: options.fetch(:type, :ok)) end def Failure(value = nil, options = {}) failure!(value, type: options.fetch(:type, :error)) end def Failure!(value = nil, options = {}) failure!(value, type: options.fetch(:type, :error)) end def self.Success(value = nil, options = {}) new.success!(value, type: options.fetch(:type, :ok)) end def self.Success!(...) Success(...) end def self.Failure(value = nil, options = {}) new.failure!(value, type: options.fetch(:type, :error)) end def self.Failure!(...) Failure(...) end Success = ->(*kwargs) { Success(*kwargs) } Failure = ->(*kwargs) { Failure(*kwargs) } end end