Skip to content
This repository

Proposal: Template inheritance #38

Open
spullara opened this Issue February 17, 2012 · 129 comments
Sam Pullara

At Twitter we run into a very common case where we want to have one template where we maintain the "bones" of the page and each real page on the site merely replaces sections of that page with appropriate content. We would like to avoid putting any business logic in the bones of the page for including the right content, nor do we want to write custom backing code for each of those pages.

I give up trying to put my code in the issue, here is a gist: https://gist.github.com/1854699

David Santiago

I'm pretty uninterested in the logic-less template stuff, but this strikes me as something that could be really useful to have, and so I'd like to see something like this.

But what strikes me about it is that sub.mustache is not really a mustache template but more of a list of substitutions (which are mustache templates). Is there any way an inheriting template isn't just a list of substitutions? Because if not, why couldn't it just be defined that if an implementation wants to create a mechanism for creating derived templates, it can do that by letting you define (however you like; json? yaml? list of mustache sections?) a mapping of names to mustache-template strings or mustache files and replacing regular interpolation tags with the indicated mustache code when the derived template is loaded? It seems to me (albeit after only like 4 minutes thought) that this would potentially be even more convenient while simultaneously not requiring major changes to the parsers of existing mustaches. And also, it would prevent us from using up two precious special characters to implement this proposal. But, I'm probably missing something in that logic.

Gwendal Roué

Two cents:

As @davidsantiago, I regret that sub.mustache is "not really a mustache template", and, more specifically, that we don't know what happens when sub.mustache contains content outside of the substitutions blocks. That alone makes the gist weird, even though the need is pretty clear.

I know about a solution for this problem: Ruby on Rails' one : one template is rendered in one layout.

This gist show hows a Rails-like two-pass rendering could look in Mustache (the syntax mimics Rail's one) : https://gist.github.com/1855111

The main differences with @spullara's gist:

  • sub.mustache has no reference to its layout - the rendering code should take care of rendering sub.mustache in the layout.mustache
  • the content of sub.mustache is no longer a specific substitution, instead there is a dedicated place for it in the layout.
  • there is no default value for any substitution
Sam Pullara

Thanks for the feedback. sub.mustache is actually a mustache template, the example usage failed to show that in all its glory. Another example that has come up for us is for having similar widgets that are displayed differently in different places but use the same base template. I do agree though that within the {{<super}}, the top level has to be replacements. However, nothing stops you from using the {{<}} syntax anywhere within any template. {{<}} means "replace any blocks in this partial with blocks that i have specified within this tag, then include the partial".

The RoR solution lacks the ability to have multiple layouts in a single page, also I need some external mechanism to connect the two templates. It also doesn't seem to support a large hierarchy of template "classes". For example, we might have:

General Twitter Page < Settings style page < Profile settings page

Re: characters. This scheme can be implemented without introducing new characters through some elaborate lambda gymnastics but it wouldn't be very clear what was going on when you looked at the template. Could be ameliorated by using a naming convention e.g. {{#<super}} and {{#$content}}. My personal opinion is that this is such a widespread issue with real life mustache usages that it just might be worth it.

Gwendal Roué

{{<}} means "replace any blocks in this partial with blocks that i have specified within this tag, then include the partial".

Thanks for this sentence. It's quite clear, now.

It's also clear that {{<}} can be seen as a kind of inheritance, and as well as a function call with arguments. More people should know Handlebars.js. In Handlebars, no need for new punctuation, no need for an extension to the spec: I quite think you could just write a simple 'content_for' helper, and write : https://gist.github.com/1855986.

Really, Yehuda Katz's announcement is refreshing: http://yehudakatz.com/2010/09/09/announcing-handlebars-js/
Handlebars.js website: http://handlebarsjs.com/

Sam Pullara

That is pretty close. The only gap is that when you use multi-level inheritance the higher one in the stack wins instead of the lowest one in the stack. Default content also doesn't work with this model.

David Santiago

OK, yeah, that functionality wasn't clear to me from the initial example. That does leave the "templateness" of sub.mustache intact. However, as you say, there is still the way that the inside of the ">" tag is basically putting forth a map notation for mustache. Mustache has always seemingly been happy to leave maps to the language implementing it, so I still feel a little uncomfortable with this and can't say why. I just wish that the inside of that tag didn't require so much special meaning and new parsing. That is why I still really like the idea of letting this just be a partial with template substitutions for interpolation tags. The spec is already vague about where exactly the implementation should go looking for partials, so this could be very easily slipped into current implementations with a minimum of new syntax, just an expansion of what partials mean, in that partials might have associated files that create substitutions when they are loaded.

Regarding the other character, I was saying that I think you could leave off the $, and just jam the template into the ordinary interpolation tags. This is already kind of what lambdas do, in that a lambda passed in for an interpolation tag will return mustache code that is then parsed and rendered in that context. So there is already a precedent for a regular interpolation tag being used as a site for more template code to be inserted. The difference here would be that instead of this happening due to a function passed into the context map, it's happening because a derived template is instantiating itself (and thus wouldn't need to happen every time the template is called).

Sam Pullara

The biggest problem with using # is that the identity transformation is so goofy. Even though it looks like you are replacing it with the same thing, they would be interpreted much differently:

https://gist.github.com/1881261

David Santiago

I'm not at all following what you're saying... What is it about the # tags? What is the identity transformation?

Sam Pullara

Ah sorry, by "identity transformation" I mean a replacement that leaves you with the original. If we reuse # tags we have the issue that to replace the section with something that means the same thing you have to double them.

David Santiago

OK, I see now what you're saying. If we grant the syntax you want for using sections as keys and their values in a partial, the repetition in that example seems clear enough to me. Certainly the identity transformation is not a motivating use case for this feature, and having the source code for it, when it is necessary, shake out in this way doesn't strike me as sufficient motivation for the addition of a new tag type. There are no current semantics defined for sections when they are being used as the sites of template inheritance replacements, so there is some leeway here to posit new rules if that's necessary.

Sam Pullara

So currently the semantics for # sections is such that if they are not present in the backing code, they are "false". It might make more sense to use {{^}} instead in this case to get something that is closer to the {{$}} behavior. Not sure if I am explaining this well enough, but {{#}} has very different semantics.

David Santiago

I don't know if you're explaining it well enough, but I'm not quite following you. I assume you're talking about the resolution rules hereabouts: https://github.com/mustache/spec/blob/master/specs/sections.yml#L11 Those rules name a few different places to look for the contents of a section tag... is there some reason another place to look couldn't be added to those rules? I'm not seeing it.

Sam Pullara

So lets take the example where you want a page to evaluate two different ways, once with the default text and once with your modified text. In order for that to work, based on Rule 2), you have to have a singular valued hash matching the name of the section in the top level template so the section renders at all:

2) Walk the context stack from top to bottom, finding the first context
that is a) a hash containing the name as a key OR b) an object responding
to a method with the given name.

If you don't have that, the section won't be evaluated. When I extend the top level template, suddenly that "section" is satisfied and it doesn't even reference the section code that I use in the super template. Having to offer specific backing code in order for the template to render properly is what I am trying to avoid by suggesting a declarative template inheritance feature. This is why the sub template isn't just a hash of values but literally replaces the template code in the super template. The real issue is the default for {{#}} is false, not true -- which is why I suggested that {{^}} would be more appropriate.

David Santiago

OK, gotcha, thanks. I had not been considering the use case of wanting to have default code for when nothing is provided by a derived template and there is no desire to have a flag in the context to control whether that default code renders or not. I agree that that's not desirable.

If a partial has {{something}}, {{#something}}{{/something}} or {{^something}}{{/something}}, I thought we'd like to have a way to replace that tag with an arbitrary expansion, but Mustache doesn't currently have a way to name groups of code other than sections and inverted sections. So then you'd have to say: when you're replacing, match the tag names regardless of the tag type. That way you could get a section/inverted section named "something" inserted in the place of {{something}} or whatever. Here we're using sections/inverted sections just for their code-grouping semantic to define the key/value syntax for the replacement part of the {{<}} tag. Although you're right that {{^}} would be more natural for the replacement sites, it's not clear to me which is more natural and meaningful in the key/value replacement syntax, especially when you add on the question of whether they should match the replacement site or be the opposite for the replacement to avoid confusion about "double negatives."

That makes me unhappy, and you already had a solution to that, which was to define a new tag type that allows you to name a group of code, but without the implied "here or not" choice between a section or inverted section. So {{#}} means "Render this group of code if we are given a truthy value for its name," {{^}} means "Render this group of code if we aren't given a truthy value for its name," and {{$}} means "Render this group of code if we aren't given a substitution from a partial, and if we are, render that replacement." This expansion of syntax allows more information to remain "in mustache," as mustache is then expanded to mean more things. This trades away the ability to "replace anything" in the parent template for one that has to be prepared with replacement sites and requires a special idea of what is "default" in the template that is above and beyond just the template itself as it would already exist in mustache as it is today.

I also had a solution to that, which was to not get into the key/value syntax business in the first place and leave those to the implementation's maps. In that world, {{}}, {{#}}, and {{^}} can all be replaced equally naturally when the super (actually just a partial, now) is loaded by the implementation with the use of a map of the tag name->source code replacements that the implementation knows how to find. All that's needed is some rules for how those replacements should be made from the map, assuming this map already exists. This offers "replace anything" capability and retains implementation simplicity by avoiding the addition of any new syntax, but it comes at the cost of requiring that derived templates have some external storage format outside of mustache to store their replacement maps (the spec itself shows that mustache can be very naturally embedded in YAML, for one example). I think we assign different weights to how much we value these things; I don't value having a mustache version of a key/value map that much.

Anyhow, I think your idea for derived templates is great, and I think I'm gonna try adding my version to my mustache implementation just to check it out. I just hope the mustache language stays small and provides a small number of very flexible primitives. The language is pretty much defined by the 5 or 6 special characters that start tags, and I hope the language doesn't expand to many more tags than that, or it'll stop being easy to learn and keep in your head.

Rob Sayre

I added this feature to Hogan as well as the Ruby implementation (not submitted yet).

It's useful and helps avoid triple stache usage.

Matthew Cheely

In general, I like the fact that the mustache spec is very light, and doesn't add many features, but this is one I'd like to see. In addition to being generally useful, it resolves an issue that has been nagging at me about mustache which is a tendency for markup to get mixed in with logic & data (sort of the opposite of the issue with most templating toos). In particular, this seems to be a problem to me when creating generic re-usable templates that aren't bound to specific data types. Things like form inputs (and the associated markup). Take the following examples: https://gist.github.com/2176799

The thing that bothers me about these templates are that the id, class & href attributes that have to be defined in code to make them re-useable. I would like be able to edit markup unrelated to application data in the templates. With @spullara's inheritance proposal, data could come from the application, and markup could stay in the templates.

Olivier Vaillancourt ovaillancourt referenced this issue in twitter/hogan.js April 16, 2012
Open

Template inheritance docs #70

Kristian Lewis Jones
klj613 commented June 26, 2012

inheritance +1

7rans
trans commented June 28, 2012

-1

To sum up my assessment: "intolerably inelegant".

Sam Pullara

Would love to hear more trans. It really works very well for things that mustache is very bad at doing without introducing logic to the templates. What in particular do you find inelegant?

7rans
trans commented June 28, 2012

I give Hogan credit for at least using blocks to designate the template, not just a top-line like dust.js. That makes it a little better than I originally thought. (Documentation on this is bit hard to come by. I had to read some terse tests.)

But I also think:

  1. The use of < is a bit too easy to mistake for >.

  2. Dummy text clutters up the layout template, the use of blocks (the $ block) are meaningless.

  3. The use of $ in the layout template seems rather unnecessary anyway. Without it layout templates would be perfectly reusable with or without template inheritance.

  4. Using $ in both the layout template and the content template makes it unclear which is which at a glance.

  5. Why $? B/c it's next to # on the keyboard? Try =, which makes the intent much clearer.

Taken alone each of these points might seem rather trivial, but taken all together it leaves me feel'n a bit too perlismy.

Sam Pullara
7rans
trans commented June 29, 2012

Suggestions? I think the symmetry between the two makes a lot of sense.

Yes, I think the symmetry, on its face, does seem like a good idea. But on reconsideration I had to agree with another poster in #44. Using a more distinct symbols would give better "contrast", making it a bit easier to read. My idea was to use a combination of # and >, e.g. {{#> layout}}, but that has it's short-comings too. Really this is the least troubling of my points. I can live with it. (I'd just rather not have to!)

That isn't dummy text, it sits in as the default if it isn't overridden.

We don't have such defaults for normal variable substitutions. So why have them for these? Use inverted sections instead (e.g. {{^$title}}). On the other hand, I am not against these per-se, if they can be optional somehow, b/c most of time the default is a YAGNI. What if it used plain variable substitution (e.g. {{title}}), and only use $ notation if a default is needed. This pattern could then apply to normal variables as well, which would be a more useful feature. I don't think there needs to be a distinction between variable substitution and template substitution, and templates would be more flexible/reusable that way.

They are usable without template inheritance. If not overridden, it is as if they aren't there.

But the default would show up, right?

Believe it or not, it started out as $ to indicate that something
could be replaced and = to set it. This was deemed extraneous by all
who reviewed it.

Really? I'm a bit surprised. I invite the distinction so it is immediately recognizable which is which. Also, what happens if you use template inheritance inside another template inheritance?

Aside, was wondering also if a template block could forgo any "slot definitions", in which case it would default to a special name. e.g.

  <p>{{{yield}}}</p>
  {{< layout}}
    Just content here, no slot defs.
  {{/ layout}}
Kristian Lewis Jones
klj613 commented June 30, 2012

template inheritance is a good thing and having default blocks help you not to repeat yourself and have it so you can override them. e.g. a sidebar might he overrided only on a few templates.

Twig template system is very nice. It for PHP framework symfony2.

7rans
trans commented June 30, 2012

I am not disputing there value. I just want to see them be as developer friendly as possible.

With regards to defaults, when you need them then yes it's a good thing. Most of time we don't need them, and we end up with silly filler, like {{$title}}Page Title{{/title}}.

gw0 commented July 04, 2012
  1. The use of < is a bit too easy to mistake for >.

Suggestions? I think the symmetry between the two makes a lot of sense.

What about {{<<super}}? This way it is distinguishable from > and it can also be understood that there is some special kind of input from super (in Bash << represents reading from input until a special line is read).

gw0 commented July 04, 2012

I would also like to note that template inheritance is the most powerful and useful feature of Django and Jinja2 template engine (check out its goodies). Without template inheritance you mostly end up with chaotic and unreusable templates.

Pieter van de Bruggen
Owner
pvande commented July 30, 2012

@spullara I'd be interested to know whether your needs would be met by an inheritance pragma...

{{! layout.mustache }}
<html>
  <head><title>{{ title }}</title></head>
  <body>
    {{{yield}}}
  </body>
</html>
{{! content.mustache }}
{{% INHERIT layout yield %}}
<div>Hello, {{name}}!</div>
data = { :title => 'Greetings', :name => 'world' }
Mustache.render File.read('content.mustache'), data

Yielding:

<html>
  <head><title>Greetings</title></head>
  <body>
    <div>Hello, world!</div>
  </body>
</html>

With the INHERIT pragma taking both a template name (resolved like partials) and an (optional) content name. Suspected behavior is as follows:

  • Content template is rendered normally.
  • Pragma causes the parent template to be fetched and rendered.
    • Parent template is rendered against the the same data content was rendered against
    • Parent template's context stack also includes a reference to the content template, named with the pragma's content name.
  • Multiple inheritance is not supported.
  • Returned result is the top-level template.
Sam Pullara

This actually isn't close to the way we actually use it. We need:

1) multiple inhertiance
2) multiple scoped inclusions per page
3) various levels of nesting and overriding
4) multiple replacements in a single parent

Pieter van de Bruggen
Owner
pvande commented July 30, 2012

Can you give me examples of what those uses actually look like? The only one of those that I feel as if I have a passable understanding of right now is "multiple replacements in a single parent", and that seems more directly expressed with an inheritance hierarchy.

Is there any chance we can see some real-world templates that require that functionality?

Matthew Cheely

I have a few examples of specific use cases for the template inheritance proposed in this issue. A bit of background: At Lulu, we are developing a suite of applications which are independent from one another, but share page layouts and styles.

Here's a gist containing shared parent layouts, a parent layout for a specific app, and a dummy page implemented in a specific app (note that I can't use '/' in the filenames in the gist, so I've used ':' as a path separator instead: https://gist.github.com/3220568

I think these match up with 1 & 3 in Sam's list (assuming I'm understanding his points correctly)
1) there are 4 levels of inheritance from page.html to about-me.html
3) about-me.html replaces content several levels up the inheritance heirarchy

Here's another gist with a different use case that's not about page layout, but is about embedding commonly re-used basic layouts in a page multiple times, with different override values for each embedding. Specifically, these are templates for form inputs, and all the associated labels/errors/descriptions/etc, that go with them: https://gist.github.com/3220634

I think these match up with 2 & 4 in Sam's list:
2) datepicker.html is included in the page twice, in the scope of a different object each time
3) the {{$id}} replacements for fields affect both the label's for attribute and the input's id attribute

Sam Pullara

Thanks @mcheely! Those a great real world examples that mirror the kinds of things that we are doing as well and why we added the feature in the first place.

7rans
trans commented July 31, 2012

@mcheely I took your example and adjusted it to use the syntax I think would be most optimal for readability. See https://gist.github.com/3221814

The syntax has a very well defined design. The . is used to indicate an inheritable template. I have chosen . instead of < b/c the later is easy to get confused with <, i.e. "which direction is which?". Then = is used for slot definitions. This differentiates them from substitute sections so templates can be used in other templates. Normal variables are used for slots when there are no defaults, which make the pages more reusable. Lastly, the only difference between # and $ is that the contents of the former are not shown if it is undefined, but just the opposite for the later. This actually gives $ additional use. # could be used for slots too, but the default content would be pointless.

As Handlebars.js has shown us, # does not define a specific construct, only that it is a block form. What it actually is and does depends on what it references. And that's really the key to Mustache's elegance.

Rob Sayre
sayrer commented July 31, 2012

imho "rough consensus and running code" favors the syntax proposed by @spullara. the objections/suggestions proposed so far are either bikeshedding or uninformed by implementation.

John Anderson

Any progress on getting inheritance into the spec? We are starting a new project and have chosen mustache as the primary templating engine for server and client side rendering but its hard to accomplish this without basic template inheritance.

John Anderson

@spullara Have you attempted any patches for this? I'm really interested in getting some inheritance into mustache. Without it I'm having a hard time maintaining my templates.

I need to be able to swap out specific "sections" with the child. So for instance I would define a "section" called MENU and then the child inheriting should be able to define/include their own menu and replace the parents'

Sam Pullara

@sontek This is implemented in at least mustache.java and hogan.js. What language are you using?

