Fix bugs relating to . and this.
First, I missed some reference checks when I stopped interning names. Fixed those. Second, when iterating over an array which contained null elements, the wrong thing was happening.
This commit is contained in:
@@ -35,9 +35,6 @@ public abstract class BasicCollector implements Mustache.Collector
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Mustache.VariableFetcher createFetcher (Object ctx, String name) {
|
public Mustache.VariableFetcher createFetcher (Object ctx, String name) {
|
||||||
// support both .name and this.name to fetch members
|
|
||||||
if (name == Template.DOT_NAME || name == Template.THIS_NAME) return THIS_FETCHER;
|
|
||||||
|
|
||||||
if (ctx instanceof Map<?,?>) return MAP_FETCHER;
|
if (ctx instanceof Map<?,?>) return MAP_FETCHER;
|
||||||
|
|
||||||
// if the name looks like a number, potentially use one of our 'indexing' fetchers
|
// if the name looks like a number, potentially use one of our 'indexing' fetchers
|
||||||
@@ -73,7 +70,7 @@ public abstract class BasicCollector implements Mustache.Collector
|
|||||||
Map<?,?> map = (Map<?,?>)ctx;
|
Map<?,?> map = (Map<?,?>)ctx;
|
||||||
if (map.containsKey(name)) return map.get(name);
|
if (map.containsKey(name)) return map.get(name);
|
||||||
// special case to allow map entry set to be iterated over
|
// special case to allow map entry set to be iterated over
|
||||||
if (name == "entrySet") return map.entrySet();
|
if ("entrySet".equals(name)) return map.entrySet();
|
||||||
return Template.NO_FETCHER_FOUND;
|
return Template.NO_FETCHER_FOUND;
|
||||||
}
|
}
|
||||||
@Override public String toString () {
|
@Override public String toString () {
|
||||||
@@ -113,15 +110,6 @@ public abstract class BasicCollector implements Mustache.Collector
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected static final Mustache.VariableFetcher THIS_FETCHER = new Mustache.VariableFetcher() {
|
|
||||||
public Object get (Object ctx, String name) throws Exception {
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
@Override public String toString () {
|
|
||||||
return "THIS_FETCHER";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
protected static abstract class ArrayHelper implements Mustache.VariableFetcher {
|
protected static abstract class ArrayHelper implements Mustache.VariableFetcher {
|
||||||
public Object get (Object ctx, String name) throws Exception {
|
public Object get (Object ctx, String name) throws Exception {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -856,8 +856,10 @@ public class Mustache {
|
|||||||
@Override public void execute (Template tmpl, Template.Context ctx, Writer out) {
|
@Override public void execute (Template tmpl, Template.Context ctx, Writer out) {
|
||||||
Object value = tmpl.getValueOrDefault(ctx, _name, _line);
|
Object value = tmpl.getValueOrDefault(ctx, _name, _line);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw new MustacheException.Context("No key, method or field with name '" + _name +
|
String msg = Template.isThisName(_name) ?
|
||||||
"' on line " + _line, _name, _line);
|
"Resolved '.' to null (which is disallowed), on line " + _line :
|
||||||
|
"No key, method or field with name '" + _name + "' on line " + _line;
|
||||||
|
throw new MustacheException.Context(msg, _name, _line);
|
||||||
}
|
}
|
||||||
write(out, _escaper.escape(_formatter.format(value)));
|
write(out, _escaper.escape(_formatter.format(value)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ public class Template {
|
|||||||
// if we reach here, we found nothing in this or our parent contexts...
|
// if we reach here, we found nothing in this or our parent contexts...
|
||||||
|
|
||||||
// if we have a compound key, decompose the value and resolve it step by step
|
// if we have a compound key, decompose the value and resolve it step by step
|
||||||
if (name != DOT_NAME && name.indexOf(DOT_NAME) != -1) {
|
if (!name.equals(DOT_NAME) && name.indexOf(DOT_NAME) != -1) {
|
||||||
return getCompoundValue(ctx, name, line, missingIsNull);
|
return getCompoundValue(ctx, name, line, missingIsNull);
|
||||||
} else {
|
} else {
|
||||||
// otherwise let checkForMissing() decide what to do
|
// otherwise let checkForMissing() decide what to do
|
||||||
@@ -297,6 +297,11 @@ public class Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Object getValueIn (Object data, String name, int line) {
|
protected Object getValueIn (Object data, String name, int line) {
|
||||||
|
// if we're getting `.` or `this` then just return the whole context; we do this before the
|
||||||
|
// null check because it may be valid for the context to be null (if we're iterating over a
|
||||||
|
// list which contains nulls, for example)
|
||||||
|
if (isThisName(name)) return data;
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
throw new NullPointerException(
|
throw new NullPointerException(
|
||||||
"Null context for variable '" + name + "' on line " + line);
|
"Null context for variable '" + name + "' on line " + line);
|
||||||
@@ -412,6 +417,10 @@ public class Template {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static boolean isThisName (String name) {
|
||||||
|
return DOT_NAME.equals(name) || THIS_NAME.equals(name);
|
||||||
|
}
|
||||||
|
|
||||||
protected static final String DOT_NAME = ".";
|
protected static final String DOT_NAME = ".";
|
||||||
protected static final String THIS_NAME = "this";
|
protected static final String THIS_NAME = "this";
|
||||||
protected static final String FIRST_NAME = "-first";
|
protected static final String FIRST_NAME = "-first";
|
||||||
|
|||||||
@@ -321,6 +321,12 @@ public abstract class SharedTests extends GWTTestCase
|
|||||||
execute(context("things", Arrays.asList("bar", "baz", "bif"))));
|
execute(context("things", Arrays.asList("bar", "baz", "bif"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testNestedNullThis () {
|
||||||
|
check("bar!bif", Mustache.compiler().defaultValue("!").
|
||||||
|
compile("{{#things}}{{.}}{{/things}}").
|
||||||
|
execute(context("things", Arrays.asList("bar", null, "bif"))));
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void testNewlineSkipping () {
|
@Test public void testNewlineSkipping () {
|
||||||
testNewlineSkipping("\n");
|
testNewlineSkipping("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user