Scalate User Guide

Scala Template Engine: like HAML or JSP without the crap but with added Scala coolness

Scalate User Guide

Scalate is a template engine based on the Scala language.

Features

Template Languages

Scalate supports a number of different template languages as template languages have various different sweet spots depending on your requirements.

Ssp (Scala Server Pages)

If you know Velocity, JSP or Erb from Rails 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>
#end
<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

Jade

The Jade syntax is similar to Scaml, its a modified dialect of Haml where element names do not require a leading % symbol which can make it a little easier to read.

.jade 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 more details see the Jade reference

Mustache

The Scalate Mustache template language is a Scala dialect of cross-language Mustache template engine for logic-less templates which also work inside the browser using mustache.js.

Mustache is logic-less, using simple tags which can be used to represent loops, expressions or logical branching.

Given the following attributes:

Map(
  "name" -> "Chris",
  "value" -> 10000,
  "taxed_value" -> 10000 - (10000 * 0.4),
  "in_ca" -> true
  )

Then the following mustache file will generate

.mustache file

Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}

produces

Hello Chris
You have just won $10000!
Well, $6000.0, after taxes.

For more detail see the Mustache Reference

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)    

Accessing request state inside a Scala function

As you write snippet functions for use in your templates you might find yourself needing to access the current HttpServletRequest or HttpServletResponse.

There is a simple helper import you can use…

import org.fusesource.scalate.servlet.ServletRenderContext._

object MySnippets {
  def foo = {
    // thanks to the import I now have access to the renderContext
    // along with the standard servlet objects:
    // request, response, servletContext, servletConfig
    request.getParameter("foo") 
  }
}

This helps you keep your snippet functions nice and small.

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>

Or using Velocity style directives this might look like this

#do(foo(id))
product ${id}
#end

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", Map("customer" -> c, "title" -> "Customer")) %>

When passing attributes you can use the Scala symbol notation for keys if you prefer…

<% render("/customers/contact.ssp", Map('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/scalate/layouts/default.ssp (or /WEB-INF/scalate/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>

  ${unescape(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", Map("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
<%}%>

Or using Velocity style directives this might look like this

#do( layout("foo.ssp") )
Foo
#end

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

Making templates more DRY

When you create a number of templates in a directory you might find you are repeating the same sets of imports across many templates. This doesn't feel terribly DRY. Scala 2.8 supports package objects which allows you to define types, variables and methods at the package scope to be reused inside classes and traits defined inside the package.

So Scalate supports a similar feature for templates which are code generated like SSP, Scaml and Jade.

The basic idea is Scalate will look in the same package as the template for a Scala/Java class called ScalatePackage which must extend TemplatePackage. If there is no ScalatePackage in the package, its parent package is searched all the way to the root package (i.e. no package name).

If a ScalatePackage class is found then its header method is invoked to generate any shared imports, variables or methods across templates.

For example you could add the following Scala code to a file called src/main/scala/foo/ScalatePackage.scala to add some default imports you want to share across a number of templates in a the foo directory and its descendants…

package foo

import org.fusesource.scalate.TemplateSource
import org.fusesource.scalate.support.TemplatePackage


/**
 * Defines some common imports, attributes and methods across templates in package foo and below
 */
class ScalatePackage extends TemplatePackage {

  /** Returns the Scala code to add to the top of the generated template method */
   def header(source: TemplateSource, bindings: List[Binding]) = """

// some shared imports
import com.acme._
import com.acme.something.MyHelper._

// some helper methods
// would be better being imported from a helper class like MyHelper above
def time = new java.util.Date()

  """
}

You can then use the usual expressive composition features of Scala to use inheritance, traits, delegation and so forth to decide how to spread this code across your templates and decide how to combine these things at the package level to be inherited by all child packages and templates. You might find moving templates into functional directories makes it easier to reuse common boilerplate imports, values and methods across templates.

Scalate Samples

Getting Started

The easiest way to get started is to try the Getting Started Guide

Running the Sample Web Application

The source code comes with a sample web application called scalate-sample which includes a number of exmample templates you can play around with>

Scalate can be built either using Maven or SBT

Requirements

General Requirements:

Web Container Requirements:

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

You might want to refer to the Frameworks Documentation to see if there is some specific instructions on using Scalate with your favourite web framework.

Using Scalate as Servlet filter in your Web Application

You could add one or more of the above to your servlet container's server-wide configuration if you prefer.

Mapping URIs to templates with the Filter

The Scalate template filter looks for templates in several locations to satisfy a request.
For example, if requested URI is /path/file.html, then it will for templates in this order:

  1. /path/file.html.${ext}
  2. /WEB-INF/path/file.html.${ext}
  3. /path/file.${ext}
  4. /WEB-INF/path/file.${ext}

Where ${ext} gets replaced with all the template extensions supported by the Template Engine. If the requested URI already ends with template extension then it would get looked up in the root and under the /WEB-INF directory.

Using Scalate with JAXRS/Jersey

Our recommendation is to start with JOG (Jersey on Guice).

To get up to speed quickly with JOG try the Getting Started Guide which uses the Scalate Tool and WAR Overlay to include the Console in your web application.

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

Working Directory, Caching, Reloading

Scalate uses a working directory to store the generated scala source files and the compiled JVM bytecode for templates. This can be configured on a TemplateEngine using the workingDirectory property. If no configuration is made Scalate will use the scalate.workdir system property by default.

The archetypes or projects created by the scalate tool or the modules in the scalate source all set the scalate.workdir to be the maven property of the same name; which defaults to target/_scalate

If you wanted to run a web application using a different directory, such as /tmp you could do

mvn -Dscalate.workdir=/tmp jetty:run

In production settings you can disable the caching and reloading of templates if you wish using the allowCaching and allowReload properties on TemplateEngine which default to scalate.allowCaching and scalate.allowReload respectively.

Configuring the TemplateEngine in your web app

Scalate supports a standard bootstrap mechanism which tries to be framework agnostic so it can work in servlets or using the servlet filter or works when generating static websites and is easy to plugin to other frameworks.

Just add a class called scalate.Boot which should be a class with a method called run() which can then do whatever you need to configure things before the template engine starts to render your templates.

If you need access to the TemplateEngine then just add a constructor argument. (You can also pass in ServletContext as a constructor parameter if you are inside a web application and other values which may come from your framework).

e.g.

package scalate

import org.fusesource.scalate.TemplateEngine
import java.io.File

class Boot(engine: TemplateEngine) extends Logging {

  def run: Unit = {
    // lets change the workingDirectory
    engine.workingDirectory = new File("myScalateWorkDir")
  }
}

Precompiling Templates

Scalate currently lazily compiles templates on the fly, then it will cache the compiled template and only recompile it if it detects the source template has changed.

In production you probably want all your templates to be precompiled so that

To do this you just need to include the maven-scalate-plugin into your project. The plugin only precompiles when you are packaging into a war to avoid slowing down your development mode cycles.

The archetypes created by the scalate tool come with this plugin enabled already.

Otherwise you can just add this to your pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.fusesource.scalate</groupId>
      <artifactId>maven-scalate-plugin</artifactId>
      <version>1.4.0</version>
      <executions>
        <execution>
          <goals>
            <goal>precompile</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Precompiling templates with SBT

The archetypes created by the scalate tool have their SBT build configuration setup so that the templates are precompiled before they are packaged. If you need to add the precompiler to an existing sbt project then you need to first add the plugin dependency:

lazy val scalate_plugin = "org.fusesource.scalate" % "sbt-scalate-plugin" % "1.4.0"

And then in your WebProject, you will need to add the org.fusesource.scalate.sbt.PrecompilerProject trait. And then make sure the Scalate dependencies are added to the project. For example:

class Project(info: ProjectInfo) extends 
      DefaultWebProject(info) with 
      PrecompilerProject {

  lazy val scalate_core = "org.fusesource.scalate" % "scalate-core" % "1.4.0" 
  lazy val servlet = "javax.servlet" % "servlet-api"% "2.5" 
  lazy val logback = "ch.qos.logback" % "logback-classic" % "0.9.26"

}

Using Scalate on GAE

If you are using Scalate on Google AppEngine (GAE) then you will probably want to precompile all your templates before you deploy them; so that each request is processed very quickly - so app engine won't kill your thread midway through.

To see an example of a Scalate project already setup using GAE try the the hello-scalate-appengine project by Yasushi Abe.

Possible Gotchas

Class Loaders

Scalate can sometimes struggle with ClassLoaders. This is due to the Scala compiler requiring an explicit class path to be specified as a String of names rather than taking an actual ClassLoader object.

So Scalate works fine with expanded WARs, or servlet containers who's ClassLoader implements URLClassLoader or an AntClassLoader like thing or the Play Framework. But you might be able to find some application server that doens't provide an easy-to-diagnose ClassLoader object which may require an explicitly configured class path for compiling.

A work around is to precompile your templates with the maven plugin (see the section above).

Character Encoding

Scalate currently assumes that

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.

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.