Add 'mrbgems/mruby-io/' from commit '3c8e1f94c44252c836f79a48bb17726da28e2756'
[mruby.git] / mrbgems / mruby-io / mrblib / file.rb
blob514efc1c67860069e9fb58b79e3debb2074e40ee
1 class File < IO
2   class FileError < Exception; end
3   class NoFileError < FileError; end
4   class UnableToStat < FileError; end
5   class PermissionError < FileError; end
7   attr_accessor :path
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
19   def self.join(*names)
20     return "" if names.empty?
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
36     return names[0] if names.size == 1
38     if names[0][-1] == File::SEPARATOR
39       s = names[0][0..-2]
40     else
41       s = names[0].dup
42     end
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
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
72           unless home_dir
73             raise ArgumentError, "couldn't find HOME environment -- expanding '~'"
74           end
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("/")
84           home_dir = _gethome(user)
86           unless home_dir
87             raise ArgumentError, "user #{user} doesn't exist"
88           end
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
99       expanded_path
100     end
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
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
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
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
152   def self.directory?(file)
153     FileTest.directory?(file)
154   end
156   def self.exist?(file)
157     FileTest.exist?(file)
158   end
160   def self.exists?(file)
161     FileTest.exists?(file)
162   end
164   def self.file?(file)
165     FileTest.file?(file)
166   end
168   def self.pipe?(file)
169     FileTest.pipe?(file)
170   end
172   def self.size(file)
173     FileTest.size(file)
174   end
176   def self.size?(file)
177     FileTest.size?(file)
178   end
180   def self.socket?(file)
181     FileTest.socket?(file)
182   end
184   def self.symlink?(file)
185     FileTest.symlink?(file)
186   end
188   def self.zero?(file)
189     FileTest.zero?(file)
190   end
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
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