Skip to content

Commit

Permalink
Add JsResult#withFilter to avoid warnings in for-comprehensions
Browse files Browse the repository at this point in the history
Fix JsResult#map to satisfy the identity functor law
  • Loading branch information
julienrf committed Sep 21, 2012
1 parent 2aeec7b commit 59fae0e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,16 @@ object JsError {
}
}

sealed trait JsResult[+A] {
sealed trait JsResult[+A] { self =>

def fold[X](invalid: Seq[(JsPath, Seq[ValidationError])] => X, valid: A => X): X = this match {
case JsSuccess(v,_) => valid(v)
case JsError(e) => invalid(e)
}

def map[X](f: A => X): JsResult[X] = this match {
case JsSuccess(v,_) => JsSuccess(f(v))
case JsError(e) => JsError(e)
case JsSuccess(v, path) => JsSuccess(f(v), path)
case e: JsError => e
}

def filterNot(error:ValidationError)(p: A => Boolean): JsResult[A] =
Expand All @@ -71,7 +72,34 @@ sealed trait JsResult[+A] {

def flatMap[X](f: A => JsResult[X]): JsResult[X] = this match {
case JsSuccess(v, path) => f(v).repath(path)
case JsError(e) => JsError(e)
case e: JsError => e
}

def foreach(f: A => Unit): Unit = this match {
case JsSuccess(a, _) => f(a)
case _ => ()
}

def withFilter(p: A => Boolean) = new WithFilter(p)

final class WithFilter(p: A => Boolean) {
def map[B](f: A => B): JsResult[B] = self match {
case JsSuccess(a, path) =>
if (p(a)) JsSuccess(f(a), path)
else JsError()
case e: JsError => e
}
def flatMap[B](f: A => JsResult[B]): JsResult[B] = self match {
case JsSuccess(a, path) =>
if (p(a)) f(a).repath(path)
else JsError()
case e: JsError => e
}
def foreach(f: A => Unit): Unit = self match {
case JsSuccess(a, _) if p(a) => f(a)
case _ => ()
}
def withFilter(q: A => Boolean) = new WithFilter(a => p(a) && q(a))
}

//def rebase(json: JsValue): JsResult[A] = fold(valid = JsSuccess(_), invalid = (_, e, g) => JsError(json, e, g))
Expand All @@ -80,7 +108,7 @@ sealed trait JsResult[+A] {
case JsError(es) => JsError(es.map{ case (p, s) => path ++ p -> s })
}

def get:A
def get: A

def getOrElse[AA >: A](t: => AA):AA = this match {
case JsSuccess(a,_) => a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,4 +482,27 @@ object JsonValidSpec extends Specification {
}
}

"JsResult" should {

"be usable in for-comprehensions" in {
val res = JsSuccess("foo")
val x = for {
s <- res
if s.size < 5
} yield 42
x must equalTo (JsSuccess(42))
}

"be a functor" in {
"JsSuccess" in {
val res1: JsResult[String] = JsSuccess("foo", JsPath(List(KeyPathNode("bar"))))
res1.map(identity) must equalTo (res1)
}

"JsError" in {
val res2: JsResult[String] = JsError(Seq(JsPath(List(KeyPathNode("bar"))) -> Seq(ValidationError("baz.bah"))))
res2.map(identity) must equalTo (res2)
}
}
}
}

0 comments on commit 59fae0e

Please sign in to comment.