pathname2 1.6.3 → 1.6.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ == 1.6.4 - 20-Jan-2011
2
+ * Explicitly remove the Pathname const if it is already defined in order
3
+ to avoid a superclass mismatch error. This library assumes that if you
4
+ require pathname2, you want my version of the Pathname class.
5
+ * Updated URI handling for Ruby 1.9.x.
6
+ * Added the Pathname() method, a synonym for Pathname.new.
7
+ * Some Rakefile and gemspec tweaks.
8
+ * Some updates to the test suite, including some specifically for Windows 7.
9
+
1
10
  == 1.6.3 - 2-Oct-2009
2
11
  * Updated Windows platform handling code to include mingw and cygwin.
3
12
  * Added the :gem rake task.
data/README CHANGED
@@ -1,109 +1,99 @@
1
1
  == Description
2
- A drop-in replacement for the current Pathname class.
2
+ A drop-in replacement for the current Pathname class.
3
3
 
4
4
  == Prerequisites
5
- * Ruby 1.8.0 or later
6
- * facade 1.0.0 or later (available on the RAA and as a gem)
7
- * windows-pr 0.5.1 or later (available on the RAA and as a gem)
5
+ * facade 1.0.4 or later
6
+ * windows-pr 1.1.2 or later (Windows only)
8
7
 
9
- The windows-pr library is only required on MS Windows.
10
-
11
- == Installation, pure Ruby
12
- === Manual Installation
13
- rake test (optional)
14
- rake install
15
-
16
- === Gem Installation
17
- rake test (optional)
18
- gem install pathname2-<version>.gem
19
-
20
- == Installation, C extension
21
- rake test_c (optional)
22
- rake install_c
8
+ == Installation
9
+
10
+ gem install pathname2
23
11
 
24
12
  == Synopsis
25
- require "pathname2"
13
+ require 'pathname2'
26
14
 
27
- # Unix
28
- path1 = "/foo/bar/baz"
29
- path2 = "../zap"
15
+ # Unix
16
+ path1 = "/foo/bar/baz"
17
+ path2 = "../zap"
30
18
 
31
- path1 + path2 # "/foo/bar/zap"
32
- path1 / path2 # "/foo/bar/zap" (same as +)
33
- path1.exists? # Does this path exist?
34
- path1.dirname # "/foo/bar"
35
- path1.to_a # ['foo','bar','baz']
19
+ path1 + path2 # "/foo/bar/zap"
20
+ path1 / path2 # "/foo/bar/zap" (same as +)
21
+ path1.exists? # Does this path exist?
22
+ path1.dirname # "/foo/bar"
23
+ path1.to_a # ['foo','bar','baz']
36
24
 
37
- # Windows
38
- path1 = "C:/foo/bar/baz"
39
- path2 = "../zap"
25
+ # Windows
26
+ path1 = "C:/foo/bar/baz"
27
+ path2 = "../zap"
40
28
 
41
- path1 + path2 # "C:\\foo\\bar\\zap"
42
- path1.root # "C:\\"
43
- path1.to_a # ['C:','foo','bar','baz']
29
+ path1 + path2 # "C:\\foo\\bar\\zap"
30
+ path1.root # "C:\\"
31
+ path1.to_a # ['C:','foo','bar','baz']
44
32
 
45
33
  == Windows Notes
46
- All forward slashes are converted to backslashes for Pathname objects.
34
+ All forward slashes are converted to backslashes for Pathname objects.
47
35
 
48
36
  == Differences between Unix and Windows
49
- If your pathname consists solely of ".", or "..", the return
50
- value for Pathname#clean will be different. On Win32, "\\" is returned,
51
- while on Unix "." is returned. I consider this an extreme edge case and
52
- will not worry myself with it.
37
+ If your pathname consists solely of ".", or "..", the return
38
+ value for Pathname#clean will be different. On Win32, "\\" is returned,
39
+ while on Unix "." is returned. I consider this an extreme edge case and
40
+ will not worry myself with it.
53
41
 
54
42
  == Differences between Pathname in the standard library and this version
55
- * It is a subclass of String (and thus, mixes in Enumerable).
56
- * It has sensical to_a and root instance methods.
57
- * It works on Windows and Unix. The current implementation does not work
58
- with Windows path names very well, and not at all when it comes to UNC
59
- paths.
60
- * The Pathname#cleanpath method works differently - it always returns
61
- a canonical pathname. In addition, there is no special consideration
62
- for symlinks (yet), though I'm not sure it warrants it.
63
- * The Pathname#+ method auto cleans.
64
- * It uses a facade for all File and Dir methods, as well as most FileUtils
65
- methods.
66
- * Pathname#clean works slightly differently. In the stdlib version,
67
- Pathname#clean("../a") returns "../a". In this version, it returns "a".
68
- This affects other methods, such as Pathname#relative_path_from.
69
- * Accepts file urls and converts them to paths automatically, e.g.
70
- file:///foo%20bar/baz becomes '/foo/bar/baz'.
71
- * Adds a Kernel level +pn+ method as a shortcut.
72
- * Allows you to add paths together with the '/' operator.
43
+ * It is a subclass of String (and thus, mixes in Enumerable).
44
+ * It has sensical to_a and root instance methods.
45
+ * It works on Windows and Unix. The current implementation does not work
46
+ with Windows path names very well, and not at all when it comes to UNC
47
+ paths.
48
+ * The Pathname#cleanpath method works differently - it always returns
49
+ a canonical pathname. In addition, there is no special consideration
50
+ for symlinks (yet), though I'm not sure it warrants it.
51
+ * The Pathname#+ method auto cleans.
52
+ * It uses a facade for all File and Dir methods, as well as most FileUtils
53
+ methods.
54
+ * Pathname#clean works slightly differently. In the stdlib version,
55
+ Pathname#clean("../a") returns "../a". In this version, it returns "a".
56
+ This affects other methods, such as Pathname#relative_path_from.
57
+ * Accepts file urls and converts them to paths automatically, e.g.
58
+ file:///foo%20bar/baz becomes '/foo/bar/baz'.
59
+ * Adds a Kernel level +pn+ method as a shortcut.
60
+ * Allows you to add paths together with the '/' operator.
73
61
 
74
62
  == Method Priority
75
- Because there is some overlap in method names between File, Dir, and
76
- FileUtils, the priority is as follows:
63
+ Because there is some overlap in method names between File, Dir, and
64
+ FileUtils, the priority is as follows:
77
65
 
78
- * File
79
- * Dir
80
- * FileUtils
66
+ * File
67
+ * Dir
68
+ * FileUtils
81
69
 
82
- In other words, whichever of these defines a given method first is the
83
- method that is used by the pathname2 library.
70
+ In other words, whichever of these defines a given method first is the
71
+ method that is used by the pathname2 library.
84
72
 
85
73
  == Known Issues
86
- In Ruby 1.8.3 and 1.8.4 you will see a failure in the test suite regarding
87
- 'fu_world_writable?' from FileUtils. You can ignore this. That method is
88
- supposed to be private. See ruby-core:7383.
74
+ In Ruby 1.8.3 and 1.8.4 you will see a failure in the test suite regarding
75
+ 'fu_world_writable?' from FileUtils. You can ignore this. That method is
76
+ supposed to be private. See ruby-core:7383.
89
77
 
90
- Any other issues should be reported on the project page at
91
- http://www.rubyforge.org/projects/shards
78
+ Any other issues should be reported on the project page at
79
+ http://www.rubyforge.org/projects/shards
80
+
81
+ The git repo itself is located at https://github.com/djberg96/pathname2
92
82
 
93
83
  == Future Plans
94
- Suggestions welcome.
84
+ Suggestions welcome.
95
85
 
96
86
  == License
97
- Artistic 2.0
87
+ Artistic 2.0
98
88
 
99
89
  == Copyright
100
- (C) 2003-2009 Daniel J. Berger
101
- All rights reserved.
90
+ (C) 2003-2011 Daniel J. Berger
91
+ All rights reserved.
102
92
 
103
93
  == Warranty
104
- This library is provided "as is" and without any express or
105
- implied warranties, including, without limitation, the implied
106
- warranties of merchantability and fitness for a particular purpose.
94
+ This library is provided "as is" and without any express or
95
+ implied warranties, including, without limitation, the implied
96
+ warranties of merchantability and fitness for a particular purpose.
107
97
 
108
98
  == Author
