Ssp pages are like a Scala version of Velocity, JSP or Erb from Rails in syntax but using Scala code for expressions instead of Java/EL/Ruby.
If you know Velocity, JSP or Erb then hopefully the syntax of Ssp is familiar; only using Scala as the language of expressions and method invocations.
A Ssp template consists of plain text, usually an HTML document, which has special Ssp tags embedded in it so that
portions of the document are rendered dynamically. Everything outside of a <% ... %>
and ${ ... }
sequence
are considered literal text and are generally passed through to the rendered document unmodified.
${ }
or <%= %>
Code wrapped by <%=
and %>
or with '${' and '}' is evaluated and the output is inserted into the document.
For example:
<p>
<%= List("hi", "there", "reader!").mkString(" ") %>
${ "yo "+(3+4) }
</p>
is rendered as:
<p>
hi there reader!
yo 7
</p>
<% %>
Code wrapped by <%
and %>
is evaluated but not inserted into the document.
For example:
<%
var foo = "hello"
foo += " there"
foo += " you!"
%>
<p>${foo}</p>
is rendered as:
<p>hello there you!</p>
If you like to use Velocity style directives you can also use #{
}#
<%@ %>
When a Scalate template is rendered, the caller can pass an attribute map which the template is in charge of rendering. To bind an attribute to a type safe Scala variable an SSP template uses the following syntax to declare the attribute:
<%@ val foo: MyType %>
If the attribute map does not contain a “foo” entry, then a NoValueSetException is thrown when the the template is rendered.
To avoid this exception, a default value can be configured. For example:
<%@ val bar: String = "this is the default value" %>
The attribute is now available for use as an expression.
Its very common to have a template based on a single object who's members are frequently accessed. In this cases, it's convenient to import all the object's members. This can be done by adding the import keyword to the attribute declaration.
For example:
<%@ import val model: Person %>
<p>Hello ${name}, what is the weather like in ${city}</p>
is the same as:
<%@ val model: Person %>
<% import model._ %>
<p>Hello ${name}, what is the weather like in ${city}</p>
Which is the same as:
<%@ val model: Person %>
<p>Hello ${model.name}, what is the weather like in ${model.city}</p>
To perform logical branching or looping Scalate supports Velocity style directives.
The velocity style directives all start with a #
and either take an expression in parens, or don't.
For example #if
takes an expression, such as #if (x > 5)
. There can be whitespace between the directive name and the parens if required. So you can use any of these
#if(x > 5)
#if (x > 5)
#if( x > 5 )
When a directive doesn't take an expression you can use parens around the directive name to separate it more clearly from text.
For example if you want to generate an if/else in a single line: #if (x > 5)a#(else)b#end
#for
The #for
directive is used to iterate over expressions in a Scala like way.
<ul>
#for (i <- 1 to 5)
<li>${i}</li>
#end
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
Just like in the Scala language you can perform multiple nested loops using sequence comprehensions.
For example for a nested loop of both x and y…
<ul>
#for (x <- 1 to 2; y <- 1 to 2)
<li>(${x}, ${y})</li>
#end
</ul>
<ul>
<li>(1, 1)</li>
<li>(1, 2)</li>
<li>(1, 1)</li>
<li>(2, 1)</li>
</ul>
#if
You can perform if/elseif/else branches using the #if
, #elseif
(or #elif
), #else
and #end
directives.
The use of #elseif
and #else
are optional. You can just use #if
and #end
if you like
<p>
#if (customer.type == "Gold")
Special stuff...
#end
</p>
<p>
Special stuff...
</p>
Or you can use each directive together, using as many #elseif
directives as you like
<p>
#if (n == "James")
Hey James
#elseif (n == "Hiram")
Yo Hiram
#else
Dunno
#end
</p>
<p>
Hey James
</p>
#set
You often want to take a section of a template and assign it to an attribute which you can then pass into a layout or some other template.
For example you might wish to define a head section to allow a page to define custom output to go into the HTML head element…
#set (head)
... some page specific JavaScript includes here...
#end
...rest of the page here...
Then in the layout we could use
<%@ var body: String %>
<%@ var title: String = "Some Default Title" %>
<%@ var head: String = "" %>
<html>
<head>
<title>${title}</title>
<%-- page specific head goes here --%>
${unescape(head)}
</head>
<body>
<p>layout header goes here...</p>
${unescape(body)}
<p>layout footer goes here...</p>
</body>
</html>
#match
You can perform Scala style pattern matching using the #match
, #case
, #otherwise
and #end
directives.
You can think of matching in Scala as being like a Java switch statement only way more powerful.
The #match
takes an expression to match on, then each #case
takes a value, filter or type expression to match on.
<p>
#match (customer.type)
#case("Gold")
Great stuff
#case("Silver")
Good stuff
#otherwise
No stuff
#end
</p>
<p>
Special stuff...
</p>
This example shows how you can use type expressions instead to match on
<p>
#match (person)
#case(m: Manager)
${m.name} manages ${m.manages.size} people
#case(p: Person)
${p.name} is not a manager
#otherwise
Not a person
#end
</p>
<p>
Hey James
</p>
#do
The #do
directive can be used to invoke a function passing a block of template as an argument such as when you want to apply a specific layout to a block of template or want to call a function passing a template block, a little like you might do using custom tags in JSP.
#do(layout("someLayout.ssp"))
this is some template output...
#end
#import
The #import
directive can be used as an alternative to using <% import somePackage %>
to import Scala/Java packages, classes or methods.
#import(java.util.Date)
<p>The time is now ${new Date}</p>
<p>The time is now Thu Apr 15 15:19:41 IST 2010</p>
#{
and }#
scripletsSometimes you just want to include a couple of lines of Scala code in a template such as to define a few variables, add a few imports or whatever.
If you don't like the JSP / Erb style <%
.. %>
tags you can use velocity style #{
.. }#
instead
#{
import java.util.Date
val now = new Date
}#
Hello the time is ${now}
<%-- --%>
Ssp comments prevent everything inside the comment markers from being inserted in to the rendered document.
<%-- this is a comment --%>
${include(someUri)}
You can include other scripts in your page using the include method
${include("relativeOrAbsoluteURL"}
The URL is then evaluated and included in place in your template.