File: file_system.rb

package info (click to toggle)
libfakefs-ruby 0.2.1-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 260 kB
  • ctags: 444
  • sloc: ruby: 1,924; makefile: 6
file content (136 lines) | stat: -rw-r--r-- 3,052 bytes parent folder | download
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