Scala Templates with Scalate, Mustache, and SSP
The scalate library makes it easy to use Mustache or SSP templates with Scala.
This blog post will show how to use Mustache and SSP templates and compares the different templating philosophies (Mustache is logic-less and SSP templates contain logic).
There are pros / cons to the different templating styles. Luckily scalate makes it easy for you to use either style.
Simple Mustache example
Suppose you have the following simple_example.mustache
file:
I like {{programming_language}}
The code is {{code_description}}
Here's how to generate a file with programming_language
set to "Scala" and code_description
set to "pretty".
import org.fusesource.scalate.TemplateEngine
val sourceDataPath = new java.io.File("./src/test/resources/simple_example.mustache").getCanonicalPath
val engine = new TemplateEngine
val someAttributes = Map(
"programming_language" -> "Scala",
"code_description" -> "pretty"
)
engine.layout(sourceDataPath, someAttributes)
Here's the string that's returned:
I like Scala
The code is pretty
Add library to SBT
You need to add the following line to your build.sbt
file to access the scalate library:
libraryDependencies += "org.scalatra.scalate" %% "scalate-core" % "1.9.6"
The import org.fusesource.scalate.TemplateEngine
import statement and org.scalatra.scalate
package name aren't aligned like they are for most projects. Just keep that in mind when you're using the library.
More Mustache examples
Lists
Let's look at how to render a list of values via a Mustache template. Suppose you'd like to display a bulleted list of popular Scala projects.
Here's a Mustache template that'll display a list of values:
{{#popular_projects}}
<b>{{name}}</b>
{{/popular_projects}}
And here is the Scala code:
val sourceDataPath = new java.io.File("./src/test/resources/scala_projects.mustache").getCanonicalPath
val engine = new TemplateEngine
val someAttributes = Map(
"popular_projects" -> List(
Map("name" -> "Spark"),
Map("name" -> "Play"),
Map("name" -> "Akka")
)
)
engine.layout(sourceDataPath, someAttributes)
It'll return this string:
<b>Spark</b>
<b>Play</b>
<b>Akka</b>
Boolean values
You can include boolean values to imitate if statement logic.
Here's a Mustache template that'll add "probably likes functional programming" to a list if the loves_scala?
flag is set to true.
**nerd profile**
* applies unix philosophy to human interactions
* dreams in binary
{{#loves_scala?}}
* probably likes functional programming
{{/loves_scala?}}
Here's Scala code that uses this template and outputs a string:
val sourceDataPath = new java.io.File("./src/test/resources/boolean_example.mustache").getCanonicalPath
val engine = new TemplateEngine
val someAttributes = Map(
"loves_scala?" -> true
)
println(engine.layout(sourceDataPath, someAttributes))
**nerd profile**
* applies unix philosophy to human interactions
* dreams in binary
* probably likes functional programming
Functions
Mustache can even handle functions that take string arguments.
Here's a Mustache template that includes a function.
select
{{#comma_delimited}}
{{column_names}}
{{/comma_delimited}}
from
{{table_name}}
Here's the Scala code that executes the function (it assumes the column names are passed in as a pipe delimited string).
val sourceDataPath = new java.io.File("./src/test/resources/function_example.mustache").getCanonicalPath
val engine = new TemplateEngine
val someAttributes = Map(
"column_names" -> "first_name|last_name|age",
"comma_delimited" -> ((cols: String) => cols.replaceAll("\\|", ",")),
"table_name" -> "fun_people"
)
println(engine.layout(sourceDataPath, someAttributes))
Here's what the code outputs:
select
first_name,last_name,age
from
fun_people
From what I can tell, the functions can only accept a single string argument. They don't work if you supply a sequence of strings for example.
The Mustache template was intentionally formatted strangely to output the SQL code with proper indentation.
SSP
SSP is another templating framework, similar to ERB in Ruby.
SSP does not follow the "logic-less templates" philosophy used by Mustache. You can add lots of logic to a SSP template.
Let's define an object that we'll access in our SSP template:
object FunStuff {
val dinnertime = "eating stuff!"
}
Let's create a simple_example.ssp
file that contains some arbitrary code and also accesses the FunStuff
object.
<% import mrpowers.scalate.example.FunStuff %>
<p>
My message is "<%= List("hi", "there", "reader!").mkString(" ") %>"
At dinnertime, I like <%= FunStuff.dinnertime %>
</p>
Notice that the template needs to import the FunStuff
object.
Let's write some Scala code that'll use the template to generate a string.
val sourceDataPath = new java.io.File("./src/test/resources/simple_example.ssp").getCanonicalPath
val engine = new TemplateEngine
println(engine.layout(sourceDataPath))
Here's the string that's returned:
<p>
My message is "hi there reader!"
At dinnertime, I like eating stuff!
</p>
scalate is intelligent enough to recognize that the file extension is ssp
, so the code should be processed with the SSP templating engine.
Templating philosophies
Logic-less templates force you to keep logic out of the templates. This makes the templates approachable to folks that are comfortable modifying HTML / SQL logic, but aren't programmers. Templates with logic aren't approachable for non-coders.
Here is a great blog on the benefits of logic-less templating.
The author argues that in the MVC context, it's best to keep logic in the views and keep the templates simple (with only HTML / mustaches).
Tips on picking templating languages
The creator of scalate has some great tips on picking a templating language in this slide deck - see slide 18.
Key points:
- Use mustache if you'd like non-programmers to "own the templates"
- Use SSP if you'd like the option to do complex template hacking
Other template options
scalate also supports Scaml (a Scala version of HAML) and Jade (another template engine inspired by HAML). There is a separate Scalatags library to build XML / HTML / CSS.
These options are only applicable for HTML templating. I personally prefer writing HTML than using fancy templating engines.
Conclusion
Scala offers great support for all different types of templating.
Templates are generally used to create HTML for websites, but they can also be used to generate SQL and other types of files.
Logic-less templating encourages a good separation of logic and makes the templates more approachable for semi-technical users, which is often desirable.
See the examples in this repo if you'd like working code snippets of all the code covered in this blog post.