diff --git a/src/main/scala/gov/wicourts/json/formlet/Formlet.scala b/src/main/scala/gov/wicourts/json/formlet/Formlet.scala index d1d1f06..46450cb 100644 --- a/src/main/scala/gov/wicourts/json/formlet/Formlet.scala +++ b/src/main/scala/gov/wicourts/json/formlet/Formlet.scala @@ -8,7 +8,7 @@ import scalaz.NonEmptyList.nel import scalaz.std.function._ import scalaz.std.option._ -import scalaz.syntax.applicative._ +import scalaz.syntax.monad._ import scalaz.syntax.monoid._ import scalaz.syntax.validation._ @@ -171,6 +171,20 @@ case class Formlet[M[_], I, V, E, A](run: I => M[(Validation[E, A], V)]) { def local[X](f: X => I): Formlet[M, X, V, E, A] = Formlet(run compose f) def contramap[X](f: X => I): Formlet[M, X, V, E, A] = local(f) + + def orElse( + x: => Formlet[M, I, V, E, A] + )( + implicit M: Monad[M] + ): Formlet[M, I, V, E, A] = + Formlet(i => + this.run(i).flatMap { case (result, view) => + result.fold( + _ => x.run(i), + j => M.point((j.success[E], view)) + ) + } + ) } object Formlet { diff --git a/src/test/scala/gov/wicourts/json/formlet/FormsSpec.scala b/src/test/scala/gov/wicourts/json/formlet/FormsSpec.scala index 41f5b56..f3bb85b 100644 --- a/src/test/scala/gov/wicourts/json/formlet/FormsSpec.scala +++ b/src/test/scala/gov/wicourts/json/formlet/FormsSpec.scala @@ -106,6 +106,15 @@ class FormsSpec extends Specification { val results = r.obj.eval(None) results.leftMap(_.toJson.nospaces) must_== """{"nameLOther":["Nope"]}""".failure } + + "can fail to an alternative" >> { + val failing = string("nameL", None) + .mapValidation(_ => "No way!".failureNel[Option[String]]) + val good = string("nameL", None) + .mapValidation(_ => "Success!".some.successNel[String]) + val results = (failing orElse good).obj.eval(None) + results must_== "Success!".some.success + } } "A number form" >> {