Skip to content

Instantly share code, notes, and snippets.

@MiroslavCsonka
Created July 11, 2016 13:35
Show Gist options
  • Save MiroslavCsonka/2b21b358aa14cd920d6c4884074735bd to your computer and use it in GitHub Desktop.
Save MiroslavCsonka/2b21b358aa14cd920d6c4884074735bd to your computer and use it in GitHub Desktop.
case class With[+A, +B](a: A, b: B)
case class Pass[A](value: A) extends Result[A]
case class Fail(errors: List[String]) extends Result[Nothing]
sealed trait Result[+A] {
def and[B](that: Result[B]): Result[A With B] = (this, that) match {
case (Pass(a), Pass(b)) => Pass(With(a, b))
case (Pass(_), Fail(e)) => Fail(e)
case (Fail(e), Pass(_)) => Fail(e)
case (Fail(e), Fail(thatE)) => Fail(e ++ thatE)
}
def map[B](f: A => B): Result[B] = flatMap((a) => Pass(f(a)))
def flatMap[B](f: (A) => Result[B]): Result[B] = this match {
case Pass(a) => f(a)
case Fail(e) => Fail(e)
}
}
def parseInt(number: String): Result[Int] = try {
Pass(number.toInt)
} catch {
case e: NumberFormatException => Fail(List(s"$number is not parsable to int"))
}
def validatePresence[K](map: Map[K, String], key: K): Result[String] = if (map.isDefinedAt(key)) {
Pass(map(key))
} else {
Fail(List(s"Key $key is not in the map"))
}
def validateEmail(email: String): Result[String] = Pass(email)
def isAdult(age: Int): Result[Int] = if (age >= 18) {
Pass(age)
} else {
Fail(List("Isnt old enough"))
}
case class Person(name: String, email: String, age: Int)
val form = Map(
"email" -> "[email protected]",
"age" -> "22",
"name" -> "Mirek"
)
val nameValidation = validatePresence(form, "name")
val emailValidation = validatePresence(form, "email").flatMap(validateEmail)
val ageValidation = validatePresence(form, "age").flatMap(parseInt).flatMap(isAdult)
nameValidation and emailValidation and ageValidation map {
case name With email With age => Person(name, email, age)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment