1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/find.rb
naruse b2996b30d9 Find.find -> Use Dir.children instead of Dir.entries
Dir.children is available since Feature #11302.
Find.find can use of the new list (having no '.' neither '..' entries),
making now superflous an if statement.

This change can improve the performance of Find.find when the path
has lots of entries (thousands?).

https://bugs.ruby-lang.org/issues/11302
patched by Espartaco Palma <esparta@gmail.com>
https://github.com/ruby/ruby/pull/1697 fix GH-1697
[Feature #13896]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59926 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2017-09-15 17:00:49 +00:00

88 lines
2.5 KiB
Ruby

# frozen_string_literal: true
#
# find.rb: the Find module for processing all files under a given directory.
#
#
# The +Find+ module supports the top-down traversal of a set of file paths.
#
# For example, to total the size of all files under your home directory,
# ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
#
# require 'find'
#
# total_size = 0
#
# Find.find(ENV["HOME"]) do |path|
# if FileTest.directory?(path)
# if File.basename(path)[0] == ?.
# Find.prune # Don't look any further into this directory.
# else
# next
# end
# else
# total_size += FileTest.size(path)
# end
# end
#
module Find
#
# Calls the associated block with the name of every file and directory listed
# as arguments, then recursively on their subdirectories, and so on.
#
# Returns an enumerator if no block is given.
#
# See the +Find+ module documentation for an example.
#
def find(*paths, ignore_error: true) # :yield: path
block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
fs_encoding = Encoding.find("filesystem")
paths.collect!{|d| raise Errno::ENOENT, d unless File.exist?(d); d.dup}.each do |path|
path = path.to_path if path.respond_to? :to_path
enc = path.encoding == Encoding::US_ASCII ? fs_encoding : path.encoding
ps = [path]
while file = ps.shift
catch(:prune) do
yield file.dup.taint
begin
s = File.lstat(file)
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
raise unless ignore_error
next
end
if s.directory? then
begin
fs = Dir.children(file, encoding: enc)
rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
raise unless ignore_error
next
end
fs.sort!
fs.reverse_each {|f|
f = File.join(file, f)
ps.unshift f.untaint
}
end
end
end
end
nil
end
#
# Skips the current file or directory, restarting the loop with the next
# entry. If the current file is a directory, that directory will not be
# recursively entered. Meaningful only within the block associated with
# Find::find.
#
# See the +Find+ module documentation for an example.
#
def prune
throw :prune
end
module_function :find, :prune
end