109
- Daniel J. Berger
99
+ Daniel J. Berger
data/Rakefile CHANGED
@@ -1,41 +1,43 @@
1
- require 'rake'
2
- require 'rake/clean'
3
- require 'rake/testtask'
4
-
5
- desc 'Install pathname2 library (non-gem)'
6
- task :install do
7
- cp 'lib/pathname2.rb', Config::CONFIG['sitelibdir']
8
- end
9
-
10
- desc 'Build the pathname2 gem'
11
- task :gem do
12
- spec = eval(IO.read('pathname2.gemspec'))
13
- Gem::Builder.new(spec).build
14
- end
15
-
16
- desc "Install the pathname2 libarary as a gem"
17
- task :install_gem => [:gem] do
18
- file = Dir["*.gem"].first
19
- sh "gem install #{file}"
20
- end
21
-
22
- desc 'Run the test suite for the pure Ruby version'
23
- Rake::TestTask.new('test') do |t|
24
- t.warning = true
25
- t.verbose = true
26
-
27
- if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
28
- t.test_files = FileList['test/test_pathname_windows.rb']
29
- else
30
- t.test_files = FileList['test/test_pathname.rb']
31
- end
32
- end
33
-
34
- desc 'Run the Pathname benchmark suite'
35
- task :benchmark do
36
- sh 'ruby -Ilib benchmarks/bench_pathname.rb'
37
- end
38
-
39
- desc 'Run the benchmark suite for Pathname#+ vs File.join'
40
- task :benchmark_plus do
41
- sh 'ruby -Ilib benchmarks/bench_plus.rb'
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ CLEAN.include("**/*.gem", "**/*.rbc")
6
+
7
+ namespace :gem do
8
+ desc "Build the pathname2 gem"
9
+ task :create => [:clean] do
10
+ spec = eval(IO.read('pathname2.gemspec'))
11
+ Gem::Builder.new(spec).build
12
+ end
13
+
14
+ desc "Install the pathname2 gem"
15
+ task :install => [:create] do
16
+ file = Dir["*.gem"].first
17
+ sh "gem install #{file}"
18
+ end
19
+ end
20
+
21
+ desc 'Run the test suite for the pure Ruby version'
22
+ Rake::TestTask.new('test') do |t|
23
+ t.warning = true
24
+ t.verbose = true
25
+
26
+ if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
27
+ t.test_files = FileList['test/test_pathname_windows.rb']
28
+ else
29
+ t.test_files = FileList['test/test_pathname.rb']
30
+ end
31
+ end
32
+
33
+ desc 'Run the Pathname benchmark suite'
34
+ task :benchmark do
35
+ sh 'ruby -Ilib benchmarks/bench_pathname.rb'
36
+ end
37
+
38
+ desc 'Run the benchmark suite for Pathname#+ vs File.join'
39
+ task :benchmark_plus do
40
+ sh 'ruby -Ilib benchmarks/bench_plus.rb'
41
+ end
42
+
43
+ task :default => :test
data/lib/pathname2.rb CHANGED
@@ -12,7 +12,7 @@
12
12
  # == Usage
13
13
  #
14
14
  # require "pathname2"
15
- #
15
+ #
16
16
  # # Unix
17
17
  # path1 = Pathname.new("/foo/bar/baz")
18
18
  # path2 = Pathname.new("../zap")
@@ -34,1075 +34,1091 @@
34
34
  # imperator on IRC (irc.freenode.net)
35
35
  #
36
36
  # == Copyright
37
- # Copyright (c) 2005-2008 Daniel J. Berger.
37
+ # Copyright (c) 2005-2011 Daniel J. Berger.
38
38
  # Licensed under the same terms as Ruby itself.
39
39
  #
40
40
  require 'facade'
41
41
  require 'fileutils'
42
- require 'rbconfig'
43
42
 
44
- if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
45
- require 'windows/path'
46
- require 'windows/file'
47
- require 'windows/error'
48
- require 'windows/limits'
43
+ if File::ALT_SEPARATOR
44
+ require 'windows/path'
45
+ require 'windows/file'
46
+ require 'windows/error'
47
+ require 'windows/limits'
49
48
  end
50
49
 
50
+ # You're mine now.
51
+ Object.send(:remove_const, :Pathname) if defined?(Pathname)
52
+
51
53
  class Pathname < String
52
- class Error < StandardError; end
53
- extend Facade
54
-
55
- facade File, File.methods(false).map{ |m| m.to_sym } - [
56
- :chmod, :lchmod, :chown, :lchown, :dirname, :fnmatch, :fnmatch?,
57
- :link, :open, :rename, :symlink, :truncate, :utime, :basename,
58
- :expand_path, :join
59
- ]
60
-
61
- facade Dir, Dir.methods(false).map{ |m| m.to_sym } - [
62
- :chdir,
63
- :glob,
64
- :foreach,
65
- :mkdir,
66
- :open
67
- ]
68
-
69
- private
70
-
71
- alias :_plus_ :+ # Used to prevent infinite loops in some cases
72
-
73
- if Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
74
- include Windows::Path
75
- include Windows::File
76
- include Windows::Error
77
- include Windows::Limits
78
- end
79
-
80
- public
81
-
82
- # The version of the pathname2 library
83
- VERSION = '1.6.3'
84
-
85
- # The maximum length of a path
86
- MAXPATH = 1024 unless defined? MAXPATH # Yes, I willfully violate POSIX
87
-
88
- # Returns the expanded path of the current working directory.
89
- #
90
- # Synonym for Pathname.new(Dir.pwd).
91
- #
92
- def self.pwd
93
- new(Dir.pwd)
94
- end
95
-
96
- class << self
97
- alias getwd pwd
98
- end
99
-
100
- # Creates and returns a new Pathname object.
101
- #
102
- # On platforms that define File::ALT_SEPARATOR, all forward slashes are
103
- # replaced with the value of File::ALT_SEPARATOR. On MS Windows, for
104
- # example, all forward slashes are replaced with backslashes.
105
- #
106
- # File URL's will be converted to Pathname objects, e.g. the file URL
107
- # "file:///C:/Documents%20and%20Settings" will become
108
- # 'C:\Documents and Settings'.
109
- #
110
- # Examples:
111
- #
112
- # Pathname.new("/foo/bar/baz"
113
- # Pathname.new("foo")
114
- # Pathname.new("file:///foo/bar/baz")
115
- # Pathname.new("C:\\Documents and Settings\\snoopy")
116
- #
117
- def initialize(path)
118
- if path.length > MAXPATH
119
- msg = "string too long. maximum string length is " + MAXPATH.to_s
120
- raise Error, msg
54
+ class Error < StandardError; end
55
+ extend Facade
56
+
57
+ facade File, File.methods(false).map{ |m| m.to_sym } - [
58
+ :chmod, :lchmod, :chown, :lchown, :dirname, :fnmatch, :fnmatch?,
59
+ :link, :open, :realpath, :rename, :symlink, :truncate, :utime,
60
+ :basename, :expand_path, :join
61
+ ]
62
+
63
+ facade Dir, Dir.methods(false).map{ |m| m.to_sym } - [
64
+ :chdir, :entries, :glob, :foreach, :mkdir, :open
65
+ ]
66
+
67
+ private
68
+
69
+ alias :_plus_ :+ # Used to prevent infinite loops in some cases
70
+
71
+ if File::ALT_SEPARATOR
72
+ include Windows::Path
73
+ include Windows::File
74
+ include Windows::Error
75
+ include Windows::Limits
76
+ end
77
+
78
+ public
79
+
80
+ # The version of the pathname2 library
81
+ VERSION = '1.6.4'
82
+
83
+ # The maximum length of a path
84
+ MAXPATH = 1024 unless defined? MAXPATH # Yes, I willfully violate POSIX
85
+
86
+ # Returns the expanded path of the current working directory.
87
+ #
88
+ # Synonym for Pathname.new(Dir.pwd).
89
+ #
90
+ def self.pwd
91
+ new(Dir.pwd)
92
+ end
93
+
94
+ class << self
95
+ alias getwd pwd
96
+ end
97
+
98
+ # Creates and returns a new Pathname object.
99
+ #
100
+ # On platforms that define File::ALT_SEPARATOR, all forward slashes are
101
+ # replaced with the value of File::ALT_SEPARATOR. On MS Windows, for
102
+ # example, all forward slashes are replaced with backslashes.
103
+ #
104
+ # File URL's will be converted to Pathname objects, e.g. the file URL
105
+ # "file:///C:/Documents%20and%20Settings" will become
106
+ # 'C:\Documents and Settings'.
107
+ #
108
+ # Examples:
109
+ #
110
+ # Pathname.new("/foo/bar/baz"
111
+ # Pathname.new("foo")
112
+ # Pathname.new("file:///foo/bar/baz")
113
+ # Pathname.new("C:\\Documents and Settings\\snoopy")
114
+ #
115
+ def initialize(path)
116
+ if path.length > MAXPATH
117
+ msg = "string too long. maximum string length is " + MAXPATH.to_s
118
+ raise Error, msg
119
+ end
120
+
121
+ @sep = File::ALT_SEPARATOR || File::SEPARATOR
122
+ @win = File::ALT_SEPARATOR
123
+
124
+ # Handle File URL's. The separate approach for Windows is necessary
125
+ # because Ruby's URI class does not (currently) parse absolute file URL's
126
+ # properly when they include a drive letter.
127
+ if @win
128
+ if PathIsURL(path)
129
+ buf = 0.chr * MAXPATH
130
+ len = [buf.length].pack("l")
131
+ if PathCreateFromUrl(path, buf, len, 0) == S_OK
132
+ path = buf.strip
133
+ else
134
+ raise Error, "invalid file url: #{path}"
135
+ end
121
136
  end
122
-
123
- @sep = File::ALT_SEPARATOR || File::SEPARATOR
124
- @win = Config::CONFIG['host_os'] =~ /mswin|win32|dos|cygwin|mingw/i
125
-
126
- # Handle File URL's. The separate methods for Windows are necessary
127
- # because Ruby's URI class does not (currently) parse absolute file URL's
128
- # properly when they include a drive letter.
129
- if @win
130
- if PathIsURL(path.dup) # Dup to avoid frozen string issues
131
- buf = 0.chr * MAXPATH
132
- len = [buf.length].pack("l")
133
- if PathCreateFromUrl(path, buf, len, 0) == S_OK
134
- path = buf.strip
135
- else
136
- raise Error, "invalid file url: #{path}"
137
- end
138
- end
139
- else
140
- if path.index('file:///', 0)
141
- require 'uri'
142
- path = URI.decode(URI.parse(path).path)
143
- end
137
+ else
138
+ if path.index('file:///', 0)
139
+ require 'uri'
140
+ if RUBY_VERSION.to_f >= 1.9
141
+ path = URI::Parser.new.unescape(path)[7..-1] # Blech
142
+ else
143
+ path = URI.decode(URI.parse(path).path)
144
+ end
145
+ end
146
+ end
147
+
148
+ # Convert forward slashes to backslashes on Windows
149
+ path = path.tr("/", @sep) if @win
150
+ super(path)
151
+ end
152
+
153
+ # Returns a real (absolute) pathname of +self+ in the actual filesystem.
154
+ #
155
+ # Unlike most Pathname methods, this one assumes that the path actually
156
+ # exists on your filesystem. If it doesn't, an error is raised. If a
157
+ # circular symlink is encountered a system error will be raised.
158
+ #
159
+ # Example:
160
+ #
161
+ # Dir.pwd # => /usr/local
162
+ # File.exists?('foo') # => true
163
+ # Pathname.new('foo').realpath # => /usr/local/foo
164
+ #
165
+ def realpath
166
+ File.stat(self) # Check to ensure that the path exists
167
+
168
+ if File.symlink?(self)
169
+ file = self.dup
170
+
171
+ while true
172
+ file = File.join(File.dirname(file), File.readlink(file))
173
+ break unless File.symlink?(file)
144
174
  end
