Scalate User Guide
Scalate is a template engine based on the Scala language.
Features
-
Supports multiple template syntaxes
- Ssp: like JSP/ASP pages in syntax but using Scala code for expressions
- Scaml: like Haml pages in syntax, but again with Scala as the expression language.
-
inbuilt support for layouts
-
Easy to use replacement for JSP’s in J2EE web container
-
No hard dependencies on a web container. It can be used in a standalone application to template things like emails.
-
JAXRS integration so that Scalate template can render JAXRS resouces
Ssp (Scala Server Pages)
If you know JSP or ASP then hopefully the syntax of Ssp is familiar; only using Scala as the language of expressions and method invocations.
.ssp file
<%@ var user: User %>
<p>Hi ${user.name},</p>
<% for(i <- 1 to 3) { %>
<p><%= i %></p>
<% } %>
<p>See, I can count!</p>
produces
<p>Hi James,</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>See, I can count!</p>
For full documentation of the Ssp syntax see the Ssp Reference Guide
Scaml (Scala Markup Language)
Scaml is a markup language that’s used to cleanly and simply describe the XHTML of any web document, without the use of inline code. It is Scala version of Haml. Scaml functions as a replacement for inline page templating systems such as PHP, ERB, and ASP. However, Scaml avoids the need for explicitly coding XHTML into the template, because it is actually an abstract description of the XHTML, with some code to generate dynamic content.
.scaml file
-@ var user: User
%p Hi #{user.name},
- for(i <- 1 to 3)
%p= i
%p See, I can count!
produces
<p>Hi James,</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>See, I can count!</p>
For full documentation of the Scaml syntax see the Scaml Reference Guide
Calling Scala functions
Its very simple to invoke any scala function inside Scalate. By default if the function you call returns NodeSeq then the output will already be properly XML encoded; so things output nicely without any possible cross scripting hacks etc.
For example the following function creates a hypertext link using Scala’s XML support
object Cheese {
def foo(productId: Int) =
<a href={"/products/" + productId} title="Product link">My Product</a>
}
This function can be invoked in your Ssp code as
<% import Cheese._ %>
${foo(123)}
If your template is in the same package as the Cheese class then the import is not required.
The Scaml version is
- import Cheese._
= foo(123)
Passing a template block to a Scala function
To use the JSP concept of custom tags, you might want to pass a block of template to a function for further processing or transformation.
This can be done by just adding a parameter list of the form (body: => Unit) to your method. For example
import org.fusesource.scalate.RenderContext.capture
object Cheese {
def foo(productId: Int)(body: => Unit) =
<a href={"/products/" + productId} title="Product link">capture(body)</a>
}
See how the body is captured using the capture(body) function. Now the text of the hypertext link can be specified as a block of template in Ssp
<%@ val id: Int = 123 %>
<% import Cheese._ %>
<%= foo(id) { %>
product ${id}
<% } %>
This should generate something like
<a href="/products/123" title="Product link">product 123</a>
The Scaml version is
-@ val id: Int = 123
- import Cheese._
= foo(id)
product #{id}
Notice the Scaml version is simpler, not requiring the open and close { } tokens as it uses indentation.
Views
From within your Scala code or inside a template you often want to render an object or collection of objects. Scalate uses a convention over configuration mechanism so that you can render any object using a simple method call in your template. e.g. in SSP
<%@ var it: User %>
<p>Something...</p>
<% view(it) %>
<p>... more stuff </p>
View names
The view method takes a model object and an optional view name. The view name defaults to “index” if you do not specify one. For exmaple you could have various views for an object such as “index”, “edit”, “detail”, etc. Then you might want to show the edit view of an object via
<%@ var it: User %>
<% view(it, "edit") %>
Scalate will then look for the template called packageDirectory.ClassName.viewName.(ssp|scaml) and render that. For example in the sample web application to render an org.fusesource.scalate.sample.Person object Scalate uses the org/fusesource/scalate/sample/Person.index.ssp template.
Notice that since the view is defined within the package of the model object, there is no need to import the org.fusesource.scalate.sample.Person, instead you can just refer to the model type directly as Person.
If a template is not found for the exact class name then the class and interface (trait) hierarchies are walked until one is found.
So for example you could provide a template for a generic trait you have - such as a template to render any scala.Product which will then render any case class; then you can customise the view on a class by class basis as required.
The ‘it’ variable
By default we use the variable named it to refer to the model parameter. This convention means that when working with JAXRS and Jersey’s implicit views the model object is implicitly available to any templates using this naming convention.
Collections
If you have a collection of objects you wish to view then you can use a simple helper method called collection which works like the view method described above.
<%@ var it: List[Person] %>
<% collection(it) %>
As with the view method you can specify an optional view name if you won’t want to use the “index” default.
Also you can specify a separator to use between views of objects. The following example shows a horizontal line between views…
<% val people = List(Person("James", "Strachan"), Person("Hiram", "Chirino")) %>
<% collection(people, separator = "<hr/>") %>
Or without using named arguments
<% collection(people, "index", "<hr/>") %>
If a collection contains different types of objects then the correct view will be used for each element in the collection.
You can also supply a function for the separator if you want it to be dynamic
<% var x = 1 %>
collection(people, separator = {x += 1; <h3>Person {x}</h3>})
Render templates
It is common to want to refactor large templates into smaller reusable pieces. Its easy to render a template from inside another template with the render method as follows
<% render("foo.ssp") %>
This will render a template called foo.ssp relative to the current template. You can use absolute names if you prefer
<% render("/customers/contact.ssp") %>
You can also pass parameters into the template if it takes any
<% render("/customers/contact.ssp", "customer" -> c, "title" -> "Customer") %>
When passing attributes you can use the Scala symbol notation for keys if you prefer…
<% render("/customers/contact.ssp", 'customer -> c, 'title -> "Customer") %>
If you prefer you can pass in a body to the template using the layout method as described in using explicit layouts inside a template.
Layouts
Its quite common to want to style all pages in a similar way; such as adding a header and footer, a common navigation bar or including a common set of CSS stylesheets.
You can achieve this using the layout support in Scalate.
All you need to do is create a layout template in /WEB-INF/layouts/default.ssp (or /WEB-INF/layouts/default.scaml if you prefer). Here is a simple example layout which lays out the body and lets the title be customized on a per page basis.
<%@ var body: String %>
<%@ var title: String = "Some Default Title" %>
<html>
<head>
<title>${title}</title>
</head>
<body>
<p>layout header goes here...</p>
<%= body %>
<p>layout footer goes here...</p>
</body>
</html>
Then all pages will be wrapped in this layout by default.
This means your templates don’t need to include the whole html/head/body stuff, typically you’ll just want the actual content to be displayed in the part of the layout you need. So a typical page might look like this…
<h3>My Page</h3>
<p>This is some text</p>
Changing the title or layout template
To set parameters on a layout or to change the layout template used, just output attribute values in your template.
<% attributes("layout") = "/WEB-INF/layouts/custom.ssp" %>
<% attributes("title") = "This is the custom title" %>
<h3>Custom page</h3>
<p>This is some text</p>
Disabling layouts
If you wish to disable the use of the layout on a template, just set the layout attribute to ”” the empty string.
<% attributes("layout") = "" %>
<html>
<body>
<h1>No Layout</h1>
<p>This page does not use the layout</p>
</body>
</html>
To see examples of layouts in use, try running the sample web application and looking at the layout related example pages.
Explicit layouts inside a template
You may want to layout some content within part of your template explicitly rather than just applying a layout to an entire page.
For example you may want to create a layout as follows in file foo.ssp
<%@ val body: String = "Bar" %>
<table>
<tr>
<th>Some Header</th>
</tr>
<tr>
<td><%= body %></td>
</tr>
</table>
Then we can invoke this template passing in the body as follows in Ssp
<% render("foo.ssp", "body" -> "Foo") %>
However if you want to pass in the body as a block of template you can use the layout method as follows
<% layout("foo.ssp") {%>
Foo
<%}%>
Both will generate the same response.
Using the above mechanism via either the render or layout methods is quite like creating a JSP custom tag inside a .tag file if you come from a JSP background.
The nice thing is there’s really no difference technically between a regular template, a layout or a ‘tag’ template or a ‘partial’ (to use Rails terminology), they are all just templates which can have parameters which can be mandatory or optional.
Capturing output
Sometimes you may wish to capture the result of rendering a block of template, assign it to a variable and then pass it as an argument to some method. For this the capture method can be used.
For example
<% val foo = capture { %>
hello there ${user.name} how are you?
<%}%>
...
${foo}
...
${foo}
We capture the block which generates a greeting, assign it to the foo variable which we can then render or pass into methods etc.
The Scaml version of this is a bit more concise
- var foo = capture
hello there #{user.name} how are you?
...
= foo
...
= foo
Running the Samples
The easiest way to play with Scalate is to try out the sample web application.
Scalate can be built either using Maven or SBT
Requirements
General Requirements:
- Java 5 runtime or Newer
- Scala 2.8
Web Container Requirements:
- Servlet 2.5 container or Newer
Using Maven
Install Maven version 2.0.9 or later. Then type
mvn install
To run the sample web application
cd scalate-sample
mvn jetty:run
Then open the sample home page
Using SBT
You can also use sbt to build Scalate.
To setup your sbt environment and import the dependencies from the maven pom files type
./sbt
update
Then to build the code type
compile
to run the tests
test
For more information see the sbt building instructions
Using Scalate in your Web Application
-
Add something like the following to your web.xml file to support Ssp and Scaml pages:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<servlet> <servlet-name>TemplateEngineServlet</servlet-name> <servlet-class>org.fusesource.scalate.servlet.TemplateEngineServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>TemplateEngineServlet</servlet-name> <url-pattern>*.ssp</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>TemplateEngineServlet</servlet-name> <url-pattern>*.scaml</url-pattern> </servlet-mapping>
-
Include the following JARs in your servlet’s runtime environment (probably in WEB-INF/lib):
- scala-compiler.jar
- scala-library.jar
- scalate-core.jar
You could add one or more of the above to your servlet container’s server-wide configuration if you prefer
Possible Gotchas
-
Works with expanded WARs - or servlet containers who’s ClassLoader implements URLClassLoader
-
Assumes template source files are all UTF-8-encoded.
-
Assumes template output is all UTF-8-encoded.
-
No support for pre-compiled templates (e.g., via a custom Ant task).
Embedding Scalate in your Application or Framework
Scalate does not have any hard dependencies on a web framework or even HTTP. It can be used as a standalone rendering engine in your application. For more information on how to embed in your application, please reference the Scalate Embedding Guide
IDE plugins
Using an IDE plugin can make it much easier to view and edit Scalate templates.
TextMate plugin
If you use TextMate (which on OS X is a great text editor) you can install the Scalate plugin as follows:
cd ~/Library/Application\ Support/TextMate/Bundles/
git clone git://github.com/scalate/Scalate.tmbundle.git
If you have not already done so you will also need a Scala plugin for TextMate which the Ssp and Scaml languages uses for the Scala code blocks.
We like the version by Dean Wampler though there’s a few around github and one included in sbaz in the Scala distro too.
cd ~/Library/Application\ Support/TextMate/Bundles/
git clone git://github.com/deanwampler/Scala.tmbundle.git
When you restart TextMate you should now get syntax highlighting and more when you open up either a Ssp or Scaml file.
The current plugin does not highlight Scala expressions terribly well with the default Mac Classic colour scheme in TextMate. We found that it helps to add an extra colour to your scheme.
- open TextMate preferences via the TextMate menu or by hitting the apple key and ’,’
- select Fonts & Colors
- hit + to add a new entry
- type “Scaml expression” and pick a colour to use such as dark green (to differentiate from static markup text)
- in the Scope Selector: field enter source.scala
- you now should see Scala expressions in your Scaml file highlighted in green (so you can more easily tell the difference between static text and scala expressions)
If you are an IDE hacker
We created Scalate specifically to be IDE friendly and we’d love to help create more and better IDE plugins (plus we love contributions!). It should be easy to reuse any JSP / Erb / HAML IDE plugins but just swizzle them a little to use the Scala language instead - then get all the benefits of smart completion from Scala’s static type system.
We’ve a page on writing IDE plugins for Scalate which has more details on how an IDE plugin should ideally work for Scalate.