lib/rumonade/either.rb in rumonade-0.2.2 vs lib/rumonade/either.rb in rumonade-0.3.0
- old
+ new
@@ -42,19 +42,52 @@
# @return [RightProjection] Projects this Either as a Right.
def right
RightProjection.new(self)
end
- # @param [Either] other the either to combine with
- # @return [Either] Returns a +Left+ with all Left values (if any), otherwise a +Right+ with all Right values
- def +(other)
- if [self, other].any?(&:left?)
- Left([self, other].map { |either| either.left.to_opt }.flatten)
- else
- Right([self, other].map { |either| either.right.to_opt }.flatten)
- end
+ # Default concatenation function used by {#+}
+ DEFAULT_CONCAT = lambda { |a,b| a + b }
+
+ # @param [Either] other the other +Either+ to concatenate
+ # @param [Hash] opts the options to concatenate with
+ # @option opts [Proc] :concat_left (DEFAULT_CONCAT) The function to concatenate +Left+ values
+ # @option opts [Proc] :concat_right (DEFAULT_CONCAT) the function to concatenate +Right+ values
+ # @yield [right_value] optional block to transform concatenated +Right+ values
+ # @yieldparam [Object] right_values the concatenated +Right+ values yielded to optional block
+ # @return [Either] if both are +Right+, returns +Right+ with +right_value+'s concatenated,
+ # otherwise a +Left+ with +left_value+'s concatenated
+ def +(other, opts = {})
+ opts = { :concat_left => DEFAULT_CONCAT, :concat_right => DEFAULT_CONCAT }.merge(opts)
+ result =
+ case self
+ when Left
+ case other
+ when Left then Left(opts[:concat_left].call(self.left_value, other.left_value))
+ when Right then Left(self.left_value)
+ end
+ when Right
+ case other
+ when Left then Left(other.left_value)
+ when Right then Right(opts[:concat_right].call(self.right_value, other.right_value))
+ end
+ end
+ if block_given? then result.right.map { |right_values| yield right_values } else result end
end
+ alias_method :concat, :+
+
+ # @return [Either] returns an +Either+ of the same type, with the +left_value+ or +right_value+
+ # lifted into an +Array+
+ def lift_to_a
+ lift(Array)
+ end
+
+ # @param [#unit] monad_class the {Monad} to lift the +Left+ or +Right+ value into
+ # @return [Either] returns an +Either+of the same type, with the +left_value+ or +right_value+
+ # lifted into +monad_class+
+ def lift(monad_class)
+ fold(lambda {|l| Left(monad_class.unit(l)) }, lambda {|r| Right(monad_class.unit(r))})
+ end
end
# The left side of the disjoint union, as opposed to the Right side.
class Left < Either
# @param left_value the value to store in a +Left+, usually representing a failure result
@@ -72,10 +105,15 @@
# @return [String] Returns a +String+ representation of this object.
def to_s
"Left(#{left_value})"
end
+
+ # @return [String] Returns a +String+ containing a human-readable representation of this object.
+ def inspect
+ "Left(#{left_value.inspect})"
+ 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
@@ -93,10 +131,15 @@
# @return [String] Returns a +String+ representation of this object.
def to_s
"Right(#{right_value})"
end
+
+ # @return [String] Returns a +String+ containing a human-readable representation of this object.
+ def inspect
+ "Right(#{right_value.inspect})"
+ end
end
# @param (see Left#initialize)
# @return [Left]
def Left(left_value)
@@ -182,10 +225,15 @@
# @return [String] Returns a +String+ representation of this object.
def to_s
"LeftProjection(#{either_value})"
end
+
+ # @return [String] Returns a +String+ containing a human-readable representation of this object.
+ def inspect
+ "LeftProjection(#{either_value.inspect})"
+ end
end
# Projects an Either into a Right.
class RightProjection
class << self
@@ -257,9 +305,14 @@
end
# @return [String] Returns a +String+ representation of this object.
def to_s
"RightProjection(#{either_value})"
+ end
+
+ # @return [String] Returns a +String+ containing a human-readable representation of this object.
+ def inspect
+ "RightProjection(#{either_value.inspect})"
end
end
end
end
\ No newline at end of file