145
175
 
146
- # Convert forward slashes to backslashes on Windows
147
- path = path.tr("/", @sep) if @win
148
- super(path)
149
- end
150
-
151
- # Returns a real (absolute) pathname of +self+ in the actual filesystem.
152
- #
153
- # Unlike most Pathname methods, this one assumes that the path actually
154
- # exists on your filesystem. If it doesn't, an error is raised. If a
155
- # circular symlink is encountered a system error will be raised.
156
- #
157
- # Example:
158
- #
159
- # Dir.pwd # => /usr/local
160
- # File.exists?('foo') # => true
161
- # Pathname.new('foo').realpath # => /usr/local/foo
162
- #
163
- def realpath
164
- File.stat(self) # Check to ensure that the path exists
165
-
166
- if File.symlink?(self)
167
- file = self.dup
168
-
169
- while true
170
- file = File.join(File.dirname(file), File.readlink(file))
171
- break unless File.symlink?(file)
172
- end
173
-
174
- self.class.new(file).clean
176
+ self.class.new(file).clean
177
+ else
178
+ self.class.new(Dir.pwd) + self
179
+ end
180
+ end
181
+
182
+ # Returns the children of the directory, files and subdirectories, as an
183
+ # array of Pathname objects. If you set +with_directory+ to +false+, then
184
+ # the returned pathnames will contain the filename only.
185
+ #
186
+ # Note that the result never contain the entries '.' and '..' in the
187
+ # the directory because they are not children. Also note that this method
188
+ # is *not* recursive.
189
+ #
190
+ # Example:
191
+ #
192
+ # path = Pathname.new('/usr/bin')
193
+ # path.children # => ['/usr/bin/ruby', '/usr/bin/perl', ...]
194
+ # path.children(false) # => ['ruby', 'perl', ...]
195
+ #
196
+ def children(with_directory = true)
197
+ with_directory = false if self == '.'
198
+ result = []
199
+ Dir.foreach(self) { |file|
200
+ next if file == '.' || file == '..'
201
+ if with_directory
202
+ result << self.class.new(File.join(self, file))
175
203
  else
176
- self.class.new(Dir.pwd) + self
177
- end
178
- end
179
-
180
- # Returns the children of the directory, files and subdirectories, as an
181
- # array of Pathname objects. If you set +with_directory+ to +false+, then
182
- # the returned pathnames will contain the filename only.
183
- #
184
- # Note that the result never contain the entries '.' and '..' in the
185
- # the directory because they are not children. Also note that this method
186
- # is *not* recursive.
187
- #
188
- # Example:
189
- #
190
- # path = Pathname.new('/usr/bin')
191
- # path.children # => ['/usr/bin/ruby', '/usr/bin/perl', ...]
192
- # path.children(false) # => ['ruby', 'perl', ...]
193
- #
194
- def children(with_directory = true)
195
- with_directory = false if self == '.'
196
- result = []
197
- Dir.foreach(self) { |file|
198
- next if file == '.' || file == '..'
199
- if with_directory
200
- result << self.class.new(File.join(self, file))
201
- else
202
- result << self.class.new(file)
203
- end
204
- }
205
- result
206
- end
207
-
208
- # Windows only
209
- #
210
- # Removes the decoration from a path string. Non-destructive.
211
- #
212
- # Example:
213
- #
214
- # path = Pathname.new('C:\Path\File[5].txt')
215
- # path.undecorate # => C:\Path\File.txt.
216
- #
217
- def undecorate
218
- unless @win
219
- raise NotImplementedError, "not supported on this platform"
220
- end
221
- buf = 0.chr * MAXPATH
222
- buf[0..self.length-1] = self
223
- PathUndecorate(buf)
224
- self.class.new(buf.split(0.chr).first)
225
- end
226
-
227
- # Windows only
228
- #
229
- # Performs the substitution of Pathname#undecorate in place.
230
- #
231
- def undecorate!
232
- unless @win
233
- raise NotImplementedError, "not supported on this platform"
234
- end
235
- buf = 0.chr * MAXPATH
236
- buf[0..self.length-1] = self
237
- PathUndecorate(buf)
238
- replace(buf.split(0.chr).first)
239
- self
240
- end
241
-
242
- # Windows only
243
- #
244
- # Returns the short path for a long path name.
245
- #
246
- # Example:
247
- #
248
- # path = Pathname.new('C:\Program Files\Java')
249
- # path.short_path # => C:\Progra~1\Java.
250
- #
251
- def short_path
252
- unless @win
253
- raise NotImplementedError, "not supported on this platform"
204
+ result << self.class.new(file)
254
205
  end
255
- buf = 0.chr * MAXPATH
256
- buf[0..self.length-1] = self
257
- GetShortPathName(self, buf, buf.length)
258
- self.class.new(buf.split(0.chr).first)
259
- end
260
-
261
- # Windows only
262
- #
263
- # Returns the long path for a long path name.
264
- #
265
- # Example:
266
- #
267
- # path = Pathname.new('C:\Progra~1\Java')
268
- # path.long_path # => C:\Program Files\Java.
269
- #
270
- def long_path
271
- unless @win
272
- raise NotImplementedError, "not supported on this platform"
206
+ }
207
+ result
208
+ end
209
+
210
+ # Windows only
211
+ #
212
+ # Removes the decoration from a path string. Non-destructive.
213
+ #
214
+ # Example:
215
+ #
216
+ # path = Pathname.new('C:\Path\File[5].txt')
217
+ # path.undecorate # => C:\Path\File.txt.
218
+ #
219
+ def undecorate
220
+ unless @win
221
+ raise NotImplementedError, "not supported on this platform"
222
+ end
223
+ buf = 0.chr * MAXPATH
224
+ buf[0..self.length-1] = self
225
+ PathUndecorate(buf)
226
+ self.class.new(buf.split(0.chr).first)
227
+ end
228
+
229
+ # Windows only
230
+ #
231
+ # Performs the substitution of Pathname#undecorate in place.
232
+ #
233
+ def undecorate!
234
+ unless @win
235
+ raise NotImplementedError, "not supported on this platform"
236
+ end
237
+ buf = 0.chr * MAXPATH
238
+ buf[0..self.length-1] = self
239
+ PathUndecorate(buf)
240
+ replace(buf.split(0.chr).first)
241
+ self
242
+ end
243
+
244
+ # Windows only
245
+ #
246
+ # Returns the short path for a long path name.
247
+ #
248
+ # Example:
249
+ #
250
+ # path = Pathname.new('C:\Program Files\Java')
251
+ # path.short_path # => C:\Progra~1\Java.
252
+ #
253
+ def short_path
254
+ unless @win
255
+ raise NotImplementedError, "not supported on this platform"
256
+ end
257
+ buf = 0.chr * MAXPATH
258
+ buf[0..self.length-1] = self
259
+ GetShortPathName(self, buf, buf.length)
260
+ self.class.new(buf.split(0.chr).first)
261
+ end
262
+
263
+ # Windows only
264
+ #
265
+ # Returns the long path for a long path name.
266
+ #
267
+ # Example:
268
+ #
269
+ # path = Pathname.new('C:\Progra~1\Java')
270
+ # path.long_path # => C:\Program Files\Java.
271
+ #
272
+ def long_path
273
+ unless @win
274
+ raise NotImplementedError, "not supported on this platform"
275
+ end
276
+ buf = 0.chr * MAXPATH
277
+ buf[0..self.length-1] = self
278
+ GetLongPathName(self, buf, buf.length)
279
+ self.class.new(buf.split(0.chr).first)
280
+ end
281
+
282
+ # Removes trailing slash, if present. Non-destructive.
283
+ #
284
+ # Example:
285
+ #
286
+ # path = Pathname.new('/usr/local/')
287
+ # path.pstrip # => '/usr/local'
288
+ #
289
+ def pstrip
290
+ str = self.dup
291
+ if @win
292
+ PathRemoveBackslash(str)
293
+ str.strip!
294
+ else
295
+ if str.to_s[-1].chr == @sep
296
+ str.strip!
297
+ str.chop!
273
298
  end
274
- buf = 0.chr * MAXPATH
275
- buf[0..self.length-1] = self
276
- GetLongPathName(self, buf, buf.length)
277
- self.class.new(buf.split(0.chr).first)
278
- end
279
-
280
- # Removes trailing slash, if present. Non-destructive.
281
- #
282
- # Example:
283
- #
284
- # path = Pathname.new('/usr/local/')
285
- # path.pstrip # => '/usr/local'
286
- #
287
- def pstrip
288
- str = self.dup
289
- if @win
290
- PathRemoveBackslash(str)
291
- str.strip!
292
- else
293
- if str.to_s[-1].chr == @sep
294
- str.strip!
295
- str.chop!
296
- end
299
+ end
300
+ self.class.new(str)
301
+ end
302
+
303
+ # Performs the substitution of Pathname#pstrip in place.
304
+ #
305
+ def pstrip!
306
+ if @win
307
+ PathRemoveBackslash(self)
308
+ strip!
309
+ else
310
+ if self.to_s[-1].chr == @sep
311
+ strip!
312
+ chop!
297
313
  end
