2009-04-23 18:58:38 -04:00
|
|
|
require "pathname"
|
2009-06-17 18:32:55 -04:00
|
|
|
require "action_view/template/template"
|
2009-04-23 18:58:38 -04:00
|
|
|
|
2009-04-14 20:22:51 -04:00
|
|
|
module ActionView
|
2009-06-17 18:32:55 -04:00
|
|
|
# Abstract superclass
|
|
|
|
class Resolver
|
|
|
|
def initialize(options)
|
|
|
|
@cache = options[:cache]
|
|
|
|
@cached = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Normalizes the arguments and passes it on to find_template
|
2009-08-07 14:00:12 -04:00
|
|
|
def find(*args)
|
2009-06-17 18:32:55 -04:00
|
|
|
find_all_by_parts(*args).first
|
|
|
|
end
|
2009-04-22 20:16:28 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
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)
|
2009-04-22 20:16:28 -04:00
|
|
|
end
|
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
# This is what child classes implement. No defaults are needed
|
|
|
|
# because Resolver guarantees that the arguments are present and
|
|
|
|
# normalized.
|
|
|
|
def find_templates(name, details, prefix, partial)
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
2009-04-22 20:16:28 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
def valid_handlers
|
|
|
|
@valid_handlers ||= TemplateHandlers.extensions
|
|
|
|
end
|
|
|
|
|
|
|
|
def handler_matcher
|
|
|
|
@handler_matcher ||= begin
|
|
|
|
e = valid_handlers.join('|')
|
|
|
|
/\.(?:#{e})$/
|
2009-04-22 20:16:28 -04:00
|
|
|
end
|
2009-06-17 18:32:55 -04:00
|
|
|
end
|
2009-04-23 18:58:38 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
def handler_glob
|
2009-08-09 06:14:24 -04:00
|
|
|
@handler_glob ||= begin
|
|
|
|
e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join
|
|
|
|
"{#{e}}"
|
|
|
|
end
|
2009-06-17 18:32:55 -04:00
|
|
|
end
|
2009-04-22 20:16:28 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
def formats_glob
|
|
|
|
@formats_glob ||= begin
|
|
|
|
'{' + Mime::SET.symbols.map { |l| ".#{l}," }.join + '}'
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|
2009-06-17 18:32:55 -04:00
|
|
|
end
|
2009-04-14 20:22:51 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
def cached(key)
|
|
|
|
return yield unless @cache
|
|
|
|
return @cached[key] if @cached.key?(key)
|
|
|
|
@cached[key] = yield
|
|
|
|
end
|
|
|
|
end
|
2009-04-14 20:22:51 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
class FileSystemResolver < Resolver
|
2009-04-14 20:22:51 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
def initialize(path, options = {})
|
|
|
|
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
|
|
|
|
super(options)
|
|
|
|
@path = Pathname.new(path).expand_path
|
|
|
|
end
|
|
|
|
|
|
|
|
# TODO: This is the currently needed API. Make this suck less
|
|
|
|
# ==== <suck>
|
|
|
|
attr_reader :path
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
path.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_str
|
|
|
|
path.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def ==(path)
|
|
|
|
to_str == path.to_str
|
|
|
|
end
|
|
|
|
|
|
|
|
def eql?(path)
|
|
|
|
to_str == path.to_str
|
|
|
|
end
|
|
|
|
# ==== </suck>
|
|
|
|
|
|
|
|
def find_templates(name, details, prefix, partial, root = "#{@path}/")
|
|
|
|
if glob = details_to_glob(name, details, prefix, partial, root)
|
|
|
|
cached(glob) do
|
|
|
|
Dir[glob].map do |path|
|
|
|
|
next if File.directory?(path)
|
|
|
|
source = File.read(path)
|
|
|
|
identifier = Pathname.new(path).expand_path.to_s
|
|
|
|
|
|
|
|
Template.new(source, identifier, *path_to_details(path))
|
|
|
|
end.compact
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|
|
|
|
end
|
2009-06-17 18:32:55 -04:00
|
|
|
end
|
2009-04-22 20:16:28 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
# :api: plugin
|
|
|
|
def details_to_glob(name, details, prefix, partial, root)
|
|
|
|
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 : ''
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|
2009-04-23 18:58:38 -04:00
|
|
|
end
|
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
"#{root}#{path}#{extensions}#{handler_glob}"
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|
2009-04-23 18:58:38 -04:00
|
|
|
|
2009-06-17 18:32:55 -04:00
|
|
|
# TODO: fix me
|
|
|
|
# :api: plugin
|
|
|
|
def path_to_details(path)
|
|
|
|
# [:erb, :format => :html, :locale => :en, :partial => true/false]
|
|
|
|
if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$')
|
|
|
|
partial = m[1] == '_'
|
|
|
|
details = (m[2]||"").split('.').reject { |e| e.empty? }
|
|
|
|
handler = Template.handler_class_for_extension(m[3])
|
|
|
|
|
|
|
|
format = Mime[details.last] && details.pop.to_sym
|
|
|
|
locale = details.last && details.pop.to_sym
|
|
|
|
|
|
|
|
return handler, :format => format, :locale => locale, :partial => partial
|
2009-04-23 18:58:38 -04:00
|
|
|
end
|
|
|
|
end
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|
2009-06-17 18:32:55 -04:00
|
|
|
|
|
|
|
class FileSystemResolverWithFallback < FileSystemResolver
|
|
|
|
|
|
|
|
def find_templates(name, details, prefix, partial)
|
|
|
|
templates = super
|
|
|
|
return super(name, details, prefix, partial, '') if templates.empty?
|
|
|
|
templates
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
2009-04-14 20:22:51 -04:00
|
|
|
end
|