1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
# frozen_string_literal: true
module Unparser
module RequireBlock
private
# Raise error unless block is provided
#
# @raise [MissingBlockError]
# if no block is given
#
# @return [self]
def require_block
fail LocalJumpError unless block_given?
self
end
end # RequireBLock
class Either
include(
Adamantium,
Concord.new(:value),
RequireBlock
)
# Execute block and wrap error in left
#
# @param [Class<Exception>] exception
#
# @return [Either<Exception, Object>]
def self.wrap_error(*exceptions)
Right.new(yield)
rescue *exceptions => error
Left.new(error)
end
# Test for left constructor
#
# @return [Boolean]
def left?
instance_of?(Left)
end
# Test for right constructor
#
# @return [Boolean]
def right?
instance_of?(Right)
end
class Left < self
# Evaluate functor block
#
# @return [Either::Left<Object>]
def fmap(&block)
require_block(&block)
end
# Evaluate applicative block
#
# @return [Either::Left<Object>]
def bind(&block)
require_block(&block)
end
# Unwrap value from left
#
# @return [Object]
def from_left
value
end
# Unwrap value from right
#
# @return [Object]
#
def from_right
if block_given?
yield(value)
else
fail "Expected right value, got #{inspect}"
end
end
# Map over left value
#
# @return [Either::Right<Object>]
def lmap
Left.new(yield(value))
end
# Evaluate left side of branch
#
# @param [#call] left
# @param [#call] _right
def either(left, _right)
left.call(value)
end
end # Left
class Right < self
# Evaluate functor block
#
# @return [Either::Right<Object>]
def fmap
Right.new(yield(value))
end
# Evaluate applicative block
#
# @return [Either<Object>]
def bind
yield(value)
end
# Unwrap value from left
#
# @return [Object]
#
def from_left
if block_given?
yield(value)
else
fail "Expected left value, got #{inspect}"
end
end
# Unwrap value from right
#
# @return [Object]
def from_right
value
end
# Map over left value
#
# @return [Either::Right<Object>]
def lmap(&block)
require_block(&block)
end
# Evaluate right side of branch
#
# @param [#call] _left
# @param [#call] right
def either(_left, right)
right.call(value)
end
end # Right
end # Either
end # Unparser
|