samskivert / jmustache

A Java implementation of the Mustache templating language.
Other
834 stars 128 forks source link

Partials with expresson #95

Closed jvmlet closed 6 years ago

jvmlet commented 6 years ago

Hello My template looks like this :

{{> {{platform}}/createMasterTable }}

It's evaluated with context {platform:'mysql'} with the result literaly as {{> mysql/createMasterTable}} instread of rendering the mysql/createMasterTable.mustache template. Is it supprted ? If not, what would be the workaround ? Thanks

samskivert commented 6 years ago

(Apologies for the delayed reply.)

Partial tags are expected to contain simply the static name of a partial to be loaded and executed. They don't "execute" a template inside the tag and then use the results of that template as the name of a partial to load. While this would be a nice feature, it doesn't follow the pattern of the Mustache language syntax: tags cannot contain other tags inside themselves. This is the same as something like HTML and XML: <foo <bar>> would be invalid (in Mustache: {{foo {{bar}} }} is invalid).

Anyhow, as to solving your actual problem, you can do it with Lambdas. The testLambdaFragExecute test demonstrates the basic technique:

    @Test public void testLambdaFragExecTemplate () {
        Template a = Mustache.compiler().compile("{{value}} should be A");
        Template b = Mustache.compiler().compile("{{value}} should be B");
        Mustache.Lambda lambda = new Mustache.Lambda() {
            public void execute (Template.Fragment frag, Writer out) {
                String which = frag.execute();
                if (which.equals("A")) {
                    frag.executeTemplate(a, out);
                } else if (which.equals("B")) {
                    frag.executeTemplate(b, out);
                } else {
                    throw new AssertionError("Invalid fragment content: " + which);
                }
            }
        };
        String tmpl = "[{{#lam}}{{value}}{{/lam}}]";
        test("[A should be A]", tmpl, context("lam", lambda, "value", "A"));
        test("[B should be B]", tmpl, context("lam", lambda, "value", "B"));
    }

The idea is that the lambda executes its fragment (which in your case will be {{platform}}/createMasterTable) and gets back the "name" of the template to be loaded (in your case mysql/createMasterTable. It then loads the partial template (the test just uses preloaded templates, but you can load templates on demand and cache them), and executes it using executeTemplate which causes the template to be executed in the same context that the lambda was executed, so that it can "see" all the data in scope at the point where the lambda occurs (this is how a partial would be executed also).

So you'd create a lambda and put it in your context as something like sqlLoader, then call it like so:

{{#sqlLoader}}{{platform}}/createMasterTable{{/sqlLoader}}

The lambda would look like the one in the test above except it would load and cache templates on demand.

jvmlet commented 6 years ago

Thanks for the detailed answer