pathname2 1.6.3 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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