Skip to content

Instantly share code, notes, and snippets.

@gabfssilva
Created October 11, 2017 19:54
Show Gist options
  • Save gabfssilva/2e625227b8dc017b84f02a05d4576659 to your computer and use it in GitHub Desktop.
Save gabfssilva/2e625227b8dc017b84f02a05d4576659 to your computer and use it in GitHub Desktop.
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