diff options
author | John Hawthorn <john@hawthorn.email> | 2018-09-12 10:50:38 -0700 |
---|---|---|
committer | John Hawthorn <john@hawthorn.email> | 2018-09-12 17:54:23 -0700 |
commit | cc9a0de6602f3c33e5ffa168c75f90451b47a208 (patch) | |
tree | 10e1ce8bafcab137ad1a93b864b09dddf665e4d3 /actionview | |
parent | 792fead512be390fdaf219b8bf3e17aa335bd7f4 (diff) | |
download | rails-cc9a0de6602f3c33e5ffa168c75f90451b47a208.tar.gz rails-cc9a0de6602f3c33e5ffa168c75f90451b47a208.tar.bz2 rails-cc9a0de6602f3c33e5ffa168c75f90451b47a208.zip |
Use wildcard glob for optimized template resolving
Diffstat (limited to 'actionview')
-rw-r--r-- | actionview/lib/action_view/template/resolver.rb | 64 |
1 files changed, 51 insertions, 13 deletions
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 5a86f10973..301b28d9ea 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -221,9 +221,7 @@ module ActionView end def query(path, details, formats, outside_app_allowed) - query = build_query(path, details) - - template_paths = find_template_paths(query) + template_paths = find_template_paths_from_details(path, details) template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed template_paths.map do |template| @@ -243,6 +241,11 @@ module ActionView files.reject { |filename| !inside_path?(@path, filename) } end + def find_template_paths_from_details(path, details) + query = build_query(path, details) + find_template_paths(query) + end + def find_template_paths(query) Dir[query].uniq.reject do |filename| File.directory?(filename) || @@ -362,19 +365,54 @@ module ActionView # An Optimized resolver for Rails' most common case. class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: - def build_query(path, details) - query = escape_entry(File.join(@path, path)) + private - exts = EXTENSIONS.map do |ext, prefix| - if ext == :variants && details[ext] == :any - "{#{prefix}*,}" - else - "{#{details[ext].compact.uniq.map { |e| "#{prefix}#{e}," }.join}}" + def find_template_paths_from_details(path, details) + # Instead of checking for every possible path, as our other globs would + # do, scan the directory for files with the right prefix. + query = "#{escape_entry(File.join(@path, path))}*" + + regex = build_regex(path, details) + + Dir[query].uniq.reject do |filename| + # This regex match does double duty of finding only files which match + # details (instead of just matching the prefix) and also filtering for + # case-insensitive file systems. + !filename.match(regex) || + File.directory?(filename) + end.sort_by do |filename| + # Because we scanned the directory, instead of checking for files + # one-by-one, they will be returned in an arbitrary order. + # We can use the matches found by the regex and sort by their index in + # details. + match = filename.match(regex) + EXTENSIONS.keys.reverse.map do |ext| + if match[ext].nil? + # No match should be last + details[ext].length + else + found = match[ext].to_sym + details[ext].index(found) + end + end end - end.join + end - query + exts - end + def build_regex(path, details) + query = escape_entry(File.join(@path, path)) + exts = EXTENSIONS.map do |ext, prefix| + match = + if ext == :variants && details[ext] == :any + ".*?" + else + details[ext].compact.uniq.map { |e| Regexp.escape(e) }.join("|") + end + prefix = Regexp.escape(prefix) + "(#{prefix}(?<#{ext}>#{match}))?" + end.join + + %r{\A#{query}#{exts}\z} + end end # The same as FileSystemResolver but does not allow templates to store |