Skip to content

Commit 8892c60

Browse files
committed
Implement Pathname#find in builtin Pathname
1 parent 5f725bf commit 8892c60

2 files changed

Lines changed: 46 additions & 29 deletions

File tree

lib/pathname.rb

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,6 @@
1010
# For documentation, see class Pathname.
1111
#
1212

13-
class Pathname # * Find *
14-
#
15-
# Iterates over the directory tree in a depth first manner, yielding a
16-
# Pathname for each file under "this" directory.
17-
#
18-
# Note that you need to require 'pathname' to use this method.
19-
#
20-
# Returns an Enumerator if no block is given.
21-
#
22-
# Since it is implemented by the standard library module Find, Find.prune can
23-
# be used to control the traversal.
24-
#
25-
# If +self+ is +.+, yielded pathnames begin with a filename in the
26-
# current directory, not +./+.
27-
#
28-
# See Find.find
29-
#
30-
def find(ignore_error: true) # :yield: pathname
31-
return to_enum(__method__, ignore_error: ignore_error) unless block_given?
32-
require 'find'
33-
if @path == '.'
34-
Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
35-
else
36-
Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
37-
end
38-
end
39-
end
40-
41-
4213
class Pathname # * FileUtils *
4314
# Recursively deletes a directory, including all directories beneath it.
4415
#

pathname_builtin.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,52 @@ def unlink()
12061206
end
12071207

12081208
class Pathname
1209+
# Iterates over the directory tree in a depth first manner, yielding a
1210+
# Pathname for each file under "this" directory.
1211+
#
1212+
# Returns an Enumerator if no block is given.
1213+
#
1214+
# If +self+ is +.+, yielded pathnames begin with a filename in the
1215+
# current directory, not +./+.
1216+
#
1217+
# If +ignore_error+ is true (the default), errors during traversal
1218+
# are silently ignored. If false, errors are raised.
1219+
#
1220+
# Pathname("/usr/local").find {|f| p f }
1221+
# #=> #<Pathname:/usr/local>
1222+
# #=> #<Pathname:/usr/local/bin>
1223+
# #=> ...
1224+
#
1225+
def find(ignore_error: true) # :yield: pathname
1226+
return to_enum(__method__, ignore_error: ignore_error) unless block_given?
1227+
raise Errno::ENOENT, @path unless File.exist?(@path)
1228+
fs_encoding = Encoding.find("filesystem")
1229+
enc = @path.encoding == Encoding::US_ASCII ? fs_encoding : @path.encoding
1230+
ps = [@path]
1231+
while file = ps.shift
1232+
catch(:prune) do
1233+
if @path == '.'
1234+
yield self.class.new(file == '.' ? file : file.delete_prefix('./'))
1235+
else
1236+
yield self.class.new(file)
1237+
end
1238+
begin
1239+
s = File.lstat(file)
1240+
if s.directory?
1241+
fs = Dir.children(file, encoding: enc)
1242+
fs.sort!
1243+
fs.reverse_each {|f|
1244+
ps.unshift File.join(file, f)
1245+
}
1246+
end
1247+
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
1248+
raise unless ignore_error
1249+
end
1250+
end
1251+
end
1252+
nil
1253+
end
1254+
12091255
undef =~ if Kernel.method_defined?(:=~)
12101256
end
12111257

0 commit comments

Comments
 (0)