→ Higher Order Mustache

27 April 2010

On the GitHub East Coast tour a few weeks ago Tom Preston-Werner and I were trying to figure out a solution to what I saw as the Final Mustache Problem: caching.

In ERB you might do this:

<% cache "user:#{current_user.id}" do %>
  Some expensive stuff.
<% end %>

At GitHub we do a fair amount of HTML caching this way. Without this feature, we couldn't start porting the site to Mustache. Solving this problem would probably let us implement syntax highlighting and other similar concepts in Mustache, too.

Here's what we got: Higher Order Sections.

  Some expensive stuff.

How? If the value of cache_by_user_id is a lambda or function, Mustache will pass the unrendered block of text to it. The block can then do whatever it wants and its return value replaces the block.

Here's how we might do caching in Ruby:

class MyView < Mustache
  def cache_by_user_id
    lambda do |text|
      cache_key = "user:#{current_user.id}"

      if value = $cache.get(cache_key)
        value
      else
        rendered = render(text)
        $cache.set(cache_key, rendered)
        rendered
      end
    end
  end
end

The lambda is passed the raw template text. If we find something in the cache, we return that and it replaces the block. If we don't find anything in the cache we render the block, store it in the cache, then return it.

Examples

I opened sourced the mustache-syntax-highlighter recently, and also created a Gist of a Markdown helper we're using. Both are Higher Order Sections in action.

Bonus: both mustache.rb and mustache.js already support this feature.