-
Notifications
You must be signed in to change notification settings - Fork 71
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
Proposal: Mutable context objects #72
Comments
Here is bobthecow's example from bobthecow/mustache.php#130, reimplemented using a mutable context object. First, the layout.
Next, the input template.
The only problem with doing it like this is that it would result in four
A few observations: Substitution for actual value
This allows an different substitution to be used if a value is set, Substitution with a default assignment
This allows an undefined value to get a default that can then be used throughout the remainder of the template. |
Do you have any idea how you might handle the append case? |
I'm not sure what you mean by "the append case". Since Since '$' is the sigil for scalars, obviously '@' should be the sigil for lists/arrays (at least to anyone knowing Perl or PHP). Unfortunately, that sigil is already used for something else, so we need to think of another. I'm going to assume '$$', which (sort of) implies multiple values. But there are things I don't like about it. Obviously It's equally obvious (to me, anyway) that What about interactions between '$' and '$$'? What does The preceding examples are why I don't like using '$$', by the way. How easy is it to even notice that while most of them are using '$$', a few are using '$'. And what if any of those values are empty strings, as earlier? I know what I think should happen, but I'm already forcing enough down peoples' throats as it is. |
FYI @samwyse:
The append case is today only implemented by GRMustache, as far as I know. It allows a section to be overridden several times, contents being then concatenated. Given
This template would render
This template would render
This template triggers the concatenation: it would render
This works also through multiple inheritance:
This template would render
The rationale (see #38 ): the analogous mechanism in Ruby On Rail's is their |
I'm going to work through your examples, but let me say that this is one of my use cases. I believe that MCOs give you additional power to decide how things are done, for instance, if you want to prepend or append when you concatenate. I've reproduced your examples, using MCOs but not the 'syntactic sugar'; I feel this better shows exactly how they will work in these cases. Given
The following template would render
The following template would render
This works also through multiple inheritance:
This template would render
I moved this example to the end, because I'm not sure what's going on. If 'content' is meant to be a list of values, then we'll need the extra stuff I talked about upthread (and the assumption that lists are rendered by concatenating all items). If we are just defining a value as a concatenation, perhaps that is built up slowly over several lines,then this should work. This template uses a concatenation: it would render
|
Syntax is arguably more complex, but it's interesting. I have a question: your mutable contexts are filled with HTML, not text: Another question: what do you mean by the following sentence?
|
@groue commented:
Yes, you should. Another test case, I believe. Thanks.
#59 was "Idea: named html chunks", wherein one could say this:
and later use it like this: I'll just say the same result can be achieved using MCOs:
which can later be used like this: #59 was closed in favor of #63, Inline partials, which was suppossedly the same thing. However, note that MCOs resolve embedded tags when they are first scanned. #59 was silent on this, but (if I'm reading it correctly) #63 expects that resolution should be delayed until they are used. Consider this:
An MCO should resolve this as 'Socrates is mortal' (using the definition of 'person' at the time that 'statement' is defined), while inline partials would resove it as 'Plato is mortal' (using the definition of 'person' when 'statement' is resolved). So, how to make MCOs behave like inline partials? By using alternate delimeters. Consider this:
I haven't mentioned it before (because it only just now occurred to me) but values in MCOs have a two-phase resolution process. In this case the first phase leaves you with '{{ person }} is mortal', and the second results in 'Plato is mortal'. And this is exactly what is proposed for inline partials. |
I've consolidated the preceding discussion into a formal spec for MCOs. It may be found here: |
Oops! Hit the wrong button! |
The fact that you still do not use triple mustache for rendering the HTML chunks stored in your "MCOs" is, I must say, troubling. What about starting using &, < and > in all your examples, and see how they behave (since I believe you have a running implementation)? On building on top of change delimiters tags: I strongly advise against it. Those |
Another point: delayed resolution is already a built-in feature of template inheritance:
This template renders Banana, Ham, Coffee with appropriate input (fetching the names from the items collection used by the layout):
|
The fact that you still do not use triple mustache for rendering the HTML chunks stored in your "MCOs" is, I must say, troubling. Hey, I did use it in the "MCOs as Named HTML Chunks" test. And as these specs are a straight copy of the examples I've been using up until now, I wasn't thinking about adding new stuff to them. What about starting using &, < and > in all your examples, and see how they behave (since I believe you have a running implementation)? I don't have an implementation of MCIs yet. I'm one if those crazy guys who likes to write test cases first. But give me a few days… and then I'll go back and sprinkle more HTML entities into the examples. On building on top of change delimiters tags: I strongly advise against it. Those {{=[[ ]]=}} tags prevent Mustache from having a grammar, and force developers to write a custom parser. Right now, I'm working to extend the existing spec, and not break existing implementations, so the change delimiters stay, at least for now. For example, handlebars.js has not change delimiters tag, a grammar (https://github.com/wycats/handlebars.js/blob/master/src/handlebars.yy), and users who need to render the sequence {{ use a backslash escape. Hmmm, I'll admit I hadn't even thought about using yacc to parse Mustache. OTOH, I suspect that while Mustache won't fit the definition of formal grammars from my Comp. Sci. class, yacc could still parse it, you'd just need a custom lexical scanner; I don't think that lex could handle changing delimiters. |
Another point: delayed resolution is already a built-in feature of template inheritance: And also lambdas. But there are open issues to specifically disallow it in other places (which I think is a bad idea, personally), so I thought I'd better specifically allow it for MCOs. I had given some thought about adding a quoting sigil (say, {{" stuff}}, as opposed to changing delimiters or using backslashes) to flag delayed resolution of tags, but I didn't want to add new syntax if at all possible and changing delimiters seems to get the job done. I must admit, however, that It would make that one example at lot easier to read. |
Yes, you do. I just mean that since mutable contexts can only store HTML, it's better to show it clearly by always using triple mustache when you render them. Using simple double mustache is almost always a bug, since one almost never wants double escaping. I thus think that all your examples should use triple mustache when outputting the content of a mutable context, as this should be the most frequent way to use them, and as you don't want to make people (including you) be mislead, and misuse your mutable contexts. I hope you will agree on that point. If so, I expect your own use of triple mustache to help yourself get a better overview of your own proposal. This may change your mind about its syntactic qualities/shortcomings. It may also open your eyes on the fact that the default mustache way (double mustache) actually opens an opportunity for your feature for being misused, with a delayed bad surprise: double mustache for mutable context rendering won't bite until they are fed with &, <, or >.
Sure. However I would not foster their use, for the reasons I have given above.
My point exactly. Lex can not handle them. Hence my critic against change delimiter tags, and my advice against relying on them for building higher-level features. |
You are probably correct.
You are bringing me around to your point of view. I see two ways to go, If the default is to evaluate early, then you need to quote things you want
evaluated then.
double-quoted tag will delay evaluation until then. If the default is to evaluate late, then you need to unquote things you
evaluated in this pass.
tags are evaluated then. In either event, I think that either type of quotes can be composed with HTML entities are only evaluated during one of the passes, not both; I'm |
You've been a long way. Thanks for your dedication. Quoting your initial post in this thread:
You have worked enough on your topic so that you are now able to compare your proposal and the template inheritance as described in issue #38. No more wading through: you're able to put the same energy in understanding #38 as I put in following you in your mutable contexts, and pointing at their (sometimes unintended) consequences. |
"Wading through" does involve a certain amount of effort. There are two things that I dislike about template inheritance, as described. I'm going to refer to your gist for examples, but I think that my complains hold true for everyone's different template proposals. At first glance, the '$' sigil seems to be context sensitive. Inside a template block (see 'sub.mustache'), MCOs use '$' to set a value without rendering it. You can use the existing Mustache syntax to perform substitution with a default value, so I exclude adding the same meaning to '$'. The '<' sigil also does two things at once. It defines a region where substitution with a default assignment can occur without rendering, and then it include a partial. Since MCOs assign without rendering, we don't need a block that suppresses rendering, and we can use the existing '>' sigil to include a partial after performing assignments. That pretty much eliminates the need for the '<' sigil. I've kept it to define regions where MCOs are in effect, but after these discussions, I'm thinking that they can be eliminated altogether. In that case, an MCO is implicitly pushed onto the stack when rendering begins, and another is pushed whenever a partial is used. I don't code Ruby, much less Ruby on Rails, so it's entirely possible that templates are understood by everyone in that community. However, I don't think that they are easily understood by users of other languages. Template syntax is certainly somewhat more concise, but conciseness doesn't seem to be a primary goal of Mustache. To be honest, I had an ulterior motive in opening this issue: I wanted to see if anyone responded. Mustache seems to be moribund. Even uncontroversial proposals that appear to patch obvious flaws have been sitting open for months. There are a lot of implementations of Mustache, but they all extend and enhance the syntax in incompatible ways to patch the not-so-obvious flaws. A few implementations seem proud to have dropped certain parts of the spec that they dislike (handlebars.js has not change delimiters tag). There are several other changes that I could have suggested, but template inheritance had the most replies. I thought that a proposal to completely eliminate them would stir some debate. I am very glad that you joined my discussion, but I'm somewhat disappointed that you were the only person to do so. Yes, I'm implementing my own version of the Mustache spec. The first thing I did was write a test harness that loads the entire spec and tests my implementation against it. I forked the spec so I could add in many pull requests that have been sitting idle, but also with a vague idea that if Mustache v1 is dead, I might re-purpose my version as Mustache v2. I don't know that I'll go that far, but my experiment has left me more confident to make my implementation Mustache-like instead of Mustache compatible. |
You are right. This repo hasn't evolved since a long time, and its owners don't even answer to any message (@defunkt & @pvande). I think they consider Mustache finished. I think that so does the public community. Mustache is now seen as a minimalist template engine, end of the story. A look at stack overflows reveals how little people are waiting from it. My position is simple: I use the very Mustache engine I have written, and I don't want to regret my choice of using it. Since the language defined by the spec is not only minimalist, but a chore invented by a stubborn minimalist nazi, that punishes you very hard as soon as you start rendering a non-trivial document, I had to extend the spec until my lib has become fluid and extensible enough. I did it in the best directions I could find, for the user's sake. It looks like you are doing the same, and this is good. This Mustache spec repository is now a forum. I've been happy discussing your feature with you on this forum :-) |
Closing this, as the proposal was superseded by template inheritance actually making it into the spec (#125) and because the comments seem to have been going in a less than constructive direction. If someone would like to give the idea of mutable context objects another chance, please feel welcome to create a new discussion for it. |
I've just waded through issue 38: Template inheritance. I know I'm a couple of years late to that dance, but I suspect that one reason why the proposal hasn't been adopted is that there was never any consensus on what should be done; there were at least two implementations that behaved slightly differently. So rather than adding to an already lengthy thread, I'm going to propose something different that accomplished the same goal: Mutable context objects (MCO). (And I think that this will also satisfy the goals of issue 63: Inline partials.
MCOs use two "new-ish" bits of syntax.
While the mutable context object is on the stack, the rest of Mustache works the same as always.
The preceding renders as:
Note that using the same key overwrites the previous value.
The preceding renders as:
Note how this interacts with partials. Here is an example of a partial:
Now, let's see what happens when it is used like this:
You wind up with this:
Needless to say, you can push multiple MCOs onto the context stack; any new values are written to the most recently created MCO (and obviously disappear when it gets popped). Any objects added to the context stack after the MCO are considered immutable, and are skipped over when adding a value. Also, by the judicious use of {{#key}} and {{^key}} sections, you have complete control over how substitutions are performed.
BTW, I expect that the last example is going to be a common use case, so I'd suggest that the following should be interpreted as doing the same thing:
Finally, I know that all of this can be done via lambdas. I would note that (a) just because anything can be computed via a Turing machine doesn't mean that you should ignore other ways of doing it, and (b) lambdas are an optional part of the spec, so IMHO that isn't a good reason to reject this or any other proposal. Also, I'm fully aware that I'm re-using sigils that other implementations have used for years. Feel free to suggest others that I could use instead, but note that this spec could, like lambdas, be an optional part of the overall spec. Conflicting implementations could then ignore it, possibly later adding an option to their engine to toggle the interpretation.
Your thoughts?
The text was updated successfully, but these errors were encountered: