forked from scalatra/scalatra
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds a render pipeline and basic example
- Loading branch information
Showing
7 changed files
with
202 additions
and
23 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.scalatra | ||
|
||
import collection.mutable | ||
import java.io.{FileInputStream, File} | ||
import util.using | ||
import util.io.copy | ||
|
||
// Perhaps making renderResponseBody a stackable method this would also give a render pipeline maybe even a better one at that | ||
//trait RenderResponseBody { | ||
// def renderResponseBody(actionResult: Any) | ||
//} | ||
|
||
/** | ||
* Allows overriding and chaining of response body rendering. Overrides [[ScalatraKernel#renderResponseBody]]. | ||
*/ | ||
trait RenderPipeline {this: ScalatraKernel => | ||
|
||
object ActionRenderer{ | ||
def apply[A: ClassManifest](fun: A => Any) = new ActionRenderer(fun) | ||
} | ||
private[scalatra] class ActionRenderer[A: ClassManifest](fun: A => Any) extends PartialFunction[Any, Any] { | ||
def apply(v1: Any) = fun(v1.asInstanceOf[A]) | ||
def isDefinedAt(x: Any) = implicitly[ClassManifest[A]].erasure.isInstance(x) | ||
} | ||
|
||
private type RenderAction = PartialFunction[Any, Any] | ||
protected val renderPipeline = new mutable.ArrayBuffer[RenderAction] with mutable.SynchronizedBuffer[RenderAction] | ||
|
||
override def renderResponseBody(actionResult: Any) { | ||
(useRenderPipeline orElse defaultRenderResponse) apply actionResult | ||
} | ||
|
||
private def useRenderPipeline: PartialFunction[Any, Any] = { | ||
case pipelined if renderPipeline.exists(_.isDefinedAt(pipelined)) => { | ||
(pipelined /: renderPipeline) { | ||
case (body, renderer) if (renderer.isDefinedAt(body)) => renderer(body) | ||
case (body, _) => body | ||
} | ||
} | ||
} | ||
|
||
private def defaultRenderResponse: PartialFunction[Any, Any] = { | ||
case bytes: Array[Byte] => | ||
response.getOutputStream.write(bytes) | ||
case file: File => | ||
using(new FileInputStream(file)) { in => copy(in, response.getOutputStream) } | ||
case _: Unit => | ||
// If an action returns Unit, it assumes responsibility for the response | ||
case x: Any => | ||
response.getWriter.print(x.toString) | ||
} | ||
|
||
/** | ||
* Prepend a new renderer to the front of the render pipeline. | ||
*/ | ||
def render[A: Manifest](fun: A => Any) { | ||
ActionRenderer(fun) +=: renderPipeline | ||
} | ||
|
||
|
||
} | ||
|
||
trait DefaultRendererPipeline { self: ScalatraKernel with RenderPipeline => | ||
render[Any] { | ||
case _: Unit => // If an action or renderer returns Unit, it assumes responsibility for the response | ||
case x => response.getWriter.print(x.toString) | ||
} | ||
|
||
render[File] {file => | ||
using(new FileInputStream(file)) {in => copy(in, response.getOutputStream)} | ||
} | ||
|
||
render[Array[Byte]] {bytes => | ||
response.getOutputStream.write(bytes) | ||
} | ||
} |
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.scalatra | ||
|
||
import org.scalatest.matchers.ShouldMatchers | ||
import test.scalatest.ScalatraFunSuite | ||
|
||
|
||
class RenderPipelineTestServlet extends ScalatraPipelinedServlet { | ||
|
||
render[String] { | ||
case s @ "the string to render" => response.getWriter print ("Rendering string: %s" format s) | ||
case s => "Augmenting string: " + s | ||
} | ||
|
||
get("/any") { | ||
11111 | ||
} | ||
|
||
get("/string") { | ||
"the string to render" | ||
} | ||
|
||
get("/augment") { | ||
"yet another string" | ||
} | ||
} | ||
|
||
class RenderPipelineTest extends ScalatraFunSuite with ShouldMatchers { | ||
|
||
addServlet(new RenderPipelineTestServlet, "/*") | ||
|
||
test("should still render defaults") { | ||
get("/any") { | ||
body should equal("11111") | ||
} | ||
} | ||
|
||
test("should render the string") { | ||
get("/string") { | ||
body should equal("Rendering string: the string to render") | ||
} | ||
} | ||
|
||
test("should augment a string") { | ||
get("/augment") { | ||
body should equal("Augmenting string: yet another string") | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
example/src/main/scala/org/scalatra/RenderPipelineExample.scala
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.scalatra | ||
|
||
|
||
|
||
class RenderPipelineExample extends ScalatraPipelinedServlet { | ||
|
||
render[String] { | ||
case s => "rendering: " + s | ||
} | ||
|
||
render[List[String]] { | ||
case l => "Rendering list:" + l.mkString(" <br />\n", " <br />\n", " <br />\n") | ||
} | ||
|
||
get("/?") { | ||
"hello I'm rendering" | ||
} | ||
|
||
get("/list") { | ||
"first" :: "second" :: "third" :: "fourth" :: Nil | ||
} | ||
} |
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