2 # NOTE: The template that this mixin is being included into is frozen
3 # so you cannot set or modify any instance variables
4 module Renderable
#:nodoc:
5 extend ActiveSupport
::Memoizable
7 def self.included(base
)
16 Template
.handler_class_for_extension(extension
)
23 memoize
:compiled_source
25 def render(view
, local_assigns
= {})
26 compile(local_assigns
)
28 stack
= view
.instance_variable_get(:@_render_stack)
31 # This is only used for TestResponse to set rendered_template
32 unless is_a
?(InlineTemplate
) || view
.instance_variable_get(:@_first_render)
33 view
.instance_variable_set(:@_first_render, self)
36 view
.send(:_evaluate_assigns_and_ivars)
37 view
.send(:_set_controller_content_type, mime_type
) if respond_to
?(:mime_type)
39 result
= view
.send(method_name(local_assigns
), local_assigns
) do |*names
|
40 ivar
= :@_proc_for_layout
41 if !view
.instance_variable_defined
?(:"@content_for_#{names.first}") && view
.instance_variable_defined
?(ivar
) && (proc
= view
.instance_variable_get(ivar
))
42 view
.capture(*names
, &proc
)
43 elsif view
.instance_variable_defined
?(ivar
= :"@content_for_#{names.first || :layout}")
44 view
.instance_variable_get(ivar
)
52 def method_name(local_assigns
)
53 if local_assigns
&& local_assigns
.any
?
54 local_assigns_keys
= "locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
56 ['_run', extension
, method_segment
, local_assigns_keys
].compact
.join('_').to_sym
60 # Compile and evaluate the template's code (if necessary)
61 def compile(local_assigns
)
62 render_symbol
= method_name(local_assigns
)
64 @
@mutex.synchronize
do
65 if recompile
?(render_symbol
)
66 compile
!(render_symbol
, local_assigns
)
71 def compile
!(render_symbol
, local_assigns
)
72 locals_code
= local_assigns
.keys
.map
{ |key
| "#{key} = local_assigns[:#{key}];" }.join
75 def #{render_symbol}(local_assigns)
76 old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
78 self.output_buffer = old_output_buffer
83 ActionView
::Base::CompiledTemplates.module_eval(source
, filename
, 0)
84 rescue Exception
=> e
# errors from template code
85 if logger
= defined?(ActionController
) && Base
.logger
86 logger
.debug
"ERROR: compiling #{render_symbol} RAISED #{e}"
87 logger
.debug
"Function body: #{source}"
88 logger
.debug
"Backtrace: #{e.backtrace.join("\n")}"
91 raise ActionView
::TemplateError.new(self, {}, e
)
95 # Method to check whether template compilation is necessary.
96 # The template will be compiled if the file has not been compiled yet, or
97 # if local_assigns has a new key, which isn't supported by the compiled code yet.
98 def recompile
?(symbol
)
99 !(ActionView
::PathSet::Path.eager_load_templates
? && Base
::CompiledTemplates.method_defined
?(symbol
))