298
- self.class.new(str)
299
- end
300
-
301
- # Performs the substitution of Pathname#pstrip in place.
302
- #
303
- def pstrip!
304
- if @win
305
- PathRemoveBackslash(self)
306
- strip!
314
+ end
315
+ self
316
+ end
317
+
318
+ # Splits a pathname into strings based on the path separator.
319
+ #
320
+ # Examples:
321
+ #
322
+ # Pathname.new('/usr/local/bin').to_a # => ['usr', 'local', 'bin']
323
+ # Pathname.new('C:\WINNT\Fonts').to_a # => ['C:', 'WINNT', 'Fonts']
324
+ #
325
+ def to_a
326
+ array = split(@sep) # Split string by path separator
327
+ array.delete("") # Remove empty elements
328
+ array
329
+ end
330
+
331
+ # Yields each component of the path name to a block.
332
+ #
333
+ # Example:
334
+ #
335
+ # Pathname.new('/usr/local/bin').each{ |element|
336
+ # puts "Element: #{element}"
337
+ # }
338
+ #
339
+ # Yields 'usr', 'local', and 'bin', in turn
340
+ #
341
+ def each
342
+ to_a.each{ |element| yield element }
343
+ end
344
+
345
+ # Returns the path component at +index+, up to +length+ components, joined
346
+ # by the path separator. If the +index+ is a Range, then that is used
347
+ # instead and the +length+ is ignored.
348
+ #
349
+ # Keep in mind that on MS Windows the drive letter is the first element.
350
+ #
351
+ # Examples:
352
+ #
353
+ # path = Pathname.new('/home/john/source/ruby')
354
+ # path[0] # => 'home'
355
+ # path[1] # => 'john'
356
+ # path[0, 3] # => '/home/john/source'
357
+ # path[0..1] # => '/home/john'
358
+ #
359
+ # path = Pathname.new('C:/Documents and Settings/John/Source/Ruby')
360
+ # path[0] # => 'C:\'
361
+ # path[1] # => 'Documents and Settings'
362
+ # path[0, 3] # => 'C:\Documents and Settings\John'
363
+ # path[0..1] # => 'C:\Documents and Settings'
364
+ #
365
+ def [](index, length=nil)
366
+ if index.is_a?(Fixnum)
367
+ if length
368
+ path = File.join(to_a[index, length])
307
369
  else
308
- if self.to_s[-1].chr == @sep
309
- strip!
310
- chop!
311
- end
370
+ path = to_a[index]
312
371
  end
313
- self
314
- end
315
-
316
- # Splits a pathname into strings based on the path separator.
317
- #
318
- # Examples:
319
- #
320
- # Pathname.new('/usr/local/bin').to_a # => ['usr', 'local', 'bin']
321
- # Pathname.new('C:\WINNT\Fonts').to_a # => ['C:', 'WINNT', 'Fonts']
322
- #
323
- def to_a
324
- array = split(@sep) # Split string by path separator
325
- array.delete("") # Remove empty elements
326
- array
327
- end
328
-
329
- # Yields each component of the path name to a block.
330
- #
331
- # Example:
332
- #
333
- # Pathname.new('/usr/local/bin').each{ |element|
334
- # puts "Element: #{element}"
335
- # }
336
- #
337
- # Yields 'usr', 'local', and 'bin', in turn
338
- #
339
- def each
340
- to_a.each{ |element| yield element }
341
- end
342
-
343
- # Returns the path component at +index+, up to +length+ components, joined
344
- # by the path separator. If the +index+ is a Range, then that is used
345
- # instead and the +length+ is ignored.
346
- #
347
- # Keep in mind that on MS Windows the drive letter is the first element.
348
- #
349
- # Examples:
350
- #
351
- # path = Pathname.new('/home/john/source/ruby')
352
- # path[0] # => 'home'
353
- # path[1] # => 'john'
354
- # path[0, 3] # => '/home/john/source'
355
- # path[0..1] # => '/home/john'
356
- #
357
- # path = Pathname.new('C:/Documents and Settings/John/Source/Ruby')
358
- # path[0] # => 'C:\'
359
- # path[1] # => 'Documents and Settings'
360
- # path[0, 3] # => 'C:\Documents and Settings\John'
361
- # path[0..1] # => 'C:\Documents and Settings'
362
- #
363
- def [](index, length=nil)
364
- if index.is_a?(Fixnum)
365
- if length
366
- path = File.join(to_a[index, length])
367
- else
368
- path = to_a[index]
369
- end
370
- elsif index.is_a?(Range)
371
- if length
372
- warn 'Length argument ignored'
373
- end
374
- path = File.join(to_a[index])
375
- else
376
- raise TypeError, "Only Fixnums and Ranges allowed as first argument"
377
- end
378
-
379
- if path && @win
380
- path = path.tr("/", "\\")
372
+ elsif index.is_a?(Range)
373
+ if length
374
+ warn 'Length argument ignored'
381
375
  end
382
-
383
- path
384
- end
385
-
386
- # Yields each component of the path, concatenating the next component on
387
- # each iteration as a new Pathname object, starting with the root path.
388
- #
389
- # Example:
390
- #
391
- # path = Pathname.new('/usr/local/bin')
392
- #
393
- # path.descend{ |name|
394
- # puts name
395
- # }
396
- #
397
- # First iteration => '/'
398
- # Second iteration => '/usr'
399
- # Third iteration => '/usr/local'
400
- # Fourth iteration => '/usr/local/bin'
401
- #
402
- def descend
403
- if root?
404
- yield root
405
- return
376
+ path = File.join(to_a[index])
377
+ else
378
+ raise TypeError, "Only Fixnums and Ranges allowed as first argument"
379
+ end
380
+
381
+ if path && @win
382
+ path = path.tr("/", "\\")
383
+ end
384
+
385
+ path
386
+ end
387
+
388
+ # Yields each component of the path, concatenating the next component on
389
+ # each iteration as a new Pathname object, starting with the root path.
390
+ #
391
+ # Example:
392
+ #
393
+ # path = Pathname.new('/usr/local/bin')
394
+ #
395
+ # path.descend{ |name|
396
+ # puts name
397
+ # }
398
+ #
399
+ # First iteration => '/'
400
+ # Second iteration => '/usr'
401
+ # Third iteration => '/usr/local'
402
+ # Fourth iteration => '/usr/local/bin'
403
+ #
404
+ def descend
405
+ if root?
406
+ yield root
407
+ return
408
+ end
409
+
410
+ if @win
411
+ path = unc? ? "#{root}\\" : ""
412
+ else
413
+ path = absolute? ? root : ""
414
+ end
415
+
416
+ # Yield the root directory if an absolute path (and not Windows)
417
+ unless @win && !unc?
418
+ yield root if absolute?
419
+ end
420
+
421
+ each{ |element|
422
+ if @win && unc?
423
+ next if root.to_a.include?(element)
406
424
  end
407
-
408
- if @win
409
- path = unc? ? "#{root}\\" : ""
410
- else
411
- path = absolute? ? root : ""
425
+ path << element << @sep
426
+ yield self.class.new(path.chop)
427
+ }
428
+ end
429
+
430
+ # Yields the path, minus one component on each iteration, as a new
431
+ # Pathname object, ending with the root path.
432
+ #
433
+ # Example:
434
+ #
435
+ # path = Pathname.new('/usr/local/bin')
436
+ #
437
+ # path.ascend{ |name|
438
+ # puts name
439
+ # }
440
+ #
441
+ # First iteration => '/usr/local/bin'
442
+ # Second iteration => '/usr/local'
443
+ # Third iteration => '/usr'
444
+ # Fourth iteration => '/'
445
+ #
446
+ def ascend
447
+ if root?
448
+ yield root
449
+ return
450
+ end
451
+
452
+ n = to_a.length
453
+
454
+ while n > 0
455
+ path = to_a[0..n-1].join(@sep)
456
+ if absolute?
457
+ if @win && unc?
458
+ path = "\\\\" << path
459
+ end
460
+ unless @win
461
+ path = root << path
462
+ end
412
463
  end
413
464
 
414
- # Yield the root directory if an absolute path (and not Windows)
415
- unless @win && !unc?
416
- yield root if absolute?
417
- end
465
+ path = self.class.new(path)
466
+ yield path
418
467
 
419
- each{ |element|
420
- if @win && unc?
421
- next if root.to_a.include?(element)
422
- end
423
- path << element << @sep
424
- yield self.class.new(path.chop)
425
- }
426
- end
427
-
428
- # Yields the path, minus one component on each iteration, as a new
429
- # Pathname object, ending with the root path.
430
- #
431
- # Example:
432
- #
433
- # path = Pathname.new('/usr/local/bin')
434
- #
435
- # path.ascend{ |name|
436
- # puts name
437
- # }
438
- #
439
- # First iteration => '/usr/local/bin'
440
- # Second iteration => '/usr/local'
441
- # Third iteration => '/usr'
442
- # Fourth iteration => '/'
443
- #
444
- def ascend
445
- if root?
446
- yield root
447
- return
448
- end
449
-
450
- n = to_a.length
451
-
452
- while n > 0
453
- path = to_a[0..n-1].join(@sep)
454
- if absolute?
455
- if @win && unc?
456
- path = "\\\\" << path
457
- end
458
- unless @win
459
- path = root << path
460
- end
461
- end
462
-
463
- path = self.class.new(path)
464
- yield path
465
-
466
- if @win && unc?
467
- break if path.root?
468
- end
469
-
470
- n -= 1
468
+ if @win && unc?
469
+ break if path.root?
471
470
  end
