August 7, 2014

Groovy Goodness: Use Custom Template Class with MarkupTemplateEngine

Since Groovy 2.3 we can use the new MarkupTemplateEngine to generate XML/HTML content. The engine compiles the template for better performance and optionally provides type checking on model attributes used in the template. We can configure the template engine to use a custom base template class instead of the default BaseTemplate. In our custom template class we can add new methods that can be invoked from our template content.

Let's create a new base template class with an icon method to output valid FontAwesome markup:

// File: FontAwesomeTemplate.groovy
package com.mrhaki.groovy.tmpl

import groovy.text.markup.*
import groovy.text.*

abstract class FontAwesomeTemplate extends BaseTemplate {

        final MarkupTemplateEngine templateEngine, 
        final Map model, 
        final Map<String,String> modelTypes, 
        final TemplateConfiguration configuration) {
        super(templateEngine, model, modelTypes, configuration)

     * Generate FontAwesome markup. 
     * @param icon Name of the icon, will be prefixed with 'fa-'.
     * @param attributes Optional extra attributes, will be added to markup
     *                   and prefixed with 'fa-'.
     * @return Span element with class attribute value for FontAwesome
    String icon(final String icon, final String[] attributes = []) {
        // Prefix attribute names with fa-.
        final faAttributes = attributes.collect { "fa-$it" }

        // Create markup.
        $/<span class="fa fa-${icon} ${faAttributes.join(' ')}"></span>/$


Now we can create a new MarkupTemplateEngine and use our FontAwesomeTemplate class as the base template. We assign our template class to the baseTemplateClass property of TemplateConfiguration:

import com.mrhaki.groovy.tmpl.*
import groovy.text.*
import groovy.text.markup.*

// Create configuration and set 
// base template class to
// FontAwesomeTemplate.
TemplateConfiguration config = new TemplateConfiguration(
    baseTemplateClass: FontAwesomeTemplate

// Create engine with configuration.
MarkupTemplateEngine engine = new MarkupTemplateEngine(config)     

// Create template with text using
// the icon method.
Template template = engine.createTemplate('''
    ul {
        // Use the name of the icon as argument
        // for the icon method.
        li icon('cloud')

        // Any extra arguments are assumed
        // to be FontAwesome attributes.
        li icon('pencil', 'large', 'rotate-90')

    // If we want to use the icon method in between
    // text we must use the ${stringOf notation}.
    p "This is a ${stringOf {icon('home')}} home icon."

    // Or use yieldUnescaped method.
    p {
        yield "This is a "
        yieldUnescaped icon('cog')
        yield " settings icon."


// Render output for template.
Writer writer = new StringWriter()                          
Writable output = template.make([:])  
String result = writer.toString()

// This is what we would expect as a result.
// (/ is the continuation character, so it is 
//  actually all one line)
def expected = $/\
<li><span class="fa fa-cloud "></span></li>\
<li><span class="fa fa-pencil fa-large fa-rotate-90"></span></li>\
<p>This is a <span class="fa fa-home "></span> home icon.</p>\
<p>This is a <span class="fa fa-cog "></span> settings icon.</p>\

assert result == expected

Code written with Groovy 2.3.6.