aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/template.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/template.rb')
-rw-r--r--actionpack/lib/action_view/template.rb66
1 files changed, 43 insertions, 23 deletions
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 164d177dcc..7e65654d0b 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -98,6 +98,8 @@ module ActionView
extend Template::Handlers
+ attr_accessor :locals
+
attr_reader :source, :identifier, :handler, :virtual_path, :formats,
:original_encoding
@@ -117,23 +119,17 @@ module ActionView
@handler = handler
@original_encoding = nil
@method_names = {}
-
- format = details[:format] || :html
- @formats = Array.wrap(format).map(&:to_sym)
- @virtual_path = details[:virtual_path].try(:sub, ".#{format}", "")
+ @locals = details[:locals] || []
+ @formats = Array.wrap(details[:format] || :html).map(&:to_sym)
+ @virtual_path = details[:virtual_path].try(:sub, ".#{@formats.first}", "")
+ @compiled = false
end
def render(view, locals, &block)
# Notice that we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
- if view.is_a?(ActionView::CompiledTemplates)
- mod = ActionView::CompiledTemplates
- else
- mod = view.singleton_class
- end
-
- method_name = compile(locals, view, mod)
+ compile!(view)
view.send(method_name, locals, &block)
end
rescue Exception => e
@@ -141,7 +137,7 @@ module ActionView
e.sub_template_of(self)
raise e
else
- raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e)
+ raise Template::Error.new(refresh(view) || self, view.respond_to?(:assigns) ? view.assigns : {}, e)
end
end
@@ -149,10 +145,12 @@ module ActionView
@mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
end
+ # TODO Remove me
def variable_name
@variable_name ||= @virtual_path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
+ # TODO Remove me
def counter_name
@counter_name ||= "#{variable_name}_counter".to_sym
end
@@ -166,7 +164,25 @@ module ActionView
end
end
- private
+ def compile!(view)
+ return if @compiled
+
+ if view.is_a?(ActionView::CompiledTemplates)
+ mod = ActionView::CompiledTemplates
+ else
+ mod = view.singleton_class
+ end
+
+ compile(view, mod)
+
+ # Just discard the source if we have a virtual path. This
+ # means we can get the template back.
+ @source = nil if @virtual_path
+ @compiled = true
+ end
+
+ protected
+
# Among other things, this method is responsible for properly setting
# the encoding of the source. Until this point, we assume that the
# source is BINARY data. If no additional information is supplied,
@@ -187,11 +203,9 @@ module ActionView
# encode the source into Encoding.default_internal. In general,
# this means that templates will be UTF-8 inside of Rails,
# regardless of the original source encoding.
- def compile(locals, view, mod)
- 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
+ def compile(view, mod)
+ method_name = self.method_name
+ locals_code = @locals.map { |key| "#{key} = local_assigns[:#{key}];" }.join
if source.encoding_aware?
# Look for # encoding: *. If we find one, we'll encode the
@@ -256,8 +270,6 @@ module ActionView
begin
mod.module_eval(source, identifier, 0)
ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
-
- method_name
rescue Exception => e # errors from template code
if logger = (view && view.logger)
logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
@@ -269,12 +281,20 @@ module ActionView
end
end
- def build_method_name(locals)
- @method_names[locals.keys.hash] ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
+ def refresh(view)
+ return unless @virtual_path
+ pieces = @virtual_path.split("/")
+ name = pieces.pop
+ partial = name.sub!(/^_/, "")
+ view.find_template(name, pieces.join, partial || false, @locals)
+ end
+
+ def method_name
+ @method_name ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".gsub('-', "_")
end
def identifier_method_name
- @identifier_method_name ||= inspect.gsub(/[^a-z_]/, '_')
+ inspect.gsub(/[^a-z_]/, '_')
end
end
end