diff --git a/src/main/java/com/samskivert/mustache/Mustache.java b/src/main/java/com/samskivert/mustache/Mustache.java index cc53473..25a7bec 100644 --- a/src/main/java/com/samskivert/mustache/Mustache.java +++ b/src/main/java/com/samskivert/mustache/Mustache.java @@ -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 does not 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 _segs = new ArrayList(); } diff --git a/src/test/java/com/samskivert/mustache/MustacheTest.java b/src/test/java/com/samskivert/mustache/MustacheTest.java index 8c3e380..b83c3d7 100644 --- a/src/test/java/com/samskivert/mustache/MustacheTest.java +++ b/src/test/java/com/samskivert/mustache/MustacheTest.java @@ -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("", Mustache.compiler().compile("{{a}}").execute(context("a", ""))); + assertEquals("<b>", Mustache.compiler().escapeHTML(true). + compile("{{a}}").execute(context("a", ""))); + } + 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)