1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
require "pathname"
require "active_support/core_ext/class"
require "action_view/template"
module ActionView
# = Action View Resolver
class Resolver
def initialize
@cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2|
h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
end
def clear_cache
@cached.clear
end
# 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
find_templates(name, prefix, partial, details)
end
end
private
def caching?
@caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes
end
# This is what child classes implement. No defaults are needed
# because Resolver guarantees that the arguments are present and
# normalized.
def find_templates(name, prefix, partial, details)
raise NotImplementedError
end
# Helpers that builds a path. Useful for building virtual paths.
def build_path(name, prefix, partial, details)
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)
locals = sort_locals(locals)
unless key && caching?
yield.each { |t| t.locals = locals }
else
@cached[key][prefix][name][partial][locals] ||= yield.each { |t| t.locals = locals }
end
end
if :locale.respond_to?("<=>")
def sort_locals(locals)
locals.sort.freeze
end
else
def sort_locals(locals)
locals = locals.map{ |l| l.to_s }
locals.sort!
locals.freeze
end
end
end
class PathResolver < Resolver
EXTENSION_ORDER = [:locale, :formats, :handlers]
private
def find_templates(name, prefix, partial, details)
path = build_path(name, prefix, partial, details)
query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats])
end
def query(path, exts, formats)
query = File.join(@path, path)
exts.each do |ext|
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << ',}'
end
Dir[query].reject { |p| File.directory?(p) }.map do |p|
handler, format = extract_handler_and_format(p, formats)
contents = File.open(p, "rb") {|io| io.read }
Template.new(contents, File.expand_path(p), handler,
:virtual_path => path, :format => format)
end
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)
end
end
class FileSystemResolver < PathResolver
def initialize(path)
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
super()
@path = File.expand_path(path)
end
def to_s
@path.to_s
end
alias :to_path :to_s
def eql?(resolver)
self.class.equal?(resolver.class) && to_path == resolver.to_path
end
alias :== :eql?
end
end
|