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 +9 -0
- data/README +66 -76
- data/Rakefile +43 -41
- data/lib/pathname2.rb +1041 -1025
- data/pathname2.gemspec +32 -32
- data/test/test_pathname.rb +466 -470
- data/test/test_pathname_windows.rb +663 -651
- metadata +39 -15
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
|
-
|
2
|
+
A drop-in replacement for the current Pathname class.
|
3
3
|
|
4
4
|
== Prerequisites
|
5
|
-
|
6
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
13
|
+
require 'pathname2'
|
26
14
|
|
27
|
-
|
28
|
-
|
29
|
-
|
15
|
+
# Unix
|
16
|
+
path1 = "/foo/bar/baz"
|
17
|
+
path2 = "../zap"
|
30
18
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
25
|
+
# Windows
|
26
|
+
path1 = "C:/foo/bar/baz"
|
27
|
+
path2 = "../zap"
|
40
28
|
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
34
|
+
All forward slashes are converted to backslashes for Pathname objects.
|
47
35
|
|
48
36
|
== Differences between Unix and Windows
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
76
|
-
|
63
|
+
Because there is some overlap in method names between File, Dir, and
|
64
|
+
FileUtils, the priority is as follows:
|
77
65
|
|
78
|
-
|
79
|
-
|
80
|
-
|
66
|
+
* File
|
67
|
+
* Dir
|
68
|
+
* FileUtils
|
81
69
|
|
82
|
-
|
83
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
91
|
-
|
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
|
-
|
84
|
+
Suggestions welcome.
|
95
85
|
|
96
86
|
== License
|
97
|
-
|
87
|
+
Artistic 2.0
|
98
88
|
|
99
89
|
== Copyright
|
100
|
-
|
101
|
-
|
90
|
+
(C) 2003-2011 Daniel J. Berger
|
91
|
+
All rights reserved.
|
102
92
|
|
103
93
|
== Warranty
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
-
|
99
|
+
Daniel J. Berger
|
data/Rakefile
CHANGED
@@ -1,41 +1,43 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/clean'
|
3
|
-
require 'rake/testtask'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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-
|
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
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
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
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
309
|
-
strip!
|
310
|
-
chop!
|
311
|
-
end
|
370
|
+
path = to_a[index]
|
312
371
|
end
|
313
|
-
|
314
|
-
|
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
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
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
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
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
|
-
|
415
|
-
|
416
|
-
yield root if absolute?
|
417
|
-
end
|
465
|
+
path = self.class.new(path)
|
466
|
+
yield path
|
418
467
|
|
419
|
-
|
420
|
-
|
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
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
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
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
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
|
-
|
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
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
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
|
-
|
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
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
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
|
-
|
633
|
-
|
634
|
-
|
635
|
-
base_arr.delete('.')
|
762
|
+
final = final.join(@sep)
|
763
|
+
final = root._plus_(final) if root != "."
|
764
|
+
final = "." if final.empty?
|
636
765
|
|
637
|
-
|
766
|
+
self.class.new(final)
|
767
|
+
end
|
638
768
|
|
639
|
-
|
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
|
-
|
649
|
-
|
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
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
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
|
-
|
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
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
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
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
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
|
-
|
887
|
+
Dir.glob(*args).map{ |file| self.class.new(file) }
|
847
888
|
end
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
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
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
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
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
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
|