John Anderson

@spullara I'm using mustache.js and pystache but I could switch to hogan.js if it has it. What was the final accepted syntax that I have to implement in pystache?

Sam Pullara

@sontek I don't think there is a syntax accepted by the spec yet. The ones implemented in hogan.js and mustache.java are the same though and they match what you find in the gist at the top.

John Anderson

Yeah, I don't mind if its not in the spec, I just need the functionality and would be nice to keep it as consistent as possible.

So there is no tests I can run to verify they are working? Just make sure the gist renders properly?

Sam Pullara

@sontek None in the spec test format. Though I should probably make a pull request for that — was hoping to wait till it was approved. Here are my mustache.java tests that might help https://github.com/spullara/mustache.java/blob/master/compiler/src/test/java/com/github/mustachejava/ExtensionTest.java

John Anderson

@spullara Trying to make a jsfiddle as an example of how to use your inheritance stuff but hogan.js 2.0 doesn't seem to work with it?

http://jsfiddle.net/7ayVQ/

Sam Pullara

@sontek I believe that it was added in 3.0

John Anderson

You are correct, updated to 3.0 and now it all works: http://jsfiddle.net/7ayVQ/2/

Devin Rhode

I think @groue's suggestion here: #issuecomment-4026898 is best.

The code from his gist is:

layout.mustache:
    <html>
    <head><title>{{{$yield title}}}</title></head>
    <body>
    {{>navigation}}
    <div class="content">
    {{{$yield}}}
    </div>
    {{>footer}}
    </body>
    </html>

sub.mustache:
    {{$content_for title}}Profile of {{username}} | Twitter{{/content_for}}
    Here is {{username}}'s profile page

However, sub.mustache has no reference to what layout it wants to use. I think a combination of this and the implementation done by hogan.js is best:

layout.mustache:
    Page header
      {{$yield content}}
    Page footer

sub.mustache
    {{<layout.mustache}}
        {{$content}}
            Profile page for: {{username}}
        {{/content}}
    {{/layout.mustache}}

Also note the use of a filename reference to the layout file. I think this is really obvious move but we should to agree to have it in the spec.

I think it's extremely clear what's going on here. Developers are familiar with the yield keyword, and this really solves a big pain-point with mustache. This is the simplest I've seen through the whole thread and, correct me if I'm wrong, mustache is all about simplicity.

I think the $content_for keyword is a little verbose, but admittedly acceptable.

What are everyone's objections/problems with this solution? @sayrer, what do you feel about the filename convention for partials and layouts for hogan.js? I really wish it had it, been using Mu instead.

Sam Pullara

To me the originally proposed syntax also seems simpler and works good in practice (try it in Mustache.Java).

John Anderson

I think the hogan.js implementation of this works perfectly:

http://jsfiddle.net/sontek/e4pnj/

Just need to get it into the spec :)

Devin Rhode

@spullara layout.mustache is a super template

If I boil it down, I'm requesting we use:

{{$yield title}}

instead of default content:

{{$title}}Confusing default text. You usually will never want this text. Furthermore, it's an opportunity to
confuse the reader to think it's a real template when it's a super template/layout file{{/title}}

I'm confident any developer that's seen a yield before will immediately know: This is a super template.

With default content, the reader can easily get confused into thinking it's a normal template. A yield clearly states this will get filled in by a page using this super layout.

We could also use$= titleinstead of$yield title but the idea is the same.

Again, instead of:

<script type="template/hogan" id="super">
  SUPER HEADER
  {{$content}}
    Somebody's profile page...
  {{/content}}
  SUPER FOOTER
</script>

<script type="template/hogan" id="child">
  {{<super}}
    {{$content}}
        Profile page for: {{username}}
    {{/content}}
  {{/super}}
</script>

I'm requesting:

<script type="template/hogan" id="super">
  SUPER HEADER
  {{$yield content}}
  //OR without the yield:
  {{$= content}}
  SUPER FOOTER
</script>

<script type="template/hogan" id="child">
  {{<super}}
    {{$content}}
        Profile page for: {{username}}
    {{/content}}
  {{/super}}
</script>

If you have an questions please ask, otherwise this is all I have to share for now.

Sam Pullara
Veena Basavaraj vybs referenced this issue in linkedin/dustjs September 18, 2012
Closed

Better base_template solution #125

@devinrhode2: Why does it look like you are only thinking in 2 layers of template inheritance? Imagine that every part of every template could be extended, even include a partial template that is extended from something and that you could even extend/reuse templates maintained by other people/projects without modifying their code...

Devin Rhode

Good point @gw0. It seems there's pretty good consensus around the approach taken by hogan.

Anything else can be under a{{%PRAGMA}} option.

7rans

I don't understand why others haven't picked up on my point that inherited template rendering does not have to be syntactically different from rendering data. And by not differentiating them, templates become much more reusable.

Devin Rhode

If someone else wants to feel free to flesh out the tests for this and submit a pull request, otherwise I can hopefully get around to it sooner or later.

Gwendal Roué

@spullara GRMustache provides template inheritance, under the name "overridable partials", since it allows a template to embed several ones.

I'd be happy to get your comments on :

Gwendal Roué

Check this gist as well: https://gist.github.com/3770302

Devin Rhode

@groue, at first glance your stuff looks pretty good. It's right in line with the layout approach that's already being implemented in a few versions, we can probably use your tests as the spec tests.

Gwendal Roué

@devinrhode2 Thanks for your feedback. Actually, I do not have too much doubt about the "overridable partials" test suite. I'm less sure about the "overridable sections" test suite.

Gwendal Roué

I have added a few tests to the GRMustache overridable partials test suites, that fix some corner cases and assert some internal Mustache consistency:

@spullara, @sayrer: I'd be really pleased getting your feedback, when you have time.

Gwendal Roué

GRMustache 6 has changed the way it renders overridden sections. In Ruby on Rails, multiple <% content_for :foo do %>...<% end %> provide multiple contents for a single <%= yield :foo %>. This is very handy.

You can achieve the same effect with GRMustache: https://github.com/groue/GRMustache/blob/master/Guides/partials.md#concatenation-of-overriding-sections

Sam Pullara

@groue i've been thinking about this for a bit. does it concatenate in every case? how to I completely override? I was expecting that we would need some additional syntax for specifying overridden vs concatenated values.

Gwendal Roué

Hi @spullara.

does it concatenate in every case?

