Writing custom taglibs
can easily become messy - explicit HTML, appending ad-hoc strings to a
StringBuilder
, adding attributes based on tag arguments can easily turn
relatively simple code into an unmaintainable mess. Not to mention trying to
trace logic paths to track down bugs..
Using MarkupBuilder
One strategy I have used to simplify construction of HTML in taglibs is to use
Groovy's MarkupBuilder
to create content is a cleaner way than raw Strings.
MarkupBuilder
extends BuilderSupport
,
which is a base class to provide support to arbitrary nested objects, allowing
the ability to create DSL-like trees.
In this case MarkupBuilder
can help to create structured, nested additions
to an object tree that when rendered to a String
, outputs valid HTML to be
used in place of the tag.
An example (taken from the class documentation):
When rendered to a StringWriter
, will output:
Notice that there are tags (root
, a
, b
, c
), attributes (a1
, a2
), and text content included in the objects added to the builder.
If we take the following code:
The MarkupBuilder
equivalent could be:
I reckon this looks much cleaner, simplier and maintainable.
You can pass in whatever attributes you want to the parameters, and a node
will be attached to the tree with the element name and attributes. The
omitNullAttributes
setting I find useful for when an attribute might be
missing (e.g. a value being passed to an input field) without disturbing the
code.
FYI: mkp is a reference to the MarkupBuilderHelper class.
Another example, with nested elements using Twitter Bootstrap CSS classes:
Many of the attributes here are variables passed to the tag function.
Testability
So how does using MarkupBuilder help make the code more testable?
Probably the most pain from maintaining taglib tests comes from inconsistencies in formatting - namely:
- Whitespace, indents - makes maintaining text matching assertions tedious
- Use of different quote marks around attributes - while syntactically correct, more tedium, and potentially causing rendering issues when mixed with grails
${var}
placeholders - Validating HTML At the very least, using MarkupBuilder makes the generated HTML more reliable and consistent, meaning that tests can be more resilient. It is difficult enough when some tests must be reduced to textual comparisons.
By the way, the official grails documentation here outlines the basic ways of testing output using Spock Specification framework.