472
471
 
473
- # Yield the root directory if an absolute path (and not Windows)
474
- unless @win
475
- yield root if absolute?
476
- end
477
- end
478
-
479
- # Returns the root directory of the path, or '.' if there is no root
480
- # directory.
481
- #
482
- # On Unix, this means the '/' character. On Windows, this can refer
483
- # to the drive letter, or the server and share path if the path is a
484
- # UNC path.
485
- #
486
- # Examples:
487
- #
488
- # Pathname.new('/usr/local').root # => '/'
489
- # Pathname.new('lib').root # => '.'
490
- #
491
- # On MS Windows:
492
- #
493
- # Pathname.new('C:\WINNT').root # => 'C:'
494
- # Pathname.new('\\some\share\foo').root # => '\\some\share'
495
- #
496
- def root
497
- dir = "."
498
-
499
- if @win
500
- buf = 0.chr * MAXPATH
501
- buf[0..self.length-1] = self
502
-
503
- if PathStripToRoot(buf)
504
- dir = buf.split(0.chr).first
505
- end
506
- else
507
- dir = "/" if self =~ /^\//
472
+ n -= 1
473
+ end
474
+
475
+ # Yield the root directory if an absolute path (and not Windows)
476
+ unless @win
477
+ yield root if absolute?
478
+ end
479
+ end
480
+
481
+ # Returns the root directory of the path, or '.' if there is no root
482
+ # directory.
483
+ #
484
+ # On Unix, this means the '/' character. On Windows, this can refer
485
+ # to the drive letter, or the server and share path if the path is a
486
+ # UNC path.
487
+ #
488
+ # Examples:
489
+ #
490
+ # Pathname.new('/usr/local').root # => '/'
491
+ # Pathname.new('lib').root # => '.'
492
+ #
493
+ # On MS Windows:
494
+ #
495
+ # Pathname.new('C:\WINNT').root # => 'C:'
496
+ # Pathname.new('\\some\share\foo').root # => '\\some\share'
497
+ #
498
+ def root
499
+ dir = "."
500
+
501
+ if @win
502
+ buf = 0.chr * MAXPATH
503
+ buf[0..self.length-1] = self
504
+
505
+ if PathStripToRoot(buf)
506
+ dir = buf.split(0.chr).first
508
507
  end
509
-
510
- self.class.new(dir)
511
- end
512
-
513
- # Returns whether or not the path consists only of a root directory.
514
- #
515
- # Examples:
516
- #
517
- # Pathname.new('/').root? # => true
518
- # Pathname.new('/foo').root? # => false
519
- #
520
- def root?
521
- if @win
522
- PathIsRoot(self)
523
- else
524
- self == root
508
+ else
509
+ dir = "/" if self =~ /^\//
510
+ end
511
+
512
+ self.class.new(dir)
513
+ end
514
+
515
+ # Returns whether or not the path consists only of a root directory.
516
+ #
517
+ # Examples:
518
+ #
519
+ # Pathname.new('/').root? # => true
520
+ # Pathname.new('/foo').root? # => false
521
+ #
522
+ def root?
523
+ if @win
524
+ PathIsRoot(self)
525
+ else
526
+ self == root
527
+ end
528
+ end
529
+
530
+ # MS Windows only
531
+ #
532
+ # Determines if the string is a valid Universal Naming Convention (UNC)
533
+ # for a server and share path.
534
+ #
535
+ # Examples:
536
+ #
537
+ # Pathname.new("\\\\foo\\bar").unc? # => true
538
+ # Pathname.new('C:\Program Files').unc? # => false
539
+ #
540
+ def unc?
541
+ unless @win
542
+ raise NotImplementedError, "not supported on this platform"
543
+ end
544
+
545
+ PathIsUNC(self)
546
+ end
547
+
548
+ # MS Windows only
549
+ #
550
+ # Returns the drive number that corresponds to the root, or nil if not
551
+ # applicable.
552
+ #
553
+ # Example:
554
+ #
555
+ # Pathname.new("C:\\foo").drive_number # => 2
556
+ #
557
+ def drive_number
558
+ unless @win
559
+ raise NotImplementedError, "not supported on this platform"
560
+ end
561
+
562
+ num = PathGetDriveNumber(self)
563
+ num >= 0 ? num : nil
564
+ end
565
+
566
+ # Compares two Pathname objects. Note that Pathnames may only be compared
567
+ # against other Pathnames, not strings. Otherwise nil is returned.
568
+ #
569
+ # Example:
570
+ #
571
+ # path1 = Pathname.new('/usr/local')
572
+ # path2 = Pathname.new('/usr/local')
573
+ # path3 = Pathname.new('/usr/local/bin')
574
+ #
575
+ # path1 <=> path2 # => 0
576
+ # path1 <=> path3 # => -1
577
+ #
578
+ def <=>(string)
579
+ return nil unless string.kind_of?(Pathname)
580
+ super
581
+ end
582
+
583
+ # Returns the parent directory of the given path.
584
+ #
585
+ # Example:
586
+ #
587
+ # Pathname.new('/usr/local/bin').parent # => '/usr/local'
588
+ #
589
+ def parent
590
+ self + ".." # Use our custom '+' method
591
+ end
592
+
593
+ # Returns a relative path from the argument to the receiver. If +self+
594
+ # is absolute, the argument must be absolute too. If +self+ is relative,
595
+ # the argument must be relative too. For relative paths, this method uses
596
+ # an imaginary, common parent path.
597
+ #
598
+ # This method does not access the filesystem. It assumes no symlinks.
599
+ # You should only compare directories against directories, or files against
600
+ # files, or you may get unexpected results.
601
+ #
602
+ # Raises an ArgumentError if it cannot find a relative path.
603
+ #
604
+ # Examples:
605
+ #
606
+ # path = Pathname.new('/usr/local/bin')
607
+ # path.relative_path_from('/usr/bin') # => "../local/bin"
608
+ #
609
+ # path = Pathname.new("C:\\WINNT\\Fonts")
610
+ # path.relative_path_from("C:\\Program Files") # => "..\\WINNT\\Fonts"
611
+ #
612
+ def relative_path_from(base)
613
+ base = self.class.new(base) unless base.kind_of?(Pathname)
614
+
615
+ if self.absolute? != base.absolute?
616
+ raise ArgumentError, "relative path between absolute and relative path"
617
+ end
618
+
619
+ return self.class.new(".") if self == base
620
+ return self if base == "."
621
+
622
+ # Because of the way the Windows version handles Pathname#clean, we need
623
+ # a little extra help here.
624
+ if @win
625
+ if root != base.root
626
+ msg = 'cannot determine relative paths from different root paths'
627
+ raise ArgumentError, msg
525
628
  end
526
- end
527
-
528
- # MS Windows only
529
- #
530
- # Determines if the string is a valid Universal Naming Convention (UNC)
531
- # for a server and share path.
532
- #
533
- # Examples:
534
- #
535
- # Pathname.new("\\\\foo\\bar").unc? # => true
536
- # Pathname.new('C:\Program Files').unc? # => false
537
- #
538
- def unc?
539
- unless @win
540
- raise NotImplementedError, "not supported on this platform"
629
+ if base == '..' && (self != '..' || self != '.')
630
+ raise ArgumentError, "base directory may not contain '..'"
541
631
  end
