diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2008-01-19 03:20:39 +0000 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2008-01-19 03:20:39 +0000 |
commit | 84b0f9c739ffb82f3b8e0571c400014c34d0e369 (patch) | |
tree | cae7ff7cf03695f0ad9483a933a097e5c898d5b2 /actionpack/lib/action_view/template_finder.rb | |
parent | 4a644575c83d78e751f49cb6ba47e1c98af693a8 (diff) | |
download | rails-84b0f9c739ffb82f3b8e0571c400014c34d0e369.tar.gz rails-84b0f9c739ffb82f3b8e0571c400014c34d0e369.tar.bz2 rails-84b0f9c739ffb82f3b8e0571c400014c34d0e369.zip |
Introduce TemplateFinder to handle view paths and lookups. Closes #10800.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8669 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_view/template_finder.rb')
-rw-r--r-- | actionpack/lib/action_view/template_finder.rb | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb new file mode 100644 index 0000000000..3d7acec33c --- /dev/null +++ b/actionpack/lib/action_view/template_finder.rb @@ -0,0 +1,161 @@ +module ActionView #:nodoc: + class TemplateFinder #:nodoc: + + class InvalidViewPath < StandardError #:nodoc: + end + + cattr_reader :processed_view_paths + @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} + + cattr_reader :file_extension_cache + @@file_extension_cache = Hash.new {|hash, key| + hash[key] = Hash.new {|hash, key| hash[key] = []} + } + + class << self #:nodoc: + + # This method is not thread safe. Mutex should be used whenever this is accessed from an instance method + def process_view_paths(*view_paths) + view_paths.flatten.compact.each do |dir| + next if @@processed_view_paths.has_key?(dir) + + @@processed_view_paths[dir] = [] + Dir.glob("#{dir}/**/*").each do |file| + unless File.directory?(file) + @@processed_view_paths[dir] << file.split(dir).last.sub(/^\//, '') + + # Build extension cache + extension = file.split(".").last + if template_handler_extensions.include?(extension) + key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') + @@file_extension_cache[dir][key] << extension + end + end + end + end + end + + def update_extension_cache_for(extension) + @@processed_view_paths.keys.each do |dir| + Dir.glob("#{dir}/**/*.#{extension}").each do |file| + key = file.split(dir).last.sub(/^\//, '').sub(/\.(\w+)$/, '') + @@file_extension_cache[dir][key] << extension + end + end + end + + def template_handler_extensions + ActionView::Base.template_handler_extensions + end + + def reload! + view_paths = @@processed_view_paths.keys + + @@processed_view_paths = Hash.new {|hash, key| hash[key] = []} + @@file_extension_cache = Hash.new {|hash, key| + hash[key] = Hash.new {|hash, key| hash[key] = []} + } + + process_view_paths(view_paths) + end + end + + attr_accessor :view_paths + + def initialize(*args) + @template = args.shift + + @view_paths = args.flatten + @view_paths = @view_paths.respond_to?(:find) ? @view_paths.dup : [*@view_paths].compact + check_view_paths(@view_paths) + end + + def prepend_view_path(path) + @view_paths.unshift(*path) + + self.class.process_view_paths(path) + end + + def append_view_path(path) + @view_paths.push(*path) + + self.class.process_view_paths(path) + end + + def view_paths=(path) + @view_paths = path + self.class.process_view_paths(path) + end + + def pick_template(template_path, extension) + file_name = "#{template_path}.#{extension}" + base_path = find_base_path_for(file_name) + base_path.blank? ? false : "#{base_path}/#{file_name}" + end + alias_method :template_exists?, :pick_template + + def file_exists?(template_path) + template_file_name, template_file_extension = path_and_extension(template_path) + if template_file_extension + template_exists?(template_file_name, template_file_extension) + else + template_exists?(template_file_name, pick_template_extension(template_path)) + end + end + + def find_base_path_for(template_file_name) + @view_paths.find { |path| processed_view_paths[path].include?(template_file_name) } + end + + # Returns the view path that the full path resides in. + def extract_base_path_from(full_path) + @view_paths.find { |p| full_path[0..p.size - 1] == p } + end + + # Gets the extension for an existing template with the given template_path. + # Returns the format with the extension if that template exists. + # + # pick_template_extension('users/show') + # # => 'html.erb' + # + # pick_template_extension('users/legacy') + # # => "rhtml" + # + def pick_template_extension(template_path) + find_template_extension_from_handler(template_path) || find_template_extension_from_first_render + end + + def find_template_extension_from_handler(template_path) + formatted_template_path = "#{template_path}.#{@template.template_format}" + + view_paths.each do |path| + if (extensions = @@file_extension_cache[path][formatted_template_path]).any? + return "#{@template.template_format}.#{extensions.first}" + elsif (extensions = @@file_extension_cache[path][template_path]).any? + return extensions.first.to_s + end + end + nil + end + + # Splits the path and extension from the given template_path and returns as an array. + def path_and_extension(template_path) + template_path_without_extension = template_path.sub(/\.(\w+)$/, '') + [ template_path_without_extension, $1 ] + end + + # Determine the template extension from the <tt>@first_render</tt> filename + def find_template_extension_from_first_render + File.basename(@template.first_render.to_s)[/^[^.]+\.(.+)$/, 1] + end + + private + + def check_view_paths(view_paths) + view_paths.each do |path| + raise(InvalidViewPath, "Unprocessed view path found in #{view_paths.inspect}") unless processed_view_paths.has_key?(path) + end + end + + end +end |