Last active
December 28, 2015 04:09
-
-
Save ardok/7440233 to your computer and use it in GitHub Desktop.
Box helper for Lift
This file contains 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
import scalaz._ | |
import Scalaz._ | |
import xml.{Elem, NodeSeq} | |
import net.liftweb.util.CssSel | |
import net.liftweb.util.Helpers._ | |
import net.liftweb.http.js.JsCmds.Noop | |
import net.liftweb.http.js.JsCmd | |
import net.liftweb.common.{Failure, Full, Box, Empty} | |
/** | |
* Example: | |
* | |
* import scalaz._ | |
* import Scalaz._ | |
* | |
* | |
* val str: Box[String] = Empty | |
* ~str // "" | |
* | |
* val str: Box[String] = Failure("failure") | |
* ~str // "" | |
* | |
* val ns: Box[NodeSeq] = Empty | |
* ~ns // NodeSeq.Empty | |
* | |
* val ns: Box[NodeSeq] = Empty | |
* ns | <lift:children>it failed!</lift:children> // output the xml | |
* | |
* val result: Box[String] = Full("") | |
* result >| S.notice("Successful") // don't care about result value if it's Full | |
* | |
* val str: String = null | |
* str.box // will be Empty | |
* | |
* `isTrueBox` and `isNotTrueBox` will be useful in a `for {} yield {}` situation | |
* Same case for `toBox` when you want to return a `Box` type in a `for yield` but the first `flatMap` | |
* happens to an `Option`. Hence, you can do `for { str <- optionStr.toBox ... } yield {}` | |
* | |
*/ | |
object BoxHelper { | |
implicit val nodeSeqMonoid: Monoid[NodeSeq] = Monoid.instance(_ ++ _, NodeSeq.Empty) | |
implicit val listNodeSeqMonoid: Monoid[List[NodeSeq]] = Monoid.instance(_ ++ _, List(NodeSeq.Empty)) | |
implicit val cssSelMonoid: Monoid[CssSel] = Monoid.instance(_ & _, "*" #> NodeSeq.Empty) | |
implicit val listCssSelMonoid: Monoid[List[CssSel]] = Monoid.instance(_ ++ _, List("*" #> NodeSeq.Empty)) | |
implicit val elemMonoid: Monoid[Elem] = Monoid.instance((x, y) => <lift:children>{x}{y}</lift:children>, <lift:children></lift:children>) | |
implicit val jsCmdMonoid: Monoid[JsCmd] = Monoid.instance(_ & _, Noop) | |
implicit val throwableMonoid: Monoid[Throwable] = | |
Monoid.instance((x, y) => new Throwable(x.getMessage + "\n" + y.getMessage), new Throwable("Failure without exception")) | |
implicit final class RichBoxBoolean(boxBoolean: Box[Boolean]) { | |
def orFalse: Boolean = boxBoolean openOr false | |
def orTrue: Boolean = boxBoolean openOr true | |
} | |
implicit final class BoxZero[T: Monoid](a: Box[T]) { | |
/** | |
* Open the box or return the Zero value of that type | |
* @return value of the box or Zero value of that type | |
*/ | |
def unary_~(implicit z: Monoid[T]): T = a openOr z.zero | |
/** | |
* Same like `unary_~` | |
*/ | |
def orZero(implicit z: Monoid[T]): T = a openOr z.zero | |
} | |
implicit final class RichBox[T](a: Box[T]) { | |
/** | |
* Follow Scalaz `|` | |
* Alias for `openOr` | |
* @return value of the box or `default` | |
*/ | |
def `|`(default: => T): T = a openOr default | |
/** | |
* Alias for `.map(_ => do_something)` | |
*/ | |
def >|[B](f: => B): Box[B] = a.map(_ => f) | |
/** | |
* Alias for `openOrThrowException` with its exception message set | |
* @return the value of the box or exception throw | |
*/ | |
def open: T = a.openOrThrowException("Trying to open a Failure / an Empty") | |
/** | |
* Alias for `openOrThrowException` | |
* @param exceptionMsg msg for exception | |
* @return the value of the box or exception throw | |
*/ | |
def open(exceptionMsg: String): T = a.openOrThrowException(exceptionMsg) | |
/** | |
* This is the same as Scalaz tuple operator | |
* @return Full(tuple) of the values or Empty | |
*/ | |
def tuple[B](b: => Box[B]): Box[(T, B)] = | |
a.toOption tuple b.toOption match { | |
case Some((x, y)) => Full((x, y)) | |
case _ => Empty | |
} | |
/** | |
* Execute a function of `T => Any` if it's a `Full` | |
*/ | |
def ifFull(map: T => Any): Any = a match { | |
case Full(f) => map(f) | |
case _ => Unit | |
} | |
/** | |
* Execute a function of `T => Any` if it's a `Failure` | |
*/ | |
def ifFailure(map: Failure => Any): Any = a match { | |
case f @ Failure(_,_,_) => map(f) | |
case _ => Unit | |
} | |
/** | |
* Execute a function of `T => Any` if it's an `Empty` | |
*/ | |
def ifEmpty(map: () => Any): Any = a match { | |
case Empty => map | |
case _ => Unit | |
} | |
} | |
implicit final class OptionToBox[T](o: Option[T]) { | |
/** | |
* Similar to `.toOption` from Box | |
* Alias for `Box` constructor | |
* @return a Box of the Option value that is passed in | |
*/ | |
def toBox: Box[T] = Box(o) | |
} | |
implicit final class ToBox[T](s: T) { | |
/** | |
* Wrap any type into a Box() by using `Box !!`, hence using `legacyNullTest` | |
* `null` will be converted to Empty | |
* @return value wrapped in a Box (Full) | |
*/ | |
def box: Box[T] = Box !! s | |
} | |
implicit final class BoxBoolean[T <: Boolean](a: Box[T]) { | |
/** | |
* Value of contained Boolean if it exists, false otherwise | |
* @return NonEmpty of the same value | |
*/ | |
def isTrue: Boolean = a.exists(identity) | |
/** | |
* Check whether the value inside the Box is true | |
* @return the Box itself | |
*/ | |
def isTrueBox: Box[Boolean] = a.filter(_ == true) | |
/** | |
* Check whether the value inside the Box is false | |
* @return the Box itself | |
*/ | |
def isNotTrueBox: Box[Boolean] = a.filter(_ == false) | |
} | |
// extra for Java lovers (`null` boolean) | |
implicit def JavaBooleanToScala(x: java.lang.Boolean): Boolean = Option(x).map(_.booleanValue) getOrElse false | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment