What Mustache can learn from Clojure
chrisvest.name
chrisvest.name
Items in lists don't have to be objects with fields; you can display primitives like strings and numbers by using {{this}}:
{{#each tags}}
<li><a href="tags.html#{{this}}">{{this}}</a></li>
{{/each}}
Shadowing properties from parent context objects isn't a problem. Handlebars allows you to reach parent contexts with a '../' notation: {{#each comments}}
<h2><a href="/posts/{{../permalink}}#{{id}}">{{title}}</a></h2>
<div>{{body}}</div>
{{/each}}
Regarding looping and conditional branching, Handlebars has an {{#if}} helper that does not evaluate to true for empty arrays: {{#if authors}}
{{#each authors}}
{{firstName}} {{lastName}}
{{/each}}
{{else}}
No authors to display.
{{/if}}
I don't fully understand the complaint about recursive data structures. I usually just register a helper that can invoke itself recursively.Consider the simple #with helper:
Handlebars.registerHelper('with', function(object, options) {
// invoke the sub-template passed as a block to the with helper with the object parameter
return options.fn(object);
});
And its usage: {{#with person}}
Name: {{name}}
{{/with}}
This means that you can build arbitrary control structures and iterators in the host language and expose them to Handlebars.However, about half the post discusses how "looping and conditional branching are conflated", and the end focuses on adding a separate branching construct to what's supposed to be a logic-free templating language. So I guess what he's trying to say is he wants to add logic to a logic-free templating language. It seems like he missed the point of Mustache: Looping and branching are conflated by design to eliminate logic from the template.
About the only way I see the connection between Clojure and Mustache at all is through the potential value destructuring could bring, and destructuring isn't exactly a feature which is unique to Clojure (CoffeeScript, Scala, and Erlang come to mind). Otherwise this post is apples and oranges: Clojure macros are about as far as you can get from a logic-free templating language. I'm wondering if the additions he proposes are sufficient to turn what's supposed to be a logic-free templating language into a Turing-complete one (see this example of why XSLT is Turing-complete: http://www.unidex.com/turing/utm.htm)
Looping and branching are conflated by design to eliminate logic from the template.
That doesn't eliminate logic, it just makes it annoying and obtuse.You can still branch in mustache templates, and you can still loop. No particular kind of logic has been eliminated. But now you need to know what a particular item happens to be in order to know what the magic branch/loop operator is going to do.
About the only thing it prevents is saying "show this if X is truthy", but only prevents it when X is a list! Removing the ability to do something for some arbitrary objects doesn't make the language clean and logic-free, it makes it annoying and complicated.
Adding an explicit "if" operator does introduce logic into the language, and may very well make the language sufficiently expressive to be Turing complete.
It's basically a finite state machine.
Now you can do a whole lot with a FSM---and lo, some people will claim that our current brand of machines are only realistically as powerful as FSMs because of the lack of infinite memory.
While you can't "write" to the Turing tape as a side effect as the language is immutable, you can create a new "tape" from previous states which is a modified version of the old tape.
Why is something that shows a message "only if person has a truthy value":
{{#person}}
Hi {{name}}!
{{/person}}
different from an `if` (except it becomes a `for` depending on the value of the argument)?As long as you use values consistently it is never the case that a single person object referred by a variable "person" transforms into a set of people.
You do not eliminate, or even reduce, the amount of logic at work by conflating looping and branching because now, apart from the normal function of these constructs, the language (or its runtime) is also making decisions about which one of these to use when given a particular piece of data.
The truth is that Mustache isn't logic-free, because it has looping and branching, and it can even call methods and functions with its lambda feature. The only template language I know of that is actually logic-free is Rife Templates: http://rifers.org/wiki/display/RIFE/GuideTemplates.html What you discover when you use that system, is that templates without logic can't really do much, so you have to control them with logic that sits outside of the templates.
As for destructering, I considered adding a Haskell example, but that idea didn't really work with where I was going with the story on data. In the end I am the most familiar with Clojures destructuring, plus its data story was a really good match here, so I just stuck with it.
However, there appears to be a set of common denominators
that can be used to represent all possible
data-structures: Maps or dictionaries, lists, strings,
numbers, boolean and null.
I'd add sets to this list. You can kind of simulate them using a map where the keys are the members and the values are anything, but they just work more smoothly when you have real support for them (like in Python and Clojure, but not Javascript/JSON).And yeah, it's easier to shoot yourself in the foot with templates that have logic, but on the other hand with logic-less templates you may need to do something that the template language won't let you do, and then you have to go and write some more code in your domain logic. Which means that you're doing something even worse than pushing your business logic into your display logic - you're pushing your display logic into your business logic!
{{%IMPLICIT-ITERATOR}}
{{#foo}}
{{.}}
{{/foo}}
But...Handlebars.I have also since found out about Handlebars.js. It looks nice. If Mustache is the 80% solution then Handlebars.js is probably the 99% solution or something like that. Except I would need an implementation in Python, and I haven't come across one.