aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/template.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2010-10-07 15:50:20 +0200
committerJosé Valim <jose.valim@gmail.com>2010-10-07 21:31:31 +0200
commitb2600bfc181664fcfe448d100ca054017b0576dd (patch)
treefab6f7d40c19288ef2447266eedefb0527ed7167 /actionpack/lib/action_view/template.rb
parentad13eb72959f685927b5212ed387d51142d51805 (diff)
downloadrails-b2600bfc181664fcfe448d100ca054017b0576dd.tar.gz
rails-b2600bfc181664fcfe448d100ca054017b0576dd.tar.bz2
rails-b2600bfc181664fcfe448d100ca054017b0576dd.zip
Remove locals dependency from template.
This means that templates does not need to store its source anymore, allowing us to reduce the ammount of memory taken by our Rails processes. Naively speaking, if your app/views contains 2MB of files, each of your processes (after being hit by a bunch of requests) will take 2MB less of memory after this commit. This is extremely important for the upcoming features. Since Rails will also render CSS and JS files, their source won't be stored as well allowing us to decrease the ammount of memory taken.
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