Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
2626 lines (1855 sloc) 41.2 KB
#LyX 1.6.10 created this file. For more info see http://www.lyx.org/
\lyxformat 345
\begin_document
\begin_header
\textclass book
\use_default_options false
\language english
\inputencoding auto
\font_roman default
\font_sans default
\font_typewriter default
\font_default_family default
\font_sc false
\font_osf false
\font_sf_scale 100
\font_tt_scale 100
\graphics default
\paperfontsize default
\spacing single
\use_hyperref false
\papersize default
\use_geometry false
\use_amsmath 1
\use_esint 1
\cite_engine basic
\use_bibtopic false
\paperorientation portrait
\secnumdepth 3
\tocdepth 3
\paragraph_separation indent
\defskip medskip
\quotes_language english
\papercolumns 1
\papersides 1
\paperpagestyle default
\tracking_changes false
\output_changes false
\author ""
\author ""
\end_header
\begin_body
\begin_layout Chapter
Lift Helpers
\begin_inset CommandInset label
LatexCommand label
name "cha:Lift-Helpers"
\end_inset
\end_layout
\begin_layout Section
Introduction
\begin_inset CommandInset label
LatexCommand label
name "sec:Introduction"
\end_inset
\end_layout
\begin_layout Standard
Lift provides a fairly useful collection of helper artifacts.
The helpers are essentially utility functions that minimize the need for
boilerplate code.
This appendix is intended to introduce some of the more common utility
classes and objects to you so that you’re familiar with them.
If you would like more details, you can look at the API documentation for
the
\family typewriter
net.liftweb.util package
\family default
.
\end_layout
\begin_layout Section
Box (or Scala's Option class on steroids)
\begin_inset CommandInset label
LatexCommand label
name "sec:Box-(or-Scala's"
\end_inset
\end_layout
\begin_layout Standard
\family typewriter
net.liftweb.util.Box
\family default
(or Scala’s
\family typewriter
scala.Option
\family default
class on steroids) is a utility class that mimics Scala’s
\family typewriter
Option
\family default
type (also heavily used inside Lift).
To understand some of the underlying concepts and assumptions, let’s take
a quick look at
\family typewriter
Option
\family default
class first.
The
\family typewriter
Option
\family default
class allows a type-safe way of dealing with a situation where you may
or may not have a result.
\family typewriter
Option
\family default
has two values, either
\family typewriter
Some(value)
\family default
, where
\family typewriter
value
\family default
is actually the value, and
\family typewriter
None
\family default
, which is used to represent nothing.
A typical example for
\family typewriter
Option
\family default
is outlined using Scala’s Map type.
Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Option-and-Map"
\end_inset
shows a definition of a
\family typewriter
Map
\family default
, a successful attempt to get the value of key
\family typewriter
a
\family default
, and an attempt to get the value of key
\family typewriter
i
\family default
.
Notice that when we retrieved the existing key-value pair for
\family typewriter
a
\family default
, the value returned was
\family typewriter
Some(A)
\family default
and when we asked for the value of key
\family typewriter
i
\family default
, we received None.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Option and Map example
\begin_inset CommandInset label
LatexCommand label
name "lst:Option-and-Map"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
scala> val cap = Map("a" -> "A", "b" -> "B")
\end_layout
\begin_layout Plain Layout
cap: scala.collection.immutable.Map[java.lang.String,java.lang.String] =
\end_layout
\begin_layout Plain Layout
Map(a -> A, b -> B)
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
scala> cap.get("a")
\end_layout
\begin_layout Plain Layout
res1: Option[java.lang.String] = Some(A)
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
scala> cap.get("i")
\end_layout
\begin_layout Plain Layout
res2: Option[java.lang.String] = None
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Getting the value out of an
\family typewriter
Option
\family default
is usually handled via Scala’s matching mechanism or via the
\family typewriter
getOrElse
\family default
function, as shown in Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Fetch-value-from"
\end_inset
:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Fetch value from an Option
\begin_inset CommandInset label
LatexCommand label
name "lst:Fetch-value-from"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
def prettyPrint(foo: Option[String]): String = foo match {
\end_layout
\begin_layout Plain Layout
case Some(x) => x
\end_layout
\begin_layout Plain Layout
case None => "Nothing found."
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
// Which would be used in conjunction with the previous code:
\end_layout
\begin_layout Plain Layout
scala> prettyPrint(cap.get("a"))
\end_layout
\begin_layout Plain Layout
res7: String = A
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
scala> prettyPrint(cap.get("i"))
\end_layout
\begin_layout Plain Layout
res8: String = Nothing found.
\end_layout
\end_inset
\end_layout
\begin_layout Standard
\family typewriter
Box
\family default
in Lift covers the same base functionality as
\family typewriter
Option
\family default
but expands the semantics for missing values.
If we have an
\family typewriter
Option
\family default
that is
\family typewriter
None
\family default
at some point, we can’t really tell why that
\family typewriter
Option
\family default
is
\family typewriter
None
\family default
, although in many situations, knowing why would be quite helpful.
With
\family typewriter
Box
\family default
, on the other hand, you have either have a
\family typewriter
Full
\family default
instance (corresponding to
\family typewriter
Some
\family default
with
\family typewriter
Option
\family default
) or an instance that subclasses
\family typewriter
EmptyBox
\family default
(corresponding to
\family typewriter
None
\family default
).
\family typewriter
EmptyBox
\family default
can either be an
\family typewriter
Empty
\family default
instance or a
\family typewriter
Failure
\family default
instance incorporating the cause for the failure.
So you can think of
\family typewriter
Box
\family default
as a container with three states: full, empty, or empty for a particular
reason.
The
\family typewriter
Failure
\family default
case class takes three arguments: a
\family typewriter
String
\family default
message to describe the failure, a
\family typewriter
Box[Throwable]
\family default
for an optional exception related to the failure, and a
\family typewriter
Box[Failure]
\family default
for chaining based on earlier
\family typewriter
Failure
\family default
s.
\end_layout
\begin_layout Standard
As an example of how we can use
\family typewriter
Box
\family default
instances in real code, consider the case where we have to do a bunch of
null checks, perform an operation, and then perform more null checks, other
operations, and so on.
Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Pseudocode-nested-operations"
\end_inset
shows an example of this sort of structure.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Pseudocode nested operations example
\begin_inset CommandInset label
LatexCommand label
name "lst:Pseudocode-nested-operations"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
x = getSomeValue();
\end_layout
\begin_layout Plain Layout
if (x != null) {
\end_layout
\begin_layout Plain Layout
y = getSomeOtherValue();
\end_layout
\begin_layout Plain Layout
if (y != null) {
\end_layout
\begin_layout Plain Layout
compute(x, y);
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\end_inset
\end_layout
\begin_layout Standard
This is tedious and error-prone in practice.
Now let’s see if we can do better by combining Lift’s
\family typewriter
Box
\family default
with Scala’s for comprehensions as shown in Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Scala-nested-operations"
\end_inset
.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Box nested operations example
\begin_inset CommandInset label
LatexCommand label
name "lst:Scala-nested-operations"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
def getSomeValue(): Box[Int] = Full(12)
\end_layout
\begin_layout Plain Layout
def getSomeOtherValue(): Box[Int] = Full(2)
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
def compute(x: Int, y: Int) = x * y
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
val res = for ( x <- getSomeValue();
\end_layout
\begin_layout Plain Layout
y <- getSomeOtherValue() if x > 10) yield compute(x,
y)
\end_layout
\begin_layout Plain Layout
println(res)
\end_layout
\end_inset
\end_layout
\begin_layout Standard
In Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Scala-nested-operations"
\end_inset
, we have two values,
\family typewriter
x
\family default
and
\family typewriter
y
\family default
, and we want to do some computation with these values.
But we must ensure that computation is done on the correct data.
For instance, the computation cannot be done if
\family typewriter
getSomeValue
\family default
returns no value.
In this context, the two functions return a
\family typewriter
Box[Int]
\family default
.
The interesting part is that if either or both of the two functions return
an
\family typewriter
Empty
\family default
Box instead of
\family typewriter
Full
\family default
(
\family typewriter
Empty
\family default
impersonating the nonexistence of the value), the
\family typewriter
res
\family default
value will also be
\family typewriter
Empty
\family default
.
However, if both functions return a
\family typewriter
Full
\family default
(like in Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Scala-nested-operations"
\end_inset
), the computation is called.
In our example the two functions return
\family typewriter
Full(12)
\family default
and
\family typewriter
Full(2)
\family default
, so
\family typewriter
res
\family default
will be a
\family typewriter
Full(24)
\family default
.
\end_layout
\begin_layout Standard
But we have something else interesting here: the
\family typewriter
if x > 10
\family default
statement (this is called a “guard” in Scala).
If the call to
\family typewriter
getSomeValue
\family default
returns a value less than or equal to 10, the
\family typewriter
y
\family default
variable won’t be initialized, and the res value will be
\family typewriter
Empty
\family default
.
This is just a taste of some of the power of using
\family typewriter
Box
\family default
for comprehensions; for more details on for comprehensions, see
\emph on
The Scala Language Specification
\emph default
, section 6.19, or one of the many Scala books available.
\end_layout
\begin_layout Standard
Lift’s
\family typewriter
Box
\family default
extends
\family typewriter
Option
\family default
with a few ideas, mainly the fact that you can add a message about why
a
\family typewriter
Box
\family default
is
\family typewriter
Empty
\family default
.
\family typewriter
Empty
\family default
corresponds to
\family typewriter
Option
\family default
’s
\family typewriter
None
\family default
and
\family typewriter
Full
\family default
to
\family typewriter
Option
\family default
’s Some.
So you can pattern match against a
\family typewriter
Box
\family default
as shown in Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Box-example"
\end_inset
.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Box example
\begin_inset CommandInset label
LatexCommand label
name "lst:Box-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
a match {
\end_layout
\begin_layout Plain Layout
Full(author) => Text("I found the author " + author.niceName)
\end_layout
\begin_layout Plain Layout
Empty => Text("No author by that name.")
\end_layout
\begin_layout Plain Layout
// message may be something like "Database disconnected."
\end_layout
\begin_layout Plain Layout
Failure(message, _, _) => Text("Nothing found due to " + message)
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
def confirmDelete {
\end_layout
\begin_layout Plain Layout
(for (val id <- param("id"); // get the ID
\end_layout
\begin_layout Plain Layout
val user <- User.find(id)) // find the user
\end_layout
\begin_layout Plain Layout
yield {
\end_layout
\begin_layout Plain Layout
user.delete_!
\end_layout
\begin_layout Plain Layout
notice("User deleted")
\end_layout
\begin_layout Plain Layout
redirectTo("/simple/index.html")
\end_layout
\begin_layout Plain Layout
}) getOrElse {error("User not found"); redirectTo("/simple/index.html")}
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\end_inset
\end_layout
\begin_layout Standard
In conjunction with Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Box-example"
\end_inset
, we can use other
\family typewriter
Box
\family default
functions, such as the
\family typewriter
openOr
\family default
function shown in Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:openOr-example"
\end_inset
.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
openOr example
\begin_inset CommandInset label
LatexCommand label
name "lst:openOr-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
lazy val UserBio = UserBio.find(By(UserBio.id, id)) openOr (new UserBio)
\end_layout
\begin_layout Plain Layout
def view (xhtml: NodeSeq): NodeSeq = passedAuthor.map({ author =>
\end_layout
\begin_layout Plain Layout
// do bind, etc here and return a NodeSeq
\end_layout
\begin_layout Plain Layout
}) openOr Text("Invalid author")
\end_layout
\end_inset
\end_layout
\begin_layout Standard
We won't be detailing all of the Box functions here, but a few words on
the most common function might be benficial.
\end_layout
\begin_layout Standard
\align center
\begin_inset Tabular
<lyxtabular version="3" rows="10" columns="3">
<features>
<column alignment="left" valignment="top" width="1in">
<column alignment="left" valignment="top" width="2.75in">
<column alignment="left" valignment="top" width="2in">
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Function name
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Description
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Short example.
Assume myBox is a Box
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
openOr
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Returns the value contained by this Box.
If the Box is Empty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox openOr
\begin_inset Quotes eld
\end_inset
The box is Empty
\begin_inset Quotes erd
\end_inset
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
map
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Apply a function on the values of this Box and return something else.
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox map (value => value +
\begin_inset Quotes eld
\end_inset
suffix
\begin_inset Quotes erd
\end_inset
)
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
dmap
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Equivalent with map(..) openOr default_value.
The default value will be returned in case the map is Empty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox dmap(
\begin_inset Quotes eld
\end_inset
default
\begin_inset Quotes erd
\end_inset
)(value => value +
\begin_inset Quotes eld
\end_inset
suffix
\begin_inset Quotes erd
\end_inset
)
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
!!
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
If the argument is null in will return an Empty, otherwise a Full containing
the arguent's value.
Note this this is a method on the Box object, not a given Box instance.
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Box !! (<a reference>)
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
?~
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Transforms an Empty to a Failure and passing a message.
If the Box is a Full it will just return
\family typewriter
this
\family default
.
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox ?~ (
\begin_inset Quotes eld
\end_inset
Error message
\begin_inset Quotes erd
\end_inset
)
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
isDefined
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Returns true if this Box contains a value
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox isDefined
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
isEmpty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Retun true is this Boxis empty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox isEmpty
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
asA[B]
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Return a Full[B] if the content of this Box is of type B, otherwise return
Empty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox asA[Person]
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
isA[B]
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Return a Full[B] if the contents of this Box is an instance of the specified
class, otherwise return Empty
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
myBox isA[Person]
\end_layout
\end_inset
</cell>
</row>
</lyxtabular>
\end_inset
\end_layout
\begin_layout Standard
Note that
\family typewriter
Box
\family default
contains a set of implicit conversion functions from/to
\family typewriter
Option
\family default
and from/to
\family typewriter
Iterable
\family default
.
\end_layout
\begin_layout Standard
Remember that Box is heavily used in Lift and most of the Lift's API's operates
with
\family typewriter
Box
\family default
es.
The rationale is to avoid
\family typewriter
n
\family default
ull references and to operate safely in context where values may be missing.
Of course, a
\family typewriter
Box
\family default
can be set to
\family typewriter
null
\family default
manually but we strongly recommend against doing so.
There are cases, however, where you are using some third party Java libraries
with APIs that return
\family typewriter
null
\family default
values.
To cope with such cases in Lift you can use the
\family typewriter
!!
\family default
function to
\family typewriter
Box
\family default
that value.
Listing
\begin_inset CommandInset ref
LatexCommand ref
reference "lst:Null-example"
\end_inset
shows how we can deal with a possible
\family typewriter
null
\family default
value.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Null example
\begin_inset CommandInset label
LatexCommand label
name "lst:Null-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
var x = getSomeValueThatMayBeNull();
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
var boxified = Box !! x
\end_layout
\begin_layout Plain Layout
\end_layout
\end_inset
\end_layout
\begin_layout Standard
In this case the
\family typewriter
boxified
\family default
variable will be
\family typewriter
Empty
\family default
if
\family typewriter
x
\family default
is
\family typewriter
null
\family default
or
\family typewriter
Full(x)
\family default
if
\family typewriter
x
\family default
is a valid value/reference..
\end_layout
\begin_layout Section
ActorPing
\begin_inset CommandInset label
LatexCommand label
name "sec:ActorPing"
\end_inset
\end_layout
\begin_layout Standard
It provides convenient functionality to schedule messages to Actors.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
ActorPing example
\begin_inset CommandInset label
LatexCommand label
name "lst:ActorPing-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
// Assume myActor an existing Actor
\end_layout
\begin_layout Plain Layout
// And a case object MyMessage
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
// Send the MyMessage message after 15 seconds
\end_layout
\begin_layout Plain Layout
ActorPing.schedule(myActor, MyMessage, 15 seconds)
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
// Send the MyMessage message every 15 seconds.
The cycle is stopped
\end_layout
\begin_layout Plain Layout
// if recipient actor exits or replied back with UnSchedule message
\end_layout
\begin_layout Plain Layout
ActorPing.scheduleAtFixedRate(myActor, MyMessage, 0 seconds, 15 seconds)
\end_layout
\end_inset
\end_layout
\begin_layout Section
ClassHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:ClassHelpers"
\end_inset
\end_layout
\begin_layout Standard
Provides convenient functions for loading classes using Java reflection,
instantiating dinamically loaded classes, invoking methods vis reflection
etc.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
ClassHelper example
\begin_inset CommandInset label
LatexCommand label
name "lst:ClassHelper-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
import _root_.net.liftweb.util.Helpers._
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
// lookup the class Bar in the three packages specified in th list
\end_layout
\begin_layout Plain Layout
findClass("Bar", "com.foo" :: "com.bar" :: "com.baz" :: Nil)
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
invokeMethod(myClass, myInstance, "doSomething")
\end_layout
\end_inset
\end_layout
\begin_layout Section
CodeHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:CodeHelpers"
\end_inset
\end_layout
\begin_layout Standard
Provides a convenient way of telling why a boolean expression failed.
For instance we are seeing manytime code like:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Expression example
\begin_inset CommandInset label
LatexCommand label
name "lst:Expression-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
var isTooYoung = false;
\end_layout
\begin_layout Plain Layout
var isTooBig = false;
\end_layout
\begin_layout Plain Layout
var isTooLazy = true;
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
var exp = isTooYoung && isTooBig && isTooLazy
\end_layout
\begin_layout Plain Layout
\end_layout
\end_inset
\end_layout
\begin_layout Standard
As you can see we have no way of telling if the exp was false because of
isTooYoung, isTooBig or isTooLazy unless we test them again.
But let's see this:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
CodeHelpers example
\begin_inset CommandInset label
LatexCommand label
name "lst:CodeHelpers-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
import net.liftweb.util._
\end_layout
\begin_layout Plain Layout
import net.liftweb.util.MonadicConversions._
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
val exp = (isTooYoung ~ "too young") &&
\end_layout
\begin_layout Plain Layout
(isTooBad ~ "too bad") &&
\end_layout
\begin_layout Plain Layout
(isToLazy ~ "too lazy")
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
println(exp match {
\end_layout
\begin_layout Plain Layout
case False(msgs) =>
\end_layout
\begin_layout Plain Layout
msgs mkString("Test failed because it is '", "' and '", "'.")
\end_layout
\begin_layout Plain Layout
case _ => "success"
\end_layout
\begin_layout Plain Layout
})
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Now if exp is a False we can tell why it failed as we have the messages
now.
\end_layout
\begin_layout Section
ControlHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:ControlHelpers"
\end_inset
\end_layout
\begin_layout Standard
Provides convenient functions for try/catch situations.
For example:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
ControlHelpers example
\begin_inset CommandInset label
LatexCommand label
name "lst:ControlHelpers-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
tryo {
\end_layout
\begin_layout Plain Layout
// code here.
Any exception thrown here will be silently caught
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
tryo((e: Throwable) => println(e)) {
\end_layout
\begin_layout Plain Layout
// code here.
Any exception here willbe caught add passed to
\end_layout
\begin_layout Plain Layout
// the above function.
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
tryo(List(classOf[ClassNotFoundException], classOf[IOException])) {
\end_layout
\begin_layout Plain Layout
// code here.
If IOException or ClassNotFoundException is thrown
\end_layout
\begin_layout Plain Layout
// (or a subclass of the two) they will be ignored.
Any other
\end_layout
\begin_layout Plain Layout
// exception will be rethrown.
\end_layout
\begin_layout Plain Layout
}
\end_layout
\end_inset
\end_layout
\begin_layout Section
CSSHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:CSSHelpers"
\end_inset
\end_layout
\begin_layout Standard
This provide a convenient functionality to fix relative root paths in CSS
(Cascade Stylesheet) files.
Here is an example:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
CSSHelper example
\begin_inset CommandInset label
LatexCommand label
name "lst:CSSHelper-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
Assume this entry in a CSS file:
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
.boxStyle {
\end_layout
\begin_layout Plain Layout
background-image: url('/img/bkg.png')
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
//in your code you can say
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
CSSHelpers.fixCSS(reader, "/myliftapp")
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
// where reader is a java.io.Reader that provides the
\end_layout
\begin_layout Plain Layout
// content of the CSS file.
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Now if your application is not deployed in the ROOT context path (
\begin_inset Quotes eld
\end_inset
/
\begin_inset Quotes erd
\end_inset
) and say it is deployed with the context root /myliftapp then the background
picture will probably notbe found.
Say
\family typewriter
http://my.domain.com/img/bkg.png
\family default
is an unknown path.
However
\family typewriter
http://my.domain.com/
\bar under
myliftapp
\bar default
/img/bkg.png
\family default
is known.
In the example above we are calling fixCSS so that it will automatically
replace the root relative paths such that
\family typewriter
background-image: url('/img/bkg.png')
\family default
becomes
\family typewriter
background-image: url('/myliftapp/img/bkg.png')
\family default
.
To use that in your lift application you can do:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
fixCSS example
\begin_inset CommandInset label
LatexCommand label
name "lst:fixCSS-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
def boot(){
\end_layout
\begin_layout Plain Layout
...
\end_layout
\begin_layout Plain Layout
LiftRules.fixCSS("styles" :: "theme" :: Nil, Empty)
\end_layout
\begin_layout Plain Layout
...
\end_layout
\begin_layout Plain Layout
}
\end_layout
\end_inset
\end_layout
\begin_layout Standard
When the
\family typewriter
/styles/theme.css
\family default
file Lift will apply the prefix specified.
But in this case we provided an Empty Box.
This actually means that Lift will apply the context path returned by
\family typewriter
S.contextPath
\family default
function which as you know returns the context path from the
\family typewriter
HttpSession
\family default
.
\end_layout
\begin_layout Standard
Internally when you call
\family typewriter
fixCSS
\family default
a dispatch function is automatically created and pre-pended to
\family typewriter
LiftRules.dispatch
\family default
.
This is needed in order to intercept the browser request to this .css resource.
Also internally we are telling Lift the this resource must be server by
Lift and not by container.
\end_layout
\begin_layout Standard
The way it works internally is that we are using Scala combinator parsers
to augment only the root relative paths with the given prefix.
\end_layout
\begin_layout Section
BindHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:BindHelpers"
\end_inset
\end_layout
\begin_layout Standard
Binders are extensiveley discussed in other chapters so we won't reiterate
them here.
\end_layout
\begin_layout Standard
\begin_inset listings
lstparams "language=XML"
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Choose template XML
\begin_inset CommandInset label
LatexCommand label
name "lst:Choose-template"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
<lift:CountGame.run form="post">
\end_layout
\begin_layout Plain Layout
<choose:guess>
\end_layout
\begin_layout Plain Layout
Guess a number between 1 and 100.<br/>
\end_layout
\begin_layout Plain Layout
Last guess: <count:last/><br />
\end_layout
\begin_layout Plain Layout
Guess: <count:input/><br/>
\end_layout
\begin_layout Plain Layout
<input type="submit" value="Guess"/>
\end_layout
\begin_layout Plain Layout
</choose:guess>
\end_layout
\begin_layout Plain Layout
<choose:win>
\end_layout
\begin_layout Plain Layout
You Win!!<br />
\end_layout
\begin_layout Plain Layout
You guessed <count:number/> after <count:count/> guesses.<br/>
\end_layout
\begin_layout Plain Layout
</choose:win>
\end_layout
\begin_layout Plain Layout
</lift:CountGame.run>
\end_layout
\end_inset
\end_layout
\begin_layout Standard
You can use the
\family typewriter
Helpers.chooseTemplate
\family default
method to extract portions of a given XML input:
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
Choose template Scala code
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
import net.liftweb.util._
\end_layout
\begin_layout Plain Layout
import Helpers._
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
class CountGame {
\end_layout
\begin_layout Plain Layout
def run(xhtml: NodeSeq): NodeSeq = {
\end_layout
\begin_layout Plain Layout
...
\end_layout
\begin_layout Plain Layout
chooseTemplate("choose", "win", xhtml);
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
}
\end_layout
\end_inset
\end_layout
\begin_layout Standard
So in the snippet conditionally we can choose between parts of the snippet
template.
In the case above only the childs of
\family typewriter
<choose:win>
\family default
node will be returned by the snippetfunction, hence rendered.
\end_layout
\begin_layout Section
HttpHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:HttpHelpers"
\end_inset
\end_layout
\begin_layout Standard
This provides helper functions for HTTP parameters manipulation, URL encoding/de
coding etc.
However there is some interesting functionality available that lets you
choose between tags of a snippet.
\end_layout
\begin_layout Section
JSON
\begin_inset CommandInset label
LatexCommand label
name "sec:JSON"
\end_inset
\end_layout
\begin_layout Standard
Lift provides its own JSON parser if you ever need one.
At a first glance it may be a bit redundant with Scala's JSON parser but
infact Scala'sparser has its own problems with large JSON objects hence
List's uses its own JSON parser implemented of course using combinator
parsers.
\end_layout
\begin_layout Section
LD
\begin_inset CommandInset label
LatexCommand label
name "sec:LD"
\end_inset
\end_layout
\begin_layout Standard
Provides utility functions for calculating the distance between words
\begin_inset Foot
status open
\begin_layout Plain Layout
http://en.wikipedia.org/wiki/Levenshtein_distance
\end_layout
\end_inset
\end_layout
\begin_layout Section
ListHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:ListHelpers"
\end_inset
\end_layout
\begin_layout Standard
Provides utility functions for manipulating lists that are not provided
by Scala libraries.
\end_layout
\begin_layout Section
NamedPartialFunctions
\begin_inset CommandInset label
LatexCommand label
name "sec:NamedPartialFunctions"
\end_inset
\end_layout
\begin_layout Standard
Provides extremly useful functions for invoking partial functions that are
chained in lists of functions.
\end_layout
\begin_layout Standard
\begin_inset listings
inline false
status open
\begin_layout Plain Layout
\begin_inset Caption
\begin_layout Plain Layout
NamedPF example
\begin_inset CommandInset label
LatexCommand label
name "lst:NamedPF-example"
\end_inset
\end_layout
\end_inset
\end_layout
\begin_layout Plain Layout
var f1: PartialFunction[Int,Int] = {
\end_layout
\begin_layout Plain Layout
case 10 => 11
\end_layout
\begin_layout Plain Layout
case 12 => 14
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
var f2: PartialFunction[Int,Int] = {
\end_layout
\begin_layout Plain Layout
case 20 => 11
\end_layout
\begin_layout Plain Layout
case 22 => 14
\end_layout
\begin_layout Plain Layout
}
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
\end_layout
\begin_layout Plain Layout
NamedPF(10, f1 :: f2 :: Nil)
\end_layout
\begin_layout Plain Layout
\end_layout
\end_inset
\end_layout
\begin_layout Standard
Remember that many LiftRules variable are RuleSeq-s.
Meaning that most of the times we re talking about lists of partial functions.
Hence internally lift uses NamedPF for invoking such functions that are
ultimately provided by the user.
Please see
\family typewriter
LiftRules.dispatch
\end_layout
\begin_layout Section
SecurityHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:SecurityHelpers"
\end_inset
\end_layout
\begin_layout Standard
Provides various functions used for random number generation, encryption/decript
ions (blowfish), hash calculations (MD5, SHA, SHA-256) and so on.
\end_layout
\begin_layout Section
TimeHelpers
\begin_inset CommandInset label
LatexCommand label
name "sec:TimeHelpers"
\end_inset
\end_layout
\begin_layout Standard
Utility functions for time operations.
For instance if also provides a set of implicit conversion functions that
allow you to type
\begin_inset Quotes eld
\end_inset
10 seconds
\begin_inset Quotes erd
\end_inset
and returns the value in milliseconds.
\end_layout
\end_body
\end_document
Something went wrong with that request. Please try again.