diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 649bd4dd5b..92501133a6 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -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 = {} diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/inline_template.rb index 965df96e3b..3e25f6902d 100644 --- a/actionpack/lib/action_view/inline_template.rb +++ b/actionpack/lib/action_view/inline_template.rb @@ -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 diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index d73dc3e2dc..2e2fff44c6 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -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 diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index 56d740f478..069d7d57af 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -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 } diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb index 887c783537..ed7b0e71ea 100644 --- a/actionpack/lib/action_view/template_handlers/compilable.rb +++ b/actionpack/lib/action_view/template_handlers/compilable.rb @@ -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