542
-
543
- PathIsUNC(self)
544
- end
545
-
546
- # MS Windows only
547
- #
548
- # Returns the drive number that corresponds to the root, or nil if not
549
- # applicable.
550
- #
551
- # Example:
552
- #
553
- # Pathname.new("C:\\foo").drive_number # => 2
554
- #
555
- def drive_number
556
- unless @win
557
- raise NotImplementedError, "not supported on this platform"
632
+ end
633
+
634
+ dest_arr = self.clean.to_a
635
+ base_arr = base.clean.to_a
636
+ dest_arr.delete('.')
637
+ base_arr.delete('.')
638
+
639
+ diff_arr = dest_arr - base_arr
640
+
641
+ while !base_arr.empty? && !dest_arr.empty? && base_arr[0] == dest_arr[0]
642
+ base_arr.shift
643
+ dest_arr.shift
644
+ end
645
+
646
+ if base_arr.include?("..")
647
+ raise ArgumentError, "base directory may not contain '..'"
648
+ end
649
+
650
+ base_arr.fill("..")
651
+ rel_path = base_arr + dest_arr
652
+
653
+ if rel_path.empty?
654
+ self.class.new(".")
655
+ else
656
+ self.class.new(rel_path.join(@sep))
657
+ end
658
+ end
659
+
660
+ # Adds two Pathname objects together, or a Pathname and a String. It
661
+ # also automatically cleans the Pathname.
662
+ #
663
+ # Adding a root path to an existing path merely replaces the current
664
+ # path. Adding '.' to an existing path does nothing.
665
+ #
666
+ # Example:
667
+ #
668
+ # path1 = '/foo/bar'
669
+ # path2 = '../baz'
670
+ # path1 + path2 # '/foo/baz'
671
+ #
672
+ def +(string)
673
+ unless string.kind_of?(Pathname)
674
+ string = self.class.new(string)
675
+ end
676
+
677
+ # Any path plus "." is the same directory
678
+ return self if string == "."
679
+ return string if self == "."
680
+
681
+ # Use the builtin PathAppend() function if on Windows - much easier
682
+ if @win
683
+ buf = 0.chr * MAXPATH
684
+ buf[0..self.length-1] = self
685
+ PathAppend(buf, string)
686
+ buf = buf.split("\0").first
687
+ return self.class.new(buf) # PathAppend cleans automatically
688
+ end
689
+
690
+ # If the string is an absolute directory, return it
691
+ return string if string.absolute?
692
+
693
+ array = to_a + string.to_a
694
+ new_string = array.join(@sep)
695
+
696
+ unless relative? || @win
697
+ temp = @sep + new_string # Add root path back if needed
698
+ new_string.replace(temp)
699
+ end
700
+
701
+ self.class.new(new_string).clean
702
+ end
703
+
704
+ alias :/ :+
705
+
706
+ # Returns whether or not the path is an absolute path.
707
+ #
708
+ # Example:
709
+ #
710
+ # Pathname.new('/usr/bin').absolute? # => true
711
+ # Pathname.new('usr').absolute? # => false
712
+ #
713
+ def absolute?
714
+ !relative?
715
+ end
716
+
717
+ # Returns whether or not the path is a relative path.
718
+ #
719
+ # Example:
720
+ #
721
+ # Pathname.new('/usr/bin').relative? # => true
722
+ # Pathname.new('usr').relative? # => false
723
+ #
724
+ def relative?
725
+ if @win
726
+ PathIsRelative(self)
727
+ else
728
+ root == "."
729
+ end
730
+ end
731
+
732
+ # Removes unnecessary '.' paths and ellides '..' paths appropriately.
733
+ # This method is non-destructive.
734
+ #
735
+ # Example:
736
+ #
737
+ # path = Pathname.new('/usr/./local/../bin')
738
+ # path.clean # => '/usr/bin'
739
+ #
740
+ def clean
741
+ return self if self.empty?
742
+
743
+ if @win
744
+ path = 0.chr * MAXPATH
745
+ if PathCanonicalize(path, self)
746
+ return self.class.new(path.split(0.chr).first)
747
+ else
748
+ return self
558
749
  end
750
+ end
559
751
 
560
- num = PathGetDriveNumber(self)
561
- num >= 0 ? num : nil
562
- end
563
-
564
- # Compares two Pathname objects. Note that Pathnames may only be compared
565
- # against other Pathnames, not strings. Otherwise nil is returned.
566
- #
567
- # Example:
568
- #
569
- # path1 = Pathname.new('/usr/local')
570
- # path2 = Pathname.new('/usr/local')
571
- # path3 = Pathname.new('/usr/local/bin')
572
- #
573
- # path1 <=> path2 # => 0
574
- # path1 <=> path3 # => -1
575
- #
576
- def <=>(string)
577
- return nil unless string.kind_of?(Pathname)
578
- super
579
- end
580
-
581
- # Returns the parent directory of the given path.
582
- #
583
- # Example:
584
- #
585
- # Pathname.new('/usr/local/bin').parent # => '/usr/local'
586
- #
587
- def parent
588
- self + ".." # Use our custom '+' method
589
- end
590
-
591
- # Returns a relative path from the argument to the receiver. If +self+
592
- # is absolute, the argument must be absolute too. If +self+ is relative,
593
- # the argument must be relative too. For relative paths, this method uses
594
- # an imaginary, common parent path.
595
- #
596
- # This method does not access the filesystem. It assumes no symlinks.
597
- # You should only compare directories against directories, or files against
598
- # files, or you may get unexpected results.
599
- #
600
- # Raises an ArgumentError if it cannot find a relative path.
601
- #
602
- # Examples:
603
- #
604
- # path = Pathname.new('/usr/local/bin')
605
- # path.relative_path_from('/usr/bin') # => "../local/bin"
606
- #
607
- # path = Pathname.new("C:\\WINNT\\Fonts")
608
- # path.relative_path_from("C:\\Program Files") # => "..\\WINNT\\Fonts"
609
- #
610
- def relative_path_from(base)
611
- base = self.class.new(base) unless base.kind_of?(Pathname)
612
-
613
- if self.absolute? != base.absolute?
614
- raise ArgumentError, "relative path between absolute and relative path"
615
- end
752
+ final = []
616
753
 
617
- return self.class.new(".") if self == base
618
- return self if base == "."
619
-
620
- # Because of the way the Windows version handles Pathname#clean, we need
621
- # a little extra help here.
622
- if @win
623
- if root != base.root
624
- msg = 'cannot determine relative paths from different root paths'
625
- raise ArgumentError, msg
626
- end
627
- if base == '..' && (self != '..' || self != '.')
628
- raise ArgumentError, "base directory may not contain '..'"
629
- end
754
+ to_a.each{ |element|
755
+ next if element == "."
756
+ final.push(element)
757
+ if element == ".." && self != ".."
758
+ 2.times{ final.pop }
630
759
  end
760
+ }
631
761
 
632
- dest_arr = self.clean.to_a
633
- base_arr = base.clean.to_a
634
- dest_arr.delete('.')
635
- base_arr.delete('.')
762
+ final = final.join(@sep)
763
+ final = root._plus_(final) if root != "."
764
+ final = "." if final.empty?
636
765
 
637
- diff_arr = dest_arr - base_arr
766
+ self.class.new(final)
767
+ end
638
768
 
639
- while !base_arr.empty? && !dest_arr.empty? && base_arr[0] == dest_arr[0]
640
- base_arr.shift
641
- dest_arr.shift
642
- end
643
-
644
- if base_arr.include?("..")
645
- raise ArgumentError, "base directory may not contain '..'"
646
- end
769
+ alias :cleanpath :clean
647
770
 
648
- base_arr.fill("..")
649
- rel_path = base_arr + dest_arr
771
+ # Identical to Pathname#clean, except that it modifies the receiver
772
+ # in place.
773
+ #
774
+ def clean!
775
+ return self if self.empty?
650
776
 
651
- if rel_path.empty?
652
- self.class.new(".")
653
- else
654
- self.class.new(rel_path.join(@sep))
655
- end
656
- end
657
-
658
- # Adds two Pathname objects together, or a Pathname and a String. It
659
- # also automatically cleans the Pathname.
660
- #
661
- # Adding a root path to an existing path merely replaces the current
662
- # path. Adding '.' to an existing path does nothing.
663
- #
664
- # Example:
665
- #
666
- # path1 = '/foo/bar'
667
- # path2 = '../baz'
668
- # path1 + path2 # '/foo/baz'
669
- #
670
- def +(string)
671
- unless string.kind_of?(Pathname)
672
- string = self.class.new(string)
777
+ if @win
778
+ path = 0.chr * MAXPATH
779
+ if PathCanonicalize(path, self)
780
+ replace(path.split(0.chr).first)
673
781
  end
782
+ return self
783
+ end
674
784
 
675
- # Any path plus "." is the same directory
676
- return self if string == "."
677
- return string if self == "."
678
-
679
- # Use the builtin PathAppend() function if on Windows - much easier
680
- if @win
681
- buf = 0.chr * MAXPATH
682
- buf[0..self.length-1] = self
683
- PathAppend(buf, string)
684
- buf = buf.split("\0").first
685
- return self.class.new(buf) # PathAppend cleans automatically
686
- end
687
-
688
- # If the string is an absolute directory, return it
689
- return string if string.absolute?
690
-
691
- array = to_a + string.to_a
692
- new_string = array.join(@sep)
693
-
694
- unless relative? || @win
695
- temp = @sep + new_string # Add root path back if needed
696
- new_string.replace(temp)
697
- end
698
-
699
- self.class.new(new_string).clean
700
- end
701
-
702
- alias :/ :+
703
-
704
- # Returns whether or not the path is an absolute path.
705
- #
706
- # Example:
707
- #
708
- # Pathname.new('/usr/bin').absolute? # => true
709
- # Pathname.new('usr').absolute? # => false
710
- #
711
- def absolute?
712
- !relative?
713
- end
714
-
715
- # Returns whether or not the path is a relative path.
716
- #
717
- # Example:
718
- #
719
- # Pathname.new('/usr/bin').relative? # => true
720
- # Pathname.new('usr').relative? # => false
721
- #
722
- def relative?
723
- if @win
724
- PathIsRelative(self)
725
- else
726
- root == "."
727
- end
728
- end
729
-
730
- # Removes unnecessary '.' paths and ellides '..' paths appropriately.
731
- # This method is non-destructive.
732
- #
733
- # Example:
734
- #
735
- # path = Pathname.new('/usr/./local/../bin')
736
- # path.clean # => '/usr/bin'
737
- #
738
- def clean
739
- return self if self.empty?
740
-
741
- if @win
742
- path = 0.chr * MAXPATH
743
- if PathCanonicalize(path, self)
744
- return self.class.new(path.split(0.chr).first)
745
- else
746
- return self
747
- end
748
- end
785
+ final = []
749
786
 
