lib/kind/maybe/some.rb
# frozen_string_literal: true
require 'kind/dig'
require 'kind/presence'
module Kind
module Maybe
class Some < Monad
KindSymbol = ->(value) { STRICT.kind_of(::Symbol, value) }
VALUE_CANT_BE_NONE = "value can't be nil or Kind::Undefined".freeze
def self.[](value)
return new(value) if !KIND.nil_or_undefined?(value)
raise ArgumentError, VALUE_CANT_BE_NONE
end
def value_or(_default = UNDEFINED, &block)
@value
end
def none?; false; end
def map(method_name = UNDEFINED, &fn)
map!(method_name, &fn)
rescue StandardError => exception
None.new(exception)
end
alias_method :then, :map
alias_method :and_then, :map
def map!(method_name = UNDEFINED, &fn)
result = if UNDEFINED != method_name
return NONE_INSTANCE unless @value.respond_to?(KindSymbol[method_name])
@value.public_send(method_name)
else
fn.call(@value)
end
resolve(result)
end
alias_method :then!, :map!
alias_method :and_then!, :map!
def check(method_name = UNDEFINED, &fn)
result = if UNDEFINED != method_name
if method_name.kind_of?(::Symbol)
@value.respond_to?(method_name) ? @value.public_send(method_name) : NONE_INSTANCE
else
method_name === @value
end
else
fn.call(@value)
end
!result || KIND.nil_or_undefined?(result) ? NONE_INSTANCE : self
end
alias_method :accept, :check
def reject(method_name = UNDEFINED, &fn)
result = if UNDEFINED != method_name
if method_name.kind_of?(::Symbol)
@value.respond_to?(method_name) ? @value.public_send(method_name) : NONE_INSTANCE
else
method_name === @value
end
else
fn.call(@value)
end
result || KIND.nil_or_undefined?(result) ? NONE_INSTANCE : self
end
def try!(method_name = UNDEFINED, *args, &block)
return __try_block__(block, args) if block
return __try_method__(method_name, args) if UNDEFINED != method_name
raise ArgumentError, 'method name or a block must be present'
end
def try(method_name = UNDEFINED, *args, &block)
return __try_block__(block, args) if block
return __try_method__(method_name, args) if value.respond_to?(method_name)
NONE_INSTANCE
rescue TypeError
NONE_INSTANCE
end
def dig(*keys)
resolve(Dig.call!(value, keys))
end
def presence
resolve(Presence.(value))
end
def inspect
'#<%s value=%s>' % ['Kind::Some', value.inspect]
end
private
def __try_method__(method_name, args)
__try_block__(KindSymbol[method_name].to_proc, args)
end
def __try_block__(block, args)
result = args.empty? ? block.call(value) : block.call(*args.unshift(value))
resolve(result)
end
def resolve(result)
return result if Maybe::None === result
return NONE_INSTANCE if KIND.nil_or_undefined?(result)
return None.new(result) if ::Exception === result
Some.new(result)
end
private_constant :KindSymbol, :VALUE_CANT_BE_NONE
end
end
end