No escaping of HTML by default. Added Compiler builder mechanism to specify

default HTML escaping behavior. Possibly pattern overkill, but if we add any
other options later, this will scale nicely.
This commit is contained in:
Michael Bayne
2010-10-21 20:49:53 +00:00
parent a7984b1594
commit 89c1590ec1
2 changed files with 49 additions and 11 deletions
@@ -23,21 +23,48 @@ import java.util.Map;
*/
public class Mustache
{
/** An interface to the Mustache compilation process. */
public static class Compiler {
/** Whether or not HTML entities are escaped by default. */
public final boolean escapeHTML;
/** Compiles the supplied template into a repeatedly executable intermediate form. */
public Template compile (String template)
{
return compile(new StringReader(template));
}
/** Compiles the supplied template into a repeatedly executable intermediate form. */
public Template compile (Reader source)
{
return Mustache.compile(source, this);
}
/** Returns a compiler that either does or does not escape HTML by default. */
public Compiler escapeHTML (boolean escapeHTML) {
return new Compiler(escapeHTML);
}
protected Compiler (boolean escapeHTML) {
this.escapeHTML = escapeHTML;
}
}
/**
* Compiles the supplied template into a repeatedly executable intermediate form.
* Returns a compiler that <em>does not</em> escape HTML by default.
*/
public static Template compile (String template)
public static Compiler compiler ()
{
return compile(new StringReader(template));
return new Compiler(false);
}
/**
* Compiles the supplied template into a repeatedly executable intermediate form.
*/
public static Template compile (Reader source)
protected static Template compile (Reader source, Compiler compiler)
{
// a hand-rolled parser; whee!
Accumulator accum = new Accumulator();
Accumulator accum = new Accumulator(compiler);
char start1 = '{', start2 = '{', end1 = '}', end2 = '}';
int state = TEXT, startPos = 0, endPos = 0;
StringBuilder text = new StringBuilder();
@@ -156,6 +183,10 @@ public class Mustache
protected static final int TAG = 3;
protected static class Accumulator {
public Accumulator (Compiler compiler) {
_compiler = compiler;
}
public void addTextSegment (StringBuilder text) {
if (text.length() > 0) {
_segs.add(new StringSegment(text.toString()));
@@ -172,7 +203,7 @@ public class Mustache
switch (tag.charAt(0)) {
case '#':
requireNoNewlines(tag, line);
return new Accumulator() {
return new Accumulator(_compiler) {
public Template.Segment[] finish () {
throw new MustacheException("Section missing close tag " +
"[line=" + line + ", name=" + tag1 + "]");
@@ -186,7 +217,7 @@ public class Mustache
case '^':
requireNoNewlines(tag, line);
return new Accumulator() {
return new Accumulator(_compiler) {
public Template.Segment[] finish () {
throw new MustacheException("Inverted section missing close tag " +
"[line=" + line + ", name=" + tag1 + "]");
@@ -213,7 +244,7 @@ public class Mustache
default:
requireNoNewlines(tag, line);
_segs.add(new VariableSegment(tag, true));
_segs.add(new VariableSegment(tag, _compiler.escapeHTML));
return this;
}
}
@@ -243,6 +274,7 @@ public class Mustache
}
}
protected Compiler _compiler;
protected final List<Template.Segment> _segs = new ArrayList<Template.Segment>();
}
@@ -46,7 +46,7 @@ public class MustacheTest
}
@Test public void testCallSiteReuse () {
Template tmpl = Mustache.compile("{{foo}}");
Template tmpl = Mustache.compiler().compile("{{foo}}");
Object ctx = new Object() {
String getFoo () { return "bar"; }
};
@@ -56,7 +56,7 @@ public class MustacheTest
}
@Test public void testCallSiteChange () {
Template tmpl = Mustache.compile("{{foo}}");
Template tmpl = Mustache.compiler().compile("{{foo}}");
assertEquals("bar", tmpl.execute(new Object() {
String getFoo () { return "bar"; }
}));
@@ -113,9 +113,15 @@ public class MustacheTest
test("foobar", "foo{{! nothing to see here}}bar", new Object());
}
@Test public void testEscapeHTML () {
assertEquals("<b>", Mustache.compiler().compile("{{a}}").execute(context("a", "<b>")));
assertEquals("&lt;b&gt;", Mustache.compiler().escapeHTML(true).
compile("{{a}}").execute(context("a", "<b>")));
}
protected void test (String expected, String template, Object ctx)
{
assertEquals(expected, Mustache.compile(template).execute(ctx));
assertEquals(expected, Mustache.compiler().compile(template).execute(ctx));
}
protected static Object context (Object... data)