Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 8341

Show
Ignore:
Timestamp:
12/09/07 22:11:11 (10 months ago)
Author:
bitsweat
Message:

Refactor Action View template handlers. Closes #10437.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r8335 r8341  
    11*SVN* 
     2 
     3* Refactor Action View template handlers.  #10437 [Josh Peek] 
    24 
    35* Fix DoubleRenderError message and leave out mention of returning false from filters.  Closes #10380 [fcheung] 
  • trunk/actionpack/lib/action_view.rb

    r7425 r8341  
    2222#++ 
    2323 
     24require 'action_view/template_handler' 
     25require 'action_view/template_handlers/builder' 
     26require 'action_view/template_handlers/erb' 
     27require 'action_view/template_handlers/rjs' 
     28 
    2429require 'action_view/base' 
    2530require 'action_view/partials' 
     31require 'action_view/template_error' 
    2632 
    2733ActionView::Base.class_eval do 
  • trunk/actionpack/lib/action_view/base.rb

    r8299 r8341  
    1 require 'erb' 
    2 require 'builder' 
    3  
    4 class ERB 
    5   module Util 
    6     HTML_ESCAPE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' } 
    7  
    8     def html_escape(s) 
    9       s.to_s.gsub(/[&\"><]/) { |special| HTML_ESCAPE[special] } 
    10     end 
    11   end 
    12 end 
    13  
    141module ActionView #:nodoc: 
    152  class ActionViewError < StandardError #:nodoc: 
     
    229216    @@computed_public_paths = {} 
    230217 
    231     @@templates_requiring_setup = Set.new(%w(builder rxml rjs)) 
    232  
    233     # Order of template handers checked by #file_exists? depending on the current #template_format 
    234     DEFAULT_TEMPLATE_HANDLER_PREFERENCE = [:erb, :rhtml, :builder, :rxml, :javascript, :delegate] 
    235     TEMPLATE_HANDLER_PREFERENCES = { 
    236       :js       => [:javascript, :erb, :rhtml, :builder, :rxml, :delegate], 
    237       :xml      => [:builder, :rxml, :erb, :rhtml, :javascript, :delegate], 
    238       :delegate => [:delegate] 
    239     } 
     218    @@template_handlers = {} 
     219    @@default_template_handlers = nil 
    240220 
    241221    class ObjectWrapper < Struct.new(:value) #:nodoc: 
     
    261241    # return the rendered template as a string. 
    262242    def self.register_template_handler(extension, klass) 
    263       TEMPLATE_HANDLER_PREFERENCES[extension.to_sym] = TEMPLATE_HANDLER_PREFERENCES[:delegate] 
    264       @@template_handlers[extension] = klass 
    265     end 
     243      @@template_handlers[extension.to_sym] = klass 
     244    end 
     245 
     246    def self.register_default_template_handler(extension, klass) 
     247      register_template_handler(extension, klass) 
     248      @@default_template_handlers = klass 
     249    end 
     250 
     251    def self.handler_for_extension(extension) 
     252      @@template_handlers[extension.to_sym] || @@default_template_handlers 
     253    end 
     254 
     255    register_default_template_handler :erb, TemplateHandlers::ERB 
     256    register_template_handler :rjs, TemplateHandlers::RJS 
     257    register_template_handler :builder, TemplateHandlers::Builder 
     258 
     259    # TODO: Depreciate old template extensions 
     260    register_template_handler :rhtml, TemplateHandlers::ERB 
     261    register_template_handler :rxml, TemplateHandlers::Builder 
    266262 
    267263    def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc: 
     
    298294          template_extension = pick_template_extension(template_path).to_s 
    299295          unless template_extension 
    300             raise ActionViewError, "No #{template_handler_preferences.to_sentence} template found for #{template_path} in #{view_paths.inspect}" 
     296            raise ActionViewError, "No template found for #{template_path} in #{view_paths.inspect}" 
    301297          end 
    302298          template_file_name = full_template_path(template_path, template_extension) 
     
    360356    # The hash in <tt>local_assigns</tt> is made available as local variables. 
    361357    def render_template(template_extension, template, file_path = nil, local_assigns = {}) #:nodoc: 
    362       if handler = @@template_handlers[template_extension] 
     358      handler = self.class.handler_for_extension(template_extension) 
     359 
     360      if template_handler_is_compilable?(handler) 
     361        compile_and_render_template(template_extension, template, file_path, local_assigns) 
     362      else 
    363363        template ||= read_template_file(file_path, template_extension) # Make sure that a lazyily-read template is loaded. 
    364364        delegate_render(handler, template, local_assigns) 
    365       else 
    366         compile_and_render_template(template_extension, template, file_path, local_assigns) 
    367365      end 
    368366    end 
     
    421419        find_template_extension_for(template_path) 
    422420      end 
    423     end 
    424  
    425     def delegate_template_exists?(template_path)#:nodoc: 
    426       delegate = @@template_handlers.find { |k,| template_exists?(template_path, k) } 
    427       delegate && delegate.first.to_sym 
    428     end 
    429  
    430     def erb_template_exists?(template_path)#:nodoc: 
    431       template_exists?(template_path, :erb) 
    432     end 
    433  
    434     def builder_template_exists?(template_path)#:nodoc: 
    435       template_exists?(template_path, :builder) 
    436     end 
    437  
    438     def rhtml_template_exists?(template_path)#:nodoc: 
    439       template_exists?(template_path, :rhtml) 
    440     end 
    441  
    442     def rxml_template_exists?(template_path)#:nodoc: 
    443       template_exists?(template_path, :rxml) 
    444     end 
    445  
    446     def javascript_template_exists?(template_path)#:nodoc: 
    447       template_exists?(template_path, :rjs) 
    448421    end 
    449422 
     
    469442    end 
    470443 
    471     def template_handler_preferences 
    472       TEMPLATE_HANDLER_PREFERENCES[template_format] || DEFAULT_TEMPLATE_HANDLER_PREFERENCE 
    473     end 
    474  
    475444    # Adds a view_path to the front of the view_paths array. 
    476445    # This change affects the current request only. 
     
    531500      def find_template_extension_from_handler(template_path, formatted = nil) 
    532501        checked_template_path = formatted ? "#{template_path}.#{template_format}" : template_path 
    533         template_handler_preferences.each do |template_type| 
    534           extension = 
    535             case template_type 
    536               when :javascript 
    537                 template_exists?(checked_template_path, :rjs) && :rjs 
    538               when :delegate 
    539                 delegate_template_exists?(checked_template_path) 
    540               else 
    541                 template_exists?(checked_template_path, template_type) && template_type 
    542             end 
    543           if extension 
     502 
     503        @@template_handlers.each do |extension,| 
     504          if template_exists?(checked_template_path, extension) 
    544505            return formatted ? "#{template_format}.#{extension}" : extension.to_s 
    545506          end 
     
    568529      def delegate_render(handler, template, local_assigns) 
    569530        handler.new(self).render(template, local_assigns) 
     531      end 
     532 
     533      def delegate_compile(handler, template) 
     534        handler.new(self).compile(template) 
     535      end 
     536 
     537      def template_handler_is_compilable?(handler) 
     538        handler.new(self).respond_to?(:compile) 
    570539      end 
    571540 
     
    610579      # Method to create the source code for a given template. 
    611580      def create_template_source(extension, template, render_symbol, locals) 
    612         if template_requires_setup?(extension) 
    613           body = case extension.to_sym 
    614             when :rxml, :builder 
    615               content_type_handler = (controller.respond_to?(:response) ? "controller.response" : "controller") 
    616               "#{content_type_handler}.content_type ||= Mime::XML\n" + 
    617               "xml = Builder::XmlMarkup.new(:indent => 2)\n" + 
    618               template + 
    619               "\nxml.target!\n" 
    620             when :rjs 
    621               "controller.response.content_type ||= Mime::JS\n" + 
    622               "update_page do |page|\n#{template}\nend" 
    623           end 
    624         else 
    625           body = ERB.new(template, nil, @@erb_trim_mode).src 
    626         end 
     581        # TODO: Have handler passed to this method because was already looked up in render_template 
     582        handler = self.class.handler_for_extension(extension) 
     583        body = delegate_compile(handler, template) 
    627584 
    628585        @@template_args[render_symbol] ||= {} 
     
    636593 
    637594        "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend" 
    638       end 
    639  
    640       def template_requires_setup?(extension) #:nodoc: 
    641         @@templates_requiring_setup.include? extension.to_s 
    642595      end 
    643596 
     
    667620        render_source = create_template_source(extension, template, render_symbol, local_assigns.keys) 
    668621 
     622        # TODO: Push line_offset logic into appropriate TemplateHandler class 
    669623        line_offset = @@template_args[render_symbol].size 
    670624        if extension 
     
    696650  end 
    697651end 
    698  
    699 require 'action_view/template_error'