diff --git a/lib/handlebars_assets/config.rb b/lib/handlebars_assets/config.rb
index 9a54aa0..4fe63f5 100644
--- a/lib/handlebars_assets/config.rb
+++ b/lib/handlebars_assets/config.rb
@@ -6,7 +6,7 @@ module HandlebarsAssets
module Config
extend self
- attr_writer :compiler, :compiler_path, :ember, :multiple_frameworks,
+ attr_writer :compiler, :compiler_runtime, :compiler_path, :ember, :multiple_frameworks,
:haml_options, :known_helpers, :known_helpers_only, :options,
:patch_files, :patch_path, :path_prefix, :slim_options, :template_namespace,
:precompile, :haml_enabled, :slim_enabled,
@@ -17,6 +17,10 @@ def compiler
@compiler || 'handlebars.js'
end
+ def compiler_runtime
+ @compiler_runtime || 'handlebars.runtime.js'
+ end
+
def self.configure
yield self
end
@@ -94,7 +98,7 @@ def template_namespace
end
def handlebars_extensions
- @hbs_extensions ||= ['hbs', 'handlebars']
+ @hbs_extensions ||= %w(hbs handlebars)
end
def hamlbars_extensions
diff --git a/lib/handlebars_assets/handlebars.rb b/lib/handlebars_assets/handlebars.rb
index 7e2eb20..b1f89df 100644
--- a/lib/handlebars_assets/handlebars.rb
+++ b/lib/handlebars_assets/handlebars.rb
@@ -5,7 +5,6 @@
module HandlebarsAssets
class Handlebars
class << self
-
def precompile(*args)
context.call('Handlebars.precompile', *args)
end
diff --git a/lib/handlebars_assets/server.rb b/lib/handlebars_assets/server.rb
new file mode 100644
index 0000000..6cce9ba
--- /dev/null
+++ b/lib/handlebars_assets/server.rb
@@ -0,0 +1,29 @@
+require 'handlebars_assets'
+
+%w(responder controller handlers/handlebars extensions).each do |lib|
+ require File.join('handlebars_assets', 'server', lib)
+end
+
+module HandlebarsAssets
+ module Server
+ extend self
+ HANDLER = HandlebarsAssets::Server::Handlers::Handlebars
+
+ def self.register_template_handlers
+ Config.handlebars_extensions.each do |ext|
+ ActionView::Template.register_template_handler(ext, HANDLER)
+ end
+ end
+
+ def self.register_mime_types
+ Config.handlebars_extensions.each do |ext|
+ Mime::Type.register_alias 'text/html', ext.to_sym
+ end
+ end
+ end
+end
+
+if defined?(Rails)
+ ::HandlebarsAssets::Server.register_template_handlers
+ ::HandlebarsAssets::Server.register_mime_types
+end
diff --git a/lib/handlebars_assets/server/controller.rb b/lib/handlebars_assets/server/controller.rb
new file mode 100644
index 0000000..43aef90
--- /dev/null
+++ b/lib/handlebars_assets/server/controller.rb
@@ -0,0 +1,61 @@
+module HandlebarsAssets
+ module Server
+ # Prepare a controller to use respond_with
+ # to render a Handlebars template (for GET requests, currently)
+ #
+ # You must require 'handlebar_assets/server'
+ # in your controller, as it is not loaded by default.
+ #
+ # require 'handlebars_assets/server'
+ #
+ # class MyApp < ActionController::Base
+ # include HandlebarsAssets::Server::Controller
+ #
+ # respond_to :hbs # or :handlebars
+ #
+ # def show
+ # @bike = Bike.find(params[:id])
+ # render_with(@bike) # Look ma, no 'to_hbs'!
+ # end
+ # end
+ #
+ # Your class must define #to_hbs (or #to_handlebars)
+ # that returns a Hash of JSON-compatible objects.
+ #
+ # You can specify the location of your templates:
+ #
+ # handlebars_templates path: 'app/assets/...'
+ #
+ # -or-
+ #
+ # handlebars_templates paths: ['array', 'of', 'paths']
+ #
+ # 'app/assets/javascripts/templates' is prepended on
+ # include, so you do not need to add this line
+ # if you keep your templates in that directory
+ #
+ # If you support other mime types (like JSON), in the same
+ # controller, you'll need to give your template a 'js' or
+ # 'jst' format in order to keep Rails from trying to use
+ # the view for everything:
+ #
+ # show.js.hbs # *not* show.hbs or show.html.hbs
+ #
+ module Controller
+ extend ActiveSupport::Concern
+
+ DEFAULT_HBS_TEMPLATE_PATH = 'app/assets/javascripts/templates'
+
+ included do
+ self.responder = HandlebarsAssets::Server::Responder
+
+ def self.handlebars_templates(options = {})
+ paths = options[:paths] || options[:path] || []
+ Array(paths).reverse_each { |p| prepend_view_path(p) }
+ end
+
+ handlebars_templates path: DEFAULT_HBS_TEMPLATE_PATH
+ end
+ end
+ end
+end
diff --git a/lib/handlebars_assets/server/extensions.rb b/lib/handlebars_assets/server/extensions.rb
new file mode 100644
index 0000000..286e64b
--- /dev/null
+++ b/lib/handlebars_assets/server/extensions.rb
@@ -0,0 +1,30 @@
+module HandlebarsAssets
+ module Server
+ module Extensions
+ def context_for(template, extra = '')
+ tmpl = "var template = Handlebars.template(#{precompile(template)})"
+ context = [runtime, extra, tmpl].join('; ')
+
+ ExecJS.compile(context)
+ end
+
+ def render(template, *args)
+ locals = args.last.is_a?(Hash) ? args.pop : {}
+ extra = args.first.to_s
+ context_for(template, extra).call('template', locals)
+ end
+
+ protected
+
+ def runtime
+ @runtime ||= runtime_path.read
+ end
+
+ def runtime_path
+ @runtime_path ||= assets_path.join(HandlebarsAssets::Config.compiler_runtime)
+ end
+ end
+ end
+end
+
+::HandlebarsAssets::Handlebars.send(:extend, HandlebarsAssets::Server::Extensions)
diff --git a/lib/handlebars_assets/server/handlers/handlebars.rb b/lib/handlebars_assets/server/handlers/handlebars.rb
new file mode 100644
index 0000000..ab9dd1f
--- /dev/null
+++ b/lib/handlebars_assets/server/handlers/handlebars.rb
@@ -0,0 +1,31 @@
+module HandlebarsAssets
+ module Server
+ module Handlers
+ class Handlebars
+ def self.call(template)
+ new.call(template)
+ end
+
+ def call(template)
+ if template.locals.blank?
+ "#{template.source.inspect}.html_safe"
+ else
+ <<-HBS
+ variable_names = controller.instance_variable_names
+ variable_names -= %w[@template]
+ if controller.respond_to?(:protected_instance_variables)
+ variable_names -= controller.protected_instance_variables
+ end
+ variable_names.reject! { |name| name.starts_with? '@_' }
+
+ variables = variable_names.inject({}) { |acc,name| acc[name.sub(/^@/, "")] = controller.instance_variable_get(name); acc }
+ variables.merge!(local_assigns)
+
+ HandlebarsAssets::Handlebars.render(#{template.source.inspect}, variables).html_safe
+ HBS
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/handlebars_assets/server/responder.rb b/lib/handlebars_assets/server/responder.rb
new file mode 100644
index 0000000..be06570
--- /dev/null
+++ b/lib/handlebars_assets/server/responder.rb
@@ -0,0 +1,44 @@
+module HandlebarsAssets
+ module Server
+ # Provides the requisite #to_{format} methods a Responder needs
+ # to handle respond_with
+ class Responder < ActionController::Responder
+ # Ask the resource to give a HandleBars-compatible
+ # representation and then passes it back to
+ # render
with the appropriate new options.
+ #
+ # Add the HBS-compatible version of the resource
+ # to the locals hash, and ensure [:js, :jst] is in
+ # the list of requested formats.
+ def to_handlebars
+ display resource, resource_options if resourceful?
+ end
+ alias_method :to_hbs, :to_handlebars
+
+ private
+
+ # Aggregate the options for displaying this resource
+ # and return the new Hash.
+ def resource_options
+ { locals: resource_locals, formats: resource_formats }
+ end
+
+ # Merge any user-supplied locals with the formatted resource
+ # and return the Hash
+ def resource_locals
+ (options.delete(:locals) || {}).merge!(resource.send(:"to_#{format}"))
+ end
+
+ # Merge any user-supplied formats with our
+ # supported format(s) and return the new Array.
+ def resource_formats
+ supported_formats | (options.delete(:formats) || [])
+ end
+
+ # :nodoc:
+ def supported_formats
+ [:js, :jst]
+ end
+ end
+ end
+end