aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/lib/action_view/template/template.rb
blob: 0eedc596d2bed8c30b98c28ba883e1ee4f3b406d (plain) (tree)
1
2
3
4
5
6
7
8
9


                                                           
             

                                   
                 
                
                           
                                                          
    




                                                        





                                                                                          
       
    







                                                

       








                                           
 
         
 























                                                                                      
 






                                                                                         
       
     
  
# encoding: utf-8
# This is so that templates compiled in this file are UTF-8

require 'set'
require "action_view/template/path"

module ActionView
  class Template
    extend TemplateHandlers
    attr_reader :source, :identifier, :handler, :mime_type
    
    def initialize(source, identifier, handler, details)
      @source     = source
      @identifier = identifier
      @handler    = handler
      @details    = details

      format = details[:format] || begin
        # TODO: Clean this up
        handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
      end
      @mime_type = Mime::Type.lookup_by_extension(format.to_s)
    end
    
    def render(view, locals, &blk)
      method_name = compile(locals, view)
      view.send(method_name, locals, &blk)
    end
    
    # TODO: Figure out how to abstract this
    def variable_name
      identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
    end

    # TODO: Figure out how to abstract this
    def counter_name
      "#{variable_name}_counter".to_sym
    end
    
    # TODO: kill hax
    def partial?
      @details[:partial]
    end

  private

    def compile(locals, view)
      method_name = build_method_name(locals)
      
      return method_name if view.respond_to?(method_name)
      
      locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join

      source = <<-end_src
        def #{method_name}(local_assigns)
          old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)}
        ensure
          self.output_buffer = old_output_buffer
        end
      end_src

      begin
        ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0)
        method_name
      rescue Exception => e # errors from template code
        if logger = (view && view.logger)
          logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
          logger.debug "Function body: #{source}"
          logger.debug "Backtrace: #{e.backtrace.join("\n")}"
        end

        raise ActionView::TemplateError.new(self, {}, e)
      end
    end
  
    def build_method_name(locals)
      # TODO: is locals.keys.hash reliably the same?
      "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
    end
  end
end