Created
October 11, 2017 19:54
-
-
Save gabfssilva/2e625227b8dc017b84f02a05d4576659 to your computer and use it in GitHub Desktop.
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
private object Validations { | |
trait Validator[F[_], T] { | |
def validate(field: F[T]): Boolean | |
} | |
trait NotEmpty[F[_], T] extends Validator[F, T] | |
trait NotBlank[F[_], T] extends Validator[F, T] | |
trait Contains[F[_], T] extends Validator[F, T] | |
implicit def optionNotEmpty[T]: NotEmpty[Option, T] = new NotEmpty[Option, T] { | |
override def validate(field: Option[T]): Boolean = field.isDefined | |
} | |
implicit def listNotEmpty[T]: NotEmpty[List, T] = new NotEmpty[List, T] { | |
override def validate(field: List[T]): Boolean = field.nonEmpty | |
} | |
implicit def optionNotBlank: NotBlank[Option, String] = new NotBlank[Option, String] { | |
override def validate(field: Option[String]): Boolean = field.isDefined | |
} | |
implicit def contains[T]: T => Contains[Option, T] = item => new Contains[Option, T] { | |
override def validate(field: Option[T]): Boolean = field.contains(item) | |
} | |
val notNull: Option[String] => Boolean = field => field.isDefined && field.orNull.nonEmpty | |
def notEmpty[F[_], T](field: F[T])(implicit ev: NotEmpty[F, T]): Boolean = ev.validate(field) | |
def notBlank[F[_], T](field: F[T])(implicit ev: NotBlank[F, T]): Boolean = ev.validate(field) | |
def contains[F[_], T](item: T, field: F[T])(implicit ev: T => Contains[F, T]): Boolean = ev(item).validate(field) | |
case class Violations(failures: List[IllegalArgumentException]) extends RuntimeException { | |
def validate() = if(failures.nonEmpty) throw this | |
override def toString: String = failures.map(e => e.getMessage).mkString(",") | |
} | |
case class Rule(precondition: Boolean, message: () => String) | |
case class Require(rule: Rule, last: Option[Require] = None) { | |
def and(precondition: Boolean, message: => String): Require = { | |
Require(Rule(precondition, () => message), Some(this)) | |
} | |
def eval(): Violations = this match { | |
case Require(Rule(false, message), Some(l)) => | |
Violations(new IllegalArgumentException(message()) :: l.eval().failures) | |
case Require(Rule(false, message), None) => | |
Violations(List(new IllegalArgumentException(message()))) | |
case Require(Rule(true, _), Some(l)) => | |
Violations(l.eval().failures) | |
case Require(Rule(true, _), None) => | |
Violations(List.empty) | |
} | |
} | |
def requireThat(value: Boolean, message: => String) = Require(Rule(value, () => message)) | |
} | |
object Sample extends App { | |
case class Test(valueOne: Option[String], valueTwo: Option[String]) { | |
requireThat(notBlank(valueOne), "valueOne cannot be null") | |
.and(notBlank(valueTwo), "valueTwo cannot be null") | |
.eval() | |
.validate() | |
} | |
Test(None, Some("a")) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment