# module Find

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).start_with?('.')
          Find.prune       # Don't look any further into this directory.
        else
          next
        end
      else
        total_size += FileTest.size(path)
      end
    end

### Public Class Methods

find(*paths, ignore_error: true) { |path| ... } click to toggle source

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.

    # File lib/find.rb, line 38
    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
            begin
              s = File.lstat(file)
            rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
              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, Errno::EINVAL
                raise unless ignore_error
                next
              end
              fs.sort!
              fs.reverse_each {|f|
                f = File.join(file, f)
                ps.unshift f
              }
            end
          end
        end
      end
      nil
    end

prune() click to toggle source

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.

    # File lib/find.rb, line 83
    def prune
      throw :prune
    end

### Private Instance Methods

find(*paths, ignore_error: true) { |path| ... } click to toggle source

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.

    # File lib/find.rb, line 38
    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
            begin
              s = File.lstat(file)
            rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
              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, Errno::EINVAL
                raise unless ignore_error
                next
              end
              fs.sort!
              fs.reverse_each {|f|
                f = File.join(file, f)
                ps.unshift f
              }
            end
          end
        end
      end
      nil
    end

prune() click to toggle source

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.

    # File lib/find.rb, line 83
    def prune
      throw :prune
    end