diff options
Diffstat (limited to 'actionview/lib/action_view/template/resolver.rb')
-rw-r--r-- | actionview/lib/action_view/template/resolver.rb | 62 |
1 files changed, 54 insertions, 8 deletions
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 7859c58b43..bf68e93c58 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -3,7 +3,7 @@ require "active_support/core_ext/class" require "active_support/core_ext/module/attribute_accessors" require "action_view/template" require "thread" -require "concurrent" +require "concurrent/map" module ActionView # = Action View Resolver @@ -55,6 +55,10 @@ module ActionView @query_cache = SmallCache.new end + def inspect + "#<#{self.class.name}:0x#{(object_id << 1).to_s(16)} keys=#{@data.size} queries=#{@query_cache.size}>" + end + # Cache the templates returned by the block def cache(key, name, prefix, partial, locals) if Resolver.caching? @@ -84,6 +88,23 @@ module ActionView @query_cache.clear end + # Get the cache size. Do not call this + # method. This method is not guaranteed to be here ever. + def size # :nodoc: + size = 0 + @data.each_value do |v1| + v1.each_value do |v2| + v2.each_value do |v3| + v3.each_value do |v4| + size += v4.size + end + end + end + end + + size + @query_cache.size + end + private def canonical_no_templates(templates) @@ -126,6 +147,12 @@ module ActionView end end + def find_all_anywhere(name, prefix, partial=false, details={}, key=nil, locals=[]) + cached(key, [name, prefix, partial], details, locals) do + find_templates(name, prefix, partial, details, true) + end + end + def find_all_with_query(query) # :nodoc: @cache.cache_query(query) { find_template_paths(File.join(@path, query)) } end @@ -187,15 +214,16 @@ module ActionView private - def find_templates(name, prefix, partial, details) + def find_templates(name, prefix, partial, details, outside_app_allowed = false) path = Path.build(name, prefix, partial) - query(path, details, details[:formats]) + query(path, details, details[:formats], outside_app_allowed) end - def query(path, details, formats) + def query(path, details, formats, outside_app_allowed) query = build_query(path, details) template_paths = find_template_paths(query) + template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed template_paths.map do |template| handler, format, variant = extract_handler_and_format_and_variant(template, formats) @@ -210,14 +238,24 @@ module ActionView end end + def reject_files_external_to_app(files) + files.reject { |filename| !inside_path?(@path, filename) } + end + def find_template_paths(query) - Dir[query].reject do |filename| + Dir[query].uniq.reject do |filename| File.directory?(filename) || # deals with case-insensitive file systems. !File.fnmatch(query, filename, File::FNM_EXTGLOB) end end + def inside_path?(path, filename) + filename = File.expand_path(filename) + path = File.join(path, '') + filename.start_with?(path) + end + # Helper for building query glob string based on resolver's pattern. def build_query(path, details) query = @pattern.dup @@ -228,8 +266,12 @@ module ActionView partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) query.gsub!(/:action/, partial) - details.each do |ext, variants| - query.gsub!(/:#{ext}/, "{#{variants.compact.uniq.join(',')}}") + details.each do |ext, candidates| + if ext == :variants && candidates == :any + query.gsub!(/:#{ext}/, "*") + else + query.gsub!(/:#{ext}/, "{#{candidates.compact.uniq.join(',')}}") + end end File.expand_path(query, @path) @@ -323,7 +365,11 @@ module ActionView query = escape_entry(File.join(@path, path)) exts = EXTENSIONS.map do |ext, prefix| - "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}" + if ext == :variants && details[ext] == :any + "{#{prefix}*,}" + else + "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}" + end end.join query + exts |