class ActionView::PathResolver
:nodoc:
An abstract class that implements a Resolver with path semantics.
def _find_all(name, prefix, partial, details, key, locals)
def _find_all(name, prefix, partial, details, key, locals) path = Path.build(name, prefix, partial) query(path, details, details[:formats], locals, cache: !!key) end
def build_query(path, details)
def build_query(path, details) query = @pattern.dup prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1" query.gsub!(/:prefix(\/)?/, prefix) partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) query.gsub!(":action", partial) 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) end
def build_unbound_template(template, virtual_path)
def build_unbound_template(template, virtual_path) handler, format, variant = extract_handler_and_format_and_variant(template) source = source_for_template(template) UnboundTemplate.new( source, template, handler, virtual_path: virtual_path, format: format, variant: variant, ) end
def clear_cache
def clear_cache @unbound_templates.clear @path_parser = PathParser.new super end
def escape_entry(entry)
def escape_entry(entry) entry.gsub(/[*?{}\[\]]/, '\\\\\\&') end
def extract_handler_and_format_and_variant(path)
from the path, or the handler, we should return the array of formats given
Extract handler, formats and variant from path. If a format cannot be found neither
def extract_handler_and_format_and_variant(path) details = @path_parser.parse(path) handler = Template.handler_for_extension(details[:handler]) format = details[:format] || handler.try(:default_format) variant = details[:variant] # Template::Types[format] and handler.default_format can return nil [handler, format, variant] end
def find_template_paths(query)
def find_template_paths(query) 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 find_template_paths_from_details(path, details)
def find_template_paths_from_details(path, details) if path.name.include?(".") ActiveSupport::Deprecation.warn("Rendering actions with '.' in the name is deprecated: #{path}") end query = build_query(path, details) find_template_paths(query) end
def initialize
def initialize @pattern = DEFAULT_PATTERN @unbound_templates = Concurrent::Map.new @path_parser = PathParser.new super end
def inside_path?(path, filename)
def inside_path?(path, filename) filename = File.expand_path(filename) path = File.join(path, "") filename.start_with?(path) end
def query(path, details, formats, locals, cache:)
def query(path, details, formats, locals, cache:) template_paths = find_template_paths_from_details(path, details) template_paths = reject_files_external_to_app(template_paths) template_paths.map do |template| unbound_template = if cache @unbound_templates.compute_if_absent([template, path.virtual]) do build_unbound_template(template, path.virtual) end else build_unbound_template(template, path.virtual) end unbound_template.bind_locals(locals) end end
def reject_files_external_to_app(files)
def reject_files_external_to_app(files) files.reject { |filename| !inside_path?(@path, filename) } end
def source_for_template(template)
def source_for_template(template) Template::Sources::File.new(template) end