aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/template/resolver.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2010-10-10 09:24:17 +0200
committerJosé Valim <jose.valim@gmail.com>2010-10-10 09:26:53 +0200
commit38d78f99d52801d8392a7229b40edae74cc3d142 (patch)
tree1526a3dd884ec1cadb287b8c8a54dbe160201d19 /actionpack/lib/action_view/template/resolver.rb
parentc7408a0e40545558872efb4129fe4bf097c9ce2f (diff)
downloadrails-38d78f99d52801d8392a7229b40edae74cc3d142.tar.gz
rails-38d78f99d52801d8392a7229b40edae74cc3d142.tar.bz2
rails-38d78f99d52801d8392a7229b40edae74cc3d142.zip
Resolvers now consider timestamps.
Before this patch, every request in development caused the template to be compiled, regardless if it was updated in the filesystem or not. This patch now checks the timestamp and only compiles it again if any change was done. While this probably won't show any difference for current setups, but it will be useful for asset template handlers (like SASS), as compiling their templates is slower than ERb, Haml, etc.
Diffstat (limited to 'actionpack/lib/action_view/template/resolver.rb')
-rw-r--r--actionpack/lib/action_view/template/resolver.rb67
1 files changed, 46 insertions, 21 deletions
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 9ec39b16f0..5c6877a923 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -16,7 +16,7 @@ module ActionView
# Normalizes the arguments and passes it on to find_template.
def find_all(name, prefix=nil, partial=false, details={}, locals=[], key=nil)
- cached(key, prefix, name, partial, locals) do
+ cached(key, [name, prefix, partial], details, locals) do
find_templates(name, prefix, partial, details)
end
end
@@ -35,37 +35,55 @@ module ActionView
end
# Helpers that builds a path. Useful for building virtual paths.
- def build_path(name, prefix, partial, details)
+ def build_path(name, prefix, partial)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
path
end
- # Get the handler and format from the given parameters.
- def retrieve_handler_and_format(handler, format, default_formats=nil)
- handler = Template.handler_class_for_extension(handler)
- format = format && Mime[format]
- format ||= handler.default_format if handler.respond_to?(:default_format)
- format ||= default_formats
- [handler, format]
- end
-
- def cached(key, prefix, name, partial, locals)
+ # Hnadles templates caching. If a key is given and caching is on
+ # always check the cache before hitting the resolver. Otherwise,
+ # it always hits the resolver but check if the resolver is fresher
+ # before returning it.
+ def cached(key, path_info, details, locals) #:nodoc:
+ name, prefix, partial = path_info
locals = sort_locals(locals)
- unless key && caching?
- yield.each { |t| t.locals = locals }
+
+ if key && caching?
+ @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals)
else
- @cached[key][prefix][name][partial][locals] ||= yield.each { |t| t.locals = locals }
+ fresh = decorate(yield, path_info, details, locals)
+ return fresh unless key
+
+ scope = @cached[key][name][prefix][partial]
+ cache = scope[locals]
+ mtime = cache && cache.map(&:updated_at).max
+
+ if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime }
+ scope[locals] = fresh
+ else
+ cache
+ end
+ end
+ end
+
+ # Ensures all the resolver information is set in the template.
+ def decorate(templates, path_info, details, locals) #:nodoc:
+ cached = nil
+ templates.each do |t|
+ t.locals = locals
+ t.formats = details[:formats] || [:html] if t.formats.empty?
+ t.virtual_path ||= (cached ||= build_path(*path_info))
end
end
- if :locale.respond_to?("<=>")
- def sort_locals(locals)
+ if :symbol.respond_to?("<=>")
+ def sort_locals(locals) #:nodoc:
locals.sort.freeze
end
else
- def sort_locals(locals)
+ def sort_locals(locals) #:nodoc:
locals = locals.map{ |l| l.to_s }
locals.sort!
locals.freeze
@@ -79,7 +97,7 @@ module ActionView
private
def find_templates(name, prefix, partial, details)
- path = build_path(name, prefix, partial, details)
+ path = build_path(name, prefix, partial)
query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats])
end
@@ -96,17 +114,24 @@ module ActionView
contents = File.open(p, "rb") {|io| io.read }
Template.new(contents, File.expand_path(p), handler,
- :virtual_path => path, :format => format)
+ :virtual_path => path, :format => format, :updated_at => mtime(p))
end
end
+ # Returns the file mtime from the filesystem.
+ def mtime(p)
+ File.stat(p).mtime
+ end
+
# Extract handler and formats from path. If a format cannot be a found neither
# from the path, or the handler, we should return the array of formats given
# to the resolver.
def extract_handler_and_format(path, default_formats)
pieces = File.basename(path).split(".")
pieces.shift
- retrieve_handler_and_format(pieces.pop, pieces.pop, default_formats)
+ handler = Template.handler_class_for_extension(pieces.pop)
+ format = pieces.last && Mime[pieces.last]
+ [handler, format]
end
end