Added mechanism to customize toString-ing of values.

This commit is contained in:
Michael Bayne
2014-01-08 10:50:37 -08:00
parent 9372c7009e
commit acc339ee13
@@ -55,6 +55,10 @@ public class Mustache
* mustache implementation. Default is false. */ * mustache implementation. Default is false. */
public final boolean zeroIsFalse; public final boolean zeroIsFalse;
/** Handles converting objects to strings when rendering a template. The default formatter
* uses {@link String#valueOf}. */
public final Formatter formatter;
/** Handles escaping characters in substituted text. */ /** Handles escaping characters in substituted text. */
public final Escaper escaper; public final Escaper escaper;
@@ -88,8 +92,8 @@ public class Mustache
* context. */ * context. */
public Compiler standardsMode (boolean standardsMode) { public Compiler standardsMode (boolean standardsMode) {
return new Compiler(standardsMode, this.nullValue, this.missingIsNull, return new Compiler(standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); this.escaper, this.loader, this.collector, this.delims);
} }
/** 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
@@ -97,8 +101,8 @@ public class Mustache
* supplied default for missing keys and existing keys that return null values. */ * supplied default for missing keys and existing keys that return null values. */
public Compiler defaultValue (String defaultValue) { public Compiler defaultValue (String defaultValue) {
return new Compiler(this.standardsMode, defaultValue, true, return new Compiler(this.standardsMode, defaultValue, true,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); this.escaper, this.loader, this.collector, this.delims);
} }
/** Returns a compiler that will use the given value for any variable that resolves to /** Returns a compiler that will use the given value for any variable that resolves to
@@ -114,43 +118,50 @@ public class Mustache
* </ul> */ * </ul> */
public Compiler nullValue (String nullValue) { public Compiler nullValue (String nullValue) {
return new Compiler(this.standardsMode, nullValue, false, return new Compiler(this.standardsMode, nullValue, false,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); this.escaper, this.loader, this.collector, this.delims);
} }
/** Returns a compiler that will treat empty string as a false value if parameter is true. */ /** Returns a compiler that will treat empty string as a false value if parameter is true. */
public Compiler emptyStringIsFalse (boolean emptyStringIsFalse) { public Compiler emptyStringIsFalse (boolean emptyStringIsFalse) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
emptyStringIsFalse, this.zeroIsFalse, this.escaper, emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); this.escaper, this.loader, this.collector, this.delims);
} }
/** Returns a compiler that will treat zero as a false value if parameter is true. */ /** Returns a compiler that will treat zero as a false value if parameter is true. */
public Compiler zeroIsFalse (boolean zeroIsFalse) { public Compiler zeroIsFalse (boolean zeroIsFalse) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, zeroIsFalse, this.escaper, this.emptyStringIsFalse, zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); this.escaper, this.loader, this.collector, this.delims);
}
/** Configures the {@link Formatter} used to turn objects into strings. */
public Compiler withFormatter (Formatter formatter) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, formatter,
this.escaper, this.loader, this.collector, this.delims);
} }
/** Configures the {@link Escaper} used to escape substituted text. */ /** Configures the {@link Escaper} used to escape substituted text. */
public Compiler withEscaper (Escaper escaper) { public Compiler withEscaper (Escaper escaper) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, this.delims); escaper, this.loader, this.collector, this.delims);
} }
/** 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.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
loader, this.collector, this.delims); this.escaper, loader, this.collector, this.delims);
} }
/** Returns a compiler configured to use the supplied collector. */ /** Returns a compiler configured to use the supplied collector. */
public Compiler withCollector (Collector collector) { public Compiler withCollector (Collector collector) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, collector, this.delims); this.escaper, this.loader, collector, this.delims);
} }
/** Returns a compiler configured to use the supplied delims as default delimiters. /** Returns a compiler configured to use the supplied delims as default delimiters.
@@ -158,8 +169,9 @@ public class Mustache
* opening delims and C and D are closing delims. */ * opening delims and C and D are closing delims. */
public Compiler withDelims (String delims) { public Compiler withDelims (String delims) {
return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull, return new Compiler(this.standardsMode, this.nullValue, this.missingIsNull,
this.emptyStringIsFalse, this.zeroIsFalse, this.escaper, this.emptyStringIsFalse, this.zeroIsFalse, this.formatter,
this.loader, this.collector, new Delims().updateDelims(delims)); this.escaper, this.loader, this.collector,
new Delims().updateDelims(delims));
} }
/** Returns the value to use in the template for the null-valued property {@code name}. See /** Returns the value to use in the template for the null-valued property {@code name}. See
@@ -177,13 +189,15 @@ public class Mustache
} }
protected Compiler (boolean standardsMode, String nullValue, boolean missingIsNull, protected Compiler (boolean standardsMode, String nullValue, boolean missingIsNull,
boolean emptyStringIsFalse, boolean zeroIsFalse, Escaper escaper, boolean emptyStringIsFalse, boolean zeroIsFalse, Formatter formatter,
TemplateLoader loader, Collector collector, Delims delims) { Escaper escaper, TemplateLoader loader, Collector collector,
Delims delims) {
this.standardsMode = standardsMode; this.standardsMode = standardsMode;
this.nullValue = nullValue; this.nullValue = nullValue;
this.missingIsNull = missingIsNull; this.missingIsNull = missingIsNull;
this.emptyStringIsFalse = emptyStringIsFalse; this.emptyStringIsFalse = emptyStringIsFalse;
this.zeroIsFalse = zeroIsFalse; this.zeroIsFalse = zeroIsFalse;
this.formatter = formatter;
this.escaper = escaper; this.escaper = escaper;
this.loader = loader; this.loader = loader;
this.collector = collector; this.collector = collector;
@@ -191,6 +205,13 @@ public class Mustache
} }
} }
/** Handles converting objects to strings when rendering templates. */
public interface Formatter
{
/** Converts {@code value} to a string for inclusion in a template. */
String format (Object value);
}
/** Handles lambdas. */ /** Handles lambdas. */
public interface Lambda public interface Lambda
{ {
@@ -247,7 +268,7 @@ public class Mustache
* Returns a compiler that escapes HTML by default and does not use standards mode. * Returns a compiler that escapes HTML by default and does not use standards mode.
*/ */
public static Compiler compiler () { public static Compiler compiler () {
return new Compiler(false, null, true, false, false, Escapers.HTML, return new Compiler(false, null, true, false, false, DEFAULT_FORMATTER, Escapers.HTML,
FAILING_LOADER, new DefaultCollector(), new Delims()); FAILING_LOADER, new DefaultCollector(), new Delims());
} }
@@ -580,12 +601,12 @@ public class Mustache
case '&': case '&':
requireNoNewlines(tag, tagLine); requireNoNewlines(tag, tagLine);
_segs.add(new VariableSegment(tag1, tagLine, Escapers.NONE)); _segs.add(new VariableSegment(tag1, tagLine, _comp.formatter, Escapers.NONE));
return this; return this;
default: default:
requireNoNewlines(tag, tagLine); requireNoNewlines(tag, tagLine);
_segs.add(new VariableSegment(tag, tagLine, _comp.escaper)); _segs.add(new VariableSegment(tag, tagLine, _comp.formatter, _comp.escaper));
return this; return this;
} }
} }
@@ -669,8 +690,9 @@ public class Mustache
/** A segment that substitutes the contents of a variable. */ /** A segment that substitutes the contents of a variable. */
protected static class VariableSegment extends NamedSegment { protected static class VariableSegment extends NamedSegment {
public VariableSegment (String name, int line, Escaper escaper) { public VariableSegment (String name, int line, Formatter formatter, Escaper escaper) {
super(name, line); super(name, line);
_formatter = formatter;
_escaper = escaper; _escaper = escaper;
} }
@Override public void execute (Template tmpl, Template.Context ctx, Writer out) { @Override public void execute (Template tmpl, Template.Context ctx, Writer out) {
@@ -679,10 +701,10 @@ public class Mustache
throw new MustacheException.Context("No key, method or field with name '" + _name + throw new MustacheException.Context("No key, method or field with name '" + _name +
"' on line " + _line, _name, _line); "' on line " + _line, _name, _line);
} }
String text = String.valueOf(value); write(out, _escaper.escape(_formatter.format(value)));
write(out, _escaper.escape(text));
} }
protected Escaper _escaper; protected final Formatter _formatter;
protected final Escaper _escaper;
} }
/** A helper class for block segments. */ /** A helper class for block segments. */
@@ -766,4 +788,10 @@ public class Mustache
throw new UnsupportedOperationException("Template loading not configured"); throw new UnsupportedOperationException("Template loading not configured");
} }
}; };
protected static final Formatter DEFAULT_FORMATTER = new Formatter() {
public String format (Object value) {
return String.valueOf(value);
}
};
} }