Last active
August 29, 2015 13:56
-
-
Save Chandler/8930439 to your computer and use it in GitHub Desktop.
Either Builder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait NotSatisfied { def reason: String } | |
case class MissingOption(reason: String) extends NotSatisfied | |
case class IncorrectBoolean(reason: String) extends NotSatisfied | |
/** | |
* Convert Option[T] to Either.RightProjection[MissingOption, T] | |
* for use in a for comprehension | |
* | |
* @param opt the option to consider | |
* @param e the error message string | |
* @return Either.RightProjection[MissingOption, T] | |
*/ | |
class OptionToEither[T](opt: Option[T]) { | |
def orError(e: String): Either.RightProjection[MissingOption, T] = { | |
opt match { | |
case Some(t) => Right(t).right | |
case None => Left(MissingOption(e)).right | |
} | |
} | |
} | |
/** | |
* Convert Boolean to Either.RightProjection[IncorrectBoolean, T] | |
* for use in a for comprehension | |
* | |
* @param found the boolean to consider | |
* @param required the required boolean | |
* @param e the error message string | |
* @return Either.RightProjection[IncorrectBoolean, Boolean] | |
*/ | |
class BooleanToEither(found: Boolean) { | |
def mustBe(required: Boolean, e: String): Either.RightProjection[IncorrectBoolean, Boolean] = { | |
if(found == required) | |
Right(found).right | |
else | |
Left(IncorrectBoolean(e)).right | |
} | |
} | |
/** | |
* Implicit method for converting Option[T] to OptionToEither | |
* | |
* Allows you to call myOption.onError("a error message") | |
* in a for comprehension and get back Either.RightProjection[MissingOption, T] | |
* | |
* @param opt the option to consider | |
* @return OptionToEither | |
*/ | |
implicit def BuildOptionToEither[T](opt: Option[T]) = new OptionToEither(opt) | |
/** | |
* Implicit method for converting Boolean to OptionToBoolean | |
* Allows you to call myBool.mustBe(true, "the value wasn't true") | |
* in a for comprehension and get back Either.RightProjection[IncorrectBoolean, Boolean] | |
* | |
* @param bool the boolean to consider | |
* @return BooleanToEither | |
*/ | |
implicit def BuildBooleanToEither(bool: Boolean) = new BooleanToEither(bool) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Example of how to use Eithers to get error messages out of a for comprehension | |
case class Person( | |
name: Option[String], | |
age: Option[Int]) { | |
} | |
def isTeenager(age: Int): Boolean = age > 12 && age < 20 | |
val people = List( | |
new Person(name = Some("alex"), age = Some(10)), | |
new Person(name = Some("sasha"), age = Some(16)), | |
new Person(name = None, age = Some(18)), | |
new Person(name = Some("chrissy"), age = None), | |
new Person(name = Some("mike"), age = Some(15)), | |
new Person(name = None, age = Some(100)) | |
) | |
/** | |
* Return the name of a person if they're a teenager, | |
* otherwise return an error message explaining why | |
* they aren't a teenager. | |
* | |
* @param person a Person to check for being teenage | |
* @return an either containing the name or the error message | |
*/ | |
def nameOfTeenager(person: Person): Either[NotSatisfied,String] = | |
for { | |
name <- person.name.orError("missing name") //if person.name is a none, return this error message | |
age <- person.age.orError("missing age") //same for person.age | |
_ <- isTeenager(age).mustBe(true, "is not a teenager") //isTeeanger must be true, otherwise return an error message | |
} yield { | |
name | |
} | |
val (names, errors) = people | |
.map { nameOfTeenager(_) } | |
.partition{ _.isRight } | |
//Teenagers: List(mike, sasha) | |
names.collect { case Right(t) => t } | |
//Errors: List(is not a teenager, missing name, missing age, missing name) | |
errors.collect { case Left(t) => t } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment