class Utils::Find::ConfigurableFinder

def add_file(path, file)

def add_file(path, file)
  @files[path] = file
  self
end

def close_files

def close_files
  @files.each_value do |f|
    f.closed? or f.close
  end
  nil
end

def find(*paths, &block)

def find(*paths, &block)
  block_given? or return enum_for(__method__, *paths)
  paths.map! do |d|
    File.exist?(d) or raise Errno::ENOENT
    d.dup
  end
  while file = paths.shift
    catch(:prune) do
      file = prepare_file(file)
      visit_file?(file) and yield file
      begin
        s = stat(file) or next
      rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
        next
      end
      if s.directory? then
        begin
          tried = false
          fs = Dir.entries(file)
        rescue Errno::EMFILE
          tried and raise
          close_files
          tried = true
          retry
        rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
          next
        end
        fs.sort!
        fs.reverse_each do |f|
          next if f == "." or f == ".."
          f = File.join(file, f)
          paths.unshift f.untaint
        end
      end
    end
  end
end

def get_file(path)

def get_file(path)
  @files[path]
end

def include_suffix?(suffix)

def include_suffix?(suffix)
  @suffix.nil? || @suffix.include?(suffix)
end

def initialize(opts = {})

def initialize(opts = {})
  @files = {}
  opts[:suffix].full? { |s| @suffix = [*s] }
  @follow_symlinks = opts.fetch(:follow_symlinks, false)
end

def prepare_file(file)

def prepare_file(file)
  path = file.dup.taint
  path.extend PathExtension
  path.finder = self
  path
end

def stat(file)

def stat(file)
  @follow_symlinks ? file.stat : file.lstat
end

def visit_file?(file)

def visit_file?(file)
  suffix = File.extname(file).full?(:[], 1..-1) || ''
  include_suffix?(suffix)
end