→ Mustache 0.9.0
I'm very happy to announce Mustache 0.9.0, probably the most major release so far. Sinatra 1.0, new parser, bugfixes, and more!
Grab it:
gem install mustache
Or check http://defunkt.github.com/mustache/ for other implementations.
Sinatra 1.0
The release of Sinatra 1.0 changed the way templates are rendered. As such, previous versions of Mustache use an old API and won't work with it.
If you're upgrading from Mustache 0.7.0 or lower please note that the settings have changed very slightly. This diff is an example of one app I upgraded to Sinatra 1.0 + Mustache 0.9 -- pretty painless, and the settings all have better names (finally).
Anyway, Mustache 0.9.0 works great with Sinatra 1.0 and even provides some big improvements:
Caching
The first time a Mustache template is rendered it is compiled into pure Ruby and cached, even if there's no associated view class. Subsequent calls use the cached version which completely bypasses the parsing and generating stages.
Overriding Content in Layouts
Previously there was no easy way to change the layout from a view
class. Take this layout.mustache:
And these views:
class Layout < Mustache
def title
"layout"
end
end
class Index < Layout
def title
"index"
end
end
You'd expect it to work, and you'd hope it would work, but it would not. Now it does. Just make sure your views inherit from your layout and everything will be dandy.
Syntax Errors
More syntax errors are caught and the error messages are much more helpful thanks to the new parser (more on that below).
For example, here's a broken template:
And here's what we get trying to tokenize it:
Or take this broken template:
Again, helpful output:
Tag names are a bit more strict as they more closely resemble allowed Ruby method names, with a few exceptions. If you have a big problem with this please file an issue.
New Parser
Magnus Holm has once again torn Mustache's parser apart and rebuilt it into something beautiful. This time it's an entirely new scanner and generator.
Mustache used to loop through a template looking for regular
expressions and building up a compiled Ruby string along the way. As a
result we had some obscure bugs in nested sections and whatnot. The
new parser uses Ruby's StringScanner to intelligently build an array
of tokens from a string template.
Using the mustache command line utility we can see exactly what
Mustache::Parser returns for a given template:
Pretty neat. Internally this token stream is handed to
Mustache::Generator who compiles it into a Ruby string:
$ mustache -c hi.mustache
"#{if v = ctx[:greet?]
if v == true
"Hello #{CGI.escapeHTML(ctx[:name].to_s)}!"
else
v = [v] unless v.is_a?(Array) # shortcut when passed non-array
v.map { |h|
ctx.push(h)
r = "Hello #{CGI.escapeHTML(ctx[:name].to_s)}!"
ctx.pop
r }.join
end
end}"
This compiled string is the actual code run in your app to produce HTML output. Fun to look at but mostly useless unless you're familiar with Mustache's internals.
Bugfixes
Recursive partials, nested sections with names matching outer sections, and other bugs are now fixed. Many bugs were fixed by the new parser.
Speedup
When we started to allow Ruby objects to server as section contexts, the implementation slowed down Mustache dramatically. That's been fixed and things are (when compiled and cached) once again speedy.
Mustache 1.0
This release would be 1.0 but there's no Rails integration. That's next on the list - see you then.