Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should sections with lambdas /higher order functions be able to render content? #19

Closed
marcinkoziej opened this issue Jun 17, 2011 · 6 comments

Comments

@marcinkoziej
Copy link

Hello.

In the spec the ability to render section content in lambda is not mentioned.
Im talking about this example from http://mustache.github.com/mustache.5.html

{
    "name": "Willy",
    "wrapped": function() {
        return function(text) {
            return "<b>" + render(text) + "</b>"
        }
    }
}

this functionality is also mentioned in this post about using lambdas to implement caching or syntax highlighting: http://ozmm.org/posts/higher_order_mustache.html

If musteche doesn't accept this behaviour, what is the use of lambdas except for prepending/appending text to it's argument?

@pvande
Copy link
Contributor

pvande commented Jun 17, 2011

The manual is somewhat out of date. The spec expresses that content returned from lambdas is automatically rendered before being interpolated.
Lambda caching was a core part of the spec, but was removed when it proved to be impossible to implement in ways that met user expectations.

Even without caching or a provided #render method, you still have the raw template string available and you still have access to the top-level Mustache.render. (The ozzm example is actually just calling Mustache#render.) This is more than adequate for most template string manipulations, but does not provide a mechanism to access / resolve data against the current context stack -- if you have a legitimate use case for the latter behavior, I'd be interested in hearing it.

@groue
Copy link

groue commented Oct 9, 2011

http://ozmm.org/posts/higher_order_mustache.html provides with a use case for accessing the current context stack.

https://github.com/defunkt/mustache-syntax-highlighter provide with a use case for having the lambda output not being automatically rendered, in order to avoid the processing of unexpected (user data) {{ sequences in the output. Since mustache does not provide any way to escape its {{ tags, there is absolutely no way to be sure that user data won't be mustache-processed. Changing delimiters is not a solution (user data may still contain the "safe" delimiters, and the lambda could not restore delimiters to their original values, since these are unavailable).

The automatic rendering of lambda output is also a performance burden, since the mustache engine must parse and process each and every lambda output.

All those use cases and issues are solved if the spec would give access to both the render(text) function, and to the context stack.

@pvande
Copy link
Contributor

pvande commented Oct 9, 2011

@groue I'm sorry, I don't see the context stack use case on that page, can you inline your use case?

As for not automatically rendering, where is this "user data" with unexpected mustaches coming from? The raw template string sent to the lambda should be completely reasonable. A user-provided name (for example) should be interpolated using {{name}}, which will output the mustaches cleanly (but becomes a problem iff you render the text twice).

The only other place content can come from would be the lambda itself. The lambda cannot presently access the context stack (which would permit the lambda to directly inject the user-provided data, effectively leading to the "double render" problem), so the problem is restricted to external functions invoked from within the lambda, which ends up being a completely predictable issue.

Caching parse trees makes the most common performance issues go away, and parsing / rendering needn't be expensive. The biggest mark against automatic rendering is that if prohibits templates relying on the behavior from being statically compiled (which has been an issue before).

If anything, the potential for mistakes and misuse leaves me more firmly opposed to providing access to render and the context stack -- not that it should prohibit anyone from implementing these features...

@groue
Copy link

groue commented Oct 10, 2011

I admit having not being very clear, and even giving wrong arguments.

On http://ozmm.org/posts/higher_order_mustache.html, here is the line where defunkt uses the current context, for his benefit:

cache_key = "user:#{current_user.id}"

Without this access, he could not build his cache key. I think this is a strong argument for context stack access from the lambda. The rest of my arguments are consequences of this hypothesis.

On your question and your answers to it :

As for not automatically rendering, where is this "user data" with unexpected mustaches coming from?

Your answers are all 100% correct, but only if we forbid access to the current context.

If we conclude that access to the current context is desirable and valid (as exemplified by the defunkt example above), then nothing prevents the lambda to output some "user data" coming from the current context. And since there is no way to escape the mustache tags, the API would here should a deep weakness.

Second, and this argument is a new one, please consider it with a fresh mind :

Look at this template (inspired by defunkt's ruby syntax highlighting lambda):

{{#highlight_ruby}} def ... end {{/highlight_ruby}}

We don't have any issue with mustache automatic rendering here, because the helper outputs HTML tags, which do not contain any {{.

But now, look at this equivalent template :

{{=< >=}}<#highlight_ruby> def ... end </highlight_ruby>

Maybe you'll tell me: "but why in hell would somebody be stupid enough to use < and > in a mustache template which outputs HTML?"

That's not my point. My point is : automatic lambda rendering forces lambdas to know about the current mustache delimiters, in order to prevent automatic rendering to do anything wrong.

This forever prevents the building any mustache lambda library (which a regular mustache user will eventually build, project after project).

I was, by the way, about to ask your opinion about building a "mustache standard library", a library of helpers which would be the definite answer to many of the feature requests of mustache users.

@pvande
Copy link
Contributor

pvande commented Oct 10, 2011

This may simply be my understanding, but the current_user in the example you cite is actually a piece of application context, and not data off the context stack (technically, it may be another method on the same View, in which case it would be both -- and totally permitted by both the spec and the current implementation). The context stack is an implementation detail, and it is my strong preference that we make no rule requiring it to be exposed without a strong need. In almost no case would accessing things from the context stack be as simple as asking for a variable or method; at best, it might be a function call (find('my_context_information')) or Hash lookup (ctx['my_context_information']), though even that may be implementation dependent.

Your second argument does touch something important: sections are rendered with the current delimiters, but lambdas have no way of sanitizing their output.

If sections were rendered with the default delimiters (N.B.: I'm not suggesting this), you'd at least have enough context to know what to escape. There's also not enough information for the lambda to prepend a return to default delimiters, and some filters (e.g. diff?) might clearly benefit from pre-rendering the content...

Let me think on this one.

@jgonggrijp
Copy link
Member

This discussion continues in #155.

@mustache mustache locked and limited conversation to collaborators Nov 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants