Class: Dir

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

Class 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

.find(*paths, ignore_error: true, &block) ⇒ Object

Recursively traverse a directory, yielding each file and directory path. Supports Find.prune to skip subtrees.

Dir.find('.') do |path|
  puts path
end

Returns an enumerator if no block is given.

This is a convenience wrapper around Ruby’s Find.find.



16
17
18
# File 'lib/core/facets/dir/find.rb', line 16

def self.find(*paths, ignore_error: true, &block)
  Find.find(*paths, ignore_error: ignore_error, &block)
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

Deprecated.

Use Dir.find or Find.find instead.



12
13
14
15
# File 'lib/core/facets/dir/recurse.rb', line 12

def self.ls_r(path='.', &block)
  warn "Dir.ls_r is deprecated. Use Dir.find or Find.find instead.", uplevel: 1
  Dir.find(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

Deprecated.

Use Dir.find or Find.find instead.



6
7
8
9
# File 'lib/core/facets/dir/recurse.rb', line 6

def self.recurse(path='.', &block)
  warn "Dir.recurse is deprecated. Use Dir.find or Find.find instead.", uplevel: 1
  Dir.find(path, &block)
end