750
- final = []
751
-
752
- to_a.each{ |element|
753
- next if element == "."
754
- final.push(element)
755
- if element == ".." && self != ".."
756
- 2.times{ final.pop }
757
- end
758
- }
759
-
760
- final = final.join(@sep)
761
- final = root._plus_(final) if root != "."
762
- final = "." if final.empty?
763
-
764
- self.class.new(final)
765
- end
766
-
767
- alias :cleanpath :clean
768
-
769
- # Identical to Pathname#clean, except that it modifies the receiver
770
- # in place.
771
- #
772
- def clean!
773
- return self if self.empty?
774
-
775
- if @win
776
- path = 0.chr * MAXPATH
777
- if PathCanonicalize(path, self)
778
- replace(path.split(0.chr).first)
779
- end
780
- return self
787
+ to_a.each{ |element|
788
+ next if element == "."
789
+ final.push(element)
790
+ if element == ".." && self != ".."
791
+ 2.times{ final.pop }
781
792
  end
782
-
783
- final = []
784
-
785
- to_a.each{ |element|
786
- next if element == "."
787
- final.push(element)
788
- if element == ".." && self != ".."
789
- 2.times{ final.pop }
790
- end
791
- }
792
-
793
- final = final.join(@sep)
794
- final = root + final if root != "."
795
- final = "." if final.empty?
796
- replace(self.class.new(final))
797
-
798
- self
799
- end
800
-
801
- alias cleanpath! clean!
802
-
803
- # Similar to File.dirname, but this method allows you to specify the number
804
- # of levels up you wish to refer to.
805
- #
806
- # The default level is 1, i.e. it works the same as File.dirname. A level of
807
- # 0 will return the original path. A level equal to or greater than the
808
- # number of path elements will return the root path.
809
- #
810
- # A number less than 0 will raise an ArgumentError.
811
- #
812
- # Example:
813
- #
814
- # path = Pathname.new('/usr/local/bin/ruby')
815
- #
816
- # puts path.dirname # => /usr/local/bin
817
- # puts path.dirname(2) # => /usr/local
818
- # puts path.dirname(3) # => /usr
819
- # puts path.dirname(9) # => /
820
- #
821
- def dirname(level = 1)
822
- raise ArgumentError if level < 0
823
- local_path = self.dup
824
-
825
- level.times{ |n| local_path = File.dirname(local_path) }
826
- local_path
827
- end
828
-
829
- #-- Find facade
830
-
831
- # Pathname#find is an iterator to traverse a directory tree in a depth first
832
- # manner. It yields a Pathname for each file under the directory passed to
833
- # Pathname.new.
834
- #
835
- # Since it is implemented by the Find module, Find.prune can be used to
836
- # control the traverse.
837
- #
838
- # If +self+ is ".", yielded pathnames begin with a filename in the current
839
- # current directory, not ".".
840
- #
841
- def find(&block)
842
- require "find"
843
- if self == "."
844
- Find.find(self){ |f| yield self.class.new(f.sub(%r{\A\./}, '')) }
793
+ }
794
+
795
+ final = final.join(@sep)
796
+ final = root + final if root != "."
797
+ final = "." if final.empty?
798
+ replace(self.class.new(final))
799
+
800
+ self
801
+ end
802
+
803
+ alias cleanpath! clean!
804
+
805
+ # Similar to File.dirname, but this method allows you to specify the number
806
+ # of levels up you wish to refer to.
807
+ #
808
+ # The default level is 1, i.e. it works the same as File.dirname. A level of
809
+ # 0 will return the original path. A level equal to or greater than the
810
+ # number of path elements will return the root path.
811
+ #
812
+ # A number less than 0 will raise an ArgumentError.
813
+ #
814
+ # Example:
815
+ #
816
+ # path = Pathname.new('/usr/local/bin/ruby')
817
+ #
818
+ # puts path.dirname # => /usr/local/bin
819
+ # puts path.dirname(2) # => /usr/local
820
+ # puts path.dirname(3) # => /usr
821
+ # puts path.dirname(9) # => /
822
+ #
823
+ def dirname(level = 1)
824
+ raise ArgumentError if level < 0
825
+ local_path = self.dup
826
+
827
+ level.times{ |n| local_path = File.dirname(local_path) }
828
+ local_path
829
+ end
830
+
831
+ #-- Find facade
832
+
833
+ # Pathname#find is an iterator to traverse a directory tree in a depth first
834
+ # manner. It yields a Pathname for each file under the directory passed to
835
+ # Pathname.new.
836
+ #
837
+ # Since it is implemented by the Find module, Find.prune can be used to
838
+ # control the traverse.
839
+ #
840
+ # If +self+ is ".", yielded pathnames begin with a filename in the current
841
+ # current directory, not ".".
842
+ #
843
+ def find(&block)
844
+ require "find"
845
+ if self == "."
846
+ Find.find(self){ |f| yield self.class.new(f.sub(%r{\A\./}, '')) }
847
+ else
848
+ Find.find(self){ |f| yield self.class.new(f) }
849
+ end
850
+ end
851
+
852
+ #-- IO methods not handled by facade
853
+
854
+ # IO.foreach
855
+ def foreach(*args, &block)
856
+ IO.foreach(self, *args, &block)
857
+ end
858
+
859
+ # IO.read
860
+ def read(*args)
861
+ IO.read(self, *args)
862
+ end
863
+
864
+ # IO.readlines
865
+ def readlines(*args)
866
+ IO.readlines(self, *args)
867
+ end
868
+
869
+ # IO.sysopen
870
+ def sysopen(*args)
871
+ IO.sysopen(self, *args)
872
+ end
873
+
874
+ #-- Dir methods not handled by facade
875
+
876
+ # Dir.glob
877
+ #
878
+ # :no-doc:
879
+ # This differs from Tanaka's implementation in that it does a temporary
880
+ # chdir to the path in question, then performs the glob.
881
+ #
882
+ def glob(*args)
883
+ Dir.chdir(self){
884
+ if block_given?
885
+ Dir.glob(*args){ |file| yield self.class.new(file) }
845
886
  else
846
- Find.find(self){ |f| yield self.class.new(f) }
887
+ Dir.glob(*args).map{ |file| self.class.new(file) }
847
888
  end
848
- end
849
-
850
- #-- IO methods not handled by facade
851
-
852
- # IO.foreach
853
- def foreach(*args, &block)
854
- IO.foreach(self, *args, &block)
855
- end
856
-
857
- # IO.read
858
- def read(*args)
859
- IO.read(self, *args)
860
- end
861
-
862
- # IO.readlines
863
- def readlines(*args)
864
- IO.readlines(self, *args)
865
- end
866
-
867
- # IO.sysopen
868
- def sysopen(*args)
869
- IO.sysopen(self, *args)
870
- end
871
-
872
- #-- Dir methods not handled by facade
873
-
874
- # Dir.glob
875
- #
876
- # :no-doc:
877
- # This differs from Tanaka's implementation in that it does a temporary
878
- # chdir to the path in question, then performs the glob.
879
- #
880
- def glob(*args)
881
- Dir.chdir(self){
882
- if block_given?
883
- Dir.glob(*args){ |file| yield self.class.new(file) }
884
- else
885
- Dir.glob(*args).map{ |file| self.class.new(file) }
886
- end
887
- }
888
- end
889
-
890
- # Dir.chdir
891
- def chdir(&block)
892
- Dir.chdir(self, &block)
893
- end
894
-
895
- # Dir.entries
896
- def entries
897
- Dir.entries(self).map{ |file| self.class.new(file) }
898
- end
899
-
900
- # Dir.mkdir
901
- def mkdir(*args)
902
- Dir.mkdir(self, *args)
903
- end
904
-
905
- # Dir.opendir
906
- def opendir(&block)
907
- Dir.open(self, &block)
908
- end
909
-
910
- #-- File methods not handled by facade
911
-
912
- # File.chmod
913
- def chmod(mode)
914
- File.chmod(mode, self)
915
- end
916
-
917
- # File.lchmod
918
- def lchmod(mode)
919
- File.lchmod(mode, self)
920
- end
921
-
922
- # File.chown
923
- def chown(owner, group)
924
- File.chown(owner, group, self)
925
- end
926
-
927
- # File.lchown
928
- def lchown(owner, group)
929
- File.lchown(owner, group, self)
930
- end
931
-
932
- # File.fnmatch
933
- def fnmatch(pattern, *args)
934
- File.fnmatch(pattern, self, *args)
935
- end
936
-
937
- # File.fnmatch?
938
- def fnmatch?(pattern, *args)
939
- File.fnmatch?(pattern, self, *args)
940
- end
941
-
942
- # File.link
943
- def link(old)
944
- File.link(old, self)
945
- end
946
-
947
- # File.open
948
- def open(*args, &block)
949
- File.open(self, *args, &block)
950
- end
951
-
952
- # File.rename
953
- def rename(name)
954
- File.rename(self, name)
955
- end
956
-
957
- # File.symlink
958
- def symlink(old)
959
- File.symlink(old, self)
960
- end
961
-
962
- # File.truncate
963
- def truncate(length)
964
- File.truncate(self, length)
965
- end
966
-
967
- # File.utime
968
- def utime(atime, mtime)
969
- File.utime(atime, mtime, self)
970
- end
971
-
972
- # File.basename
973
- def basename(*args)
974
- File.basename(self, *args)
975
- end
976
-
977
- # File.expand_path
978
- def expand_path(*args)
979
- File.expand_path(self, *args)
980
- end
981
-
982
- # File.join
983
- def join(*args)
984
- File.join(self, *args)
985
- end
986
-
987
- #--
988
- # FileUtils facade. Note that methods already covered by File and Dir
989
- # are not defined here (pwd, mkdir, etc).
990
- #++
991
-
992
- # FileUtils.cd
993
- def cd(*args, &block)
994
- FileUtils.cd(self, *args, &block)
995
- end
996
-
997
- # FileUtils.mkdir_p
998
- def mkdir_p(*args)
999
- FileUtils.mkdir_p(self, *args)
1000
- end
1001
- alias mkpath mkdir_p
1002
-
1003
- # FileUtils.ln
1004
- def ln(*args)
1005
- FileUtils.ln(self, *args)
1006
- end
1007
-
1008
- # FileUtils.ln_s
1009
- def ln_s(*args)
1010
- FileUtils.ln_s(self, *args)
1011
- end
1012
-
1013
- # FileUtils.ln_sf
1014
- def ln_sf(*args)
1015
- FileUtils.ln_sf(self, *args)
1016
- end
1017
-
1018
- # FileUtils.cp
1019
- def cp(*args)
1020
- FileUtils.cp(self, *args)
1021
- end
1022
-
1023
- # FileUtils.cp_r
1024
- def cp_r(*args)
1025
- FileUtils.cp_r(self, *args)
1026
- end
1027
-
1028
- # FileUtils.mv
1029
- def mv(*args)
1030
- FileUtils.mv(self, *args)
1031
- end
889
+ }
890
+ end
891
+
892
+ # Dir.chdir
893
+ def chdir(&block)
894
+ Dir.chdir(self, &block)
895
+ end
896
+
897
+ # Dir.entries
898
+ def entries
899
+ Dir.entries(self).map{ |file| self.class.new(file) }
900
+ end
901
+
902
+ # Dir.mkdir
903
+ def mkdir(*args)
904
+ Dir.mkdir(self, *args)
905
+ end
906
+
907
+ # Dir.opendir
908
+ def opendir(&block)
909
+ Dir.open(self, &block)
910
+ end
911
+
912
+ #-- File methods not handled by facade
913
+
914
+ # File.chmod
915
+ def chmod(mode)
916
+ File.chmod(mode, self)
917
+ end
918
+
919
+ # File.lchmod
920
+ def lchmod(mode)
921
+ File.lchmod(mode, self)
922
+ end
923
+
924
+ # File.chown
925
+ def chown(owner, group)
926
+ File.chown(owner, group, self)
927
+ end
928
+
929
+ # File.lchown
930
+ def lchown(owner, group)
931
+ File.lchown(owner, group, self)
932
+ end
933
+
934
+ # File.fnmatch
935
+ def fnmatch(pattern, *args)
936
+ File.fnmatch(pattern, self, *args)
937
+ end
938
+
939
+ # File.fnmatch?
940
+ def fnmatch?(pattern, *args)
941
+ File.fnmatch?(pattern, self, *args)
942
+ end
943
+
944
+ # File.link
945
+ def link(old)
946
+ File.link(old, self)
947
+ end
948
+
949
+ # File.open
950
+ def open(*args, &block)
951
+ File.open(self, *args, &block)
952
+ end
953
+
954
+ # File.rename
955
+ def rename(name)
956
+ File.rename(self, name)
957
+ end
958
+
959
+ # File.symlink
960
+ def symlink(old)
961
+ File.symlink(old, self)
962
+ end
963
+
964
+ # File.truncate
965
+ def truncate(length)
966
+ File.truncate(self, length)
967
+ end
968
+
969
+ # File.utime
970
+ def utime(atime, mtime)
971
+ File.utime(atime, mtime, self)
972
+ end
973
+
974
+ # File.basename
975
+ def basename(*args)
976
+ File.basename(self, *args)
977
+ end
978
+
979
+ # File.expand_path
980
+ def expand_path(*args)
981
+ File.expand_path(self, *args)
982
+ end
983
+
984
+ # File.join
985
+ def join(*args)
986
+ File.join(self, *args)
987
+ end
988
+
989
+ #--
990
+ # FileUtils facade. Note that methods already covered by File and Dir
991
+ # are not defined here (pwd, mkdir, etc).
992
+ #++
993
+
994
+ # FileUtils.cd
995
+ def cd(*args, &block)
996
+ FileUtils.cd(self, *args, &block)
997
+ end
998
+
999
+ # FileUtils.mkdir_p
1000
+ def mkdir_p(*args)
1001
+ FileUtils.mkdir_p(self, *args)
1002
+ end
1003
+
1004
+ alias mkpath mkdir_p
1005
+
1006
+ # FileUtils.ln
1007
+ def ln(*args)
1008
+ FileUtils.ln(self, *args)
1009
+ end
1010
+
1011
+ # FileUtils.ln_s
1012
+ def ln_s(*args)
1013
+ FileUtils.ln_s(self, *args)
1014
+ end
1015
+
1016
+ # FileUtils.ln_sf
1017
+ def ln_sf(*args)
1018
+ FileUtils.ln_sf(self, *args)
1019
+ end
1020
+
1021
+ # FileUtils.cp
1022
+ def cp(*args)
1023
+ FileUtils.cp(self, *args)
1024
+ end
1025
+
1026
+ # FileUtils.cp_r
1027
+ def cp_r(*args)
1028
+ FileUtils.cp_r(self, *args)
1029
+ end
1030
+
1031
+ # FileUtils.mv
1032
+ def mv(*args)
1033
+ FileUtils.mv(self, *args)
1034
+ end
1032
1035
 
