1 | class File < IO
|
---|
2 | class FileError < Exception; end
|
---|
3 | class NoFileError < FileError; end
|
---|
4 | class UnableToStat < FileError; end
|
---|
5 | class PermissionError < FileError; end
|
---|
6 |
|
---|
7 | attr_accessor :path
|
---|
8 |
|
---|
9 | def initialize(fd_or_path, mode = "r", perm = 0666)
|
---|
10 | if fd_or_path.kind_of? Fixnum
|
---|
11 | super(fd_or_path, mode)
|
---|
12 | else
|
---|
13 | @path = fd_or_path
|
---|
14 | fd = IO.sysopen(@path, mode, perm)
|
---|
15 | super(fd, mode)
|
---|
16 | end
|
---|
17 | end
|
---|
18 |
|
---|
19 | def self.join(*names)
|
---|
20 | return "" if names.empty?
|
---|
21 |
|
---|
22 | names.map! do |name|
|
---|
23 | case name
|
---|
24 | when String
|
---|
25 | name
|
---|
26 | when Array
|
---|
27 | if names == name
|
---|
28 | raise ArgumentError, "recursive array"
|
---|
29 | end
|
---|
30 | join(*name)
|
---|
31 | else
|
---|
32 | raise TypeError, "no implicit conversion of #{name.class} into String"
|
---|
33 | end
|
---|
34 | end
|
---|
35 |
|
---|
36 | return names[0] if names.size == 1
|
---|
37 |
|
---|
38 | if names[0][-1] == File::SEPARATOR
|
---|
39 | s = names[0][0..-2]
|
---|
40 | else
|
---|
41 | s = names[0].dup
|
---|
42 | end
|
---|
43 |
|
---|
44 | (1..names.size-2).each { |i|
|
---|
45 | t = names[i]
|
---|
46 | if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR
|
---|
47 | t = t[1..-2]
|
---|
48 | elsif t[0] == File::SEPARATOR
|
---|
49 | t = t[1..-1]
|
---|
50 | elsif t[-1] == File::SEPARATOR
|
---|
51 | t = t[0..-2]
|
---|
52 | end
|
---|
53 | s += File::SEPARATOR + t if t != ""
|
---|
54 | }
|
---|
55 | if names[-1][0] == File::SEPARATOR
|
---|
56 | s += File::SEPARATOR + names[-1][1..-1]
|
---|
57 | else
|
---|
58 | s += File::SEPARATOR + names[-1]
|
---|
59 | end
|
---|
60 | s
|
---|
61 | end
|
---|
62 |
|
---|
63 | def self.expand_path(path, default_dir = '.')
|
---|
64 | def concat_path(path, base_path)
|
---|
65 | if path[0] == "/" || path[1] == ':' # Windows root!
|
---|
66 | expanded_path = path
|
---|
67 | elsif path[0] == "~"
|
---|
68 | if (path[1] == "/" || path[1] == nil)
|
---|
69 | dir = path[1, path.size]
|
---|
70 | home_dir = _gethome
|
---|
71 |
|
---|
72 | unless home_dir
|
---|
73 | raise ArgumentError, "couldn't find HOME environment -- expanding '~'"
|
---|
74 | end
|
---|
75 |
|
---|
76 | expanded_path = home_dir
|
---|
77 | expanded_path += dir if dir
|
---|
78 | expanded_path += "/"
|
---|
79 | else
|
---|
80 | splitted_path = path.split("/")
|
---|
81 | user = splitted_path[0][1, splitted_path[0].size]
|
---|
82 | dir = "/" + splitted_path[1, splitted_path.size].join("/")
|
---|
83 |
|
---|
84 | home_dir = _gethome(user)
|
---|
85 |
|
---|
86 | unless home_dir
|
---|
87 | raise ArgumentError, "user #{user} doesn't exist"
|
---|
88 | end
|
---|
89 |
|
---|
90 | expanded_path = home_dir
|
---|
91 | expanded_path += dir if dir
|
---|
92 | expanded_path += "/"
|
---|
93 | end
|
---|
94 | else
|
---|
95 | expanded_path = concat_path(base_path, _getwd)
|
---|
96 | expanded_path += "/" + path
|
---|
97 | end
|
---|
98 |
|
---|
99 | expanded_path
|
---|
100 | end
|
---|
101 |
|
---|
102 | expanded_path = concat_path(path, default_dir)
|
---|
103 | drive_prefix = ""
|
---|
104 | if File::ALT_SEPARATOR && expanded_path.size > 2 &&
|
---|
105 | ("A".."Z").include?(expanded_path[0].upcase) && expanded_path[1] == ":"
|
---|
106 | drive_prefix = expanded_path[0, 2]
|
---|
107 | expanded_path = expanded_path[2, expanded_path.size]
|
---|
108 | end
|
---|
109 | expand_path_array = []
|
---|
110 | if File::ALT_SEPARATOR && expanded_path.include?(File::ALT_SEPARATOR)
|
---|
111 | expanded_path.gsub!(File::ALT_SEPARATOR, '/')
|
---|
112 | end
|
---|
113 | while expanded_path.include?('//')
|
---|
114 | expanded_path = expanded_path.gsub('//', '/')
|
---|
115 | end
|
---|
116 |
|
---|
117 | if expanded_path != "/"
|
---|
118 | expanded_path.split('/').each do |path_token|
|
---|
119 | if path_token == '..'
|
---|
120 | if expand_path_array.size > 1
|
---|
121 | expand_path_array.pop
|
---|
122 | end
|
---|
123 | elsif path_token == '.'
|
---|
124 | # nothing to do.
|
---|
125 | else
|
---|
126 | expand_path_array << path_token
|
---|
127 | end
|
---|
128 | end
|
---|
129 |
|
---|
130 | expanded_path = expand_path_array.join("/")
|
---|
131 | if expanded_path.empty?
|
---|
132 | expanded_path = '/'
|
---|
133 | end
|
---|
134 | end
|
---|
135 | if drive_prefix.empty?
|
---|
136 | expanded_path
|
---|
137 | else
|
---|
138 | drive_prefix + expanded_path.gsub("/", File::ALT_SEPARATOR)
|
---|
139 | end
|
---|
140 | end
|
---|
141 |
|
---|
142 | def self.foreach(file)
|
---|
143 | if block_given?
|
---|
144 | self.open(file) do |f|
|
---|
145 | f.each {|l| yield l}
|
---|
146 | end
|
---|
147 | else
|
---|
148 | return self.new(file)
|
---|
149 | end
|
---|
150 | end
|
---|
151 |
|
---|
152 | def self.directory?(file)
|
---|
153 | FileTest.directory?(file)
|
---|
154 | end
|
---|
155 |
|
---|
156 | def self.exist?(file)
|
---|
157 | FileTest.exist?(file)
|
---|
158 | end
|
---|
159 |
|
---|
160 | def self.exists?(file)
|
---|
161 | FileTest.exists?(file)
|
---|
162 | end
|
---|
163 |
|
---|
164 | def self.file?(file)
|
---|
165 | FileTest.file?(file)
|
---|
166 | end
|
---|
167 |
|
---|
168 | def self.pipe?(file)
|
---|
169 | FileTest.pipe?(file)
|
---|
170 | end
|
---|
171 |
|
---|
172 | def self.size(file)
|
---|
173 | FileTest.size(file)
|
---|
174 | end
|
---|
175 |
|
---|
176 | def self.size?(file)
|
---|
177 | FileTest.size?(file)
|
---|
178 | end
|
---|
179 |
|
---|
180 | def self.socket?(file)
|
---|
181 | FileTest.socket?(file)
|
---|
182 | end
|
---|
183 |
|
---|
184 | def self.symlink?(file)
|
---|
185 | FileTest.symlink?(file)
|
---|
186 | end
|
---|
187 |
|
---|
188 | def self.zero?(file)
|
---|
189 | FileTest.zero?(file)
|
---|
190 | end
|
---|
191 |
|
---|
192 | def self.extname(filename)
|
---|
193 | fname = self.basename(filename)
|
---|
194 | return '' if fname[0] == '.' || fname.index('.').nil?
|
---|
195 | ext = fname.split('.').last
|
---|
196 | ext.empty? ? '' : ".#{ext}"
|
---|
197 | end
|
---|
198 |
|
---|
199 | def self.path(filename)
|
---|
200 | if filename.kind_of?(String)
|
---|
201 | filename
|
---|
202 | elsif filename.respond_to?(:to_path)
|
---|
203 | filename.to_path
|
---|
204 | else
|
---|
205 | raise TypeError, "no implicit conversion of #{filename.class} into String"
|
---|
206 | end
|
---|
207 | end
|
---|
208 | end
|
---|