class IOStreams::Paths::Matcher

Implement fnmatch logic for any path iterator

Constants

MATCH_START_CHARS

Characters indicating that pattern matching is required

Attributes

flags[R]
path[R]
pattern[R]

Public Class Methods

new(path, pattern, case_sensitive: false, hidden: false) click to toggle source

If the supplied pattern contains sub-directories without wildcards, navigate down to that directory first before applying wildcard lookups from that point on.

Examples: If the current path is “/path/work”

"a/b/c/**/*"  => "/path/work/a/b/c"
"a/b/c?/**/*" => "/path/work/a/b"
"**/*"        => "/path/work"

Note: Absolute paths in the pattern are not supported.

# File lib/io_streams/paths/matcher.rb, line 19
def initialize(path, pattern, case_sensitive: false, hidden: false)
  extract_optimized_path(path, pattern)

  @flags = ::File::FNM_EXTGLOB | ::File::FNM_PATHNAME
  @flags |= ::File::FNM_CASEFOLD unless case_sensitive
  @flags |= ::File::FNM_DOTMATCH if hidden
end

Public Instance Methods

match?(file_name) click to toggle source

Returns whether the relative `file_name` matches

# File lib/io_streams/paths/matcher.rb, line 28
def match?(file_name)
  relative_file_name = file_name.sub(path.to_s, "").sub(%r{\A/}, "")
  ::File.fnmatch?(pattern, relative_file_name, flags)
end
recursive?() click to toggle source

Whether this pattern includes a recursive match. I.e. Includes `**` anywhere in the path

# File lib/io_streams/paths/matcher.rb, line 35
def recursive?
  @recursive ||= pattern.nil? ? false : pattern.include?("**")
end

Private Instance Methods

extract_optimized_path(path, pattern) click to toggle source
# File lib/io_streams/paths/matcher.rb, line 41
def extract_optimized_path(path, pattern)
  elements = pattern.split("/")
  index    = elements.find_index { |e| e.match(MATCH_START_CHARS) }
  if index.nil?
    # No index means it has no pattern.
    @path    = path.nil? ? IOStreams.path(pattern) : path.join(pattern)
    @pattern = nil
  elsif index.zero?
    # Cannot optimize path since the very first entry contains a wildcard
    @path    = path || IOStreams.path
    @pattern = pattern
  else
    new_path = elements[0..index - 1].join("/")
    @path    = path.nil? ? IOStreams.path(new_path) : path.join(new_path)
    @pattern = elements[index..-1].join("/")
  end
end