Lookup compiled methods in CompiledTemplates instance methods set instead of using a "methods_names" hash

This commit is contained in:
Joshua Peek 2008-07-05 23:54:11 -05:00
parent ce5d958f8f
commit 9828aecd2a
5 changed files with 30 additions and 50 deletions

@ -189,10 +189,6 @@ module CompiledTemplates #:nodoc:
end
include CompiledTemplates
# Maps inline templates to their method names
cattr_accessor :method_names
@@method_names = {}
# Cache public asset paths
cattr_reader :computed_public_paths
@@computed_public_paths = {}

@ -9,13 +9,8 @@ def initialize(view, source, locals = {}, type = nil)
@extension = type
@locals = locals || {}
@method_key = "inline_#{@source.hash.abs}"
@method_segment = "inline_#{@source.hash.abs}"
@handler = Template.handler_class_for_extension(@extension).new(@view)
end
private
def method_name_path_segment
@method_key
end
end
end

@ -4,15 +4,15 @@ module Renderable
attr_accessor :locals
# TODO: These readers should be private
attr_reader :filename, :source, :handler, :method_key, :method
attr_reader :filename, :source, :handler
def render
prepare!
@handler.render(self)
end
def method_name
['_run', @extension, method_name_path_segment].compact.join('_').to_sym
def method
['_run', @extension, @method_segment].compact.join('_').to_sym
end
private
@ -23,7 +23,6 @@ def prepare!
if @handler.compilable?
@handler.compile_template(self) # compile the given template, if necessary
@method = @view.method_names[method_key] # Set the method name for this template and run it
end
@prepared = true

@ -19,7 +19,7 @@ def initialize(view, path, use_full_path = nil, locals = {})
set_extension_and_file_name
@method_key = @filename
@method_segment = compiled_method_name_file_path_segment
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
end
@ -72,7 +72,7 @@ def raise_missing_template_exception
raise MissingTemplate, "Missing #{template_type} #{full_template_path} in view path #{display_paths}"
end
def method_name_path_segment
def compiled_method_name_file_path_segment
s = File.expand_path(@filename)
s.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}/, '') if defined?(RAILS_ROOT)
s.gsub!(/([^a-zA-Z0-9_])/) { $1.ord }

@ -4,7 +4,7 @@ module Compilable
def self.included(base)
base.extend ClassMethod
# Map method names to the names passed in local assigns so far
# Map method names to the compiled local assigns
base.cattr_accessor :template_args
base.template_args = {}
end
@ -17,23 +17,34 @@ def compilable?
end
def render(template)
@view.send :execute, template
@view.send(:execute, template)
end
# Compile and evaluate the template's code
def compile_template(template)
return false unless compile_template?(template)
render_symbol = assign_method_name(template)
render_source = create_template_source(template, render_symbol)
locals_code = ""
locals_keys = cache_template_args(template.method, template.locals)
locals_keys.each do |key|
locals_code << "#{key} = local_assigns[:#{key}];"
end
source = <<-end_src
def #{template.method}(local_assigns)
old_output_buffer = output_buffer;#{locals_code};#{compile(template)}
ensure
self.output_buffer = old_output_buffer
end
end_src
begin
file_name = template.filename || 'compiled-template'
ActionView::Base::CompiledTemplates.module_eval(render_source, file_name, 0)
rescue Exception => e # errors from template code
ActionView::Base::CompiledTemplates.module_eval(source, file_name, 0)
rescue Exception => e # errors from template code
if Base.logger
Base.logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
Base.logger.debug "Function body: #{render_source}"
Base.logger.debug "ERROR: compiling #{template.method} RAISED #{e}"
Base.logger.debug "Function body: #{source}"
Base.logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
@ -47,7 +58,7 @@ def compile_template(template)
# if local_assigns has a new key, which isn't supported by the compiled code yet.
def compile_template?(template)
# Unless the template has been complied yet, compile
return true unless render_symbol = @view.method_names[template.method_key]
return true unless Base::CompiledTemplates.instance_methods.include?(template.method.to_s)
# If template caching is disabled, compile
return true unless Base.cache_template_loading
@ -56,38 +67,17 @@ def compile_template?(template)
return true if template.is_a?(InlineTemplate)
# Unless local assigns support, recompile
return true unless supports_local_assigns?(render_symbol, template.locals)
return true unless supports_local_assigns?(template.method, template.locals)
# Otherwise, use compiled method
return false
end
def assign_method_name(template)
@view.method_names[template.method_key] ||= template.method_name
end
# Method to create the source code for a given template.
def create_template_source(template, render_symbol)
body = compile(template)
def cache_template_args(render_symbol, local_assigns)
self.template_args[render_symbol] ||= {}
locals_keys = self.template_args[render_symbol].keys | template.locals.keys
locals_keys = self.template_args[render_symbol].keys | local_assigns.keys
self.template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
locals_code = ""
locals_keys.each do |key|
locals_code << "#{key} = local_assigns[:#{key}];"
end
source = <<-end_src
def #{render_symbol}(local_assigns)
old_output_buffer = output_buffer;#{locals_code};#{body}
ensure
self.output_buffer = old_output_buffer
end
end_src
return source
locals_keys
end
# Return true if the given template was compiled for a superset of the keys in local_assigns