Permalink
Browse files

Add rails support

* Templates go in app/templates/{controller}/{action}.{mime}.mustache

* Mustaches (ie, the ruby classes) go under
  app/views/{controller}/{action}.rb and should inherit from
  Mustache::Rails

* Controller ivars will be copied to your mustache class.

* You can omit declaring the Mustache. In that case, an instance of
  Mustache::Rails will be used for evaluation. If this is the case, then
  attr_readers will be defined for your controller ivars, since you can't
  access them directly from the template.

* Mustache::Rails also delegates any methods to the ActionView::Base
  instance used by rails, so helpers should work fine.

* You can't use Mustache's {{< partial }} syntax. Yet.

* There's no way to use the form helpers from rails in a mustache
  template, but alternate solutions like Bureaeucrat
  (http://github.com/tizoc/bureaucrat) which ports django's form objects
  into ruby might be useful.

* Templates can go in app/views/{controller}/{action}.{mime}.mustache
  still, if you prefer to keep them alongside your views. Mustache will
  just look for them in app/templates before.
  • Loading branch information...
1 parent ca40124 commit 99cd770f4786425a15268bc7a1a451a012f52970 @foca committed Oct 10, 2009
Showing with 58 additions and 0 deletions.
  1. +58 −0 lib/mustache/rails.rb
View
@@ -0,0 +1,58 @@
+require "mustache"
+
+class Mustache::Rails < Mustache
+ attr_accessor :view
+
+ def method_missing(method, *args, &block)
+ view.send(method, *args, &block)
+ end
+
+ def respond_to?(method, include_private=false)
+ super(method, include_private) || view.respond_to?(method, include_private)
+ end
+end
+
+class Mustache::Rails::TemplateHandler < ActionView::TemplateHandler
+ def render(template, local_assigns, &block)
+ mustache = _mustache_class_from_template(template)
+ mustache.template_file = template.filename
+
+ returning mustache.new do |result|
+ _copy_instance_variables_to(result)
+ result.view = @view
+ result[:yield] = @view.instance_variable_get(:@content_for_layout)
+ result.context.update(local_assigns)
+ end.to_html
+ end
+
+ def _copy_instance_variables_to(mustache)
+ variables = @view.controller.instance_variable_names
+ variables -= %w(@template)
+
+ if @view.controller.respond_to?(:protected_instance_variables)
+ variables -= @view.controller.protected_instance_variables
+ end
+
+ variables.each do |name|
+ mustache.instance_variable_set(name, @view.controller.instance_variable_get(name))
+ end
+
+ # If you're using an anonymous mustache, then you probably want
+ # +attr_reader+ declared for your instance variables, else there's no way
+ # you can access them on the template.
+ if mustache.class == Mustache
+ mustache.class.class_eval do
+ attr_reader *variables.map {|name| name.to_s.gsub(/^@/, '') }
+ end
+ end
+ end
+
+ def _mustache_class_from_template(template)
+ const_name = [template.base_path, template.name].compact.join("/").classify
+ defined?(const_name) ? const_name.constantize : Mustache::Rails
+ end
+end
+
+ActiveSupport::Dependencies.load_paths << Rails.root.join("app", "views").to_s
+ActionController::Base.prepend_view_path(Rails.root.join("app", "templates").to_s)
+ActionView::Template.register_template_handler(:mustache, Mustache::Rails::TemplateHandler)

0 comments on commit 99cd770

Please sign in to comment.