Modified compound variables to honor null/default configuration. Closes #10.
Kali/Bertrand convinced me that being consistent with other Mustache implementations is more important than whatever wacky reasons I was harboring for keeping compound variables different than singleton sections.
This commit is contained in:
@@ -280,18 +280,9 @@ sections. The above examples could also be represented as:
|
|||||||
Hello {{#class}}{{name}}{{/class}}!
|
Hello {{#class}}{{name}}{{/class}}!
|
||||||
|
|
||||||
Note also that one semantic difference exists between nested singleton sections
|
Note also that one semantic difference exists between nested singleton sections
|
||||||
and compound variables: compound variables do not make use of the default value
|
and compound variables: after resolving the object for the first component of
|
||||||
and null value configuration. If a null or missing value is encountered while
|
the compound variable, parent contexts will not be searched when resolving
|
||||||
resolving a compound variable, an exception is always raised.
|
subcomponents.
|
||||||
|
|
||||||
If you desire for a default value to be used when null or missing values are
|
|
||||||
encountered, use the somewhat more verbose singleton sections. The use of
|
|
||||||
sections clearly communicates to someone reading the template that the section
|
|
||||||
will not be rendered if the object it references is missing or null and allows
|
|
||||||
for a site-specific default value to be used, as in:
|
|
||||||
|
|
||||||
{{#foo}}{{name}}{{/foo}}
|
|
||||||
{{^foo}}Missing foo!{{/foo}}
|
|
||||||
|
|
||||||
Newline trimming
|
Newline trimming
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
@@ -85,9 +85,7 @@ public class Mustache
|
|||||||
|
|
||||||
/** Returns a compiler that will use the given value for any variable that is missing, or
|
/** Returns a compiler that will use the given value for any variable that is missing, or
|
||||||
* otherwise resolves to null. This is like {@link #nullValue} except that it returns the
|
* otherwise resolves to null. This is like {@link #nullValue} except that it returns the
|
||||||
* supplied default for missing keys and existing keys that return null values. Note that
|
* supplied default for missing keys and existing keys that return null values. */
|
||||||
* regardless of whether a null or default value is configured, if the resolution of part
|
|
||||||
* of a compound key results in a missing or null value, an exception will be raised. */
|
|
||||||
public Compiler defaultValue (String defaultValue) {
|
public Compiler defaultValue (String defaultValue) {
|
||||||
return new Compiler(this.escapeHTML, this.standardsMode, defaultValue, true,
|
return new Compiler(this.escapeHTML, this.standardsMode, defaultValue, true,
|
||||||
this.loader, this.collector);
|
this.loader, this.collector);
|
||||||
@@ -103,10 +101,7 @@ public class Mustache
|
|||||||
* <li>In the case of a {@link Map} being used as a context, all possible accessors are
|
* <li>In the case of a {@link Map} being used as a context, all possible accessors are
|
||||||
* assumed to exist (but potentially return null), and no exception will ever be
|
* assumed to exist (but potentially return null), and no exception will ever be
|
||||||
* raised.</li>
|
* raised.</li>
|
||||||
* </ul>
|
* </ul> */
|
||||||
* Note that regardless of whether a null or default value is configured, if the resolution
|
|
||||||
* of part of a compound key results in a missing or null value, an exception will be
|
|
||||||
* raised. */
|
|
||||||
public Compiler nullValue (String nullValue) {
|
public Compiler nullValue (String nullValue) {
|
||||||
return new Compiler(this.escapeHTML, this.standardsMode, nullValue, false,
|
return new Compiler(this.escapeHTML, this.standardsMode, nullValue, false,
|
||||||
this.loader, this.collector);
|
this.loader, this.collector);
|
||||||
|
|||||||
@@ -93,13 +93,12 @@ public class Template
|
|||||||
Object data = getValue(ctx, comps[0].intern(), line, missingIsNull);
|
Object data = getValue(ctx, comps[0].intern(), line, missingIsNull);
|
||||||
for (int ii = 1; ii < comps.length; ii++) {
|
for (int ii = 1; ii < comps.length; ii++) {
|
||||||
if (data == NO_FETCHER_FOUND) {
|
if (data == NO_FETCHER_FOUND) {
|
||||||
throw new NullPointerException(
|
if (!missingIsNull) throw new MustacheException(
|
||||||
"Missing context for compound variable '" + name + "' on line " + line +
|
"Missing context for compound variable '" + name + "' on line " + line +
|
||||||
". '" + comps[ii - 1] + "' was not found.");
|
". '" + comps[ii - 1] + "' was not found.");
|
||||||
|
return null;
|
||||||
} else if (data == null) {
|
} else if (data == null) {
|
||||||
throw new NullPointerException(
|
return null;
|
||||||
"Null context for compound variable '" + name + "' on line " + line +
|
|
||||||
". '" + comps[ii - 1] + "' resolved to null.");
|
|
||||||
}
|
}
|
||||||
// once we step into a composite key, we drop the ability to query our parent
|
// once we step into a composite key, we drop the ability to query our parent
|
||||||
// contexts; that would be weird and confusing
|
// contexts; that would be weird and confusing
|
||||||
@@ -214,12 +213,9 @@ public class Template
|
|||||||
protected Object checkForMissing (String name, int line, boolean missingIsNull, Object value)
|
protected Object checkForMissing (String name, int line, boolean missingIsNull, Object value)
|
||||||
{
|
{
|
||||||
if (value == NO_FETCHER_FOUND) {
|
if (value == NO_FETCHER_FOUND) {
|
||||||
if (missingIsNull) {
|
if (missingIsNull) return null;
|
||||||
return null;
|
throw new MustacheException(
|
||||||
} else {
|
"No method or field with name '" + name + "' on line " + line);
|
||||||
throw new MustacheException(
|
|
||||||
"No method or field with name '" + name + "' on line " + line);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ public class MustacheTest
|
|||||||
execute(context("things", Arrays.asList("bar", "baz", "bif"))));
|
execute(context("things", Arrays.asList("bar", "baz", "bif"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void testStructuredVariable () {
|
@Test public void testCompoundVariable () {
|
||||||
test("hello", "{{foo.bar.baz}}", new Object() {
|
test("hello", "{{foo.bar.baz}}", new Object() {
|
||||||
Object foo () {
|
Object foo () {
|
||||||
return new Object() {
|
return new Object() {
|
||||||
@@ -271,25 +271,39 @@ public class MustacheTest
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=NullPointerException.class)
|
@Test(expected=MustacheException.class)
|
||||||
public void testNullComponentInCompoundVariable () {
|
public void testNullComponentInCompoundVariable () {
|
||||||
// make sure that even if we have a null value configured, we freak out
|
test(Mustache.compiler(), "unused", "{{foo.bar.baz}}", new Object() {
|
||||||
test(Mustache.compiler().nullValue("foo"), "unused", "{{foo.bar.baz}}", new Object() {
|
Object foo = new Object() {
|
||||||
Object foo () {
|
Object bar = null;
|
||||||
return new Object() {
|
};
|
||||||
Object bar = null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=NullPointerException.class)
|
@Test(expected=MustacheException.class)
|
||||||
public void testMissingComponentInCompoundVariable () {
|
public void testMissingComponentInCompoundVariable () {
|
||||||
// make sure that even if we have a default value configured, we freak out
|
test(Mustache.compiler(), "unused", "{{foo.bar.baz}}", new Object() {
|
||||||
test(Mustache.compiler().defaultValue("foo"), "unused", "{{foo.bar.baz}}", new Object() {
|
Object foo = new Object(); // no bar
|
||||||
Object foo () {
|
});
|
||||||
return new Object(); // no bar
|
}
|
||||||
}
|
|
||||||
|
public void testNullComponentInCompoundVariableWithDefault () {
|
||||||
|
test(Mustache.compiler().nullValue("null"), "null", "{{foo.bar.baz}}", new Object() {
|
||||||
|
Object foo = null;
|
||||||
|
});
|
||||||
|
test(Mustache.compiler().nullValue("null"), "null", "{{foo.bar.baz}}", new Object() {
|
||||||
|
Object foo = new Object() {
|
||||||
|
Object bar = null;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMissingComponentInCompoundVariableWithDefault () {
|
||||||
|
test(Mustache.compiler().defaultValue("?"), "?", "{{foo.bar.baz}}", new Object() {
|
||||||
|
// no foo, no bar
|
||||||
|
});
|
||||||
|
test(Mustache.compiler().defaultValue("?"), "?", "{{foo.bar.baz}}", new Object() {
|
||||||
|
Object foo = new Object(); // no bar
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user