From 0a132c2fe13fb2b8d5dade9cf6abd70601376287 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Wed, 22 Apr 2009 17:16:28 -0700 Subject: Refactor ActionView::Path * Decouple from ActionController and ActionMailer * Bring back localization support. * Prepare to decouple templates from the filesystem. * Prepare to decouple localization from ActionView * Fix ActionMailer to take advantage of ActionView::Path --- actionpack/lib/action_view/template/path.rb | 151 ++++++++++++++++++---------- 1 file changed, 97 insertions(+), 54 deletions(-) (limited to 'actionpack/lib/action_view/template/path.rb') diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb index 9709549b70..660a7e91a2 100644 --- a/actionpack/lib/action_view/template/path.rb +++ b/actionpack/lib/action_view/template/path.rb @@ -1,13 +1,81 @@ module ActionView class Template + # Abstract super class class Path - attr_reader :path, :paths - delegate :hash, :inspect, :to => :path - def initialize(options) - @cache = options[:cache] + @cache = options[:cache] + @cached = {} end - + + # Normalizes the arguments and passes it on to find_template + def find_by_parts(*args) + find_all_by_parts(*args).first + end + + def find_all_by_parts(name, details = {}, prefix = nil, partial = nil) + details[:locales] = [I18n.locale] + name = name.to_s.gsub(handler_matcher, '').split("/") + find_templates(name.pop, details, [prefix, *name].compact.join("/"), partial) + end + + private + + # This is what child classes implement. No defaults are needed + # because Path guarentees that the arguments are present and + # normalized. + def find_templates(name, details, prefix, partial) + raise NotImplementedError + end + + # TODO: Refactor this to abstract out the file system + def initialize_template(file) + t = Template.new(file.split("#{self}/").last, self) + t.load! + t + end + + def valid_handlers + @valid_handlers ||= TemplateHandlers.extensions + end + + def handler_matcher + @handler_matcher ||= begin + e = valid_handlers.join('|') + /\.(?:#{e})$/ + end + end + + def handler_glob + e = TemplateHandlers.extensions.join(',') + ".{#{e}}" + end + + def formats_glob + @formats_glob ||= begin + formats = Mime::SET.map { |m| m.symbol } + '{' + formats.map { |l| ".#{l}," }.join + '}' + end + end + + def cached(key) + return yield unless @cache + return @cached[key] if @cached.key?(key) + @cached[key] = yield + end + end + + class FileSystemPath < Path + + def initialize(path, options = {}) + raise ArgumentError, "path already is a Path class" if path.is_a?(Path) + super(options) + @path = path + end + + # TODO: This is the currently needed API. Make this suck less + # ==== + attr_reader :path + def to_s if defined?(RAILS_ROOT) path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') @@ -27,61 +95,36 @@ module ActionView def eql?(path) to_str == path.to_str end - - def find_by_parts(name, extensions = nil, prefix = nil, partial = nil) - path = prefix ? "#{prefix}/" : "" + # ==== - name = name.to_s.split("/") - name[-1] = "_#{name[-1]}" if partial - - path << name.join("/") - - template = nil - - Array(extensions).each do |extension| - extensioned_path = extension ? "#{path}.#{extension}" : path - break if (template = find_template(extensioned_path)) + def find_templates(name, details, prefix, partial) + if glob = parts_to_glob(name, details, prefix, partial) + cached(glob) do + Dir[glob].map do |path| + initialize_template(path) unless File.directory?(path) + end.compact + end end - template || find_template(path) end - - private - def create_template(file) - Template.new(file.split("#{self}/").last, self) - end - end - - class FileSystemPath < Path - def initialize(path, options = {}) - raise ArgumentError, "path already is a Path class" if path.is_a?(Path) - - super(options) - @path, @paths = path, {} - - # **/*/** is a hax for symlinked directories - load_templates("#{@path}/{**/*,**}/**") if @cache - end - - private - - def load_template(template) - template.load! - template.accessible_paths.each do |path| - @paths[path] = template - end - end - - def find_template(path) - load_templates("#{@path}/#{path}{,.*}") unless @cache - @paths[path] - end - def load_templates(glob) - Dir[glob].each do |file| - load_template(create_template(file)) unless File.directory?(file) + private + + def parts_to_glob(name, details, prefix, partial) + path = "" + path << "#{prefix}/" unless prefix.empty? + path << (partial ? "_#{name}" : name) + + extensions = "" + [:locales, :formats].each do |k| + extensions << if exts = details[k] + '{' + exts.map {|e| ".#{e},"}.join + '}' + else + k == :formats ? formats_glob : '' + end end + + "#{@path}/#{path}#{extensions}#{handler_glob}" end - end end end \ No newline at end of file -- cgit v1.2.3