I'm not going to go into the syntax of Soy templates - if you've ever used a templating system like FreeMarker or Django Templates then you shouldn't have any trouble using Soy templates (though you should be aware that Soy eats white space, so your output might not be what you expect if you don't use special character commands to put whitespace into the output).
Here's an example template (that I saved as "widget.soy"):
{namespace com.maethorechannen.widgets}
/** Widget template
* @param widget Widget Data
*/
{template .widget}
<?xml version="1.0" encoding="utf-8"?>{\n}
<widget>{\n}
{\t}<widgetname>{$widget.name}</widgetname>{\n}
{\t}<width>{$widget.display.width}</width>{\n}
{\t}<height>{$widget.display.height}</height>{\n}
</widget>
{/template}
Using the templates from Scala:
At a minimum, you'll need the following imports:
import com.google.template.soy.SoyFileSet
import com.google.template.soy.data.SoyMapData
import com.google.template.soy.tofu.SoyTofu
import java.io.File
To pass your data to the ToFu rendering engine, you'll need to have your data in either a SoyMapData object or in a plain old Java Map object. As I wanted to use Scala's sugar for quickly building up a Map, I needed to write up an implicit def from Scala's Map to a SoyMapData (quick aside - the sort of thing that stops me from loving Scala is having to do something like this - the impedence mismatch between Java collections and Scala collections is still too big). This function isn't complete, but it will convert the values I was using:
implicit def mapToSoy(m: Map[String, _]): SoyMapData = {
val sm = new SoyMapData()
m.keys.foreach {k =>
val v: Any = m(k)
v match {
case s: String => sm.put(k,s)
case mm: Map[String, _] => sm.put(k, mapToSoy(mm))
case i: Int => sm.put(k, i)
}
}
return sm
}
Here's the Map I'm passing in:
val map = Map[String, Any](
"widget" -> Map[String, Any](
"name" -> "Scala Test",
"display" -> Map[String, Any](
"width"-> 240,
"height" -> 320)))
To actually use the template, I need to load the template into a SoyFileSet, and then compile the template to a rendering object
val sfs = (new SoyFileSet.Builder()).add(new File("widget.soy")).build();
val tofu = sfs.compileToJavaObj()
Finally, I render the template with my data
println(tofu.render("com.maethorechannen.widgets.widget", map, null));
Which renders the following:
<?xml version="1.0" encoding="utf-8"?>
<widget>
<widgetname>Scala Test</widgetname>
<width>240</width>
<height>320</height>
</widget>
Scala Source Code
Using the templates from Groovy:
Using Soy from Groovy is almost identical to using Soy from Scala, but without the need for the implicit def (as Groovy Map sugar returns a Java Map).
import com.google.template.soy.SoyFileSet
import com.google.template.soy.data.SoyMapData
import com.google.template.soy.tofu.SoyTofu
def map = [widget: [
name: "Widget Name",
display: [
width: 240,
height: 320
]
]]
def sfs = (new SoyFileSet.Builder()).add(new File("widget.soy")).build();
def tofu = sfs.compileToJavaObj()
println(tofu.render("com.maethorechannen.widgets.widget", map, null));
Groovy Source Code
0 comments:
Post a Comment