Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ef859dc
Showing
2 changed files
with
140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Be sure to install mustache gem and include mustache gem in project Gemfile. | ||
|
||
# Template Handler | ||
require 'mustache_rails' | ||
# Generator | ||
Rails.application.config.generators.template_engine :mustache_generator |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
require 'action_view' | ||
require 'active_support' | ||
require 'mustache' | ||
|
||
class Mustache | ||
|
||
# TODO - Think about allowing to overwrite layout methods in subclassing views | ||
# http://github.com/defunkt/mustache/blob/master/lib/mustache/sinatra.rb#L79-82 | ||
# http://github.com/defunkt/mustache/blob/master/lib/mustache/sinatra.rb#L96-102 | ||
|
||
# Remember to use {{{yield}}} (3 mustaches) as this shouldn't be escaped. | ||
# Using {{{tag}}} will skip escaping HTML so if your mustache methods return | ||
# HTML, be sure to interpolate them using 3 mustaches. | ||
|
||
# Subclass Mustache::Rails for your view files. Place view files in | ||
# app/views/:controller/:action.rb. | ||
|
||
# Mustache::Rails registers a TemplateHandler for ".rb" files. Templates go in | ||
# app/templates/:controller/:action.format.mustache | ||
|
||
class 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 | ||
|
||
# Redefine where Mustache::Rails templates locate their partials: | ||
# | ||
# (1) in the same directory as the current template file. | ||
# (2) in the shared templates path (can be configured via Config.shared_path=(value)) | ||
# | ||
def partial(name) | ||
partial_name = "#{name}.#{Config.template_extension}" | ||
template_dir = Pathname.new(self.class.template_file).dirname | ||
partial_path = File.expand_path("#{template_dir}/#{partial_name}") | ||
unless File.file?(partial_path) | ||
partial_path = "#{Config.shared_path}/#{partial_name}" | ||
end | ||
File.read(partial_path) | ||
end | ||
|
||
# You can change these defaults in, say, a Rails initializer or | ||
# environment.rb, e.g.: | ||
# | ||
# Mustache::Rails::Config.template_base_path = Rails.root.join('app', 'templates') | ||
module Config | ||
def self.template_base_path | ||
@template_base_path ||= ::Rails.root.join('app', 'templates') | ||
end | ||
|
||
def self.template_base_path=(value) | ||
@template_base_path = value | ||
end | ||
|
||
def self.template_extension | ||
@template_extension ||= 'html.mustache' | ||
end | ||
|
||
def self.template_extension=(value) | ||
@template_extension = value | ||
end | ||
|
||
def self.shared_path | ||
@shared_path ||= ::Rails.root.join('app', 'templates', 'shared') | ||
end | ||
|
||
def self.shared_path=(value) | ||
@shared_path = value | ||
end | ||
end | ||
|
||
class TemplateHandler < ActionView::Template::Handler | ||
|
||
include ActionView::Template::Handlers::Compilable | ||
|
||
self.default_format = :mustache | ||
|
||
# @return [String] its evaled in the context of the action view | ||
# hence the hack below | ||
# | ||
# @param [ActionView::Template] | ||
def compile(template) | ||
mustache_class = mustache_class_from_template(template) | ||
mustache_class.template_file = mustache_template_file(template) | ||
|
||
<<-MUSTACHE | ||
mustache = ::#{mustache_class}.new | ||
mustache.view = self | ||
mustache[:yield] = content_for(:layout) | ||
mustache.context.update(local_assigns) | ||
variables = controller.instance_variable_names | ||
variables -= %w[@template] | ||
if controller.respond_to?(:protected_instance_variables) | ||
variables -= controller.protected_instance_variables | ||
end | ||
variables.each do |name| | ||
mustache.instance_variable_set(name, controller.instance_variable_get(name)) | ||
end | ||
# Declaring an +attr_reader+ for each instance variable in the | ||
# Mustache::Rails subclass makes them available to your templates. | ||
mustache.class.class_eval do | ||
attr_reader *variables.map { |name| name.sub(/^@/, '').to_sym } | ||
end | ||
mustache.render | ||
MUSTACHE | ||
end | ||
|
||
private | ||
|
||
def mustache_class_from_template(template) | ||
const_name = ActiveSupport::Inflector.camelize(template.virtual_path.to_s) | ||
defined?(const_name) ? const_name.constantize : Mustache | ||
end | ||
|
||
def mustache_template_file(template) | ||
virtual_path = template.virtual_path.sub('alfred/views/','') | ||
"#{Config.template_base_path}/#{virtual_path}.#{Config.template_extension}" | ||
end | ||
|
||
end | ||
end | ||
end | ||
|
||
::ActiveSupport::Dependencies.load_paths << Rails.root.join("app", "views") | ||
::ActionView::Template.register_template_handler(:rb, Mustache::Rails::TemplateHandler) |