class Dir

Practical examples and pitfalls for Dir

Dir examples: list entries without depending on the working directory

Practical notes by Ruby-Doc.org

Make the root of a search explicit

A report generator may run from a terminal, a scheduled job or a test runner. Those callers need not share a working directory. Supplying a base directory to Dir.glob makes the search location visible and avoids relying on whichever directory the process inherited.

Example 1
require "tmpdir"
Dir.mktmpdir("ruby-doc-example-") do |dir|
  %w[b.txt a.txt ignored.csv].each do |name|
    File.write(File.join(dir, name), "sample")
  end
  p Dir.glob("*.txt", base: dir).sort
end
Expected output
["a.txt", "b.txt"]

The results here are names relative to the supplied base. Join them to that base when opening the files. Sorting makes the demonstration's output predictable; if an application needs a different ordering, such as modification time, make that ordering a separate step with its own rule.

Distinguish child names from openable paths

Dir.children returns child names without the special dot entries. Those names do not include the directory you asked about. A name that looks correct in a log may still open the wrong file if it is later interpreted relative to another working directory.

Example 2
require "tmpdir"
Dir.mktmpdir("ruby-doc-example-") do |dir|
  File.write(File.join(dir, "note.txt"), "ready")
  names = Dir.children(dir)
  p names
  p File.read(File.join(dir, names.fetch(0)))
end
Expected output
["note.txt"]
"ready"

The demonstration uses a temporary directory so it has no dependence on your real project files. When adapting it, include a directory among the children if the helper must handle both files and subdirectories. A directory listing alone does not tell you that every entry is a regular file.

Avoid making one helper change everybody's location

Changing the current working directory affects the process, not just one pathname variable. Even when a block restores the previous directory afterward, consider the other work happening in that process. Explicit paths are often easier to reason about in a reusable library or concurrent program.

Directory contents can also change while you process the results. Decide how to handle an entry that disappears between listing and opening. Report a missing input where the report can explain it; do not assume that a successful listing guarantees all subsequent reads will succeed.

API reference: Dir API reference

Related: File · Pathname

An object of class Dir represents a directory in the underlying file system.

It consists mainly of:

About the Examples

Some examples on this page use this simple file tree:

example/
├── config.h
├── lib/
│   ├── song/
│   │   └── karaoke.rb
│   └── song.rb
└── main.rb

Others use the file tree for the Ruby project itself.

Dir As Array-Like

A Dir object is in some ways array-like:

Dir As Stream-Like

A Dir object is in some ways stream-like.

The stream is initially open for reading, but may be closed manually (using method close), and will be closed on block exit if created by Dir.open called with a block. The closed stream may not be further manipulated, and may not be reopened.

The stream has a position, which is the index of an entry in the directory:

Examples (using the simple file tree):

dir = Dir.new('example') # => #<Dir:example>
dir.pos                  # => 0

dir.read # => "."
dir.read # => ".."
dir.read # => "config.h"
dir.read # => "lib"
dir.read # => "main.rb"
dir.pos  # => 5
dir.read # => nil
dir.pos  # => 5

dir.rewind # => #<Dir:example>
dir.pos    # => 0

dir.pos = 3 # => 3
dir.pos     # => 3

dir.seek(4) # => #<Dir:example>
dir.pos     # => 4

dir.close # => nil
dir.read  # Raises IOError.

What’s Here

First, what’s elsewhere. Class Dir:

Here, class Dir provides methods that are useful for:

Reading

Setting

Querying

Iterating

Other