1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
module FakeFS
module FileSystem
extend self
def dir_levels
@dir_levels ||= []
end
def fs
@fs ||= FakeDir.new('.')
end
def clear
@dir_levels = nil
@fs = nil
end
def files
fs.values
end
def find(path)
parts = path_parts(normalize_path(path))
return fs if parts.empty? # '/'
entries = find_recurser(fs, parts).flatten
case entries.length
when 0 then nil
when 1 then entries.first
else entries
end
end
def add(path, object=FakeDir.new)
parts = path_parts(normalize_path(path))
d = parts[0...-1].inject(fs) do |dir, part|
dir[part] ||= FakeDir.new(part, dir)
end
object.name = parts.last
object.parent = d
d[parts.last] ||= object
end
# copies directories and files from the real filesystem
# into our fake one
def clone(path)
path = File.expand_path(path)
pattern = File.join(path, '**', '*')
files = RealFile.file?(path) ? [path] : [path] + RealDir.glob(pattern, RealFile::FNM_DOTMATCH)
files.each do |f|
if RealFile.file?(f)
FileUtils.mkdir_p(File.dirname(f))
File.open(f, File::WRITE_ONLY) do |g|
g.print RealFile.open(f){|h| h.read }
end
elsif RealFile.directory?(f)
FileUtils.mkdir_p(f)
elsif RealFile.symlink?(f)
FileUtils.ln_s()
end
end
end
def delete(path)
if node = FileSystem.find(path)
node.delete
end
end
def chdir(dir, &blk)
new_dir = find(dir)
dir_levels.push dir if blk
raise Errno::ENOENT, dir unless new_dir
dir_levels.push dir if !blk
blk.call if blk
ensure
dir_levels.pop if blk
end
def path_parts(path)
path.split(File::PATH_SEPARATOR).reject { |part| part.empty? }
end
def normalize_path(path)
if Pathname.new(path).absolute?
File.expand_path(path)
else
parts = dir_levels + [path]
File.expand_path(File.join(*parts))
end
end
def current_dir
find(normalize_path('.'))
end
private
def find_recurser(dir, parts)
return [] unless dir.respond_to? :[]
pattern , *parts = parts
matches = case pattern
when '**'
case parts
when ['*'], []
parts = [] # end recursion
directories_under(dir).map do |d|
d.values.select{|f| f.is_a? FakeFile }
end.flatten.uniq
else
directories_under(dir)
end
else
dir.reject {|k,v| /\A#{pattern.gsub('?','.').gsub('*', '.*')}\Z/ !~ k }.values
end
if parts.empty? # we're done recursing
matches
else
matches.map{|entry| find_recurser(entry, parts) }
end
end
def directories_under(dir)
children = dir.values.select{|f| f.is_a? FakeDir}
([dir] + children + children.map{|c| directories_under(c)}).flatten.uniq
end
end
end
|