lib/rumonade/either.rb in rumonade-0.1.2 vs lib/rumonade/either.rb in rumonade-0.2.0

- old
+ new

@@ -58,10 +58,15 @@ # @return [Boolean] Returns +true+ if other is a +Left+ with an equal left value def ==(other) other.is_a?(Left) && other.left_value == self.left_value end + + # @return [String] Returns a +String+ representation of this object. + def to_s + "Left(#{left_value})" + end end # The right side of the disjoint union, as opposed to the Left side. class Right < Either # @param right_value the value to store in a +Right+, usually representing a success result @@ -74,10 +79,15 @@ # @return [Boolean] Returns +true+ if other is a +Right+ with an equal right value def ==(other) other.is_a?(Right) && other.right_value == self.right_value end + + # @return [String] Returns a +String+ representation of this object. + def to_s + "Right(#{right_value})" + end end # @param (see Left#initialize) # @return [Left] def Left(left_value) @@ -91,44 +101,156 @@ end class Either # Projects an Either into a Left. class LeftProjection + class << self + # @return [LeftProjection] Returns a +LeftProjection+ of the +Left+ of the given value + def unit(value) + self.new(Left(value)) + end + + # @return [LeftProjection] Returns the empty +LeftProjection+ + def empty + self.new(Right(nil)) + end + end + # @param either_value [Object] the Either value to project def initialize(either_value) @either_value = either_value end # @return Returns the Either value attr_reader :either_value + # @return [Boolean] Returns +true+ if other is a +LeftProjection+ with an equal +Either+ value def ==(other) other.is_a?(LeftProjection) && other.either_value == self.either_value end + # Binds the given function across +Left+. def bind(lam = nil, &blk) - !either_value.left? ? either_value : (lam || blk).call(either_value.left_value) + if !either_value.left? then either_value else (lam || blk).call(either_value.left_value) end end - alias_method :flat_map, :bind + + include Monad + + # @return [Boolean] Returns +false+ if +Right+ or returns the result of the application of the given function to the +Left+ value. + def any?(lam = nil, &blk) + either_value.left? && bind(lam || blk) + end + + # @return [Option] Returns +None+ if this is a +Right+ or if the given predicate does not hold for the +left+ value, otherwise, returns a +Some+ of +Left+. + def select(lam = nil, &blk) + Some(self).select { |lp| lp.any?(lam || blk) }.map { |lp| lp.either_value } + end + + # @return [Boolean] Returns +true+ if +Right+ or returns the result of the application of the given function to the +Left+ value. + def all?(lam = nil, &blk) + !either_value.left? || bind(lam || blk) + end + + # Returns the value from this +Left+ or raises +NoSuchElementException+ if this is a +Right+. + def get + if either_value.left? then either_value.left_value else raise NoSuchElementError end + end + + # Returns the value from this +Left+ or the given argument if this is a +Right+. + def get_or_else(val_or_lam = nil, &blk) + v_or_f = val_or_lam || blk + if either_value.left? then either_value.left_value else (v_or_f.respond_to?(:call) ? v_or_f.call : v_or_f) end + end + + # @return [Option] Returns a +Some+ containing the +Left+ value if it exists or a +None+ if this is a +Right+. + def to_opt + Option(get_or_else(nil)) + end + + # @return [Either] Maps the function argument through +Left+. + def map(lam = nil, &blk) + bind { |v| Left((lam || blk).call(v)) } + end + + # @return [String] Returns a +String+ representation of this object. + def to_s + "LeftProjection(#{either_value})" + end end # Projects an Either into a Right. class RightProjection + class << self + # @return [RightProjection] Returns a +RightProjection+ of the +Right+ of the given value + def unit(value) + self.new(Right(value)) + end + + # @return [RightProjection] Returns the empty +RightProjection+ + def empty + self.new(Left(nil)) + end + end + # @param either_value [Object] the Either value to project def initialize(either_value) @either_value = either_value end # @return Returns the Either value attr_reader :either_value + # @return [Boolean] Returns +true+ if other is a +RightProjection+ with an equal +Either+ value def ==(other) other.is_a?(RightProjection) && other.either_value == self.either_value end + # Binds the given function across +Right+. def bind(lam = nil, &blk) - !either_value.right? ? either_value : (lam || blk).call(either_value.right_value) + if !either_value.right? then either_value else (lam || blk).call(either_value.right_value) end end - alias_method :flat_map, :bind + + include Monad + + # @return [Boolean] Returns +false+ if +Left+ or returns the result of the application of the given function to the +Right+ value. + def any?(lam = nil, &blk) + either_value.right? && bind(lam || blk) + end + + # @return [Option] Returns +None+ if this is a +Left+ or if the given predicate does not hold for the +Right+ value, otherwise, returns a +Some+ of +Right+. + def select(lam = nil, &blk) + Some(self).select { |lp| lp.any?(lam || blk) }.map { |lp| lp.either_value } + end + + # @return [Boolean] Returns +true+ if +Left+ or returns the result of the application of the given function to the +Right+ value. + def all?(lam = nil, &blk) + !either_value.right? || bind(lam || blk) + end + + # Returns the value from this +Right+ or raises +NoSuchElementException+ if this is a +Left+. + def get + if either_value.right? then either_value.right_value else raise NoSuchElementError end + end + + # Returns the value from this +Right+ or the given argument if this is a +Left+. + def get_or_else(val_or_lam = nil, &blk) + v_or_f = val_or_lam || blk + if either_value.right? then either_value.right_value else (v_or_f.respond_to?(:call) ? v_or_f.call : v_or_f) end + end + + # @return [Option] Returns a +Some+ containing the +Right+ value if it exists or a +None+ if this is a +Left+. + def to_opt + Option(get_or_else(nil)) + end + + # @return [Either] Maps the function argument through +Right+. + def map(lam = nil, &blk) + bind { |v| Right((lam || blk).call(v)) } + end + + # @return [String] Returns a +String+ representation of this object. + def to_s + "RightProjection(#{either_value})" + end end end end \ No newline at end of file