Skip to content

Instantly share code, notes, and snippets.

@pje
Created May 2, 2018 19:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pje/81aeda476cb98c703edc6c89d461c43f to your computer and use it in GitHub Desktop.
Save pje/81aeda476cb98c703edc6c89d461c43f to your computer and use it in GitHub Desktop.
Simple implementation of the Either type for Ruby (except Left is called Failure and Right is Success)
class Either
attr_reader :value, :error
def initialize(_) ; raise(NotImplementedError.new) ; end
def failure? ; is_a?(Failure) ; end
def success? ; is_a?(Success) ; end
def get_or_else(_) ; raise(NotImplementedError.new) ; end
def map ; raise(NotImplementedError.new) ; end
def ==(other)
[:class, :value, :error].all? { |s| public_send(s) == other.public_send(s) }
end
def hash
[value, error].hash
end
alias :eql? :==
alias :left? :failure?
alias :right? :success?
end
class Failure < Either
def initialize(error)
@error = error
end
def get_or_else(value)
value
end
def map
Failure.new(error)
end
end
class Success < Either
def initialize(value)
@value = value
end
def get_or_else(_)
value
end
def map
Success.new(yield(value))
end
end
require "minitest/autorun"
require_relative "either"
class TestFailure < Minitest::Test
def setup
@either = Failure.new("foo")
end
def test_failure?
assert @either.failure?
end
def test_success?
refute @either.success?
end
def test_map
assert_equal Failure.new("foo"), @either.map { |e| "bar" }
end
def test_get_or_else
assert_equal "bar", @either.get_or_else("bar")
end
def test_equality
assert_equal @either, Failure.new("foo")
end
def test_inequality
refute_equal @either, Failure.new("bar")
end
end
class TestSuccess < Minitest::Test
def setup
@either = Success.new("foo")
end
def test_failure?
refute @either.failure?
end
def test_success?
assert @either.success?
end
def test_map
assert_equal Success.new("bar"), @either.map { |e| "bar" }
end
def test_get_or_else
assert_equal "foo", @either.get_or_else("bar")
end
def test_equality
assert_equal @either, Success.new("foo")
end
def test_inequality
refute_equal @either, Success.new("bar")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment