Added compiler option to provide defaults for missing values

Call missingVariableValue(value) on a Compiler object to get a new
version that will insert "value" for missing values (rather than
throwing an exception).  Useful when you have templates you would
rather generated *something* instead of erroring or for when objects may
have null values themselves.
This commit is contained in:
John Montgomery
2011-04-15 10:01:40 +01:00
parent d04f2c2f76
commit 5d59eada29
3 changed files with 44 additions and 7 deletions
@@ -38,6 +38,9 @@ public class Mustache
/** Whether or not standards mode is enabled. */ /** Whether or not standards mode is enabled. */
public final boolean standardsMode; public final boolean standardsMode;
/** Replace missnig values with this value - if null will throw an exception on missing values. */
public final String missingVariableValue;
/** The template loader in use during this compilation. */ /** The template loader in use during this compilation. */
public final TemplateLoader loader; public final TemplateLoader loader;
@@ -53,24 +56,32 @@ public class Mustache
/** Returns a compiler that either does or does not escape HTML by default. */ /** Returns a compiler that either does or does not escape HTML by default. */
public Compiler escapeHTML (boolean escapeHTML) { public Compiler escapeHTML (boolean escapeHTML) {
return new Compiler(escapeHTML, this.standardsMode, this.loader); return new Compiler(escapeHTML, this.standardsMode, this.missingVariableValue, this.loader);
} }
/** Returns a compiler that either does or does not use standards mode. Standards mode /** Returns a compiler that either does or does not use standards mode. Standards mode
* disables the non-standard JMustache extensions like looking up missing names in a parent * disables the non-standard JMustache extensions like looking up missing names in a parent
* context. */ * context. */
public Compiler standardsMode (boolean standardsMode) { public Compiler standardsMode (boolean standardsMode) {
return new Compiler(this.escapeHTML, standardsMode, this.loader); return new Compiler(this.escapeHTML, standardsMode, this.missingVariableValue, this.loader);
}
/**
* Returns a compiler that will replace missing variables with the given value
**/
public Compiler missingVariableValue (String missingVariableValue) {
return new Compiler(this.escapeHTML, this.standardsMode, missingVariableValue, this.loader);
} }
/** Returns a compiler configured to use the supplied template loader to handle partials. */ /** Returns a compiler configured to use the supplied template loader to handle partials. */
public Compiler withLoader (TemplateLoader loader) { public Compiler withLoader (TemplateLoader loader) {
return new Compiler(this.escapeHTML, this.standardsMode, loader); return new Compiler(this.escapeHTML, this.standardsMode, this.missingVariableValue, loader);
} }
protected Compiler (boolean escapeHTML, boolean standardsMode, TemplateLoader loader) { protected Compiler (boolean escapeHTML, boolean standardsMode, String missingVariableValue, TemplateLoader loader) {
this.escapeHTML = escapeHTML; this.escapeHTML = escapeHTML;
this.standardsMode = standardsMode; this.standardsMode = standardsMode;
this.missingVariableValue = missingVariableValue;
this.loader = loader; this.loader = loader;
} }
} }
@@ -88,7 +99,7 @@ public class Mustache
*/ */
public static Compiler compiler () public static Compiler compiler ()
{ {
return new Compiler(true, false, FAILING_LOADER); return new Compiler(true, false, null, FAILING_LOADER);
} }
/** /**
@@ -468,8 +479,7 @@ public class Mustache
_escapeHTML = escapeHTML; _escapeHTML = escapeHTML;
} }
@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.getValue(ctx, _name, _line); Object value = tmpl.getValueWithDefault(ctx, _name, _line);
// TODO: configurable behavior on missing values
if (value == null) { if (value == null) {
throw new MustacheException( throw new MustacheException(
"No key, method or field with name '" + _name + "' on line " + _line); "No key, method or field with name '" + _name + "' on line " + _line);
@@ -126,6 +126,12 @@ public class Template
return null; return null;
} }
protected Object getValueWithDefault (Context ctx, String name, int line)
{
Object value = getValue(ctx, name, line);
return value != null? value : _compiler.missingVariableValue;
}
protected Object getValueIn (Object data, String name, int line) protected Object getValueIn (Object data, String name, int line)
{ {
if (data == null) { if (data == null) {
@@ -284,6 +284,27 @@ public class MustacheTest
"parentProperty", "bar")); "parentProperty", "bar"));
} }
@Test(expected = MustacheException.class)
public void testMissingValue () {
String tmpl = "{{ missing }} {{ notmissing }}";
Mustache.compiler().compile(tmpl).
execute(Collections.singletonMap("notmissing", "bar"));
}
@Test public void testMissingValueWithDefault () {
String tmpl = "{{ missing }}{{ notmissing }}";
String result = Mustache.compiler().missingVariableValue("").compile(tmpl).
execute(Collections.singletonMap("notmissing", "bar"));
assertEquals("bar", result);
}
@Test public void testMissingValueWithDefaultNonEmptyString () {
String tmpl = "{{ missing }}{{ notmissing }}";
String result = Mustache.compiler().missingVariableValue("foo").compile(tmpl).
execute(Collections.singletonMap("notmissing", "bar"));
assertEquals("foobar", result);
}
protected void test (Mustache.Compiler compiler, String expected, String template, Object ctx) protected void test (Mustache.Compiler compiler, String expected, String template, Object ctx)
{ {
assertEquals(expected, compiler.compile(template).execute(ctx)); assertEquals(expected, compiler.compile(template).execute(ctx));