Class: Dir

Inherits:
Object show all
Defined in:
lib/core/facets/dir/lookup.rb,
lib/core/facets/dir/ascend.rb,
lib/core/facets/dir/parent.rb,
lib/core/facets/dir/recurse.rb,
lib/core/facets/dir/multiglob.rb,
lib/core/facets/dir/each_child.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.ascend(dir, inclusive = true, &blk) ⇒ Object

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?


20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/core/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) ⇒ Object

Descend a directory path.

d = []

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

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

CREDIT: Daniel Berger, Jeffrey Schwab



46
47
48
49
50
51
52
53
# File 'lib/core/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

.lookup(rel_path, parent_path = '.') ⇒ Object

Lookup directory tree for a path.

TODO: Make a non class method version of this?

Returns full path or `nil` if not found. [String,nil]



9
10
11
12
13
14
15
16
17
18
# File 'lib/core/facets/dir/lookup.rb', line 9

def self.lookup(rel_path, parent_path='.')
  while true
    path = File.expand_path(rel_path, parent_path)

    return path if File.exists?(path)
    return nil if path == '/'

    parent_path = File.expand_path('..', parent_path)
  end
end

.ls_r(path = '.', &block) ⇒ Object

Same as Dir#recurse.



30
31
32
# File 'lib/core/facets/dir/recurse.rb', line 30

def self.ls_r(path='.', &block)
  recurse(path, &block)
end

.multiglob(*patterns) ⇒ Object

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/**/*')


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
# File 'lib/core/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) ⇒ Object

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/**/**')


66
67
68
69
70
71
72
73
74
75
76
# File 'lib/core/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) ⇒ Boolean

Is a path parental to another?

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

TODO: Needs improvement.

TODO: Instance version?

Returns:

  • (Boolean)


11
12
13
# File 'lib/core/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) ⇒ Object

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.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/core/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

Instance Method Details

#each_child(*ignore) ⇒ Object

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



8
9
10
11
12
13
# File 'lib/core/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