1033
1036
  # FileUtils.rm
1034
- def rm(*args)
1035
- FileUtils.rm(self, *args)
1036
- end
1037
- alias remove rm
1038
-
1039
- # FileUtils.rm_f
1040
- def rm_f(*args)
1041
- FileUtils.rm_f(self, *args)
1042
- end
1043
-
1044
- # FileUtils.rm_r
1045
- def rm_r(*args)
1046
- FileUtils.rm_r(self, *args)
1047
- end
1048
-
1049
- # FileUtils.rm_rf
1050
- def rm_rf(*args)
1051
- FileUtils.rm_rf(self, *args)
1052
- end
1053
-
1054
- # FileUtils.rmtree
1055
- def rmtree(*args)
1056
- FileUtils.rmtree(self, *args)
1057
- end
1058
-
1059
- # FileUtils.install
1060
- def install(*args)
1061
- FileUtils.install(self, *args)
1062
- end
1063
-
1064
- # FileUtils.touch
1065
- def touch(*args)
1066
- FileUtils.touch(*args)
1067
- end
1068
-
1069
- # FileUtils.compare_file
1070
- def compare_file(file)
1071
- FileUtils.compare_file(self, file)
1072
- end
1073
-
1074
- # FileUtils.uptodate?
1075
- def uptodate?(*args)
1076
- FileUtils.uptodate(self, *args)
1077
- end
1078
-
1079
- # FileUtils.copy_file
1080
- def copy_file(*args)
1081
- FileUtils.copy_file(self, *args)
1082
- end
1083
-
1084
- # FileUtils.remove_dir
1085
- def remove_dir(*args)
1086
- FileUtils.remove_dir(self, *args)
1087
- end
1088
-
1089
- # FileUtils.remove_file
1090
- def remove_file(*args)
1091
- FileUtils.remove_dir(self, *args)
1092
- end
1093
-
1094
- # FileUtils.copy_entry
1095
- def copy_entry(*args)
1096
- FileUtils.copy_entry(self, *args)
1097
- end
1037
+ def rm(*args)
1038
+ FileUtils.rm(self, *args)
1039
+ end
1040
+
1041
+ alias remove rm
1042
+
1043
+ # FileUtils.rm_f
1044
+ def rm_f(*args)
1045
+ FileUtils.rm_f(self, *args)
1046
+ end
1047
+
1048
+ # FileUtils.rm_r
1049
+ def rm_r(*args)
1050
+ FileUtils.rm_r(self, *args)
1051
+ end
1052
+
1053
+ # FileUtils.rm_rf
1054
+ def rm_rf(*args)
1055
+ FileUtils.rm_rf(self, *args)
1056
+ end
1057
+
1058
+ # FileUtils.rmtree
1059
+ def rmtree(*args)
1060
+ FileUtils.rmtree(self, *args)
1061
+ end
1062
+
1063
+ # FileUtils.install
1064
+ def install(*args)
1065
+ FileUtils.install(self, *args)
1066
+ end
1067
+
1068
+ # FileUtils.touch
1069
+ def touch(*args)
1070
+ FileUtils.touch(*args)
1071
+ end
1072
+
1073
+ # FileUtils.compare_file
1074
+ def compare_file(file)
1075
+ FileUtils.compare_file(self, file)
1076
+ end
1077
+
1078
+ # FileUtils.uptodate?
1079
+ def uptodate?(*args)
1080
+ FileUtils.uptodate(self, *args)
1081
+ end
1082
+
1083
+ # FileUtils.copy_file
1084
+ def copy_file(*args)
1085
+ FileUtils.copy_file(self, *args)
1086
+ end
1087
+
1088
+ # FileUtils.remove_dir
1089
+ def remove_dir(*args)
1090
+ FileUtils.remove_dir(self, *args)
1091
+ end
1092
+
1093
+ # FileUtils.remove_file
1094
+ def remove_file(*args)
1095
+ FileUtils.remove_dir(self, *args)
1096
+ end
1097
+
1098
+ # FileUtils.copy_entry
1099
+ def copy_entry(*args)
1100
+ FileUtils.copy_entry(self, *args)
1101
+ end
1098
1102
  end
1099
1103
 
1100
1104
  module Kernel
1101
- # Usage: pn{ path }
1102
- #
1103
- # A shortcut for Pathname.new
1104
- #
1105
- def pn
1106
- instance_eval{ Pathname.new(yield) }
1107
- end
1105
+ # Usage: pn{ path }
1106
+ #
1107
+ # A shortcut for Pathname.new
1108
+ #
1109
+ def pn
1110
+ instance_eval{ Pathname.new(yield) }
1111
+ end
1112
+
1113
+ begin
1114
+ remove_method(:Pathname)
1115
+ rescue NoMethodError, NameError
1116
+ # Do nothing, not defined.
1117
+ end
1118
+
1119
+ # Synonym for Pathname.new
1120
+ #
1121
+ def Pathname(path)
1122
+ Pathname.new(path)
1123
+ end
1108
1124
  end