Added skipping of newlines immediately following section open and close tags.

This commit is contained in:
Michael Bayne
2010-10-21 23:19:10 +00:00
parent 0bef6a06e5
commit eb225b0b48
2 changed files with 47 additions and 4 deletions
@@ -75,6 +75,7 @@ public class Mustache
int state = TEXT, startPos = 0, endPos = 0;
StringBuilder text = new StringBuilder();
int line = 0;
boolean skipNewline = false;
while (true) {
char c;
@@ -90,6 +91,13 @@ public class Mustache
if (c == '\n') {
line++;
// if we just parsed an open section or close section task, we'll skip the first
// newline character following it, if desired; TODO: handle CR, sigh
if (skipNewline) {
continue;
}
} else {
skipNewline = false;
}
switch (state) {
@@ -126,6 +134,7 @@ public class Mustache
// TODO: change delimiters
} else {
accum = accum.addTagSegment(text, line);
skipNewline = accum.skipNewline();
}
state = TEXT;
} else {
@@ -142,6 +151,7 @@ public class Mustache
// TODO: change delimiters
} else {
accum = accum.addTagSegment(text, line);
skipNewline = accum.skipNewline();
}
state = TEXT;
} else {
@@ -195,6 +205,12 @@ public class Mustache
_compiler = compiler;
}
public boolean skipNewline () {
// return true if we just added a compound segment which means we're immediately
// following the close section tag
return (_segs.size() > 0 && _segs.get(_segs.size()-1) instanceof CompoundSegment);
}
public void addTextSegment (StringBuilder text) {
if (text.length() > 0) {
_segs.add(new StringSegment(text.toString()));
@@ -212,11 +228,15 @@ public class Mustache
case '#':
requireNoNewlines(tag, line);
return new Accumulator(_compiler) {
public Template.Segment[] finish () {
@Override public boolean skipNewline () {
// if we just opened this section, we want to skip a newline
return (_segs.size() == 0) || super.skipNewline();
}
@Override public Template.Segment[] finish () {
throw new MustacheException("Section missing close tag " +
"[line=" + line + ", name=" + tag1 + "]");
}
protected Accumulator addCloseSectionSegment (String itag, int line) {
@Override protected Accumulator addCloseSectionSegment (String itag, int line) {
requireSameName(tag1, itag, line);
outer._segs.add(new SectionSegment(itag, super.finish()));
return outer;
@@ -226,11 +246,15 @@ public class Mustache
case '^':
requireNoNewlines(tag, line);
return new Accumulator(_compiler) {
public Template.Segment[] finish () {
@Override public boolean skipNewline () {
// if we just opened this section, we want to skip a newline
return (_segs.size() == 0) || super.skipNewline();
}
@Override public Template.Segment[] finish () {
throw new MustacheException("Inverted section missing close tag " +
"[line=" + line + ", name=" + tag1 + "]");
}
protected Accumulator addCloseSectionSegment (String itag, int line) {
@Override protected Accumulator addCloseSectionSegment (String itag, int line) {
requireSameName(tag1, itag, line);
outer._segs.add(new InvertedSectionSegment(itag, super.finish()));
return outer;
@@ -147,6 +147,25 @@ public class MustacheTest
});
}
@Test public void testNewlineSkipping () {
String tmpl = "list:\n" +
"{{#items}}\n" +
"{{this}}\n" +
"{{/items}}\n" +
"{{^items}}\n" +
"no items\n" +
"{{/items}}\n" +
"endlist";
test("list:\n" +
"one\n" +
"two\n" +
"three\n" +
"endlist", tmpl, context("items", Arrays.asList("one", "two", "three")));
test("list:\n" +
"no items\n" +
"endlist", tmpl, context("items", Collections.emptyList()));
}
protected void test (String expected, String template, Object ctx)
{
assertEquals(expected, Mustache.compiler().compile(template).execute(ctx));