Permalink
Browse files

Added ActionView::Base.register_template_handler for easy integration…

… of an alternative template language to ERb and Builder. See test/controller/custom_handler_test.rb for a usage example #656 [Jamis Buck]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@694 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 9be37c9 commit 9a5d6d6388a20f29c63f85a95d215b0b34ea9cfd @dhh dhh committed Feb 19, 2005
Showing with 77 additions and 15 deletions.
  1. +2 −0 actionpack/CHANGELOG
  2. +42 −15 actionpack/lib/action_view/base.rb
  3. +33 −0 actionpack/test/controller/custom_handler_test.rb
View
@@ -1,5 +1,7 @@
*SVN*
+* Added ActionView::Base.register_template_handler for easy integration of an alternative template language to ERb and Builder. See test/controller/custom_handler_test.rb for a usage example #656 [Jamis Buck]
+
* Added AssetTagHelper that provides methods for linking a HTML page together with other assets, such as javascripts, stylesheets, and feeds.
* Added FormTagHelper that provides a number of methods for creating form tags that doesn't rely on conventions with an object assigned to the template like FormHelper does. With the FormTagHelper, you provide the names and values yourself.
@@ -130,6 +130,7 @@ class Base
@@compiled_erb_templates = {}
@@loaded_templates = {}
+ @@template_handlers = {}
def self.load_helpers(helper_dir)#:nodoc:
Dir.foreach(helper_dir) do |helper_file|
@@ -151,6 +152,10 @@ def #{method}(*args, &block)
end
end
+ def self.register_template_handler(extension, klass)
+ @@template_handlers[extension] = klass
+ end
+
def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)#:nodoc:
@base_path, @assigns = base_path, assigns_for_first_render
@controller = controller
@@ -193,26 +198,32 @@ def render(template_path, local_assigns = {})
# Renders the +template+ which is given as a string as either rhtml or rxml depending on <tt>template_extension</tt>.
# The hash in <tt>local_assigns</tt> is made available as local variables.
def render_template(template_extension, template, local_assigns = {})
- b = binding
- local_assigns.each { |key, value| eval "#{key} = local_assigns[\"#{key}\"]", b }
- @assigns.each { |key, value| instance_variable_set "@#{key}", value }
- xml = Builder::XmlMarkup.new(:indent => 2)
-
- send(pick_rendering_method(template_extension), template, binding)
+ send(pick_rendering_method(template_extension), template_extension,
+ template, local_assigns)
end
def pick_template_extension(template_path)#:nodoc:
- if erb_template_exists?(template_path)
+ if match = delegate_template_exists?(template_path)
+ match.first
+ elsif erb_template_exists?(template_path)
"rhtml"
elsif builder_template_exists?(template_path)
"rxml"
else
- raise ActionViewError, "No rhtml or rxml template found for #{template_path}"
+ raise ActionViewError, "No rhtml, rxml, or delegate template found for #{template_path}"
end
end
def pick_rendering_method(template_extension)#:nodoc:
- (template_extension == "rxml" ? "rxml" : "rhtml") + "_render"
+ if @@template_handlers[template_extension]
+ "delegate_render"
+ else
+ (template_extension == "rxml" ? "rxml" : "rhtml") + "_render"
+ end
+ end
+
+ def delegate_template_exists?(template_path)#:nodoc:
+ @@template_handlers.find { |k,| template_exists?(template_path, k) }
end
def erb_template_exists?(template_path)#:nodoc:
@@ -224,7 +235,7 @@ def builder_template_exists?(template_path)#:nodoc:
end
def file_exists?(template_path)#:nodoc:
- erb_template_exists?(template_path) || builder_template_exists?(template_path)
+ erb_template_exists?(template_path) || builder_template_exists?(template_path) || delegate_template_exists?(template_path)
end
# Returns true is the file may be rendered implicitly.
@@ -250,16 +261,32 @@ def read_template_file(template_path)
@@loaded_templates[template_path]
end
- def rhtml_render(template, binding)
+ def evaluate_locals(local_assigns = {})
+ b = binding
+
+ local_assigns.each { |key, value| eval "#{key} = local_assigns[\"#{key}\"]", b }
+ @assigns.each { |key, value| instance_variable_set "@#{key}", value }
+ xml = Builder::XmlMarkup.new(:indent => 2)
+
+ b
+ end
+
+ def rhtml_render(extension, template, local_assigns)
+ b = evaluate_locals(local_assigns)
@@compiled_erb_templates[template] ||= ERB.new(template, nil, '-')
- @@compiled_erb_templates[template].result(binding)
+ @@compiled_erb_templates[template].result(b)
end
- def rxml_render(template, binding)
+ def rxml_render(extension, template, local_assigns)
@controller.headers["Content-Type"] ||= 'text/xml'
- eval(template, binding)
+ eval(template, evaluate_locals(local_assigns))
+ end
+
+ def delegate_render(extension, template, local_assigns)
+ delegator = @@template_handlers[extension].new(self)
+ delegator.render(template, local_assigns)
end
end
end
-require 'action_view/template_error'
+require 'action_view/template_error'
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class CustomHandler
+ def initialize( view )
+ @view = view
+ end
+
+ def render( template, local_assigns )
+ [ template,
+ local_assigns,
+ @view ]
+ end
+end
+
+class CustomHandlerTest < Test::Unit::TestCase
+ def setup
+ ActionView::Base.register_template_handler "foo", CustomHandler
+ @view = ActionView::Base.new
+ end
+
+ def test_custom_render
+ result = @view.render_template( "foo", "hello <%= one %>", "one" => "two" )
+ assert_equal(
+ [ "hello <%= one %>", { "one" => "two" }, @view ],
+ result )
+ end
+
+ def test_unhandled_extension
+ # uses the ERb handler by default if the extension isn't recognized
+ result = @view.render_template( "bar", "hello <%= one %>", "one" => "two" )
+ assert_equal "hello two", result
+ end
+end

0 comments on commit 9a5d6d6

Please sign in to comment.