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
|
# frozen_string_literal: true
module FakeFS
# Handles globbing for FakeFS.
module Globber
extend self
def expand(pattern)
pattern = pattern.to_s
return [pattern] if pattern[0] != '{' || pattern[-1] != '}'
part = +''
result = []
each_char_with_levels pattern, '{', '}' do |chr, level|
case level
when 0
case chr
when '{'
# noop
else
part << chr
end
when 1
case chr
when ','
result << part
part = +''
when '}'
# noop
else
part << chr
end
else
part << chr
end
end
result << part
result
end
def path_components(pattern)
pattern = pattern.to_s
part = +''
result = []
each_char_with_levels pattern, '{', '}' do |chr, level|
if level == 0 && chr == File::SEPARATOR
result << part
part = +''
else
part << chr
end
end
result << part
drop_root(result).reject(&:empty?)
end
def regexp(pattern, find_flags = 0, gave_char_class = false)
pattern = pattern.to_s
# Escape .+?*()$ characters unless already escaped.
regex_body =
pattern
.gsub(/(?<!\\)\./, '\.')
.gsub(/(?<!\\)\+/) { '\+' }
.gsub(/(?<!\\)\?/, '.')
.gsub(/(?<!\\)\*/, '.*')
.gsub(/(?<!\\)\(/, '\(')
.gsub(/(?<!\\)\)/, '\)')
.gsub(/(?<!\\)\$/, '\$')
# Unless we're expecting character class contructs in regexes, escape all brackets
# since if we're expecting them, the string should already be properly escaped.
unless gave_char_class
regex_body = regex_body.gsub(/(?<!\\)([\[\]])/, '\\\\\1')
end
# This matches nested braces and attempts to do something correct most of the time
# There are known issues (i.e. {,*,*/*}) that cannot be resolved with out a total
# refactoring
loop do
break unless regex_body.gsub!(/(?<re>\{(?:(?>[^{}]+)|\g<re>)*\})/) do
"(#{Regexp.last_match[1][1..-2].gsub(',', '|')})"
end
end
# if we are matching dot files/directories, add that to the regex
if find_flags == File::FNM_DOTMATCH
regex_body = "(\.)?" + regex_body
end
regex_body = regex_body.gsub(/\A\./, '(?!\.).')
/\A#{regex_body}\Z/
end
private
def each_char_with_levels(string, level_start, level_end)
level = 0
string.each_char do |chr|
yield chr, level
case chr
when level_start
level += 1
when level_end
level -= 1
end
end
end
def drop_root(path_parts)
# we need to remove parts from root dir at least for windows and jruby
return path_parts if path_parts.nil? || path_parts.empty?
root = RealFile.expand_path('/').split(File::SEPARATOR).first
path_parts.shift if path_parts.first == root
path_parts
end
end
end
|