Yes, it does. The "outermost" overrided section provides default content. It is replaced by the first (in the order defined by the "flattening" of partials) overriding section, and extended by all others.

how to I completely override? I was expecting that we would need some additional syntax for specifying overridden vs concatenated values.

It looks (after a few Google searches) that not many people want to escape the default concatenation mechanism of Rails', and I have assumed concatenation was the way to go.

What do you think?

Gwendal Roué

@spullara I've been realizing lately that your mustache.java and my GRMustache are the only viable options for writing cross-platform iOS/Android templates.

I've already shipped a few applications that use the exact same set of templates. Those templates use lambdas to embed CSS and javascript files, as well as multi-resolution images. I can't tell you how grateful I am :-)

Your support for {{<layout}} and concurrent rendering also puts you in the very restricted set of Mustache implementations that try to go beyond a spec that hasn't evolved for eons.

What about we would work on improving our compatibility and provide a nice pair of reliable tools. Why not even a set of sample codes that cover the most common use cases?

Joe Esposito

+1 for this. It's an excellent feature in jinja. I really like the originally suggested solution here too.

Template inheritance has definitely helped with site maintainability in the past few years. It's really the only thing keeping me attached to jinja instead of switching over to a language-neutral solution like mustache, which I think is a really good thing to have. Template inheritance is just too practical to give up.

Gwendal Roué

@joeyespo You may ask the people behind pystache to come here and look at what @spullara and I have done

Joe Esposito

@groue will do!

@groue @spullara In terms of overriding vs concatenating, for what it's worth, jinja always overrides. However, it also exposes a base value you can use to concatenate if you need to.

For example, the mustache equivalent would look something like this:

super.mustache:

...
<head>
    <title>{{$title}}Twitter{{/title}}</title>
</head>
...

sub.mustache:

{{<super}}
{{$title}}Profile of {{username}} | {{$base}}{{/title}}
...
{{/super}}

This will produce "Profile of username | Twitter" by accessing super's $title through the $base variable.

I'm not suggesting it has to be that way, just trying to spark some new ideas since this ultimately lets the user decide without introducing any new syntax. The simple syntax is really what makes jinja so attractive. Yet, it does so without sacrificing flexibility.

Gwendal Roué

Thanks for the suggestion @joeyespo. User feedback is essential in these matters.

Justin Hileman

My proposed implementation in Mustache.php is identical to @spullara's initial gist, except:

  • It is enabled with a pragma tag ({{% BLOCKS }}).
  • The subtemplate uses the pragma tag to indicate its parent ({{% BLOCKS parent=layout }}).

Having used similar template language features in the past, this one makes the most sense to me, as well as feeling most in line with the logic-less nature of Mustache.

Also, pragmas are awesome. All y'all should use 'em for your non-spec extensions to Mustache :)

You can check out the implementation here.

Sam Pullara
Justin Hileman

No, I'm not suggesting using pragmas for the blocks, I'm suggesting using pragmas to toggle the functionality. I'm using {{$ foo }}{{/ foo }} for my blocks.

Check out the first two code blocks bobthecow/mustache.php#130 for examples.

Sam Pullara

With the current setup, you can have multiple sections that inherit in a single page:

{{<super1}}
{{$foo}}...{{/foo}}
{{/super1}}
{{<super2}}
{{$bar}}...{{/bar}}
{{/super2}}

Or even nested within each other. I don't think there is any way to do that with pragmas without breaking up the page.

Justin Hileman

Gotcha. That's the part where I said the pragma-based single inheritance "feels the most in line with the logic-less nature of Mustache" :)

Justin Hileman

That said, I'm not completely against it, I just feel like we can get 90% of the good with a simpler implementation, and that feels more "mustache" to me.

Sam Pullara
Gwendal Roué

@bobthecow I'm happy you've joined this feature :-)

GRMustache talks about "overrideable sections" in order to prevent the reader to think single inheritance. Actually it's simpler to implement this way (rather than introducing a whole new concept of real template single inheritance in the code base).

@spullara @bobthecow we should settle something about the behavior of our libs when a section is overrided several times. I don't know how your libs behave. GRMustache used to render the last one, and now it renders a concatenation.

Justin Hileman

@groue Thanks. I actually implemented it 5 months ago — check the date on that commit :)

I've just been waiting on the Mustache.php v2.2.0 release before opening a PR to discuss it. And that was waiting on a committee to decide how logging would look in PHP. Committee finished, so I released v2.2.0, and now I'm working to get a few things into v2.3.0 that I implemented a while ago (inheritance and anchored lookups).

As far as multiple overrides, I think it's far more intuitive that it actually does override rather than concatenates. It might make sense to expose the parent block as a {{{ parent }}} property or something, but I'm not really happy with that name, so I wouldn't suggest using it :)

Gwendal Roué

it's far more intuitive that it actually does override rather than concatenates

Overriding if of course fundamental. The question is: how should we behave when there are several overrides. A related question is: do we want to help partials to feed a single HTML header section (for injection HTML headers for instance).

The default behavior of content_for/yield in ERB (default template engine of Ruby on Rails) is to concatenate, with quite few requests on stackoverflow of users who want to disable the concatenation.

Ignoring this fact would be stupid. Concatenation is useful.

Based on that, GRMustache overrides and concatenates multiple overrides.

Now I hope that things are a little clearer.

Oscar Bernal

Hi all, this is a pretty old thread but hopefully you are still keeping an eye out for this. Scalate has an implementation for layouts (http://scalate.fusesource.org/documentation/mustache.html) which seems very mustache-like and doesn't require using any more further special characters. I wonder if something like that would make more sense to everyone? It definitely is a big need to be able to do this.

Justin Hileman

@obernal That's an interesting approach, but a little too magic for my taste. It would feel a lot more mustache (to me) to use an explicit tag to denote sections for replacement, rather than parsing the html <body> and <title> tags and such.

Gwendal Roué
groue commented June 20, 2013

For the record, {{<layout}} {{$override}}...{{/override}} {{/layout}} is already implemented, with happy users, by three Mustache engines: hogan.js, spullara/mustache.java, and groue/GRMustache.

Oscar Bernal

And that is exactly why we chose mustache.java :) Hopefully this will be added to the spec at some point then. Thanks for the implementations and the discussion!

Gwendal Roué
groue commented June 20, 2013

Thanks @obernal. Don't be too optimistic: the spec hasn't evolved in years, is definitely unmaintained, and no discussions has occurred in months since no decision could never emerge.

