Permalink
Browse files

Added BoxOrRaw and enhanced RestHelper

  • Loading branch information...
1 parent 71161ef commit 454ad8b2aa3b65fa9a6f23a9373ebf73d36cf9dd @dpp dpp committed Mar 3, 2011
@@ -712,4 +712,57 @@ object ParamFailure {
}
}
+/**
+ * Sometimes it's convenient to access either a Box[T]
+ * or a T. If you specify BoxOrRaw[T], the
+ * either a T or a Box[T] can be passed and the "right thing"
+ * will happen
+ */
+sealed trait BoxOrRaw[T] {
+ def box: Box[T]
+}
+
+/**
+ * The companion object that has helpful conversions
+ */
+object BoxOrRaw {
+ /**
+ * Convert a T to a BoxOrRaw[T]
+ */
+ implicit def rawToBoxOrRaw[T, Q <: T](r: Q): BoxOrRaw[T] =
+ RawBoxOrRaw(r: T)
+
+ /**
+ * Convert a Box[T] to a BoxOrRaw[T]
+ */
+ implicit def boxToBoxOrRaw[T, Q <% T](r: Box[Q]): BoxOrRaw[T] = {
+ BoxedBoxOrRaw(r.map(v => v: T))
+ }
+
+ /**
+ * Convert an Option[T] to a BoxOrRaw[T]
+ */
+ implicit def optionToBoxOrRaw[T, Q <% T](r: Option[Q]): BoxOrRaw[T] = {
+ BoxedBoxOrRaw(r.map(v => v: T))
+ }
+
+ /**
+ * Convert a BoxOrRaw[T] to a Box[T]
+ */
+ implicit def borToBox[T](in: BoxOrRaw[T]): Box[T] = in.box
+}
+
+/**
+ * The Boxed up BoxOrRaw
+ */
+final case class BoxedBoxOrRaw[T](box: Box[T]) extends BoxOrRaw[T]
+
+/**
+ * The raw version of BoxOrRaw
+ */
+final case class RawBoxOrRaw[T](raw: T) extends BoxOrRaw[T] {
+ def box: Box[T] =
+ if (raw.asInstanceOf[Object] ne null) Full(raw) else Empty
+}
+
// vim: set ts=2 sw=2 et:
@@ -112,10 +112,21 @@ object Qop extends Enumeration(0, "auth", "auth-int", "auth,auth-int") {
val AUTH, AUTH_INT, AUTH_AND_AUTH_INT = Value
}
+/**
+ * Companion object with builder
+ */
+object UnauthorizedDigestResponse {
+ def apply(realm: String, qop: Qop.Value, nonce: String, opaque: String): UnauthorizedDigestResponse =
+ new UnauthorizedDigestResponse(realm,
+ qop,
+ nonce,
+ opaque)
+}
+
/**
* 401 Unauthorized Response.
*/
-case class UnauthorizedDigestResponse(override val realm: String, qop: Qop.Value, nonce: String, opaque: String) extends UnauthorizedResponse(realm) {
+class UnauthorizedDigestResponse(override val realm: String, qop: Qop.Value, nonce: String, opaque: String) extends UnauthorizedResponse(realm) {
override def toResponse = InMemoryResponse(Array(), List("WWW-Authenticate" -> (
"Digest realm=\"" + realm + "\", " +
"qop=\"" + qop + "\", " +
@@ -273,9 +284,12 @@ object JsonResponse {
def apply(_json: JsonAST.JValue, _headers: List[(String, String)], _cookies: List[HTTPCookie], code: Int): LiftResponse = {
new JsonResponse(new JsExp {
- lazy val toJsCmd = Printer.pretty(JsonAST.render((_json)))
+ lazy val toJsCmd = jsonPrinter(JsonAST.render((_json)))
}, _headers, _cookies, code)
}
+
+ lazy val jsonPrinter: scala.text.Document => String =
+ LiftRules.jsonOutputConverter.vend
}
case class JsonResponse(json: JsExp, headers: List[(String, String)], cookies: List[HTTPCookie], code: Int) extends LiftResponse {
@@ -379,7 +393,12 @@ object DoRedirectResponse {
def apply(url: String): LiftResponse = RedirectResponse(url, Nil: _*)
}
-case class RedirectWithState(override val uri: String, state: RedirectState, override val cookies: HTTPCookie*) extends RedirectResponse(uri, cookies: _*)
+object RedirectWithState {
+ def apply(uri: String, state: RedirectState, cookies: HTTPCookie*): RedirectWithState =
+ new RedirectWithState(uri, state, cookies :_*)
+}
+
+class RedirectWithState(override val uri: String, state: RedirectState, override val cookies: HTTPCookie*) extends RedirectResponse(uri, cookies: _*)
object RedirectState {
def apply(f: () => Unit, msgs: (String, NoticeType.Value)*): RedirectState = new RedirectState(Full(f), msgs: _*)
@@ -388,9 +407,12 @@ case class RedirectState(func: Box[() => Unit], msgs: (String, NoticeType.Value)
object MessageState {
implicit def tuple2MessageState(msg: (String, NoticeType.Value)) = MessageState(msg)
+
+ def apply(msgs: (String, NoticeType.Value)*): MessageState =
+ new MessageState(msgs :_*)
}
-case class MessageState(override val msgs: (String, NoticeType.Value)*) extends RedirectState(Empty, msgs: _*)
+class MessageState(override val msgs: (String, NoticeType.Value)*) extends RedirectState(Empty, msgs: _*)
/**
* Stock XHTML doctypes available to the lift programmer.
@@ -413,7 +435,7 @@ object DocType {
* Avoid using this in favor of LiftRules.docType
*
*/
-@deprecated
+@deprecated("Avoid using this in favor of LiftRules.docType")
object ResponseInfo {
def docType: PartialFunction[Req, Box[String]] = new PartialFunction[Req, Box[String]](){
@@ -126,6 +126,15 @@ trait LiftRules extends Factory with FormVendor with LazyLoggable {
*/
val sessionInactivityTimeout = new FactoryMaker[Box[Long]](Empty){}
+ /**
+ * The function that converts a scala.text.Document to
+ * a String (used for JsonAST.JValue to text convertion.
+ * By default, use Printer.pretty for dev mode and
+ * Printer.compact for other modes
+ */
+ val jsonOutputConverter = new FactoryMaker[scala.text.Document => String]({
+ import json.Printer
+ if (Props.devMode) Printer.pretty _ else Printer.compact _}){}
/**
@@ -273,9 +273,9 @@ trait RestHelper extends LiftRules.DispatchPF {
* A function that chooses JSON or XML based on the request..
* Use with serveType
*/
- implicit def jxSel(req: Req): Box[JsonXmlSelect] =
- if (jsonResponse_?(req)) Full(JsonSelect)
- else if (xmlResponse_?(req)) Full(XmlSelect)
+ implicit def jxSel(req: Req): BoxOrRaw[JsonXmlSelect] =
+ if (jsonResponse_?(req)) JsonSelect
+ else if (xmlResponse_?(req)) XmlSelect
else None
/**
@@ -290,16 +290,16 @@ trait RestHelper extends LiftRules.DispatchPF {
* to a the appropriate LiftResponse based on the selected response
* type.
*/
- protected def serveType[T, SelectType](selection: Req => Box[SelectType])
- (pf: PartialFunction[Req, Box[T]])
+ protected def serveType[T, SelectType](selection: Req => BoxOrRaw[SelectType])
+ (pf: PartialFunction[Req, BoxOrRaw[T]])
(implicit cvt: PartialFunction[(SelectType, T, Req), LiftResponse]): Unit = {
serve(new PartialFunction[Req, () => Box[LiftResponse]] {
def isDefinedAt(r: Req): Boolean =
selection(r).isDefined && pf.isDefinedAt(r)
def apply(r: Req): () => Box[LiftResponse] =
() => {
- pf(r) match {
+ pf(r).box match {
case Full(resp) =>
val selType = selection(r).open_! // Full because pass isDefinedAt
if (cvt.isDefinedAt((selType, resp, r)))
@@ -326,7 +326,7 @@ trait RestHelper extends LiftRules.DispatchPF {
* converters use Lift JSON's Extraction.decompose to convert the object
* into JSON and then Xml.toXml() to convert to XML.
*/
- protected def serveJx[T](pf: PartialFunction[Req, Box[T]])
+ protected def serveJx[T](pf: PartialFunction[Req, BoxOrRaw[T]])
(implicit cvt: JxCvtPF[T]): Unit =
serveType(jxSel)(pf)(cvt)
@@ -340,7 +340,7 @@ trait RestHelper extends LiftRules.DispatchPF {
* Any (note that the response must be convertable into
* JSON vis Lift JSON Extraction.decompose
*/
- protected def serveJxa(pf: PartialFunction[Req, Box[Any]]): Unit =
+ protected def serveJxa(pf: PartialFunction[Req, BoxOrRaw[Any]]): Unit =
serveType(jxSel)(pf)(new PartialFunction[(JsonXmlSelect,
Any, Req), LiftResponse] {
def isDefinedAt(p: (JsonXmlSelect, Any, Req)) =
@@ -609,10 +609,25 @@ trait RestHelper extends LiftRules.DispatchPF {
}
+/**
+ * Do some magic to prefix path patterns with a single List
+ */
final class ListServeMagic(list: List[String]) {
val listLen = list.length
- def >>(pf: PartialFunction[Req, () => Box[LiftResponse]]):
+ def prefixJx[T](pf: PartialFunction[Req, BoxOrRaw[T]]): PartialFunction[Req, BoxOrRaw[T]] =
+ new PartialFunction[Req, BoxOrRaw[T]] {
+ def isDefinedAt(req: Req): Boolean =
+ req.path.partPath.startsWith(list) && {
+ pf.isDefinedAt(req.withNewPath(req.path.drop(listLen)))
+ }
+
+ def apply(req: Req): BoxOrRaw[T] =
+ pf.apply(req.withNewPath(req.path.drop(listLen)))
+ }
+
+
+ def prefix(pf: PartialFunction[Req, () => Box[LiftResponse]]):
PartialFunction[Req, () => Box[LiftResponse]] =
new PartialFunction[Req, () => Box[LiftResponse]] {
def isDefinedAt(req: Req): Boolean =

0 comments on commit 454ad8b

Please sign in to comment.