Scalate was designed to be easily embedded into your application or framework.
The TemplateEngine
class is your main way that you will be interfacing with Scalate. It is located
in the org.fusesource.scalate
package, you you might want to start off with that package import:
import org.fusesource.scalate._
Once you create and configure and instance of TemplateEngine
, it can be treated as a thread safe
singleton. It has sensible configuration defaults so you could just use the following to compile
and render a template:
val engine = new TemplateEngine
val output = engine.layout("/path/to/template.ssp")
Variables can passed as attributes to the template via the render context. For example:
val output = engine.layout("/foo/bar.scaml", Map("name" -> ("Hiram", "Chirino"), "city" -> "Tampa"))
A template can then access those attributes once they declare a variable binding. For example:
<%@ var name:(String,String) %>
<%@ var city:String %>
<p> Hello ${name._1} ${name._2}, from ${city}. </p>
Would be rendered as:
<p> Hello Hiram Chirino from Tampa. </p>
Each template syntax has it's own way of passing in and binding attributes. For more details on on how to declare attribute bindings in your template please reference:
If you wish you can export attributes from the template using the attributes on the context in a similar way as above.
For example inside a SSP page:
<% attributes("title") = "This is my new title" %>
<p> This is some content. </p>
Now if the page is using layouts, the title attribute would be set on the page. i.e. this template outputs the title attribute so that it could be used by the layout.
Implicitly bound variables allow templates to access variables which they have not declared via a variable binding statement. For this to happen, the variable declaration is specified outside the template, when the template is compiled.
You can configure implicit variable bindings on the TemplateEngine
. Every template compiled
will then have variable declared. For example:
val engine = new TemplateEngine
engine.bindings = List(Binding("name", "(String,String)"))
You can also specify additional binding variables when you load the template:
val template = engine.load("/path/to/template.ssp", List(Binding("city", "String")))
In the above example, the name
and city
variables would be implicitly bound in the template.
This means that previous example template would now need to omit the explicit variable
declarations of name
and city
. The new template would look like:
<p> Hello ${name._1} ${name._2}, from ${city}. </p>
When you configure an implicitly bound variable you choose to have the variable's members imported into your templates name space. This is especially handy when you want to automatically expose helper methods to your template.
For example, lets say you want all templates to be able to use a method called log
, then you could
Define the Helper Class
class MyHelper {
def log(message:String) = {
...
}
}
Include it in the the implicit bindings. Setting the 3rd Binding parameter to true enables the member importing.
engine.bindings = List(Binding("helper", "MyHelper", true))
Add an instance of the helper to the render context.
context.attributes += "helper" -> new MyHelper
The method is now available for use in all templates:
<p> Going to log something..</p>
<% log("Our template just executed.") %>
The out of the box servlet integration that Scalate provides uses the above trick to give all rendered templates
access to an imported “context” variable which is an instance of the DefaultRenderContext
which is the same
object which is collecting the render results. It provides the template a bunch of handy helper methods to do things
like capture
to get the result of rendering nested content or filter
to apply a transformation filter to some content.
TemplateEngine
The template engine needs a working directory to generate scala code and java byte codes associated with the templates. By default, it use a location under your java temporary directory. You probably want to change this so that it uses data location configured for your application:
engine.workingDirectory = new File("/var/lib/myapp/work")
Scalate needs to know what class path to compile the templates against. By default it builds a class path using
all the jars in the ClassLoader
which loaded the Scalate jar. If you are in fancy mutli-ClassLoader
application,
like OSGi, they this simple heuristic will not work and you will need to specify the class path that the TemplateEngine
should compile against. For example:
engine.classpath = "/path/to/lib.jar:/path/to/another-lib.jar"
In the default configuration, templates are loaded from the file system. The path you pass to the TemplateEngine.load
method is expected to file path to an actual template file. If you want to load templates from different location, perhaps the classpath or database you will need to supply the TemplateEngine
a custom implementation of ResourceLoader
.
Here's simple example that loads a dynamically generated template:
engine.resourceLoader = new FileResourceLoader {
override def resource(uri: String): Option[Resource] =
Some(Resource.fromText(uri, "Some text"))
}
If you are running in production it may make sense to disable template reloading.
It should be slightly quicker as it avoids doing file system checks for template modifications:
engine.allowReload = false
If you have a large number of templates and would rather not cache them in as compiled java classes in memory, you can disable template caching altogether with:
engine.allowCaching = false