Justin Hileman

@groue @spullara given this: https://gist.github.com/spullara/1854699

... what happens to sub.mustache content inside the {{< super }} block but not inside a {{$ replacement }} block?

{{<super}}
    {{$title}}Profile of {{username}} | Twitter{{/title}}
    Wheeeeee!
{{/super}}
Gwendal Roué
groue commented June 20, 2013

@bobthecow It is ignored entirely. This is typically the case of white spaces and new lines around each overridable section.

Gwendal Roué
groue commented June 20, 2013

@bobthecow, if you are interested, here are some slightly more interesting questions you could ask yourself (and compare your solutions to the solutions given by hogan, mustache.java, and GRMustache):

  • what if a section gets overriden several times in a template ? {{$content}}…{{/content}} {{$content}}…{{/content}}?
  • what if a section gets overriden several times accross several nested layouts?
  • can a partial override a section (given the template T that uses the layout L, can the partial P included in T override a section declared in L) ?
  • can a partial be layout-based ?
  • what if a template contains several {{<super1}}...{{/super1}}...{{<super2}}...{{/super2}} layouts?

You may have your own subtle questions. Bring them on - most of them may be already solved.

Gwendal Roué
groue commented June 20, 2013

Also:

  • can replacement sections be nested? In the layout ? In the template ? How does replacement work in this case?
  • what is the nature of the identifier inside a {{$ xxx }} tag? Is it an expression just as in {{# user.items}}...{{/...}} sections? Is it something else?
Justin Hileman

These are all great questions :)

Do we have anything resembling a spec or acceptance tests for this?

Gwendal Roué
groue commented June 21, 2013

I don't know for hogan.js, but mustache.java has some tests, and so does GRMustache:

What I can quickly tell you is that @spullara's mustache.java and GRMustache already have a few divergences:

  • When a section gets overriden several times, GRMustache concatenates their contents (rationale: the analogous mechanism in Ruby On Rail's is their yield/content_for pair. It does concatenate multiple content_for, and there aren't much questions on StackOverflow from people who want to disable the feature - so I guess they hit the sweet spot). mustache.java does not concatenate. I don't know how it handles multiple replacement sections.
  • GRMustache processes the content of a {{$ xxx }} tag as an expression just as {{# user.items }} (the context stack is extended by the value inside the overridable section). I tend to believe it is a mistake that I will have to fix. It mostly works well, though: I still have to exhibit the undesired behavior.
Justin Hileman
  • I tend to lean toward not concatenating multiple overrides (but possibly allowing a {{ parent }} or {{ yield }} type value so they can explicitly include the previous value?)

  • I'm with Java on the {{$ foo }} not being added to the context stack. It seems problematic, especially for things like this:

    {{$ title }} {{ title }} | My Awesome Site {{/ title }}
    

    ... which I can imagine are not uncommon.

Gwendal Roué
groue commented June 21, 2013

Make your own opinion. Anyway, convergence of implementations is far out of sight, with everybody adding "seems", "lean", "doesn't look" and other non-arguments in order to add something to the "discussions" here. At least try to find some minimum common ground, that would be nice for users, our only real targets. Cheers, and good luck.

Justin Hileman

That common ground is what I'm looking for, hence the questions :)

I'm totally happy switching from my initial single inheritance implementation to the multiple inheritance that seems to be favored, but I'd prefer to see at least some semblance of consensus on how it works.

Gwendal Roué
groue commented June 24, 2013

@spullara has said that he considers his java implementation done and finished. I don't know about hogan.js. My own GRMustache is pretty satisfying also, a lot of work and thought has been put into. Read the three docs, check the three test sets (you've got links to mine above), and pick up your favorite!

Matt DeClaire

I've been lurking in this discussion for a while, and I'd like to see some consensus arise. I feel like there is some talking past each other on the issue of reused content areas. I created a gist outlining the two types of {{$content}} area reuse as I see them, and how I understand they'd be rendered. Can you comment?

Gwendal Roué
groue commented July 18, 2013

@mattdeclaire It looks like you got it. Any precise question? Have you checked the test suites of current implementations?

Matt DeClaire

I got the impression from @bobthecow's comment, regarding override vs. concatenate, that he was referring to my sub-page use case, while you were referring to my alt-page use case. If that was the case, I'm hoping to unclog the process and towards getting this feature implemented (in PHP, where I need it).

Gwendal Roué
groue commented July 18, 2013

Well, ask @bobthecow directly. I do not expect the spec to evolve. None of the spec maintainers, @defunkt, @pvande and @janl have given any sign of life for a long time. None of the interesting issues in this repo, since it became public, was ever given a conclusion - talk about an active spec. Everybody has moved on. Mustache is dead. Some implementations may be still alive: check with them directly, good luck!

Gwendal Roué
groue commented July 18, 2013

Mustache is dead. Some implementations may be still alive.

I mean it. Watch for developers who take care of their users, and are able to go beyond the corpse of a spec.

Matt DeClaire

I'm interested in a cohesive experience between two languages, which is what the spec enforces. Absent activity in the spec, if we can get you guys to agree, and commit to a "side spec", then that works, too. I'd hate to see implementations diverse, when that was the selling point of Mustache in the first place.

I hear an appreciate your devotion to the users. But, I'm a Mustache user, not a MustachePHP or MustacheJS user. Devotion to keeping the teams together is tantamount to taking care of the users. If the spec is dead, then I hope you guys fork it, become maintainers of the New Mustache, and keep collaboration alive.

Jan Lehnardt
Owner
janl commented July 18, 2013

fwiw, I never worked on the spec, I don’t know why I was added to this repo, this whole thing is a not-paid-for open source so maybe keep your ranting to yourself.

Mustache is very much alive and could totally use engaged people like you to keep it going, so why not redirect some of that energy into a fork and win the world?

<3

Gwendal Roué
groue commented July 18, 2013

Thanks, @janl, for your message.

I'm interested in a cohesive experience between two languages, which is what the spec enforces. Absent activity in the spec, if we can get you guys to agree, and commit to a "side spec", then that works, too. I'd hate to see implementations diverse, when that was the selling point of Mustache in the first place.

My point of view exactly for years, until it became clear nothing would ever happen here. I've been a long way since: https://github.com/groue/GRMustache/blob/master/Guides/compatibility.md

I hear an appreciate your devotion to the users. But, I'm a Mustache user, not a MustachePHP or MustacheJS user. Devotion to keeping the teams together is tantamount to taking care of the users. If the spec is dead, then I hope you guys fork it, become maintainers of the New Mustache, and keep collaboration alive.

I'm an Objective-C developer, a language without any focus on the web and HTML. I don't see myself as a maintainer of a forked spec.

Here is my contribution: I used to make a compilation of feature requests on other repos and stackoverflow, to see what were the most important issues to address. All of them have their answer in GRMustache - thanks to a few versatile hooks that open wide the door to user-injected code - check the FAQ.

Joe Esposito

Handlebars seems to be a popular fork of mustache. Fwiw they have partials. One of the strengths of a common strength is simplicity. The only problem with feature-loading a fork is it becomes much more difficult to push those features out or re-implement them all from scratch.

Joe Esposito

FWIW in the concat vs override argument, I come from using Jinja2, which is for HTML. I couldn't imagine having concat be the default because most projects use more than two levels of nested extending, and overriding lets you override specific sections of HTML, allowing you to override a template that overrides the base.

Concatenating would be useful for the <script> and <style> sections, but that's really the only exception. And there's a perfectly fine workaround that's similar to the suggested yield call--the {{ yield }} call. This also lets you customize whether you want your scripts to appear before or after that block you're overriding. If concat becomes the default, you'll have to be more cautious with your HTML template.

Matt DeClaire

@janl, I apologize if my comments came off as accusatory. But, I don't think I was ranting. For devotees like me, who appreciate the work you guys do/have done, but can't prioritize contributing ourselves, certainly there is room to add our own perspective. This as an important proposal that lost steam. I just wanted to +1 the issue to show there is interest.

@groue, web focus shouldn't be a prerequisite to maintaining the language agnostic Mustache. But that doesn't make it an easy undertaking. Pushing forward on your implementation certainly helps the community.

Jan Lehnardt
Owner
janl commented July 18, 2013

@mattdeclaire thanks, no harm done :)

Gwendal Roué
groue commented July 18, 2013

I couldn't imagine having concat be the default because most projects use more than two levels of nested extending, and overriding lets you override specific sections of HTML, allowing you to override a template that overrides the base.

Valid point @joeyespo, assuming the premise. GRMustache used to render the last override, until I compared the feature with RoR's yield/content_for pair, which concats, and that I noticed that there are very few questions on the web from people who want to disable RoR's concatenation. I must admit I miss user data to support one option, or the other. I don't know the point of view of other implementors (@sayrer (hogan.js), @spullara) of this question.

@mattdeclaire I guess I have been ranting, too...

Sam Pullara

@groue I think the concatenation option seems useful, but I haven't gotten any requests for it.

Re: spec forking. I'm not that interested in forking the spec as we would have to change the name of mustache. Why can't the original authors engage?

Gwendal Roué
groue commented July 21, 2013

@spullara Same for me (no request to remove it :wink:) I've been using template inheritance myself, for very simple cases (a common layout shared between a couple of different HTML pages that display on iOS apps), and I never used concatenation personally. I would eventually use it only if I were developing actual web sites, as I do in Ruby on Rails. I don't know if you are using your own library for building complex enough websites yourself. Maybe @sayrer or @fat or @mattrobenolt from hogan.js, a genuinely web-targetted mustache engine, will eventually show up here, and give their point of view?

Why can't the original authors engage?

+1

Yuriy Nemtsov nemtsov referenced this issue in twitter/hogan.js August 15, 2013
Merged

Support for deep inheritance substitutions #149

Levi Lewis

This is a highly discouraging issue. I've been lurking for over a year watching this hoping that once a conclusion was reached my wife and I could move www.fit.edu over to mustache templates. We've been holding back waiting for this.

Nicolas Gallagher

The sort of template inheritance @spullara described is something I find useful at Twitter. I haven't had the need for concatenation, but nested inheritance would help to modularize our components.

Atanas Minev

Template inheritance is a powerful construct for abstracting common structure.

I'm going to implement it in jtmpl, which redefines Mustache as a DSL for writing UIs by augmenting a templating engine with automatic data-binding.

Here's the syntax I'm going to use: atmin/jtmpl#4

Edd Sowden edds referenced this issue from a commit in alphagov/govuk_template November 18, 2013
Edd Sowden Add Mustache inheritance version
There is a [proposed extension to Mustache to support template
inheritance][1]. This produces a version of the template which can be
used by implementations which support it.

[1]: mustache/spec#38
ab11702
Edd Sowden edds referenced this issue in alphagov/govuk_template November 18, 2013
Merged

Add Mustache inheritance version #37

Jamie Hill

Has this really not made it into the spec yet? Do the spec maintainers even look at these issues anymore?

Edd Sowden edds referenced this issue from a commit in alphagov/govuk_template November 18, 2013
Edd Sowden Add Mustache inheritance version
There is a [proposed extension to Mustache to support template
inheritance][1]. This produces a version of the template which can be
used by implementations which support it.

[1]: mustache/spec#38
0a68963
Edd Sowden edds referenced this issue from a commit in alphagov/govuk_template November 18, 2013
Edd Sowden Add Mustache inheritance version
There is a [proposed extension to Mustache to support template
inheritance][1]. This produces a version of the template which can be
used by implementations which support it.

[1]: mustache/spec#38
f1dd4e1
looterz

Would love to have this as well.

Maxime Fabre

Any news on this ? Mustache is the only templating language that has support on so many languages but the fact it lacks inheritance is really a problem in my opinion.

JoshWillik

+1 for inheritance, this is the only reason I use Jade over mustache

Levi Lewis

LinkedIn's fork of DustJS. You'll never look back.

Maxime Fabre

Twig has a JS implementation now too, making it usable in PHP and JS.

Levi Lewis

Twig's javascript client isn't fully compatible with the PHP counterpart. Has that changed?

Maxime Fabre

As far as I know nearly everything is supported, apart from some minor things here and there but they're not stuff I've ever used, personally.

造轮子工程师

If anyone of you just using Mustache-like template engines such as original Mustache, Hogan or Handlebars in express, you can try npm MustLayout to perfectly resolve template inheritance.

Gwendal Roué
groue commented March 15, 2014

@spullara, @necolas The Objective-C implementation GRMustache v7.0.0 passes all template inheritance tests of hogan.js and spullara/mustache.java. Particularly, inherited sections are no longer concatenated, for compatibility's sake. You may well be interested in GRMustache test suite: https://github.com/groue/GRMustache/blob/master/src/tests/Public/v7.0/Suites/groue:GRMustache/GRMustacheSuites/inheritable_partials.json

Jamie Hill

Just going to throw something out there…

I was about to start adding layout support to Tache when I realised, maybe this can be achieved without a change to the spec at all; turns out it can, with the clever use of lambdas, no spec change needed.

Just as long as the Mustache implementation can return template objects from lambdas (something I've found to be extremely useful in Tache), it is pretty easy to create an object to capture the layout blocks as template objects and use them when rendering the layout, here is the gist: https://gist.github.com/thelucid/9574028

Gwendal Roué
groue commented March 16, 2014

@thelucid The point of template inheritance is to avoid double-pass rendering: the application code should be identical, whether the rendered template is a plain one, or a inherits from another one.

Jamie Hill

@groue I thought that might come up, there is actually no double pass render though as you might expect. The first render's sole responsibility is to capture the blocks and this is therefore extremely cheap, the second render then renders the entire template as a whole; each template part is only ever rendered once.

As for your second point, why should the application code need to be identical for plain or inherited, the layout is then tightly coupled to the template? This solution is actually a little more flexible as the inherited template doesn't need to know what it's inheriting, a kind of polymorphism if you like. This way you could have two layouts that both have 'main' and 'sub' content regions and render a template with either layout without having to make a change to the template.

capture = Capture.new

CaptureView.new(capture).render <<-eos
{{#layout.main}}The main content{{/layout.main}}
{{#layout.sub}}The sub content{{/layout.sub}}
eos

puts MyView.new(capture).render <<-eos
[layout 1 header]
{{#layout.main}}Layout 1 default main content{{/layout.main}}
{{#layout.sub}}Layout 1 default sub content{{/layout.sub}}
[layout 1 footer]
eos

puts MyView.new(capture).render <<-eos
[layout 2 header]
{{#layout.main}}Layout 2 default main content{{/layout.main}}
{{#layout.sub}}Layout 2 default sub content{{/layout.sub}}
[layout 2 footer]
eos
Gwendal Roué
groue commented March 16, 2014

@thelucid In GRMustache, at least (I don't know about hogan & mustache.java), inheritable templates and partials share the same underlying idea: splitting a template into partials or having a template inherit from another one is a mere matter of template organization. It is not a matter of the application code.

template.mustache:
users: {{# users }}{{ name }},{{/ users }}

should be 100% equivalent to (partial extraction):

template.mustache:
users: {{# users }}{{> user }},{{/ users }}

user.mustache:
{{ name }}

should be 100% equivalent to (inherired template):

template.mustache:
{{< layout }}{{$ user }}{{ name }}{{/ user }}{{/ layout }}

layout.mustache:
users: {{# users }}{{$ user }}{{/ user }}{{/ users }}

For example, your application could have a function returning a template or a template name, saying "give this template an array of users, and it will render the expected page". Should the original full template eventually be split into partials, or inherit any layout, this should not require this function or dependent code to be changed or refactored. I believe it is a desirable property of a Mustache library.

// Returns the path to the template.
// The template should be provided with a "users" key.
//
// -> NB: This method would not change after a change in template organization.
- (NSString *)templatePath
{
  return @"/path/to/template.mustache";
}

// Returns the rendering of the template, given an array of users.
//
// -> NB: This method would not change after a change in template organization.
- (NSString *)renderTemplateWithUsers:(NSArray *)users
{
    NSString *templatePath = self.templatePath;
    GRMustacheTemplate *template = [GRMustacheTemplate templateFromContentsOfFile:templatePath error:nil];

    id data = @{ @"users": users };
    return [template renderObject:data error:nil];
}
Gwendal Roué
groue commented March 16, 2014

@thelucid I did not say it, but your use case is still valid, of course.

Jamie Hill

@groue I don't agree that the template is the best place to define the layout.

Take for example an application where you want a different layout based on whether the user is logged in. In Rails for example, this can be achieved simply by setting the layout to an admin layout at a controller level, the same goes when using my suggested approach.

Without this flexibility, to set a layout at a view level, your template would wrongly contain the logic of whether to display the logged in layout or not. With my suggested solution, you would simply do:

puts MyView.new(capture).render(user.authenticated? ? authenticated_layout : guest_layout)

I can understand that you are wary as you've already implemented all the layout code in your library, however, layouts can be achieved without a change in the spec and with greater flexibility.

Nicolas Gallagher

Related: defining and composing of components. This is the Ember/handbars syntax (which is a little confusing in what seems to be further overloading of #): http://emberjs.com/guides/components/wrapping-content-in-a-component/

<script type="text/x-handlebars" id="components/blog-post">
  <h1>{{title}}</h1>
  <div class="body">{{yield}}</div>
</script>

{{#blog-post title=title}}
  <p class="author">by {{author}}</p>
  {{body}}
{{/blog-post}}
造轮子工程师

@thelucid IMO, view is just view or template, and any controller should not contain any condition to choose which view or layout to render with. There is only one view should be bind to a controller. And if you want to switch view just like in your example of authentication, what you just need is filter or interceptor before a real end controller to render.

For example if you send a GET to http://somedomain.com/home, and you want authenticated users to view their home page, while users not authenticated to view wrong message or redirect to login, you could do like this (I just use node.js to express):

function authenticate (request, response, next) {
    if (!user) {
        return response.render(403, 'message.tpl', message);
    }
    next(); // This means request passed through this interceptor and go to next handler
}

function home(request, response, next) {
    //after looking up some data, render to the home view (template)
    response.render('home.tpl', someData);
}

home.interceptor = [authenticate]; // the interceptor queue, any request to /home should run these interceptors first. You can add more.

And back to your template and layout description, here need totally different template targets ('message.tpl' and 'home.tpl'), anyone could define their layout in itself. Why not?

Jamie Hill

@mytharcher In most cases, you just need to switch the overall layout and not the inner template for authenticated users, with the approach I have suggested this is simple. This approach has worked great in Rails for years and personally moving this logic to the template seems plain wrong as the whole philosophy of Mustache is logic less templates. Also, the fact that it doesn't require a change to the spec keeps Mustache more focused.

Jamie Hill

…this solution also negates the need for the (potentially confusing) left arrow and dollar sign syntax and the additional learning curve that comes with this for new users.

Justin Hileman bobthecow referenced this issue in defunkt/mustache April 17, 2014
Open

Nice approach to nested layouts #138

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.