# class Dir

### Public Class Methods

ascend(dir, inclusive=true, &blk) click to toggle source

Ascend a directory path.

    a = []

    Dir.ascend("/var/log") do |path|
      a << path
    end

    a  #=> ['/var/log', '/var', '/']

CREDIT: Daniel Berger, Jeffrey Schwab

TODO: make it work with windows too use FileTest#root?

    # File lib/facets/dir/ascend.rb, line 20
    def self.ascend(dir, inclusive=true, &blk)
      dir = dir.dup
      blk.call(dir) if inclusive
      ri = dir.rindex('/')
      while ri
        dir = dir.slice(0...ri)
        if dir == ""
          blk.call('/') ; break
        end
        blk.call( dir )
        ri = dir.rindex('/')
      end
    end

descend(path) { || ... } click to toggle source

Descend a directory path.

    d = []

    Dir.descend("/var/log") do |path|
      d << path
    end

    d  #=> ['/', '/var', '/var/log']

CREDIT: Daniel Berger, Jeffrey Schwab

    # File lib/facets/dir/ascend.rb, line 46
    def self.descend(path) #:yield:
      paths = path.split('/')
      paths.size.times do |n|
        pth = File.join(*paths[0..n])
        pth = "/" if pth == ""
        yield(pth)
      end
    end

ls_r(path='.', &block) click to toggle source

Same as Dir#recurse.

    # File lib/facets/dir/recurse.rb, line 30
    def self.ls_r(path='.', &block)
      recurse(path, &block)
    end

multiglob(*patterns) click to toggle source

Like `glob` but can take multiple patterns.

    Dir.multiglob('tmp  .rb', 'tmp/*.py')

Rather then constants for options multiglob accepts a trailing options hash of symbol keys…

    :noescape    File::FNM_NOESCAPE
    :casefold    File::FNM_CASEFOLD
    :pathname    File::FNM_PATHNAME
    :dotmatch    File::FNM_DOTMATCH
    :strict      File::FNM_PATHNAME && File::FNM_DOTMATCH

It also has an option for recurse…

    :recurse     Recurively include contents of directories.

For example

    Dir.multiglob('tmp/*', :recurse => true)

would have the same result as

    Dir.multiglob('tmp/   *')

    # File lib/facets/dir/multiglob.rb, line 28
    def self.multiglob(*patterns)
      options  = (Hash === patterns.last ? patterns.pop : {})

      if options.delete(:recurse)
        ##patterns += patterns.collect{ |f| File.join(f, '**', '**') }
        multiglob_r(*patterns)
      end

      bitflags = 0
      bitflags |= File::FNM_NOESCAPE if options[:noescape]
      bitflags |= File::FNM_CASEFOLD if options[:casefold]
      bitflags |= File::FNM_PATHNAME if options[:pathname] or options[:strict]
      bitflags |= File::FNM_DOTMATCH if options[:dotmatch] or options[:strict]

      patterns = [patterns].flatten.compact

      if options[:recurse]
        patterns += patterns.collect{ |f| File.join(f, '**', '**') }
      end

      files = []
      files += patterns.collect{ |pattern| Dir.glob(pattern, bitflags) }.flatten.uniq

      return files
    end

multiglob_r(*patterns) click to toggle source

The same as `multiglob`, but recusively includes directories.

    Dir.multiglob_r('tmp')

is equivalent to

    Dir.multiglob('tmp', :recurse=>true)

The effect of which is

    Dir.multiglob('tmp', 'tmp   /**')

    # File lib/facets/dir/multiglob.rb, line 66
    def self.multiglob_r(*patterns)
      options = Hash === patterns.last ? patterns.pop : {}
      matches = multiglob(*patterns)
      directories = matches.select{ |m| File.directory?(m) }
      matches += directories.map{ |d| multiglob_r(File.join(d, '**'), options) }.flatten
      matches.uniq
      ##options = (Hash === patterns.last ? patterns.pop : {})
      ##options[:recurse] = true
      ##patterns << options
      ##multiglob(*patterns)
    end

parent?(parent_path, child_path) click to toggle source

Is a path parental to another?

    Dir.parent?('parent', 'parent/child')  #=> true

TODO: Needs improvement.

TODO: Instance version?

    # File lib/facets/dir/parent.rb, line 11
    def self.parent?(parent_path, child_path)
      %r^#{Regexp.escape(parent_path)}| =~ child_path ? true : false
    end

recurse(path='.', &block) click to toggle source

Recursively scan a directory and pass each file to the given block.

    Dir.recurse('.') do |path|
      # ...
    end

CREDIT: George Moschovitis

TODO: If fully compatible, reimplement as alias of Find.find, or just copy and paste Find.find code here if it looks more robust.

    # File lib/facets/dir/recurse.rb, line 14
    def self.recurse(path='.', &block)
      list = []
      stoplist = ['.', '..']
      Dir.foreach(path) do |f|
        next if stoplist.include?(f)
        filename = (path == '.' ? f : path + '/' + f)
        list << filename
        block.call(filename) if block
        if FileTest.directory?(filename) and not FileTest.symlink?(filename)
          list.concat(Dir.recurse(filename, &block))
        end
      end
      list
    end

### Public Instance Methods

each_child(*ignore) { |file| ... } click to toggle source

Like each, except the “.” and “..” special files are ignored. You can use `ignore` to override '.' and '..' and ignore other entries via a exact match or regular expression.

CREDIT: Tyler Rick

    # File lib/facets/dir/each_child.rb, line 8
    def each_child(*ignore)
      ignore = ['.', '..'] if ignore.empty?
      each do |file|
        yield file unless ignore.any?{ |i| i === file }
      end
    end