GithubHelp home page GithubHelp logo

jmustache's Introduction

This is a Java implementation of the Mustache template language.

Build Status

Motivations

  • Zero dependencies. You can include this single tiny library in your project and start making use of templates.

  • Usability on a variety of target platforms. This implementation makes very limited demands on the JVM in which it runs and as a result is usable on Android, or on other limited JVMs. It is even possible to avoid the use of reflection and provide all of your data as a series of nested maps.

  • Proguard and JarJar friendly. Though the library will reflectively access your data (if you desire it), the library makes no other internal use of reflection or by name instantiation of classes. So you can embed it using Proguard or JarJar without any annoying surprises.

  • Minimal API footprint. There are really only two methods you need to know about: compile and execute. You can even chain them together in cases where performance is of no consequence.

Its existence justified by the above motivations, this implementation then strives to provide additional benefits:

  • It is available via Maven Central, see below for details.
  • It is reasonably performant. Templates are parsed separately from execution. A template will specialize its variables on (class of context, name) pairs so that if a variable is first resolved to be (for example) a field of the context object, that will be attempted directly on subsequent template invocations, and the slower full resolution will only be tried if accessing the variable as a field fails.

Get It

JMustache is available via Maven Central and can thus be easily added to your Maven, Ivy, etc. projects by adding a dependency on com.samskivert:jmustache:1.15. Or download the pre-built jar file.

Documentation

In addition to the usage section below, the following documentation may be useful:

Usage

Using JMustache is very simple. Supply your template as a String or a Reader and get back a Template that you can execute on any context:

String text = "One, two, {{three}}. Three sir!";
Template tmpl = Mustache.compiler().compile(text);
Map<String, String> data = new HashMap<String, String>();
data.put("three", "five");
System.out.println(tmpl.execute(data));
// result: "One, two, five. Three sir!"

Use Reader and Writer if you're doing something more serious:

void executeTemplate (Reader template, Writer out, Map<String, String> data) {
   Mustache.compiler().compile(template).execute(data, out);
}

The execution context can be any Java object. Variables will be resolved via the following mechanisms:

  • If the context is a MustacheCustomContext, MustacheCustomContext.get will be used.
  • If the context is a Map, Map.get will be used.
  • If a non-void method with the same name as the variable exists, it will be called.
  • If a non-void method named (for variable foo) getFoo exists, it will be called.
  • If a field with the same name as the variable exists, its contents will be used.

Example:

class Person {
    public final String name;
    public Person (String name, int age) {
        this.name = name;
        _age = age;
    }
    public int getAge () {
        return _age;
    }
    protected int _age;
}

String tmpl = "{{#persons}}{{name}}: {{age}}\n{{/persons}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
    Object persons = Arrays.asList(new Person("Elvis", 75), new Person("Madonna", 52));
});

// result:
// Elvis: 75
// Madonna: 52

As you can see from the example, the fields (and methods) need not be public. The persons field in the anonymous class created to act as a context is accessible. Note that the use of non-public fields will not work in a sandboxed security environment.

Sections behave as you would expect:

  • Boolean values enable or disable the section.
  • Array, Iterator, or Iterable values repeatedly execute the section with each element used as the context for each iteration. Empty collections result in zero instances of the section being included in the template.
  • An unresolvable or null value is treated as false. This behavior can be changed by using strictSections(). See Default Values for more details.
  • Any other object results in a single execution of the section with that object as a context.

See the code in MustacheTest.java for concrete examples. See also the Mustache documentation for details on the template syntax.

Partials

If you wish to make use of partials (e.g. {{>subtmpl}}) you must provide a Mustache.TemplateLoader to the compiler when creating it. For example:

final File templateDir = ...;
Mustache.Compiler c = Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
    public Reader getTemplate (String name) {
        return new FileReader(new File(templateDir, name));
    }
});
String tmpl = "...{{>subtmpl}}...";
c.compile(tmpl).execute();

The above snippet will load new File(templateDir, "subtmpl") when compiling the template.

Lambdas

JMustache implements lambdas by passing you a Template.Fragment instance which you can use to execute the fragment of the template that was passed to the lambda. You can decorate the results of the fragment execution, as shown in the standard Mustache documentation on lambdas:

String tmpl = "{{#bold}}{{name}} is awesome.{{/bold}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
   String name = "Willy";
   Mustache.Lambda bold = new Mustache.Lambda() {
        public void execute (Template.Fragment frag, Writer out) throws IOException {
            out.write("<b>");
            frag.execute(out);
            out.write("</b>");
        }
    };
});
// result:
<b>Willy is awesome.</b>

You can also obtain the results of the fragment execution to do things like internationalization or caching:

Object ctx = new Object() {
    Mustache.Lambda i18n = new Mustache.Lambda() {
         public void execute (Template.Fragment frag, Writer out) throws IOException {
             String key = frag.execute();
             String text = // look up key in i18n system
             out.write(text);
         }
    };
};
// template might look something like:
<h2>{{#i18n}}title{{/i18n}}</h2>
{{#i18n}}welcome_msg{{/i18n}}

There is also limited support for decompiling (unexecuting) the template and obtaining the original Mustache template text contained in the section. See the documentation for Template.Fragment for details on the limitations.

Default Values

By default, an exception will be thrown any time a variable cannot be resolved, or resolves to null (except for sections, see below). You can change this behavior in two ways. If you want to provide a value for use in all such circumstances, use defaultValue():

String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().defaultValue("what").compile(tmpl).execute(new Object() {
    String exists = "Say";
    String nullValued = null;
    // String doesNotExist
});
// result:
Say what what?

If you only wish to provide a default value for variables that resolve to null, and wish to preserve exceptions in cases where variables cannot be resolved, use nullValue():

String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().nullValue("what").compile(tmpl).execute(new Object() {
    String exists = "Say";
    String nullValued = null;
    // String doesNotExist
});
// throws MustacheException when executing the template because doesNotExist cannot be resolved

When using a Map as a context, nullValue() will only be used when the map contains a mapping to null. If the map lacks a mapping for a given variable, then it is considered unresolvable and throws an exception.

Map<String,String> map = new HashMap<String,String>();
map.put("exists", "Say");
map.put("nullValued", null);
// no mapping exists for "doesNotExist"
String tmpl = "{{exists}} {{nullValued}} {{doesNotExist}}?";
Mustache.compiler().nullValue("what").compile(tmpl).execute(map);
// throws MustacheException when executing the template because doesNotExist cannot be resolved

Do not use both defaultValue and nullValue in your compiler configuration. Each one overrides the other, so whichever one you call last is the behavior you will get. But even if you accidentally do the right thing, you have confusing code, so don't call both, use one or the other.

Sections

Sections are not affected by the nullValue() or defaultValue() settings. Their behavior is governed by a separate configuration: strictSections().

By default, a section that is not resolvable or which resolves to null will be omitted (and conversely, an inverse section that is not resolvable or resolves to null will be included). If you use strictSections(true), sections that refer to an unresolvable value will always throw an exception. Sections that refer to a resolvable but null value never throw an exception, regardless of the strictSections() setting.

Extensions

JMustache extends the basic Mustache template language with some additional functionality. These additional features are enumerated below:

Not escaping HTML by default

You can change the default HTML escaping behavior when obtaining a compiler:

Mustache.compiler().escapeHTML(false).compile("{{foo}}").execute(new Object() {
    String foo = "<bar>";
});
// result: <bar>
// not: &lt;bar&gt;

User-defined object formatting

By default, JMustache uses String.valueOf to convert objects to strings when rendering a template. You can customize this formatting by implementing the Mustache.Formatter interface:

Mustache.compiler().withFormatter(new Mustache.Formatter() {
    public String format (Object value) {
      if (value instanceof Date) return _fmt.format((Date)value);
      else return String.valueOf(value);
    }
    protected DateFormat _fmt = new SimpleDateFormat("yyyy/MM/dd");
}).compile("{{msg}}: {{today}}").execute(new Object() {
    String msg = "Date";
    Date today = new Date();
})
// result: Date: 2013/01/08

User-defined escaping rules

You can change the escaping behavior when obtaining a compiler, to support file formats other than HTML and plain text.

If you only need to replace fixed strings in the text, you can use Escapers.simple:

String[][] escapes = {{ "[", "[[" }, { "]", "]]" }};
Mustache.compiler().withEscaper(Escapers.simple(escapes)).
  compile("{{foo}}").execute(new Object() {
      String foo = "[bar]";
  });
// result: [[bar]]

Or you can implement the Mustache.Escaper interface directly for more control over the escaping process.

Special variables

this

You can use the special variable this to refer to the context object itself instead of one of its members. This is particularly useful when iterating over lists.

Mustache.compiler().compile("{{this}}").execute("hello"); // returns: hello
Mustache.compiler().compile("{{#names}}{{this}}{{/names}}").execute(new Object() {
    List<String> names () { return Arrays.asList("Tom", "Dick", "Harry"); }
});
// result: TomDickHarry

Note that you can also use the special variable . to mean the same thing.

Mustache.compiler().compile("{{.}}").execute("hello"); // returns: hello
Mustache.compiler().compile("{{#names}}{{.}}{{/names}}").execute(new Object() {
    List<String> names () { return Arrays.asList("Tom", "Dick", "Harry"); }
});
// result: TomDickHarry

. is apparently supported by other Mustache implementations, though it does not appear in the official documentation.

-first and -last

You can use the special variables -first and -last to perform special processing for list elements. -first resolves to true when inside a section that is processing the first of a list of elements. It resolves to false at all other times. -last resolves to true when inside a section that is processing the last of a list of elements. It resolves to false at all other times.

One will often make use of these special variables in an inverted section, as follows:

String tmpl = "{{#things}}{{^-first}}, {{/-first}}{{this}}{{/things}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
    List<String> things = Arrays.asList("one", "two", "three");
});
// result: one, two, three

Note that the values of -first and -last refer only to the inner-most enclosing section. If you are processing a section within a section, there is no way to find out whether you are in the first or last iteration of an outer section.

-index

The -index special variable contains 1 for the first iteration through a section, 2 for the second, 3 for the third and so forth. It contains 0 at all other times. Note that it also contains 0 for a section that is populated by a singleton value rather than a list.

String tmpl = "My favorite things:\n{{#things}}{{-index}}. {{this}}\n{{/things}}";
Mustache.compiler().compile(tmpl).execute(new Object() {
    List<String> things = Arrays.asList("Peanut butter", "Pen spinning", "Handstands");
});
// result:
// My favorite things:
// 1. Peanut butter
// 2. Pen spinning
// 3. Handstands

Compound variables

In addition to resolving simple variables using the context, you can use compound variables to extract data from sub-objects of the current context. For example:

Mustache.compiler().compile("Hello {{field.who}}!").execute(new Object() {
    public Object field = new Object() {
        public String who () { return "world"; }
    }
});
// result: Hello world!

By taking advantage of reflection and bean-property-style lookups, you can do kooky things:

Mustache.compiler().compile("Hello {{class.name}}!").execute(new Object());
// result: Hello java.lang.Object!

Note that compound variables are essentially short-hand for using singleton sections. The above examples could also be represented as:

Hello {{#field}}{{who}}{{/field}}!
Hello {{#class}}{{name}}{{/class}}!

Note also that one semantic difference exists between nested singleton sections and compound variables: after resolving the object for the first component of the compound variable, parent contexts will not be searched when resolving subcomponents.

Newline trimming

If the opening or closing section tag are the only thing on a line, any surrounding whitespace and the line terminator following the tag are trimmed. This allows for civilized templates, like:

Favorite foods:
<ul>
  {{#people}}
  <li>{{first_name}} {{last_name}} likes {{favorite_food}}.</li>
  {{/people}}
</ul>

which produces output like:

Favorite foods:
<ul>
  <li>Elvis Presley likes peanut butter.</li>
  <li>Mahatma Gandhi likes aloo dum.</li>
</ul>

rather than:

Favorite foods:
<ul>

  <li>Elvis Presley likes peanut butter.</li>

  <li>Mahatma Gandhi likes aloo dum.</li>

</ul>

which would be produced without the newline trimming.

Nested Contexts

If a variable is not found in a nested context, it is resolved in the next outer context. This allows usage like the following:

String template = "{{outer}}:\n{{#inner}}{{outer}}.{{this}}\n{{/inner}}";
Mustache.compiler().compile(template).execute(new Object() {
    String outer = "foo";
    List<String> inner = Arrays.asList("bar", "baz", "bif");
});
// results:
// foo:
// foo.bar
// foo.baz
// foo.bif

Note that if a variable is defined in an inner context, it shadows the same name in the outer context. There is presently no way to access the variable from the outer context.

Invertible Lambdas

For some applications, it may be useful for lambdas to be executed for an inverse section rather than having the section omitted altogether. This allows for proper conditional substitution when statically translating templates into other languages or contexts:

String template = "{{#condition}}result if true{{/condition}}\n" +
  "{{^condition}}result if false{{/condition}}";
Mustache.compiler().compile(template).execute(new Object() {
    Mustache.InvertibleLambda condition = new Mustache.InvertibleLambda() {
        public void execute (Template.Fragment frag, Writer out) throws IOException {
            // this method is executed when the lambda is referenced in a normal section
            out.write("if (condition) {console.log(\"");
            out.write(toJavaScriptLiteral(frag.execute()));
            out.write("\")}");
        }
        public void executeInverse (Template.Fragment frag, Writer out) throws IOException {
            // this method is executed when the lambda is referenced in an inverse section
            out.write("if (!condition) {console.log(\"");
            out.write(toJavaScriptLiteral(frag.execute()));
            out.write("\")}");
        }
        private String toJavaScriptLiteral (String execute) {
            // note: this is NOT a complete implementation of JavaScript string literal escaping
            return execute.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"");
        }
    };
});
// results:
// if (condition) {console.log("result if true")}
// if (!condition) {console.log("result if false")}

Of course, you are not limited strictly to conditional substitution -- you can use an InvertibleLambda whenever you need a single function with two modes of operation.

Standards Mode

The more intrusive of these extensions, specifically the searching of parent contexts and the use of compound variables, can be disabled when creating a compiler, like so:

Map<String,String> ctx = new HashMap<String,String>();
ctx.put("foo.bar", "baz");
Mustache.compiler().standardsMode(true).compile("{{foo.bar}}").execute(ctx);
// result: baz

Thread Safety

JMustache is internally thread safe with the following caveats:

  • Compilation: compiling templates calls out to a variety of helper classes: Mustache.Formatter, Mustache.Escaper, Mustache.TemplateLoader, Mustache.Collector. The default implementations of these classes are thread-safe, but if you supply custom instances, then you have to ensure that your custom instances are thread-safe.

  • Execution: executing templates can call out to some helper classes: Mustache.Lambda, Mustache.VariableFetcher. The default implementations of these classes are thread-safe, but if you supply custom instances, then you have to ensure that your custom instances are thread-safe.

  • Context data: if you mutate the context data passed to template execution while the template is being executed, then you subject yourself to race conditions. It is in theory possible to use a thread-safe map (ConcurrentHashMap or Collections.synchronizedMap) for your context data, which would allow you to mutate the data while templates were being rendered based on that data, but you're playing with fire by doing that. I don't recommend it. If your data is supplied as POJOs where fields or methods are called via reflection to populate your templates, volatile fields and synchronized methods could similarly be used to support simultaneous reading and mutating, but again you could easily make a mistake that introduces race conditions or cause weirdness when executing your templates. The safest approach when rendering the same template via simultaneous threads is to pass immutable/unchanging data as the context for each execution.

  • VariableFetcher cache: template execution uses one internal cache to store resolved VariableFetcher instances (because resolving a variable fetcher is expensive). This cache is thread-safe by virtue of using a ConcurrentHashMap. It's possible for a bit of extra work to be done if two threads resolve the same variable at the same time, but they won't conflict with one another, they'll simply both resolve the variable instead of one resolving the variable and the other using the cached resolution.

So the executive summary is: as long as all helper classes you supply are thread-safe (or you use the defaults), it is safe to share a Mustache.Compiler instance across threads to compile templates. If you pass immutable data to your templates when executing, it is safe to have multiple threads simultaneously execute a single Template instance.

Limitations

In the name of simplicity, some features of Mustache were omitted or simplified:

  • {{= =}} only supports one or two character delimiters. This is just because I'm lazy and it simplifies the parser.

jmustache's People

Contributors

agentgt avatar bruckner avatar deadmoose avatar dependabot[bot] avatar egaga avatar hierynomus avatar jlewallen avatar joecqupt avatar johnsensible avatar martiell avatar maximebochon avatar meros avatar mjeanroy avatar npryce avatar quentinburley avatar rgdoliveira avatar robbytx avatar samskivert avatar sh-cho avatar skaba avatar sps avatar tominsam avatar valotas avatar whymarrh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jmustache's Issues

Formatter doesn't get the correct type

Formatter gets the date as String when using like this:

{{#date}}
    <span class="date">{{date}}</span>
{{/date}}

Is there a way to do a null check without calling format?

null value in nested context doesn't cover variable in outer context

If variable is defined in inner context, but it's value is null, then outer context is searched.

Example:
context (HashMap): {"a": "outer", "b": [{"a":null}]}
Template: {{#b}}{{a}}{{/b}}
Result: outer

Online JS tester returns no result here, so it probably should return defaultValue/nullValue (if set) or throw an exception. I also checked official Objective-C implementation and it worked as JS version.

If inner "a" is set to anything else, it behaves as expected.

Jmustache is slow on android

Hello Guys,

Is there any means to accelerate jmustache on Android ? It's very slow. Because of serialization I suppose ? Can we use parceable or anything else to do the job ?

"-index" is 0 when used inside conditional block within list block

I have a class like this:

public final class Foo {
	private final String name;
	private final Integer quantity;

	public Foo(final String name, final Integer quantity) {
		this.name = name;
		this.quantity = quantity;
	}

	public String getName() { return name; }
	public Integer getQuantity() { return quantity; }
}

and I have a template block like this:

{{#fooList}}
{{#quantity}}|q{{-index}}={{quantity}}{{/quantity}}|{{name}}
{{/fooList}}

Basically, I want blocks like |q1=42 displayed only when quantity is not null. Unfortunately, {{-index}} is only set to the correct element index if used directly inside the {{#fooList}} list block; it is 0 when used inside the condition block, so the expression evaluates to something like |q0=42.

I think that the behavior of {{-index}} should be changed to refer to the index corresponding to the innermost list block. It should only be 0 if the statement is being evaluated outside of any list block whatsoever.

Confusing behavior of nullValue

When I specify a nullValue("something") to the compiler, it also changes the missingIsNull property to false. The default is true if you simply call Mustache.compiler().compile(template)....

That is confusing... I just spend 20 minutes figuring out why a previously fine working section that was checking for a non-existing value was suddenly throwing exceptions at me, when I specify a null-value.

The problem is, that the documentation states that it will "still throw an exception". Or it says:

By default, an exception will be thrown any time a variable cannot be resolved, or resolves to null.

which seems to not be true.

Maybe have missingIsNull be false by default? Or don't change the value when a null-value is set?

Contextual Lambda for Dynamic Partial Implementation

I was trying to replicate the technique used in this post:

http://stackoverflow.com/questions/9162977/is-it-possible-to-switch-template-partial-based-on-hash-value-in-mustache

In order to solve the same problem with JMustache (switching templates based on an object properties), but the lack of a context when evaluating the Lambda is killing it. I've tried to hack the code to get a version with Context, but its not going well (I'm not super proficient at Java). Any chance we can get a better Lambda implementation so I can pull it off?

Displaying key of Map

Hello, I´m using swagger-codegen which uses this to handle the mustache templates.
I was wondering if there is something I could use to display the key while iterating on a map.
Something like the first anwser from here maybe?
Thanks!

proguard related issue

Hi,

I found in below code, I must keep the variable name "Object persons" unchanged after applied proguard, otherwise will cause error.

How could I create such settings in proguard file? Thanks for help!

String tmpl = "{{#persons}}{{name}}: {{age}}{{/persons}}\n";
Mustache.compiler().compile(tmpl).execute(new Object() {
Object persons = Arrays.asList(new Person("Elvis", 75), new Person("Madonna", 52));
});

Cannot access Java 8 interface default method

I am unable to retrieve a getter method that is implemented as an interface default method. I believe this is because of the way DefaultCollector.getMethod() iterates over superclasses, leaving out interfaces.

Sample code:

public class TestDefaultMethod {
    interface Foo {
        default String getFoo() {
            return "Foo";
        }
    }

    static class FooImpl implements Foo {};

    public static void main(String[] args) {
        FooImpl foo = new FooImpl();
        System.out.println(foo.getFoo()); // works fine
        Template tmpl = Mustache.compiler().compile("{{foo}}");
        System.out.println(tmpl.execute(foo)); // Exception! No method or field with name 'foo' on line 1.
    }
}

escapeHtml is very slow

because for each Variable segment it loops and does a regex replace it is very intensive. It would be better to pass the writer to the method and do the same as in StringEscapeUtils of common lang.
To keep it fast instead of having an entity map you could just do a switch on the character.

defaultValue and compound paths

Even with a defaultValue(""), the template: {{foo.bar}} will raise an exception if there is no "foo" key in the context. It would seem more consistent to return "", given that this is the behaviour of "{{#foo}}{{bar}}{{/foo}}".

We're curious to know if you consider that a bug or not.

Thread Safety

Could you enrich documentation about thread safety?
It will be good to list which classes or methods are thread safe.

Thanks

Support for GWT 2.7

Is this library compatible with GWT 2.7?
I am getting some compilation errors when I included the source files.

Standards mode

There are several key places jmustache deviates from the spec. I'd like a standards mode flag that would allow clients to optionally turn those features off.

Make the NO_FETCHER_FOUND sentinel protected instead of package-private

When creating a new collector/fetcher for a different type of Map (i.e. Scala), the fetcher needs to return the NO_FETCHER_FOUND sentinel for a missing key. That's not possible unless you build a Template subclass under the com.samskivert.mustache package to expose it. Changing it to protected would allow the exposing subclass to exist in the implementor's package.

Accessible parentContext

Hi,

Fragment has context() method to access context field. Is it possible to add parentContext() method to access parentContext field.

Thanks

Make it possible to use a custom set of delimiters by default

We sometimes want to resolve templates using a custom set of delimiters, but do not want to include those delimiters in the file. It should therefore be possible to configure the compiler with a set of custom delimiters.

Pull request coming up...

Support for Java 8 Optionals

First things first, thanks a lot for JMustache. Love it!

It would be nice if Java 8 Optionals were supported so that Optional.empty() is treated as the nullValue and if Optional.isPresent() then consider the value to be Optional.get().

What do you think?

Cannot resolve Mustache.compiler().withFormatter

Trying to play around with jmustache extension, but IDE cannot resolve

Mustache.compiler().withFormatter(new Mustache.Formatter()

Added com.samskivert:jmustache:1.8 dependency in build.gradle, am i missing something?

New release on Maven

Hello,

I've been using your library but noticed that the latest version on Maven is not up to date with this. I'm in the need for the Formatter interface but cannot use it with v1.8.

Could you bump the version and make it available on Maven?

Thanks a lot!

Question on delimiter

According to mustache doc, I can set the delimiter as follows:

* {{default_tags}}
{{=<% %>=}}
* <% erb_style_tags %>
<%={{ }}=%>
* {{ default_tags_again }}

Ref: https://mustache.github.io/mustache.5.html

After setting delimiter to <%, %>, how can I get the unescape value of the tag, which can be obtained from {{{ }}} before changing the delimiter?

I tried <%{ }%> and {<% %>} but no luck.

Trying to map {{{ and }}} to something else but no luck either.

Comments that contain left curly brace rendered as text

Comment blocks that contain a left curly brace are currently parsed as text. For example:

{{! 
this used to be a {{ tag }}, but now it's in a comment 
}}

Is output verbatim in full.

The mustache spec on comments allows any character except the closing delimiter inside a comment: "The tag's content may contain any substring (including newlines) EXCEPT the closing delimiter." Their test cases don't check this, though.

The relevant code in the parser is in Mustache.java, parseChar, when state == TAG, lines 338-350.

Differentiate a missing key from a missing value

A recent fix provided a default value when one wasn't available. I'd like to use this but I'd still like to have it throw an exception when the corresponding key (e.g. method or field) can't be found in the context in order to catch typos in the template. I think the simplest solution would be to first request the fetcher and throw an exception if that can't be found before going through the default value check.

Unable to access properties of an Object?

This may be purely intended behaviour, but if I am passing a;

HashMap String, Object

when I iterate the string, I'm unable to access properties of the object.

if I render {{this}} I see a json object being rendered, (Rather than the key=property I would get usually with mustache)

Any ideas?

False values for section keys

What logic does jmustache use when evaluating section keys to determine if the section should be displayed or not? If the key's value is "false" or "0", is it recognised as false?

The mustache manual states "If the key exists and has a value of false or an empty list, the HTML between the pound and slash will not be displayed."

Thanks.

Get unexecuted fragment in lambdas

Hello there,

You said:

Currently there is no support for "unexecuting" the template and obtaining the original Mustache template text contained in the section. File a feature request with a sane use case if you have one.

Would this be a use case: I'm currently using Gnu Gettext and thus have fragments looking like this: {{#i18n}}Some english text used as the real english text and also as the key.{{/i18n}} and the lambda looks like this:

new Mustache.Lambda() {
    public void execute (Template.Fragment frag, Writer out) throws IOException {
        String res = frag.execute();
        res = i18n.__(res); // i18n being my translation service
        out.write(res);
    }
}

So when I have a fragment looking like this: {{#i18n}}Hello {{user.name}}.{{/i18n}}
The msgid in my .pot file will be "Hello {{user.name}}." but when trying to translate, my i18n service will actually look for "Hello Paul." and therefore, find nothing.

Did I miss something? Can I actually get the fragment before it is executed? Or is it the sane use case you were talking about?

Btw, thanks for this great implementation. Been using it with Spring Boot and it works very well.

Inner null values are not masking outer values

        String text = "{{foo}} {{bar}} {{#inner}}{{foo}} {{bar}}{{/inner}}";
        Template tmpl = Mustache.compiler().nullValue("").compile(text);

        Object data = new Object() {
            String foo = "outer-foo";
            String bar = "outer-bar";

            Object inner = new Object() {
                String foo = "inner-foo";
                String bar = null;
            };

        };
        System.out.println(tmpl.execute(data));

Produces outer-foo outer-bar inner-foo outer-bar. According to the spec at https://github.com/mustache/spec/blob/master/specs/interpolation.yml, a value that is null-but-present should be returned instead of walking up the tree to the parent.

I'm relying on this behaviour in a few template to let me suppress outer values with explicit null values.

Opening <a> tag not recognized?

It seems that this does not work:

{{{<a href="https://www.promisejs.org/api/">Promise</a>}}}

I get an error saying that the closing </a> tag does not match whatever the previous opening tag is. The opening <a> tag is not recognized, I guess.

new lines rendered as whitespaces

The new lines that are part of a section in mustache templates are rendered without newlines after processing.

{{#items}}
{{name}} : {{description}}
{{/items}}

are rendered as

item1 : item1_description item2 : item2_description

Only if I deliberately provide extra new lines like:

{{#items}}

{{name}}: {{description}}

{{/items}}

I get the desired output.

Am I missing anything here?

Question on partials

I've a question about accessing partial mustache templates via relative path.

Here is an example provided in the doc:

{{> box}}

Ref: https://mustache.github.io/mustache.5.html

If I need to access the partial in the parent folder, can I do {{> ../box}} or {{> ..\box}} or the partials must be in the same folder?

If relative path is supported, would that work across different environments (e.g. Windows. Linux, Mac, etc)?

Thanks.

{{{var}}} to prevent html encoding now not works?

When use 1.9, it was ok to using triple brackets {{{var}}} to prevent html encoding,
but 1.12 not works, it encode anyway
now
"=" is encoded to "="
住所の種類 is encoded to \u4F4F\u6240\u306E\u7A2E\u985E

hope you check this at next release

Show all available variables at a specific template position

Is it possible to print out all available variables at a specific position in the mustache template for debugging purposes / to explore the available variables if you don't want to check this in the sourcecode?

If not, do you think it makes sense to add this feature?

Best regards,
Johannes

Option to make empty string falsey

A compiler option to make empty string falsey would be nice. I ported a project from server-side JavaScript to the Play framework using jmustache. The semantics I had in the JavaScript side relied on empty string as falsey. I had to change everything to null instead. That was no problem, but falsey empty string would have made the port easier.

Support for non-compound keys with periods

I'm really enjoying using JMustache (thank you), but one thing is holding me back and I can't find an easy way to address it with the public APIs. What I would like is for (in non-standards mode, which is quite useful in other ways) a Template to fallback to treating a key containing a period to be a plain old key (not a composite) if it can't resolve part of the path. This use case arises when the context for the template execution is a Map<String,?> with keys that contain periods. It's common enough that I'd expect that to be quite useful and it looks like it would be an easy change (in Template.getValue(Context, String, int, boolean)).

I won't send a pull request unless there is some agreement that it is a useful feature. I don't think it will break any existing behaviour but I'm probably not the best judge of that.

property lookup when no fetcher found

When no fetcher is found the template will try to find one every time, that can be quite costly in a loop.
One way would be to return a special fetcher that always return NO_FETCHER_FOUND instead of null in the collector.

How to deactivate unresolvable properties exception

Hello,
I'm using jmustache within the spring boot plugin. If a put a field like {{field}} that is not in the model, I keep getting an exception. I've read your docs and I've tried to se compile.defaultValue(""), but I still keep getting it. Any idea on how to solve this... ?

emptyStringIsFalse() does not work properly with inverted sections

Issue #9 (Option to make empty string falsey) was closed after pull request #20 was accepted. This change does cause empty strings to be treated as false values when determining whether to render a section like {{#foo}}...{{/foo}}. However, in JMustache 1.8, empty strings are not treated as false for an inverted section, so if your section is {{^foo}}...{{/foo}}, it will be not be rendered when foo is an empty string.

For example, this JUnit test fails:

public void testEmptyStringIsFalse()
{
    String template = "{{#emptyString}}it is true{{/emptyString}}{{^emptyString}}it is false{{/emptyString}}";
    Object context = new Object() { String emptyString = ""; };
    String result = Mustache.compiler().emptyStringIsFalse(true).compile(template).execute(context);
    assertEquals("it is false", result);
}

I expect the result to be "it is false", but instead the result is an empty string, because neither the {{#emptyString}} section nor the {{^emptyString}} section is rendered.

I'm not familiar enough with the code to suggest a fix, but my guess is that the InvertedSectionSegment class in Mustache.java needs code to handle the emptyStringIsFalse case (and probably the zeroIsFalse case too).

Nested context lost when including a partial

When in the main template, the nested context is used as described in the documentation but that feature is lost when including a partial. The partial executes with the same immediate context but loses the parent context.

Template throws exception for missing accessor when using null value and Map context

Documentation of Compiler.nullValue() states that "In the case of a Map being used as a context, all possible accessors are assumed to exist (but potentially return null), and no exception will ever be raised." Yet this

Map<String, Object> context = new HashMap<String, Object>();
Mustache.compiler().nullValue("").compile("{{foo}}").execute(context);

gives MustacheException$Context: No method or field with name 'foo'
jmustache 1.8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.