fakefs 0.13.3 → 0.14.0
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.
- checksums.yaml +4 -4
- data/lib/fakefs/base.rb +6 -8
- data/lib/fakefs/dir.rb +69 -74
- data/lib/fakefs/fake/dir.rb +2 -2
- data/lib/fakefs/fake/file.rb +3 -6
- data/lib/fakefs/fake/symlink.rb +2 -2
- data/lib/fakefs/file.rb +129 -138
- data/lib/fakefs/file_system.rb +26 -26
- data/lib/fakefs/fileutils.rb +55 -59
- data/lib/fakefs/globber.rb +11 -9
- data/lib/fakefs/kernel.rb +1 -2
- data/lib/fakefs/pathname.rb +882 -879
- data/lib/fakefs/safe.rb +1 -1
- data/lib/fakefs/version.rb +1 -1
- metadata +25 -25
data/lib/fakefs/file_system.rb
CHANGED
@@ -87,7 +87,7 @@ module FakeFS
|
|
87
87
|
new_dir = find(dir)
|
88
88
|
dir_levels.push dir if blk
|
89
89
|
|
90
|
-
|
90
|
+
raise Errno::ENOENT, dir unless new_dir
|
91
91
|
|
92
92
|
dir_levels.push dir unless blk
|
93
93
|
yield(dir) if blk
|
@@ -118,30 +118,30 @@ module FakeFS
|
|
118
118
|
|
119
119
|
def find_recurser(dir, parts)
|
120
120
|
return [] unless dir.respond_to? :[]
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
121
|
+
pattern, *parts = parts # rubocop:disable Lint/ShadowedArgument
|
122
|
+
matches =
|
123
|
+
case pattern
|
124
|
+
when '**'
|
125
|
+
case parts
|
126
|
+
when ['*']
|
127
|
+
parts = [] # end recursion
|
128
|
+
directories_under(dir).map do |d|
|
129
|
+
d.entries.select do |f|
|
130
|
+
(f.is_a?(FakeFile) || f.is_a?(FakeDir)) &&
|
131
|
+
f.name.match(/\A(?!\.)/)
|
132
|
+
end
|
133
|
+
end.flatten.uniq
|
134
|
+
when []
|
135
|
+
parts = [] # end recursion
|
136
|
+
dir.entries.flatten.uniq
|
137
|
+
else
|
138
|
+
directories_under(dir)
|
139
|
+
end
|
140
|
+
else
|
141
|
+
Globber.expand(pattern).flat_map do |subpattern|
|
142
|
+
dir.matches(Globber.regexp(subpattern))
|
143
|
+
end
|
144
|
+
end
|
145
145
|
|
146
146
|
if parts.empty? # we're done recursing
|
147
147
|
matches
|
@@ -157,7 +157,7 @@ module FakeFS
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def assert_dir(dir)
|
160
|
-
|
160
|
+
raise Errno::EEXIST, dir.name unless dir.is_a?(FakeDir)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
end
|
data/lib/fakefs/fileutils.rb
CHANGED
@@ -28,18 +28,18 @@ module FakeFS
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
alias mkpath mkdir_p
|
32
|
+
alias makedirs mkdir_p
|
33
33
|
|
34
34
|
def mkdir(list, _ignored_options = {})
|
35
35
|
list = [list] unless list.is_a?(Array)
|
36
36
|
list.each do |path|
|
37
37
|
parent = path.split('/')
|
38
38
|
parent.pop
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
unless parent.join == '' || parent.join == '.' || FileSystem.find(parent.join('/'))
|
40
|
+
raise Errno::ENOENT, path
|
41
|
+
end
|
42
|
+
raise Errno::EEXIST, path if FileSystem.find(path)
|
43
43
|
FileSystem.add(path, FakeDir.new)
|
44
44
|
end
|
45
45
|
end
|
@@ -49,10 +49,9 @@ module FakeFS
|
|
49
49
|
list.each do |l|
|
50
50
|
parent = l.split('/')
|
51
51
|
parent.pop
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
fail Errno::ENOTEMPTY, l unless FileSystem.find(l).empty?
|
52
|
+
raise Errno::ENOENT, l unless parent.join == '' || FileSystem.find(parent.join('/'))
|
53
|
+
raise Errno::ENOENT, l unless FileSystem.find(l)
|
54
|
+
raise Errno::ENOTEMPTY, l unless FileSystem.find(l).empty?
|
56
55
|
rm(l)
|
57
56
|
end
|
58
57
|
end
|
@@ -60,11 +59,11 @@ module FakeFS
|
|
60
59
|
def rm(list, options = {})
|
61
60
|
Array(list).each do |path|
|
62
61
|
FileSystem.delete(path) ||
|
63
|
-
(!options[:force] &&
|
62
|
+
(!options[:force] && raise(Errno::ENOENT, path))
|
64
63
|
end
|
65
64
|
end
|
66
|
-
|
67
|
-
|
65
|
+
alias rm_r rm
|
66
|
+
alias remove rm
|
68
67
|
|
69
68
|
def rm_f(list, options = {})
|
70
69
|
rm(list, options.merge(force: true))
|
@@ -73,17 +72,17 @@ module FakeFS
|
|
73
72
|
def rm_rf(list, options = {})
|
74
73
|
rm_r(list, options.merge(force: true))
|
75
74
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
alias rmtree rm_rf
|
76
|
+
alias safe_unlink rm_f
|
77
|
+
alias remove_entry_secure rm_rf
|
79
78
|
|
80
79
|
def ln_s(target, path, options = {})
|
81
80
|
options = { force: false }.merge(options)
|
82
|
-
|
81
|
+
raise(Errno::EEXIST, path) if FileSystem.find(path) && !options[:force]
|
83
82
|
FileSystem.delete(path)
|
84
83
|
|
85
84
|
if !options[:force] && !Dir.exist?(File.dirname(path))
|
86
|
-
|
85
|
+
raise Errno::ENOENT, path
|
87
86
|
end
|
88
87
|
|
89
88
|
FileSystem.add(path, FakeSymlink.new(target))
|
@@ -93,10 +92,10 @@ module FakeFS
|
|
93
92
|
ln_s(target, path, force: true)
|
94
93
|
end
|
95
94
|
|
96
|
-
|
95
|
+
alias symlink ln_s
|
97
96
|
|
98
97
|
def cp(src, dest, options = {})
|
99
|
-
|
98
|
+
raise Errno::ENOTDIR, dest if src.is_a?(Array) && !File.directory?(dest)
|
100
99
|
|
101
100
|
# handle `verbose' flag
|
102
101
|
RealFileUtils.cp src, dest, options.merge(noop: true)
|
@@ -108,12 +107,12 @@ module FakeFS
|
|
108
107
|
dst_file = FileSystem.find(dest)
|
109
108
|
src_file = FileSystem.find(source)
|
110
109
|
|
111
|
-
|
110
|
+
raise Errno::ENOENT, source unless src_file
|
112
111
|
|
113
112
|
if dst_file && File.directory?(dst_file)
|
114
113
|
FileSystem.add(
|
115
|
-
File.join(
|
116
|
-
|
114
|
+
File.join(dest, File.basename(source)), src_file.entry.clone(dst_file)
|
115
|
+
)
|
117
116
|
else
|
118
117
|
FileSystem.delete(dest)
|
119
118
|
FileSystem.add(dest, src_file.entry.clone)
|
@@ -123,7 +122,7 @@ module FakeFS
|
|
123
122
|
nil
|
124
123
|
end
|
125
124
|
|
126
|
-
|
125
|
+
alias copy cp
|
127
126
|
|
128
127
|
def copy_file(src, dest, _preserve = false, _dereference = true)
|
129
128
|
# Not a perfect match, but similar to what regular FileUtils does.
|
@@ -131,10 +130,12 @@ module FakeFS
|
|
131
130
|
end
|
132
131
|
|
133
132
|
def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
|
134
|
-
cp_r(
|
135
|
-
|
136
|
-
|
137
|
-
|
133
|
+
cp_r(
|
134
|
+
src, dest,
|
135
|
+
preserve: preserve,
|
136
|
+
dereference_root: dereference_root,
|
137
|
+
remove_destination: remove_destination
|
138
|
+
)
|
138
139
|
end
|
139
140
|
|
140
141
|
def cp_r(src, dest, options = {})
|
@@ -146,19 +147,11 @@ module FakeFS
|
|
146
147
|
|
147
148
|
Array(src).each do |source|
|
148
149
|
dir = FileSystem.find(source)
|
149
|
-
unless dir
|
150
|
-
if RUBY_VERSION >= '1.9.1'
|
151
|
-
fail Errno::ENOENT, source
|
152
|
-
else
|
153
|
-
# This error sucks, but it conforms to the original Ruby
|
154
|
-
# method.
|
155
|
-
fail "unknown file type: #{source}"
|
156
|
-
end
|
157
|
-
end
|
150
|
+
raise Errno::ENOENT, source unless dir
|
158
151
|
|
159
152
|
new_dir = FileSystem.find(dest)
|
160
|
-
|
161
|
-
|
153
|
+
raise Errno::EEXIST, dest if new_dir && !File.directory?(dest)
|
154
|
+
raise Errno::ENOENT, dest if !new_dir && !FileSystem.find(dest + '/../')
|
162
155
|
|
163
156
|
# This last bit is a total abuse and should be thought hard
|
164
157
|
# about and cleaned up.
|
@@ -185,43 +178,46 @@ module FakeFS
|
|
185
178
|
|
186
179
|
Array(src).each do |path|
|
187
180
|
if (target = FileSystem.find(path))
|
188
|
-
dest_path =
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
181
|
+
dest_path =
|
182
|
+
if File.directory?(dest)
|
183
|
+
File.join(dest, File.basename(path))
|
184
|
+
else
|
185
|
+
dest
|
186
|
+
end
|
193
187
|
if File.directory?(dest_path)
|
194
|
-
|
188
|
+
raise Errno::EEXIST, dest_path unless options[:force]
|
195
189
|
elsif File.directory?(File.dirname(dest_path))
|
196
190
|
FileSystem.delete(dest_path)
|
197
191
|
FileSystem.add(dest_path, target.entry.clone)
|
198
192
|
FileSystem.delete(path)
|
199
193
|
else
|
200
|
-
|
194
|
+
raise Errno::ENOENT, dest_path unless options[:force]
|
201
195
|
end
|
202
196
|
else
|
203
|
-
|
197
|
+
raise Errno::ENOENT, path
|
204
198
|
end
|
205
199
|
end
|
206
200
|
|
207
201
|
nil
|
208
202
|
end
|
209
203
|
|
210
|
-
|
204
|
+
alias move mv
|
211
205
|
|
212
206
|
def chown(user, group, list, _options = {})
|
213
207
|
list = Array(list)
|
214
208
|
list.each do |f|
|
215
209
|
if File.exist?(f)
|
216
|
-
uid =
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
210
|
+
uid =
|
211
|
+
if user
|
212
|
+
user.to_s =~ /\d+/ ? user.to_i : Etc.getpwnam(user).uid
|
213
|
+
end
|
214
|
+
gid =
|
215
|
+
if group
|
216
|
+
group.to_s =~ /\d+/ ? group.to_i : Etc.getgrnam(group).gid
|
217
|
+
end
|
222
218
|
File.chown(uid, gid, f)
|
223
219
|
else
|
224
|
-
|
220
|
+
raise Errno::ENOENT, f
|
225
221
|
end
|
226
222
|
end
|
227
223
|
list
|
@@ -244,7 +240,7 @@ module FakeFS
|
|
244
240
|
if File.exist?(f)
|
245
241
|
File.chmod(mode, f)
|
246
242
|
else
|
247
|
-
|
243
|
+
raise Errno::ENOENT, f
|
248
244
|
end
|
249
245
|
end
|
250
246
|
list
|
@@ -282,15 +278,15 @@ module FakeFS
|
|
282
278
|
def cd(dir, &block)
|
283
279
|
FileSystem.chdir(dir, &block)
|
284
280
|
end
|
285
|
-
|
281
|
+
alias chdir cd
|
286
282
|
|
287
283
|
def compare_file(file1, file2)
|
288
284
|
# we do a strict comparison of both files content
|
289
285
|
File.readlines(file1) == File.readlines(file2)
|
290
286
|
end
|
291
287
|
|
292
|
-
|
293
|
-
|
288
|
+
alias cmp compare_file
|
289
|
+
alias identical? compare_file
|
294
290
|
|
295
291
|
def uptodate?(new, old_list)
|
296
292
|
return false unless File.exist?(new)
|
data/lib/fakefs/globber.rb
CHANGED
@@ -15,7 +15,7 @@ module FakeFS
|
|
15
15
|
case level
|
16
16
|
when 0
|
17
17
|
case chr
|
18
|
-
when '{'
|
18
|
+
when '{' # rubocop:disable Lint/EmptyWhen
|
19
19
|
# noop
|
20
20
|
else
|
21
21
|
part << chr
|
@@ -25,7 +25,7 @@ module FakeFS
|
|
25
25
|
when ','
|
26
26
|
result << part
|
27
27
|
part = ''
|
28
|
-
when '}'
|
28
|
+
when '}' # rubocop:disable Lint/EmptyWhen
|
29
29
|
# noop
|
30
30
|
else
|
31
31
|
part << chr
|
@@ -63,13 +63,15 @@ module FakeFS
|
|
63
63
|
def regexp(pattern)
|
64
64
|
pattern = pattern.to_s
|
65
65
|
|
66
|
-
regex_body =
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
regex_body =
|
67
|
+
pattern
|
68
|
+
.gsub('.', '\.')
|
69
|
+
.gsub('+') { '\+' }
|
70
|
+
.gsub('?', '.')
|
71
|
+
.gsub('*', '.*')
|
72
|
+
.gsub('(', '\(')
|
73
|
+
.gsub(')', '\)')
|
74
|
+
.gsub('$', '\$')
|
73
75
|
|
74
76
|
# This matches nested braces and attempts to do something correct most of the time
|
75
77
|
# There are known issues (i.e. {,*,*/*}) that cannot be resolved with out a total
|
data/lib/fakefs/kernel.rb
CHANGED
data/lib/fakefs/pathname.rb
CHANGED
@@ -1,1049 +1,1052 @@
|
|
1
1
|
# FakeFS module
|
2
2
|
module FakeFS
|
3
|
-
|
3
|
+
#
|
4
|
+
# = pathname.rb - From MRI 1.9.2
|
5
|
+
#
|
6
|
+
# Object-Oriented Pathname Class
|
7
|
+
#
|
8
|
+
# Author:: Tanaka Akira <akr@m17n.org>
|
9
|
+
# Documentation:: Author and Gavin Sinclair
|
10
|
+
#
|
11
|
+
# For documentation, see class Pathname.
|
12
|
+
#
|
13
|
+
class Pathname
|
14
|
+
# to_path is implemented so Pathname objects are
|
15
|
+
# usable with File.open, etc.
|
16
|
+
TO_PATH = :to_path
|
17
|
+
|
18
|
+
SAME_PATHS =
|
19
|
+
if File::FNM_SYSCASE.nonzero?
|
20
|
+
proc { |a, b| a.casecmp(b).zero? }
|
21
|
+
else
|
22
|
+
proc { |a, b| a == b }
|
23
|
+
end
|
24
|
+
|
25
|
+
# :startdoc:
|
4
26
|
|
5
27
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# Author:: Tanaka Akira <akr@m17n.org>
|
11
|
-
# Documentation:: Author and Gavin Sinclair
|
12
|
-
#
|
13
|
-
# For documentation, see class Pathname.
|
28
|
+
# Create a Pathname object from the given String (or String-like object).
|
29
|
+
# If +path+ contains a NUL character (<tt>\0</tt>),
|
30
|
+
# an ArgumentError is raised.
|
14
31
|
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
TO_PATH = :to_path
|
19
|
-
|
20
|
-
SAME_PATHS =
|
21
|
-
if File::FNM_SYSCASE.nonzero?
|
22
|
-
proc { |a, b| a.casecmp(b).zero? }
|
23
|
-
else
|
24
|
-
proc { |a, b| a == b }
|
25
|
-
end
|
26
|
-
|
27
|
-
# :startdoc:
|
32
|
+
def initialize(path)
|
33
|
+
path = path.__send__(TO_PATH) if path.respond_to? TO_PATH
|
34
|
+
@path = path.dup
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
# If +path+ contains a NUL character (<tt>\0</tt>),
|
32
|
-
# an ArgumentError is raised.
|
33
|
-
#
|
34
|
-
def initialize(path)
|
35
|
-
path = path.__send__(TO_PATH) if path.respond_to? TO_PATH
|
36
|
-
@path = path.dup
|
37
|
-
|
38
|
-
if /\0/ =~ @path
|
39
|
-
fail ArgumentError, "pathname contains \\0: #{@path.inspect}"
|
40
|
-
end
|
41
|
-
|
42
|
-
taint if @path.tainted?
|
36
|
+
if /\0/ =~ @path
|
37
|
+
raise ArgumentError, "pathname contains \\0: #{@path.inspect}"
|
43
38
|
end
|
44
39
|
|
45
|
-
|
46
|
-
|
47
|
-
@path.freeze
|
48
|
-
self
|
49
|
-
end
|
40
|
+
taint if @path.tainted?
|
41
|
+
end
|
50
42
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
43
|
+
def freeze
|
44
|
+
super
|
45
|
+
@path.freeze
|
46
|
+
self
|
47
|
+
end
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
49
|
+
def taint
|
50
|
+
super
|
51
|
+
@path.taint
|
52
|
+
self
|
53
|
+
end
|
62
54
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
def ==(other)
|
69
|
-
return false unless other.is_a?(Pathname)
|
70
|
-
other.to_s == @path
|
71
|
-
end
|
55
|
+
def untaint
|
56
|
+
super
|
57
|
+
@path.untaint
|
58
|
+
self
|
59
|
+
end
|
72
60
|
|
73
|
-
|
74
|
-
|
61
|
+
#
|
62
|
+
# Compare this pathname with +other+. The comparison is string-based.
|
63
|
+
# Be aware that two different paths
|
64
|
+
# (<tt>foo.txt</tt> and <tt>./foo.txt</tt>) can refer to the same file.
|
65
|
+
#
|
66
|
+
def ==(other)
|
67
|
+
return false unless other.is_a?(Pathname)
|
68
|
+
other.to_s == @path
|
69
|
+
end
|
75
70
|
|
76
|
-
|
77
|
-
|
78
|
-
return nil unless other.is_a?(Pathname)
|
79
|
-
@path.tr('/', "\0") <=> other.to_s.tr('/', "\0")
|
80
|
-
end
|
71
|
+
alias === ==
|
72
|
+
alias eql? ==
|
81
73
|
|
82
|
-
|
83
|
-
|
84
|
-
|
74
|
+
# Provides for comparing pathnames, case-sensitively.
|
75
|
+
def <=>(other)
|
76
|
+
return nil unless other.is_a?(Pathname)
|
77
|
+
@path.tr('/', "\0") <=> other.to_s.tr('/', "\0")
|
78
|
+
end
|
85
79
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
80
|
+
def hash # :nodoc:
|
81
|
+
@path.hash
|
82
|
+
end
|
90
83
|
|
91
|
-
|
92
|
-
|
93
|
-
|
84
|
+
# Return the path as a String.
|
85
|
+
def to_s
|
86
|
+
@path.dup
|
87
|
+
end
|
94
88
|
|
95
|
-
|
96
|
-
|
97
|
-
|
89
|
+
# to_path is implemented so Pathname objects are usable
|
90
|
+
# with File.open, etc.
|
91
|
+
alias_method TO_PATH, :to_s
|
92
|
+
|
93
|
+
def inspect # :nodoc:
|
94
|
+
"#<#{self.class}:#{@path}>"
|
95
|
+
end
|
98
96
|
|
99
|
-
|
100
|
-
|
97
|
+
# Return a pathname which is substituted by String#sub.
|
98
|
+
def sub(pattern, *rest, &block)
|
99
|
+
path =
|
101
100
|
if block
|
102
|
-
|
101
|
+
@path.sub(pattern, *rest) do |*args|
|
103
102
|
begin
|
104
103
|
old = Thread.current[:pathname_sub_matchdata]
|
105
|
-
Thread.current[:pathname_sub_matchdata] =
|
106
|
-
|
107
|
-
|
104
|
+
Thread.current[:pathname_sub_matchdata] = $~
|
105
|
+
# TODO: rewrite without using eval
|
106
|
+
eval(
|
107
|
+
'$~ = Thread.current[:pathname_sub_matchdata]',
|
108
|
+
block.binding,
|
109
|
+
__FILE__,
|
110
|
+
__LINE__ - 3
|
111
|
+
)
|
108
112
|
ensure
|
109
113
|
Thread.current[:pathname_sub_matchdata] = old
|
110
114
|
end
|
111
115
|
yield(*args)
|
112
116
|
end
|
113
117
|
else
|
114
|
-
|
118
|
+
@path.sub(pattern, *rest)
|
115
119
|
end
|
116
|
-
|
117
|
-
|
120
|
+
self.class.new(path)
|
121
|
+
end
|
118
122
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
if File::ALT_SEPARATOR
|
124
|
+
SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}" \
|
125
|
+
"#{Regexp.quote File::SEPARATOR}".freeze
|
126
|
+
SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
|
127
|
+
else
|
128
|
+
SEPARATOR_LIST = (Regexp.quote File::SEPARATOR).to_s.freeze
|
129
|
+
SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
|
130
|
+
end
|
127
131
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
# Return a pathname which the extension of the basename is substituted by
|
133
|
+
# <i>repl</i>.
|
134
|
+
#
|
135
|
+
# If self has no extension part, <i>repl</i> is appended.
|
136
|
+
def sub_ext(repl)
|
137
|
+
ext = File.extname(@path)
|
138
|
+
self.class.new(@path.chomp(ext) + repl)
|
139
|
+
end
|
136
140
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
141
|
+
# chop_basename(path) -> [pre-basename, basename] or nil
|
142
|
+
def chop_basename(path)
|
143
|
+
base = File.basename(path)
|
144
|
+
if /\A#{SEPARATOR_PAT}?\z/o =~ base
|
145
|
+
return nil
|
146
|
+
else
|
147
|
+
return path[0, path.rindex(base)], base
|
145
148
|
end
|
146
|
-
|
147
|
-
|
148
|
-
# split_names(path) -> prefix, [name, ...]
|
149
|
-
def split_names(path)
|
150
|
-
names = []
|
151
|
-
while (r = chop_basename(path))
|
152
|
-
path, basename = r
|
153
|
-
names.unshift basename
|
154
|
-
end
|
149
|
+
end
|
150
|
+
private :chop_basename
|
155
151
|
|
156
|
-
|
152
|
+
# split_names(path) -> prefix, [name, ...]
|
153
|
+
def split_names(path)
|
154
|
+
names = []
|
155
|
+
while (r = chop_basename(path))
|
156
|
+
path, basename = r
|
157
|
+
names.unshift basename
|
157
158
|
end
|
158
159
|
|
159
|
-
|
160
|
+
[path, names]
|
161
|
+
end
|
160
162
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
163
|
+
private :split_names
|
164
|
+
|
165
|
+
def prepend_prefix(prefix, relpath)
|
166
|
+
if relpath.empty?
|
167
|
+
File.dirname(prefix)
|
168
|
+
elsif /#{SEPARATOR_PAT}/o =~ prefix
|
169
|
+
prefix = File.dirname(prefix)
|
170
|
+
prefix = File.join(prefix, '') if File.basename(prefix + 'a') != 'a'
|
171
|
+
prefix + relpath
|
172
|
+
else
|
173
|
+
prefix + relpath
|
171
174
|
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
175
|
+
end
|
176
|
+
private :prepend_prefix
|
177
|
+
|
178
|
+
# Returns clean pathname of +self+ with consecutive slashes and
|
179
|
+
# useless dots removed. The filesystem is not accessed.
|
180
|
+
#
|
181
|
+
# If +consider_symlink+ is +true+, then a more conservative algorithm
|
182
|
+
# is used to avoid breaking symbolic linkages.
|
183
|
+
# This may retain more <tt>..</tt> entries than absolutely necessary,
|
184
|
+
# but without accessing the filesystem, this can't be avoided.
|
185
|
+
# See #realpath.
|
186
|
+
#
|
187
|
+
def cleanpath(consider_symlink = false)
|
188
|
+
if consider_symlink
|
189
|
+
cleanpath_conservative
|
190
|
+
else
|
191
|
+
cleanpath_aggressive
|
189
192
|
end
|
193
|
+
end
|
190
194
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
195
|
+
#
|
196
|
+
# Clean the path simply by resolving and removing excess
|
197
|
+
# "." and ".." entries.
|
198
|
+
# Nothing more, nothing less.
|
199
|
+
#
|
200
|
+
def cleanpath_aggressive
|
201
|
+
path = @path
|
202
|
+
names = []
|
203
|
+
pre = path
|
204
|
+
while (r = chop_basename(pre))
|
205
|
+
pre, base = r
|
206
|
+
case base
|
207
|
+
when '.' # rubocop:disable Lint/EmptyWhen
|
208
|
+
when '..'
|
209
|
+
names.unshift base
|
210
|
+
else
|
211
|
+
if names[0] == '..'
|
212
|
+
names.shift
|
206
213
|
else
|
207
|
-
|
208
|
-
names.shift
|
209
|
-
else
|
210
|
-
names.unshift base
|
211
|
-
end
|
214
|
+
names.unshift base
|
212
215
|
end
|
213
216
|
end
|
214
|
-
if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
|
215
|
-
names.shift while names[0] == '..'
|
216
|
-
end
|
217
|
-
self.class.new(prepend_prefix(pre, File.join(*names)))
|
218
217
|
end
|
219
|
-
|
218
|
+
if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
|
219
|
+
names.shift while names[0] == '..'
|
220
|
+
end
|
221
|
+
self.class.new(prepend_prefix(pre, File.join(*names)))
|
222
|
+
end
|
223
|
+
private :cleanpath_aggressive
|
220
224
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
end
|
225
|
+
# trailing_separator?(path) -> bool
|
226
|
+
def trailing_separator?(path)
|
227
|
+
if (r = chop_basename(path))
|
228
|
+
pre, basename = r
|
229
|
+
pre.length + basename.length < path.length
|
230
|
+
else
|
231
|
+
false
|
229
232
|
end
|
233
|
+
end
|
230
234
|
|
231
|
-
|
235
|
+
private :trailing_separator?
|
232
236
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
end
|
237
|
+
# add_trailing_separator(path) -> path
|
238
|
+
def add_trailing_separator(path)
|
239
|
+
if File.basename(path + 'a') == 'a'
|
240
|
+
path
|
241
|
+
else
|
242
|
+
# xxx: Is File.join is appropriate to add separator?
|
243
|
+
File.join(path, '')
|
241
244
|
end
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
245
|
+
end
|
246
|
+
private :add_trailing_separator
|
247
|
+
|
248
|
+
def del_trailing_separator(path)
|
249
|
+
if (r = chop_basename(path))
|
250
|
+
pre, basename = r
|
251
|
+
pre + basename
|
252
|
+
elsif /#{SEPARATOR_PAT}+\z/o =~ path
|
253
|
+
$` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
|
254
|
+
else
|
255
|
+
path
|
253
256
|
end
|
254
|
-
|
255
|
-
|
256
|
-
def cleanpath_conservative
|
257
|
-
path = @path
|
258
|
-
names = []
|
259
|
-
pre = path
|
260
|
-
while (r = chop_basename(pre))
|
261
|
-
pre, base = r
|
262
|
-
names.unshift base if base != '.'
|
263
|
-
end
|
264
|
-
if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
|
265
|
-
names.shift while names[0] == '..'
|
266
|
-
end
|
267
|
-
if names.empty?
|
268
|
-
self.class.new(File.dirname(pre))
|
269
|
-
else
|
270
|
-
names << '.' if names.last != '..' && File.basename(path) == '.'
|
257
|
+
end
|
258
|
+
private :del_trailing_separator
|
271
259
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
260
|
+
def cleanpath_conservative
|
261
|
+
path = @path
|
262
|
+
names = []
|
263
|
+
pre = path
|
264
|
+
while (r = chop_basename(pre))
|
265
|
+
pre, base = r
|
266
|
+
names.unshift base if base != '.'
|
279
267
|
end
|
280
|
-
|
281
|
-
|
282
|
-
#
|
283
|
-
# Returns the real (absolute) pathname of +self+ in the actual
|
284
|
-
# filesystem not containing symlinks or useless dots.
|
285
|
-
#
|
286
|
-
# All components of the pathname must exist when this method is
|
287
|
-
# called.
|
288
|
-
#
|
289
|
-
def realpath(basedir = nil)
|
290
|
-
self.class.new(File.realpath(@path, basedir))
|
268
|
+
if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
|
269
|
+
names.shift while names[0] == '..'
|
291
270
|
end
|
271
|
+
if names.empty?
|
272
|
+
self.class.new(File.dirname(pre))
|
273
|
+
else
|
274
|
+
names << '.' if names.last != '..' && File.basename(path) == '.'
|
292
275
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
def realdirpath(basedir = nil)
|
300
|
-
self.class.new(File.realdirpath(@path, basedir))
|
276
|
+
result = prepend_prefix(pre, File.join(*names))
|
277
|
+
if /\A(?:\.|\.\.)\z/ !~ names.last && trailing_separator?(path)
|
278
|
+
self.class.new(add_trailing_separator(result))
|
279
|
+
else
|
280
|
+
self.class.new(result)
|
281
|
+
end
|
301
282
|
end
|
283
|
+
end
|
284
|
+
private :cleanpath_conservative
|
302
285
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
286
|
+
#
|
287
|
+
# Returns the real (absolute) pathname of +self+ in the actual
|
288
|
+
# filesystem not containing symlinks or useless dots.
|
289
|
+
#
|
290
|
+
# All components of the pathname must exist when this method is
|
291
|
+
# called.
|
292
|
+
#
|
293
|
+
def realpath(basedir = nil)
|
294
|
+
self.class.new(File.realpath(@path, basedir))
|
295
|
+
end
|
309
296
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
end
|
320
|
-
end
|
297
|
+
#
|
298
|
+
# Returns the real (absolute) pathname of +self+ in the actual filesystem.
|
299
|
+
# The real pathname doesn't contain symlinks or useless dots.
|
300
|
+
#
|
301
|
+
# The last component of the real pathname can be nonexistent.
|
302
|
+
#
|
303
|
+
def realdirpath(basedir = nil)
|
304
|
+
self.class.new(File.realdirpath(@path, basedir))
|
305
|
+
end
|
321
306
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
# pathnames which points to roots such as <tt>/usr/..</tt>.
|
329
|
-
#
|
330
|
-
def root?
|
331
|
-
chop_basename(@path).nil? && /#{SEPARATOR_PAT}/o =~ @path
|
332
|
-
end
|
307
|
+
# #parent returns the parent directory.
|
308
|
+
#
|
309
|
+
# This is same as <tt>self + '..'</tt>.
|
310
|
+
def parent
|
311
|
+
self + '..'
|
312
|
+
end
|
333
313
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
314
|
+
# #mountpoint? returns +true+ if <tt>self</tt> points to a mountpoint.
|
315
|
+
def mountpoint?
|
316
|
+
stat1 = lstat
|
317
|
+
begin
|
318
|
+
stat2 = parent.lstat
|
319
|
+
stat1.dev == stat2.dev && stat1.ino == stat2.ino ||
|
320
|
+
stat1.dev != stat2.dev
|
321
|
+
rescue Errno::ENOENT
|
322
|
+
false
|
338
323
|
end
|
324
|
+
end
|
339
325
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
326
|
+
#
|
327
|
+
# #root? is a predicate for root directories.
|
328
|
+
# I.e. it returns +true+ if the
|
329
|
+
# pathname consists of consecutive slashes.
|
330
|
+
#
|
331
|
+
# It doesn't access actual filesystem. So it may return +false+ for some
|
332
|
+
# pathnames which points to roots such as <tt>/usr/..</tt>.
|
333
|
+
#
|
334
|
+
def root?
|
335
|
+
chop_basename(@path).nil? && /#{SEPARATOR_PAT}/o =~ @path
|
336
|
+
end
|
348
337
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
#
|
355
|
-
def each_filename # :yield: filename
|
356
|
-
return to_enum(__method__) unless block_given?
|
357
|
-
_prefix, names = split_names(@path)
|
358
|
-
names.each { |filename| yield filename }
|
359
|
-
nil
|
360
|
-
end
|
338
|
+
# Predicate method for testing whether a path is absolute.
|
339
|
+
# It returns +true+ if the pathname begins with a slash.
|
340
|
+
def absolute?
|
341
|
+
!relative?
|
342
|
+
end
|
361
343
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
# #<Pathname:/path>
|
368
|
-
# #<Pathname:/path/to>
|
369
|
-
# #<Pathname:/path/to/some>
|
370
|
-
# #<Pathname:/path/to/some/file.rb>
|
371
|
-
#
|
372
|
-
# Pathname.new('path/to/some/file.rb').descend { |v| p v}
|
373
|
-
# #<Pathname:path>
|
374
|
-
# #<Pathname:path/to>
|
375
|
-
# #<Pathname:path/to/some>
|
376
|
-
# #<Pathname:path/to/some/file.rb>
|
377
|
-
#
|
378
|
-
# It doesn't access actual filesystem.
|
379
|
-
#
|
380
|
-
# This method is available since 1.8.5.
|
381
|
-
#
|
382
|
-
def descend
|
383
|
-
vs = []
|
384
|
-
ascend { |v| vs << v }
|
385
|
-
vs.reverse_each { |v| yield v }
|
386
|
-
nil
|
344
|
+
# The opposite of #absolute?
|
345
|
+
def relative?
|
346
|
+
path = @path
|
347
|
+
while (r = chop_basename(path))
|
348
|
+
path, _basename = r
|
387
349
|
end
|
350
|
+
path == ''
|
351
|
+
end
|
388
352
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
353
|
+
#
|
354
|
+
# Iterates over each component of the path.
|
355
|
+
#
|
356
|
+
# Pathname.new("/usr/bin/ruby").each_filename { |filename| ... }
|
357
|
+
# # yields "usr", "bin", and "ruby".
|
358
|
+
#
|
359
|
+
def each_filename # :yield: filename
|
360
|
+
return to_enum(__method__) unless block_given?
|
361
|
+
_prefix, names = split_names(@path)
|
362
|
+
names.each { |filename| yield filename }
|
363
|
+
nil
|
364
|
+
end
|
365
|
+
|
366
|
+
# Iterates over and yields a new Pathname object
|
367
|
+
# for each element in the given path in descending order.
|
368
|
+
#
|
369
|
+
# Pathname.new('/path/to/some/file.rb').descend { |v| p v}
|
370
|
+
# #<Pathname:/>
|
371
|
+
# #<Pathname:/path>
|
372
|
+
# #<Pathname:/path/to>
|
373
|
+
# #<Pathname:/path/to/some>
|
374
|
+
# #<Pathname:/path/to/some/file.rb>
|
375
|
+
#
|
376
|
+
# Pathname.new('path/to/some/file.rb').descend { |v| p v}
|
377
|
+
# #<Pathname:path>
|
378
|
+
# #<Pathname:path/to>
|
379
|
+
# #<Pathname:path/to/some>
|
380
|
+
# #<Pathname:path/to/some/file.rb>
|
381
|
+
#
|
382
|
+
# It doesn't access actual filesystem.
|
383
|
+
#
|
384
|
+
# This method is available since 1.8.5.
|
385
|
+
#
|
386
|
+
def descend
|
387
|
+
vs = []
|
388
|
+
ascend { |v| vs << v }
|
389
|
+
vs.reverse_each { |v| yield v }
|
390
|
+
nil
|
391
|
+
end
|
418
392
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
393
|
+
# Iterates over and yields a new Pathname object
|
394
|
+
# for each element in the given path in ascending order.
|
395
|
+
#
|
396
|
+
# Pathname.new('/path/to/some/file.rb').ascend { |v| p v}
|
397
|
+
# #<Pathname:/path/to/some/file.rb>
|
398
|
+
# #<Pathname:/path/to/some>
|
399
|
+
# #<Pathname:/path/to>
|
400
|
+
# #<Pathname:/path>
|
401
|
+
# #<Pathname:/>
|
402
|
+
#
|
403
|
+
# Pathname.new('path/to/some/file.rb').ascend { |v| p v}
|
404
|
+
# #<Pathname:path/to/some/file.rb>
|
405
|
+
# #<Pathname:path/to/some>
|
406
|
+
# #<Pathname:path/to>
|
407
|
+
# #<Pathname:path>
|
408
|
+
#
|
409
|
+
# It doesn't access actual filesystem.
|
410
|
+
#
|
411
|
+
# This method is available since 1.8.5.
|
412
|
+
#
|
413
|
+
def ascend
|
414
|
+
path = @path
|
415
|
+
yield self
|
416
|
+
while (r = chop_basename(path))
|
417
|
+
path, _name = r
|
418
|
+
break if path.empty?
|
419
|
+
yield self.class.new(del_trailing_separator(path))
|
434
420
|
end
|
435
|
-
|
436
|
-
|
437
|
-
def plus(path1, path2) # -> path
|
438
|
-
prefix2 = path2
|
439
|
-
index_list2 = []
|
440
|
-
basename_list2 = []
|
441
|
-
while (r2 = chop_basename(prefix2))
|
442
|
-
prefix2, basename2 = r2
|
443
|
-
index_list2.unshift prefix2.length
|
444
|
-
basename_list2.unshift basename2
|
445
|
-
end
|
421
|
+
end
|
446
422
|
|
447
|
-
|
423
|
+
#
|
424
|
+
# Pathname#+ appends a pathname fragment to this one to produce a new
|
425
|
+
# Pathname
|
426
|
+
# object.
|
427
|
+
#
|
428
|
+
# p1 = Pathname.new("/usr") # Pathname:/usr
|
429
|
+
# p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
|
430
|
+
# p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
|
431
|
+
#
|
432
|
+
# This method doesn't access the file system; it is pure string
|
433
|
+
# manipulation.
|
434
|
+
#
|
435
|
+
def +(other)
|
436
|
+
other = Pathname.new(other) unless other.is_a?(Pathname)
|
437
|
+
Pathname.new(plus(@path, other.to_s))
|
438
|
+
end
|
439
|
+
alias / +
|
448
440
|
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
441
|
+
def plus(path1, path2) # -> path
|
442
|
+
prefix2 = path2
|
443
|
+
index_list2 = []
|
444
|
+
basename_list2 = []
|
445
|
+
while (r2 = chop_basename(prefix2))
|
446
|
+
prefix2, basename2 = r2
|
447
|
+
index_list2.unshift prefix2.length
|
448
|
+
basename_list2.unshift basename2
|
449
|
+
end
|
455
450
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
prefix1 += basename1
|
462
|
-
break
|
463
|
-
end
|
451
|
+
return path2 if prefix2 != ''
|
452
|
+
|
453
|
+
prefix1 = path1
|
454
|
+
while (r1 = chop_basename(prefix1))
|
455
|
+
while !basename_list2.empty? && basename_list2.first == '.'
|
464
456
|
index_list2.shift
|
465
457
|
basename_list2.shift
|
466
458
|
end
|
467
459
|
|
468
|
-
|
469
|
-
if
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
460
|
+
prefix1, basename1 = r1
|
461
|
+
next if basename1 == '.'
|
462
|
+
if basename1 == '..' ||
|
463
|
+
basename_list2.empty? ||
|
464
|
+
basename_list2.first != '..'
|
465
|
+
prefix1 += basename1
|
466
|
+
break
|
474
467
|
end
|
475
|
-
|
476
|
-
|
477
|
-
suffix2 = path2[index_list2.first..-1]
|
478
|
-
r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
|
479
|
-
else
|
480
|
-
r1 ? prefix1 : File.dirname(prefix1)
|
481
|
-
end
|
482
|
-
end
|
483
|
-
private :plus
|
484
|
-
|
485
|
-
#
|
486
|
-
# Pathname#join joins pathnames.
|
487
|
-
#
|
488
|
-
# <tt>path0.join(path1, ..., pathN)</tt> is the same as
|
489
|
-
# <tt>path0 + path1 + ... + pathN</tt>.
|
490
|
-
#
|
491
|
-
def join(*args)
|
492
|
-
args.unshift self
|
493
|
-
result = args.pop
|
494
|
-
result = Pathname.new(result) unless result.is_a?(Pathname)
|
495
|
-
return result if result.absolute?
|
496
|
-
args.reverse_each do |arg|
|
497
|
-
arg = Pathname.new(arg) unless arg.is_a?(Pathname)
|
498
|
-
result = arg + result
|
499
|
-
return result if result.absolute?
|
500
|
-
end
|
501
|
-
result
|
468
|
+
index_list2.shift
|
469
|
+
basename_list2.shift
|
502
470
|
end
|
503
471
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
# pathnames will contain the
|
510
|
-
# filename only.
|
511
|
-
#
|
512
|
-
# For example:
|
513
|
-
# pn = Pathname("/usr/lib/ruby/1.8")
|
514
|
-
# pn.children
|
515
|
-
# # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
|
516
|
-
# Pathname:/usr/lib/ruby/1.8/Env.rb,
|
517
|
-
# Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
|
518
|
-
# pn.children(false)
|
519
|
-
# # -> [ Pathname:English.rb,
|
520
|
-
# Pathname:Env.rb,
|
521
|
-
# Pathname:abbrev.rb, ... ]
|
522
|
-
#
|
523
|
-
# Note that the result never contain the entries
|
524
|
-
# <tt>.</tt> and <tt>..</tt> in
|
525
|
-
# the directory because they are not children.
|
526
|
-
#
|
527
|
-
# This method has existed since 1.8.1.
|
528
|
-
#
|
529
|
-
def children(with_directory = true)
|
530
|
-
with_directory = false if @path == '.'
|
531
|
-
result = []
|
532
|
-
Dir.foreach(@path) do |e|
|
533
|
-
next if e == '.' || e == '..'
|
534
|
-
result <<
|
535
|
-
if with_directory
|
536
|
-
self.class.new(File.join(@path, e))
|
537
|
-
else
|
538
|
-
self.class.new(e)
|
539
|
-
end
|
472
|
+
r1 = chop_basename(prefix1)
|
473
|
+
if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1)
|
474
|
+
while !basename_list2.empty? && basename_list2.first == '..'
|
475
|
+
index_list2.shift
|
476
|
+
basename_list2.shift
|
540
477
|
end
|
541
|
-
result
|
542
478
|
end
|
543
479
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
# If you set +with_directory+ to +false+,
|
550
|
-
# then the returned pathnames will contain the filename only.
|
551
|
-
#
|
552
|
-
# Pathname("/usr/local").each_child { |f| p f }
|
553
|
-
# #=> #<Pathname:/usr/local/share>
|
554
|
-
# # #<Pathname:/usr/local/bin>
|
555
|
-
# # #<Pathname:/usr/local/games>
|
556
|
-
# # #<Pathname:/usr/local/lib>
|
557
|
-
# # #<Pathname:/usr/local/include>
|
558
|
-
# # #<Pathname:/usr/local/sbin>
|
559
|
-
# # #<Pathname:/usr/local/src>
|
560
|
-
# # #<Pathname:/usr/local/man>
|
561
|
-
#
|
562
|
-
# Pathname("/usr/local").each_child(false) { |f| p f }
|
563
|
-
# #=> #<Pathname:share>
|
564
|
-
# # #<Pathname:bin>
|
565
|
-
# # #<Pathname:games>
|
566
|
-
# # #<Pathname:lib>
|
567
|
-
# # #<Pathname:include>
|
568
|
-
# # #<Pathname:sbin>
|
569
|
-
# # #<Pathname:src>
|
570
|
-
# # #<Pathname:man>
|
571
|
-
#
|
572
|
-
def each_child(with_directory = true, &b)
|
573
|
-
children(with_directory).each(&b)
|
480
|
+
if !basename_list2.empty?
|
481
|
+
suffix2 = path2[index_list2.first..-1]
|
482
|
+
r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
|
483
|
+
else
|
484
|
+
r1 ? prefix1 : File.dirname(prefix1)
|
574
485
|
end
|
486
|
+
end
|
487
|
+
private :plus
|
575
488
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
dest_prefix = dest_directory
|
592
|
-
dest_names = []
|
593
|
-
while (r = chop_basename(dest_prefix))
|
594
|
-
dest_prefix, basename = r
|
595
|
-
dest_names.unshift basename if basename != '.'
|
596
|
-
end
|
597
|
-
base_prefix = base_directory
|
598
|
-
base_names = []
|
599
|
-
while (r = chop_basename(base_prefix))
|
600
|
-
base_prefix, basename = r
|
601
|
-
base_names.unshift basename if basename != '.'
|
602
|
-
end
|
603
|
-
unless SAME_PATHS[dest_prefix, base_prefix]
|
604
|
-
fail ArgumentError, "different prefix: #{dest_prefix.inspect} " \
|
605
|
-
"and #{base_directory.inspect}"
|
606
|
-
end
|
607
|
-
while !dest_names.empty? &&
|
608
|
-
!base_names.empty? &&
|
609
|
-
SAME_PATHS[dest_names.first, base_names.first]
|
610
|
-
dest_names.shift
|
611
|
-
base_names.shift
|
612
|
-
end
|
613
|
-
if base_names.include? '..'
|
614
|
-
fail ArgumentError, "base_directory has ..: #{base_directory.inspect}"
|
615
|
-
end
|
616
|
-
base_names.fill('..')
|
617
|
-
relpath_names = base_names + dest_names
|
618
|
-
if relpath_names.empty?
|
619
|
-
Pathname.new('.')
|
620
|
-
else
|
621
|
-
Pathname.new(File.join(*relpath_names))
|
622
|
-
end
|
489
|
+
#
|
490
|
+
# Pathname#join joins pathnames.
|
491
|
+
#
|
492
|
+
# <tt>path0.join(path1, ..., pathN)</tt> is the same as
|
493
|
+
# <tt>path0 + path1 + ... + pathN</tt>.
|
494
|
+
#
|
495
|
+
def join(*args)
|
496
|
+
args.unshift self
|
497
|
+
result = args.pop
|
498
|
+
result = Pathname.new(result) unless result.is_a?(Pathname)
|
499
|
+
return result if result.absolute?
|
500
|
+
args.reverse_each do |arg|
|
501
|
+
arg = Pathname.new(arg) unless arg.is_a?(Pathname)
|
502
|
+
result = arg + result
|
503
|
+
return result if result.absolute?
|
623
504
|
end
|
505
|
+
result
|
624
506
|
end
|
625
507
|
|
626
|
-
#
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
508
|
+
#
|
509
|
+
# Returns the children of the directory (files and subdirectories, not
|
510
|
+
# recursive) as an array of Pathname objects. By default, the returned
|
511
|
+
# pathnames will have enough information to access the files. If you set
|
512
|
+
# +with_directory+ to +false+, then the returned
|
513
|
+
# pathnames will contain the
|
514
|
+
# filename only.
|
515
|
+
#
|
516
|
+
# For example:
|
517
|
+
# pn = Pathname("/usr/lib/ruby/1.8")
|
518
|
+
# pn.children
|
519
|
+
# # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
|
520
|
+
# Pathname:/usr/lib/ruby/1.8/Env.rb,
|
521
|
+
# Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
|
522
|
+
# pn.children(false)
|
523
|
+
# # -> [ Pathname:English.rb,
|
524
|
+
# Pathname:Env.rb,
|
525
|
+
# Pathname:abbrev.rb, ... ]
|
526
|
+
#
|
527
|
+
# Note that the result never contain the entries
|
528
|
+
# <tt>.</tt> and <tt>..</tt> in
|
529
|
+
# the directory because they are not children.
|
530
|
+
#
|
531
|
+
# This method has existed since 1.8.1.
|
532
|
+
#
|
533
|
+
def children(with_directory = true)
|
534
|
+
with_directory = false if @path == '.'
|
535
|
+
result = []
|
536
|
+
Dir.foreach(@path) do |e|
|
537
|
+
next if ['.', '..'].include?(e)
|
538
|
+
result <<
|
539
|
+
if with_directory
|
540
|
+
self.class.new(File.join(@path, e))
|
541
|
+
else
|
542
|
+
self.class.new(e)
|
638
543
|
end
|
639
|
-
else
|
640
|
-
enum_for(:each_line, *args)
|
641
|
-
end
|
642
544
|
end
|
545
|
+
result
|
546
|
+
end
|
643
547
|
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
548
|
+
# Iterates over the children of the directory
|
549
|
+
# (files and subdirectories, not recursive).
|
550
|
+
# It yields Pathname object for each child.
|
551
|
+
# By default, the yielded pathnames will have enough information to access
|
552
|
+
# the files.
|
553
|
+
# If you set +with_directory+ to +false+,
|
554
|
+
# then the returned pathnames will contain the filename only.
|
555
|
+
#
|
556
|
+
# Pathname("/usr/local").each_child { |f| p f }
|
557
|
+
# #=> #<Pathname:/usr/local/share>
|
558
|
+
# # #<Pathname:/usr/local/bin>
|
559
|
+
# # #<Pathname:/usr/local/games>
|
560
|
+
# # #<Pathname:/usr/local/lib>
|
561
|
+
# # #<Pathname:/usr/local/include>
|
562
|
+
# # #<Pathname:/usr/local/sbin>
|
563
|
+
# # #<Pathname:/usr/local/src>
|
564
|
+
# # #<Pathname:/usr/local/man>
|
565
|
+
#
|
566
|
+
# Pathname("/usr/local").each_child(false) { |f| p f }
|
567
|
+
# #=> #<Pathname:share>
|
568
|
+
# # #<Pathname:bin>
|
569
|
+
# # #<Pathname:games>
|
570
|
+
# # #<Pathname:lib>
|
571
|
+
# # #<Pathname:include>
|
572
|
+
# # #<Pathname:sbin>
|
573
|
+
# # #<Pathname:src>
|
574
|
+
# # #<Pathname:man>
|
575
|
+
#
|
576
|
+
def each_child(with_directory = true, &block)
|
577
|
+
children(with_directory).each(&block)
|
578
|
+
end
|
649
579
|
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
580
|
+
#
|
581
|
+
# #relative_path_from returns a relative path from the argument to the
|
582
|
+
# receiver. If +self+ is absolute, the argument must be absolute too. If
|
583
|
+
# +self+ is relative, the argument must be relative too.
|
584
|
+
#
|
585
|
+
# #relative_path_from doesn't access the filesystem.
|
586
|
+
# It assumes no symlinks.
|
587
|
+
#
|
588
|
+
# ArgumentError is raised when it cannot find a relative path.
|
589
|
+
#
|
590
|
+
# This method has existed since 1.8.1.
|
591
|
+
#
|
592
|
+
def relative_path_from(base_directory)
|
593
|
+
dest_directory = cleanpath.to_s
|
594
|
+
base_directory = base_directory.cleanpath.to_s
|
595
|
+
dest_prefix = dest_directory
|
596
|
+
dest_names = []
|
597
|
+
while (r = chop_basename(dest_prefix))
|
598
|
+
dest_prefix, basename = r
|
599
|
+
dest_names.unshift basename if basename != '.'
|
600
|
+
end
|
601
|
+
base_prefix = base_directory
|
602
|
+
base_names = []
|
603
|
+
while (r = chop_basename(base_prefix))
|
604
|
+
base_prefix, basename = r
|
605
|
+
base_names.unshift basename if basename != '.'
|
606
|
+
end
|
607
|
+
unless SAME_PATHS[dest_prefix, base_prefix]
|
608
|
+
raise ArgumentError, "different prefix: #{dest_prefix.inspect} " \
|
609
|
+
"and #{base_directory.inspect}"
|
610
|
+
end
|
611
|
+
while !dest_names.empty? &&
|
612
|
+
!base_names.empty? &&
|
613
|
+
SAME_PATHS[dest_names.first, base_names.first]
|
614
|
+
dest_names.shift
|
615
|
+
base_names.shift
|
616
|
+
end
|
617
|
+
if base_names.include? '..'
|
618
|
+
raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
|
619
|
+
end
|
620
|
+
base_names.fill('..')
|
621
|
+
relpath_names = base_names + dest_names
|
622
|
+
if relpath_names.empty?
|
623
|
+
Pathname.new('.')
|
624
|
+
else
|
625
|
+
Pathname.new(File.join(*relpath_names))
|
654
626
|
end
|
627
|
+
end
|
628
|
+
end
|
655
629
|
|
656
|
-
|
657
|
-
|
658
|
-
|
630
|
+
# Pathname class
|
631
|
+
class Pathname # * IO *
|
632
|
+
#
|
633
|
+
# #each_line iterates over the line in the file.
|
634
|
+
# It yields a String object for each line.
|
635
|
+
#
|
636
|
+
# This method has existed since 1.8.1.
|
637
|
+
#
|
638
|
+
def each_line(*args, &block) # :yield: line
|
639
|
+
if block_given?
|
640
|
+
File.open(@path, 'r') do |io|
|
641
|
+
io.each_line(*args, &block)
|
642
|
+
end
|
643
|
+
else
|
644
|
+
enum_for(:each_line, *args)
|
659
645
|
end
|
646
|
+
end
|
660
647
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
648
|
+
# See <tt>IO.read</tt>. Returns all data from the file,
|
649
|
+
# or the first +N+ bytes if specified.
|
650
|
+
def read(*args)
|
651
|
+
File.read(@path, *args)
|
665
652
|
end
|
666
653
|
|
667
|
-
#
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
end
|
654
|
+
# See <tt>IO.binread</tt>. Returns all the bytes from the file,
|
655
|
+
# or the first +N+ if specified.
|
656
|
+
def binread(*args)
|
657
|
+
File.binread(@path, *args)
|
658
|
+
end
|
673
659
|
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
end
|
660
|
+
# See <tt>IO.readlines</tt>. Returns all the lines from the file.
|
661
|
+
def readlines(*args)
|
662
|
+
File.readlines(@path, *args)
|
663
|
+
end
|
679
664
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
665
|
+
# See <tt>IO.sysopen</tt>. Not supported by fakefs.
|
666
|
+
def sysopen(*_args)
|
667
|
+
raise NotImplementedError, 'sysopen is not supported by fakefs'
|
668
|
+
end
|
669
|
+
end
|
684
670
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
671
|
+
# Pathname class
|
672
|
+
class Pathname # * File *
|
673
|
+
# See <tt>File.atime</tt>. Returns last access time.
|
674
|
+
def atime
|
675
|
+
File.atime(@path)
|
676
|
+
end
|
689
677
|
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
678
|
+
# See <tt>File.ctime</tt>.
|
679
|
+
# Returns last (directory entry, not file) change time.
|
680
|
+
def ctime
|
681
|
+
File.ctime(@path)
|
682
|
+
end
|
694
683
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
684
|
+
# See <tt>File.mtime</tt>. Returns last modification time.
|
685
|
+
def mtime
|
686
|
+
File.mtime(@path)
|
687
|
+
end
|
699
688
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
689
|
+
# See <tt>File.chmod</tt>. Changes permissions.
|
690
|
+
def chmod(mode)
|
691
|
+
File.chmod(mode, @path)
|
692
|
+
end
|
704
693
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
end
|
694
|
+
# See <tt>File.lchmod</tt>.
|
695
|
+
def lchmod(mode)
|
696
|
+
File.lchmod(mode, @path)
|
697
|
+
end
|
710
698
|
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
699
|
+
# See <tt>File.chown</tt>. Change owner and group of file.
|
700
|
+
def chown(owner, group)
|
701
|
+
File.chown(owner, group, @path)
|
702
|
+
end
|
715
703
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
end
|
704
|
+
# See <tt>File.lchown</tt>.
|
705
|
+
def lchown(owner, group)
|
706
|
+
File.lchown(owner, group, @path)
|
707
|
+
end
|
721
708
|
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
709
|
+
# See <tt>File.fnmatch</tt>. Return +true+
|
710
|
+
# if the receiver matches the given pattern
|
711
|
+
def fnmatch(pattern, *args)
|
712
|
+
File.fnmatch(pattern, @path, *args)
|
713
|
+
end
|
726
714
|
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
715
|
+
# See <tt>File.fnmatch?</tt> (same as #fnmatch).
|
716
|
+
def fnmatch?(pattern, *args)
|
717
|
+
File.fnmatch?(pattern, @path, *args)
|
718
|
+
end
|
731
719
|
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
720
|
+
# See <tt>File.ftype</tt>. Returns "type" of file ("file", "directory",
|
721
|
+
# etc).
|
722
|
+
def ftype
|
723
|
+
File.ftype(@path)
|
724
|
+
end
|
736
725
|
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
726
|
+
# See <tt>File.link</tt>. Creates a hard link.
|
727
|
+
def make_link(old)
|
728
|
+
File.link(old, @path)
|
729
|
+
end
|
741
730
|
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
731
|
+
# See <tt>File.open</tt>. Opens the file for reading or writing.
|
732
|
+
def open(*args, &block) # :yield: file
|
733
|
+
File.open(@path, *args, &block)
|
734
|
+
end
|
746
735
|
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
736
|
+
# See <tt>File.readlink</tt>. Read symbolic link.
|
737
|
+
def readlink
|
738
|
+
self.class.new(File.readlink(@path))
|
739
|
+
end
|
751
740
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
741
|
+
# See <tt>File.rename</tt>. Rename the file.
|
742
|
+
def rename(to)
|
743
|
+
File.rename(@path, to)
|
744
|
+
end
|
756
745
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
746
|
+
# See <tt>File.stat</tt>. Returns a <tt>File::Stat</tt> object.
|
747
|
+
def stat
|
748
|
+
File.stat(@path)
|
749
|
+
end
|
761
750
|
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
751
|
+
# See <tt>File.lstat</tt>.
|
752
|
+
def lstat
|
753
|
+
File.lstat(@path)
|
754
|
+
end
|
766
755
|
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
756
|
+
# See <tt>File.symlink</tt>. Creates a symbolic link.
|
757
|
+
def make_symlink(old)
|
758
|
+
File.symlink(old, @path)
|
759
|
+
end
|
771
760
|
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
end
|
761
|
+
# See <tt>File.truncate</tt>. Truncate the file to +length+ bytes.
|
762
|
+
def truncate(length)
|
763
|
+
File.truncate(@path, length)
|
764
|
+
end
|
777
765
|
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
766
|
+
# See <tt>File.utime</tt>. Update the access and modification times.
|
767
|
+
def utime(atime, mtime)
|
768
|
+
File.utime(atime, mtime, @path)
|
769
|
+
end
|
782
770
|
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
771
|
+
# See <tt>File.basename</tt>. Returns the last component of the path.
|
772
|
+
def basename(*args)
|
773
|
+
self.class.new(File.basename(@path, *args))
|
774
|
+
end
|
787
775
|
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
776
|
+
# See <tt>File.dirname</tt>. Returns all but the last
|
777
|
+
# component of the path.
|
778
|
+
def dirname
|
779
|
+
self.class.new(File.dirname(@path))
|
780
|
+
end
|
793
781
|
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
return file.write(data)
|
798
|
-
end
|
799
|
-
end
|
782
|
+
# See <tt>File.extname</tt>. Returns the file's extension.
|
783
|
+
def extname
|
784
|
+
File.extname(@path)
|
800
785
|
end
|
801
786
|
|
802
|
-
#
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
FileTest.blockdev?(@path)
|
807
|
-
end
|
787
|
+
# See <tt>File.expand_path</tt>.
|
788
|
+
def expand_path(*args)
|
789
|
+
self.class.new(File.expand_path(@path, *args))
|
790
|
+
end
|
808
791
|
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
792
|
+
# See <tt>File.split</tt>. Returns the #dirname and the #basename in an
|
793
|
+
# Array.
|
794
|
+
def split
|
795
|
+
File.split(@path).map { |f| self.class.new(f) }
|
796
|
+
end
|
813
797
|
|
814
|
-
|
815
|
-
|
816
|
-
|
798
|
+
# See <tt>File.write</tt>. Returns the number of bytes written.
|
799
|
+
def write(path, data)
|
800
|
+
File.open(path, 'wb') do |file|
|
801
|
+
return file.write(data)
|
817
802
|
end
|
803
|
+
end
|
804
|
+
end
|
818
805
|
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
806
|
+
# Pathname class
|
807
|
+
class Pathname # * FileTest *
|
808
|
+
# See <tt>FileTest.blockdev?</tt>.
|
809
|
+
def blockdev?
|
810
|
+
FileTest.blockdev?(@path)
|
811
|
+
end
|
823
812
|
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
813
|
+
# See <tt>FileTest.chardev?</tt>.
|
814
|
+
def chardev?
|
815
|
+
FileTest.chardev?(@path)
|
816
|
+
end
|
828
817
|
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
818
|
+
# See <tt>FileTest.executable?</tt>.
|
819
|
+
def executable?
|
820
|
+
FileTest.executable?(@path)
|
821
|
+
end
|
833
822
|
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
823
|
+
# See <tt>FileTest.executable_real?</tt>.
|
824
|
+
def executable_real?
|
825
|
+
FileTest.executable_real?(@path)
|
826
|
+
end
|
838
827
|
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
828
|
+
# See <tt>FileTest.exist?</tt>.
|
829
|
+
def exist?
|
830
|
+
FileTest.exist?(@path)
|
831
|
+
end
|
843
832
|
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
833
|
+
# See <tt>FileTest.grpowned?</tt>.
|
834
|
+
def grpowned?
|
835
|
+
FileTest.grpowned?(@path)
|
836
|
+
end
|
848
837
|
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
838
|
+
# See <tt>FileTest.directory?</tt>.
|
839
|
+
def directory?
|
840
|
+
FileTest.directory?(@path)
|
841
|
+
end
|
853
842
|
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
843
|
+
# See <tt>FileTest.file?</tt>.
|
844
|
+
def file?
|
845
|
+
FileTest.file?(@path)
|
846
|
+
end
|
858
847
|
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
848
|
+
# See <tt>FileTest.pipe?</tt>.
|
849
|
+
def pipe?
|
850
|
+
FileTest.pipe?(@path)
|
851
|
+
end
|
863
852
|
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
853
|
+
# See <tt>FileTest.socket?</tt>.
|
854
|
+
def socket?
|
855
|
+
FileTest.socket?(@path)
|
856
|
+
end
|
868
857
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
858
|
+
# See <tt>FileTest.owned?</tt>.
|
859
|
+
def owned?
|
860
|
+
FileTest.owned?(@path)
|
861
|
+
end
|
873
862
|
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
863
|
+
# See <tt>FileTest.readable?</tt>.
|
864
|
+
def readable?
|
865
|
+
FileTest.readable?(@path)
|
866
|
+
end
|
878
867
|
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
868
|
+
# See <tt>FileTest.world_readable?</tt>.
|
869
|
+
def world_readable?
|
870
|
+
FileTest.world_readable?(@path)
|
871
|
+
end
|
883
872
|
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
873
|
+
# See <tt>FileTest.readable_real?</tt>.
|
874
|
+
def readable_real?
|
875
|
+
FileTest.readable_real?(@path)
|
876
|
+
end
|
888
877
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
878
|
+
# See <tt>FileTest.setuid?</tt>.
|
879
|
+
def setuid?
|
880
|
+
FileTest.setuid?(@path)
|
881
|
+
end
|
893
882
|
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
883
|
+
# See <tt>FileTest.setgid?</tt>.
|
884
|
+
def setgid?
|
885
|
+
FileTest.setgid?(@path)
|
886
|
+
end
|
898
887
|
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
888
|
+
# See <tt>FileTest.size</tt>.
|
889
|
+
def size
|
890
|
+
FileTest.size(@path)
|
891
|
+
end
|
903
892
|
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
893
|
+
# See <tt>FileTest.size?</tt>.
|
894
|
+
def size?
|
895
|
+
FileTest.size?(@path)
|
896
|
+
end
|
908
897
|
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
898
|
+
# See <tt>FileTest.sticky?</tt>.
|
899
|
+
def sticky?
|
900
|
+
FileTest.sticky?(@path)
|
901
|
+
end
|
913
902
|
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
903
|
+
# See <tt>FileTest.symlink?</tt>.
|
904
|
+
def symlink?
|
905
|
+
FileTest.symlink?(@path)
|
906
|
+
end
|
918
907
|
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
end
|
908
|
+
# See <tt>FileTest.writable?</tt>.
|
909
|
+
def writable?
|
910
|
+
FileTest.writable?(@path)
|
923
911
|
end
|
924
912
|
|
925
|
-
#
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
if block_given?
|
930
|
-
Dir.glob(*args) { |f| yield new(f) }
|
931
|
-
else
|
932
|
-
Dir.glob(*args).map { |f| new(f) }
|
933
|
-
end
|
934
|
-
end
|
913
|
+
# See <tt>FileTest.world_writable?</tt>.
|
914
|
+
def world_writable?
|
915
|
+
FileTest.world_writable?(@path)
|
916
|
+
end
|
935
917
|
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
918
|
+
# See <tt>FileTest.writable_real?</tt>.
|
919
|
+
def writable_real?
|
920
|
+
FileTest.writable_real?(@path)
|
921
|
+
end
|
922
|
+
|
923
|
+
# See <tt>FileTest.zero?</tt>.
|
924
|
+
def zero?
|
925
|
+
FileTest.zero?(@path)
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
# Pathname class
|
930
|
+
class Pathname # * Dir *
|
931
|
+
# See <tt>Dir.glob</tt>. Returns or yields Pathname objects.
|
932
|
+
def self.glob(*args) # :yield: pathname
|
933
|
+
if block_given?
|
934
|
+
Dir.glob(*args) { |f| yield new(f) }
|
935
|
+
else
|
936
|
+
Dir.glob(*args).map { |f| new(f) }
|
940
937
|
end
|
938
|
+
end
|
941
939
|
|
942
|
-
|
940
|
+
# See <tt>Dir.getwd</tt>. Returns the current working directory
|
941
|
+
# as a Pathname.
|
942
|
+
def self.getwd
|
943
|
+
new(Dir.getwd)
|
944
|
+
end
|
943
945
|
|
944
|
-
|
945
|
-
# a Pathname object.
|
946
|
-
def entries
|
947
|
-
Dir.entries(@path).map { |f| self.class.new(f) }
|
948
|
-
end
|
946
|
+
class << self; alias pwd getwd end
|
949
947
|
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
Dir.foreach(@path) { |f| yield self.class.new(f) }
|
956
|
-
end
|
948
|
+
# Return the entries (files and subdirectories) in the directory, each as
|
949
|
+
# a Pathname object.
|
950
|
+
def entries
|
951
|
+
Dir.entries(@path).map { |f| self.class.new(f) }
|
952
|
+
end
|
957
953
|
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
954
|
+
# Iterates over the entries (files and subdirectories) in the directory.
|
955
|
+
# It yields a Pathname object for each entry.
|
956
|
+
#
|
957
|
+
# This method has existed since 1.8.1.
|
958
|
+
def each_entry(*) # :yield: pathname
|
959
|
+
Dir.foreach(@path) { |f| yield self.class.new(f) }
|
960
|
+
end
|
962
961
|
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
962
|
+
# See <tt>Dir.mkdir</tt>. Create the referenced directory.
|
963
|
+
def mkdir(*args)
|
964
|
+
Dir.mkdir(@path, *args)
|
965
|
+
end
|
967
966
|
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
end
|
967
|
+
# See <tt>Dir.rmdir</tt>. Remove the referenced directory.
|
968
|
+
def rmdir
|
969
|
+
Dir.rmdir(@path)
|
972
970
|
end
|
973
971
|
|
974
|
-
#
|
975
|
-
|
976
|
-
|
977
|
-
# Pathname#find is an iterator to traverse a directory tree
|
978
|
-
# in a depth first manner.
|
979
|
-
# It yields a Pathname for each file under "this" directory.
|
980
|
-
#
|
981
|
-
# Since it is implemented by <tt>find.rb</tt>, <tt>Find.prune</tt>
|
982
|
-
# can be used to control the traverse.
|
983
|
-
#
|
984
|
-
# If +self+ is <tt>.</tt>, yielded pathnames begin with
|
985
|
-
# a filename in the current directory, not <tt>./</tt>.
|
986
|
-
#
|
987
|
-
def find(*) # :yield: pathname
|
988
|
-
require 'find'
|
989
|
-
if @path == '.'
|
990
|
-
Find.find(@path) { |f| yield self.class.new(f.sub(%r{/\A\./}, '')) }
|
991
|
-
else
|
992
|
-
Find.find(@path) { |f| yield self.class.new(f) }
|
993
|
-
end
|
994
|
-
end
|
972
|
+
# See <tt>Dir.open</tt>.
|
973
|
+
def opendir(&block) # :yield: dir
|
974
|
+
Dir.open(@path, &block)
|
995
975
|
end
|
976
|
+
end
|
996
977
|
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
978
|
+
# Pathname class
|
979
|
+
class Pathname # * Find *
|
980
|
+
#
|
981
|
+
# Pathname#find is an iterator to traverse a directory tree
|
982
|
+
# in a depth first manner.
|
983
|
+
# It yields a Pathname for each file under "this" directory.
|
984
|
+
#
|
985
|
+
# Since it is implemented by <tt>find.rb</tt>, <tt>Find.prune</tt>
|
986
|
+
# can be used to control the traverse.
|
987
|
+
#
|
988
|
+
# If +self+ is <tt>.</tt>, yielded pathnames begin with
|
989
|
+
# a filename in the current directory, not <tt>./</tt>.
|
990
|
+
#
|
991
|
+
def find(*) # :yield: pathname
|
992
|
+
require 'find'
|
993
|
+
if @path == '.'
|
994
|
+
Find.find(@path) { |f| yield self.class.new(f.sub(%r{/\A\./}, '')) }
|
995
|
+
else
|
996
|
+
Find.find(@path) { |f| yield self.class.new(f) }
|
1005
997
|
end
|
998
|
+
end
|
999
|
+
end
|
1000
|
+
|
1001
|
+
# Pathname class
|
1002
|
+
class Pathname # * FileUtils *
|
1003
|
+
# See <tt>FileUtils.mkpath</tt>. Creates a full path, including any
|
1004
|
+
# intermediate directories that don't yet exist.
|
1005
|
+
def mkpath
|
1006
|
+
require 'fileutils'
|
1007
|
+
FileUtils.mkpath(@path)
|
1008
|
+
nil
|
1009
|
+
end
|
1006
1010
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1011
|
+
# See <tt>FileUtils.rm_r</tt>. Deletes a directory and all beneath it.
|
1012
|
+
def rmtree
|
1013
|
+
# The name "rmtree" is borrowed from File::Path of Perl.
|
1014
|
+
# File::Path provides "mkpath" and "rmtree".
|
1015
|
+
require 'fileutils'
|
1016
|
+
FileUtils.rm_r(@path)
|
1017
|
+
nil
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
# Pathname class
|
1022
|
+
class Pathname # * mixed *
|
1023
|
+
# Removes a file or directory, using <tt>File.unlink</tt> or
|
1024
|
+
# <tt>Dir.unlink</tt> as necessary.
|
1025
|
+
def unlink
|
1026
|
+
if File.directory? @path
|
1027
|
+
Dir.unlink @path
|
1028
|
+
else
|
1029
|
+
File.unlink @path
|
1014
1030
|
end
|
1015
1031
|
end
|
1016
1032
|
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
#
|
1021
|
-
|
1033
|
+
alias delete unlink
|
1034
|
+
|
1035
|
+
if RUBY_VERSION > '2.4'
|
1036
|
+
# Checks if a file or directory is empty, using
|
1037
|
+
# <tt>FileTest.empty?</tt> or <tt>Dir.empty?</tt> as necessary.
|
1038
|
+
def empty?
|
1022
1039
|
if File.directory? @path
|
1023
|
-
Dir.
|
1040
|
+
Dir.empty? @path
|
1024
1041
|
else
|
1025
|
-
|
1026
|
-
end
|
1027
|
-
end
|
1028
|
-
|
1029
|
-
alias_method :delete, :unlink
|
1030
|
-
|
1031
|
-
if RUBY_VERSION > '2.4'
|
1032
|
-
# Checks if a file or directory is empty, using
|
1033
|
-
# <tt>FileTest.empty?</tt> or <tt>Dir.empty?</tt> as necessary.
|
1034
|
-
def empty?
|
1035
|
-
if File.directory? @path
|
1036
|
-
Dir.empty? @path
|
1037
|
-
else
|
1038
|
-
FileTest.empty? @path
|
1039
|
-
end
|
1042
|
+
FileTest.empty? @path
|
1040
1043
|
end
|
1041
1044
|
end
|
1042
1045
|
end
|
1046
|
+
end
|
1043
1047
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
end # RUBY_VERSION >= 1.9.3
|
1048
|
+
# Pathname class
|
1049
|
+
class Pathname
|
1050
|
+
undef =~
|
1051
|
+
end
|
1049
1052
|
end
|