aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/renderable.rb
diff options
context:
space:
mode:
authorSven Fuchs <svenfuchs@artweb-design.de>2008-07-16 03:41:11 +0200
committerSven Fuchs <svenfuchs@artweb-design.de>2008-07-16 03:41:11 +0200
commit931f366ffcacc0444fcca2fb2e2b44644db9642f (patch)
tree4c056de1273d23e2b8494cfe452caaeb98ade820 /actionpack/lib/action_view/renderable.rb
parent8691e255402b27eae594530001227fc05416a00c (diff)
parentfbef982e4b906b879240a35a1ecff447007da6b2 (diff)
downloadrails-931f366ffcacc0444fcca2fb2e2b44644db9642f.tar.gz
rails-931f366ffcacc0444fcca2fb2e2b44644db9642f.tar.bz2
rails-931f366ffcacc0444fcca2fb2e2b44644db9642f.zip
merge forward to current rails/master
Diffstat (limited to 'actionpack/lib/action_view/renderable.rb')
-rw-r--r--actionpack/lib/action_view/renderable.rb78
1 files changed, 78 insertions, 0 deletions
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb
new file mode 100644
index 0000000000..f66356c939
--- /dev/null
+++ b/actionpack/lib/action_view/renderable.rb
@@ -0,0 +1,78 @@
+module ActionView
+ module Renderable
+ # NOTE: The template that this mixin is beening include into is frozen
+ # So you can not set or modify any instance variables
+
+ def self.included(base)
+ @@mutex = Mutex.new
+ end
+
+ include ActiveSupport::Memoizable
+
+ def handler
+ Template.handler_class_for_extension(extension)
+ end
+ memoize :handler
+
+ def compiled_source
+ handler.new(nil).compile(self) if handler.compilable?
+ end
+ memoize :compiled_source
+
+ def render(view, local_assigns = {})
+ view._first_render ||= self
+ view._last_render = self
+ view.send(:evaluate_assigns)
+ compile(local_assigns) if handler.compilable?
+ handler.new(view).render(self, local_assigns)
+ end
+
+ def method(local_assigns)
+ if local_assigns && local_assigns.any?
+ local_assigns_keys = "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
+ end
+ ['_run', extension, method_segment, local_assigns_keys].compact.join('_').to_sym
+ end
+
+ private
+ # Compile and evaluate the template's code
+ def compile(local_assigns)
+ render_symbol = method(local_assigns)
+
+ @@mutex.synchronize do
+ return false unless recompile?(render_symbol)
+
+ locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
+
+ source = <<-end_src
+ def #{render_symbol}(local_assigns)
+ old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
+ ensure
+ self.output_buffer = old_output_buffer
+ end
+ end_src
+
+ begin
+ file_name = respond_to?(:filename) ? filename : 'compiled-template'
+ ActionView::Base::CompiledTemplates.module_eval(source, file_name, 0)
+ rescue Exception => e # errors from template code
+ if logger = ActionController::Base.logger
+ logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
+ logger.debug "Function body: #{source}"
+ logger.debug "Backtrace: #{e.backtrace.join("\n")}"
+ end
+
+ raise ActionView::TemplateError.new(self, {}, e)
+ end
+ end
+ end
+
+ # Method to check whether template compilation is necessary.
+ # The template will be compiled if the file has not been compiled yet, or
+ # if local_assigns has a new key, which isn't supported by the compiled code yet.
+ def recompile?(symbol)
+ meth = Base::CompiledTemplates.instance_method(template.method) rescue nil
+ !(meth && Base.cache_template_loading)
+ end
+ end
+end