class Pathname

Practical examples and pitfalls for Pathname

Pathname examples: keep path calculations readable

Practical notes by Ruby-Doc.org

Build a destination from named pieces

An export helper often receives a base directory and a report name. Keeping the base as a Pathname makes the later path calculations read as operations on a path rather than a series of unrelated string manipulations. Constructing the object does not create the destination or prove that it exists.

Example 1
require "pathname"
base = Pathname.new("/srv/reports")
report = base.join("2026", "summary.csv")
puts report
puts report.basename
puts report.extname
Expected output
/srv/reports/2026/summary.csv
summary.csv
.csv

The example uses a fixed Unix path to make the printed result predictable. In a real helper, accept the base directory from the caller and decide which path forms the interface supports. A path library does not make every operating system's path conventions identical.

Separate a tidy spelling from an existing location

cleanpath can simplify a path without consulting the filesystem. That makes it useful when preparing a display name or normalizing paths within a known logical layout. It is a different operation from realpath, which resolves an existing path and accounts for symbolic links.

Example 2
require "pathname"
path = Pathname.new("drafts/../reports/./summary.csv")
puts path.cleanpath
puts Pathname.new("/srv/reports/summary.csv")
             .relative_path_from(Pathname.new("/srv"))
Expected output
reports/summary.csv
reports/summary.csv

Do not use a neatly normalized spelling as evidence that a file is inside an allowed directory. In particular, symbolic links and later filesystem changes are separate concerns. The example is a path-calculation demonstration, not an access-control check.

Define what the caller gets back

Some path operations return another Pathname; reading file contents returns data instead. Keep that distinction visible when naming variables. A variable called report_path should not unexpectedly become the contents of the report halfway through the helper.

For output intended for a log or a protocol, convert the path to a string explicitly. For file operations, pass the path object where the receiving Ruby API accepts it. Test a relative path and an absolute path if both are allowed, and include a missing file when the helper eventually performs a read. The path calculation can succeed even when the later filesystem operation cannot.

API reference: Pathname API reference

Related: File · Dir

pathname.rb

Object-Oriented Pathname Class

Author

Tanaka Akira <akr@m17n.org>

Documentation

Author and Gavin Sinclair

For documentation, see class Pathname.

Pathname represents the name of a file or directory on the filesystem, but not the file itself.

The pathname depends on the Operating System: Unix, Windows, etc. This library works with pathnames of local OS, however non-Unix pathnames are supported experimentally.

A Pathname can be relative or absolute. It’s not until you try to reference the file that it even matters whether the file exists or not.

Pathname is immutable. It has no method for destructive update.

The goal of this class is to manipulate file path information in a neater way than standard Ruby provides. The examples below demonstrate the difference.

All functionality from File, FileTest, and some from Dir and FileUtils is included, in an unsurprising way. It is essentially a facade for all of these, and more.

Examples

Example 1: Using Pathname

require 'pathname'
pn = Pathname.new("/usr/bin/ruby")
size = pn.size              # 27662
isdir = pn.directory?       # false
dir  = pn.dirname           # Pathname:/usr/bin
base = pn.basename          # Pathname:ruby
dir, base = pn.split        # [Pathname:/usr/bin, Pathname:ruby]
data = pn.read
pn.open { |f| _ }
pn.each_line { |line| _ }

Example 2: Using standard Ruby

pn = "/usr/bin/ruby"
size = File.size(pn)        # 27662
isdir = File.directory?(pn) # false
dir  = File.dirname(pn)     # "/usr/bin"
base = File.basename(pn)    # "ruby"
dir, base = File.split(pn)  # ["/usr/bin", "ruby"]
data = File.read(pn)
File.open(pn) { |f| _ }
File.foreach(pn) { |line| _ }

Example 3: Special features

p1 = Pathname.new("/usr/lib")   # Pathname:/usr/lib
p2 = p1 + "ruby/1.8"            # Pathname:/usr/lib/ruby/1.8
p3 = p1.parent                  # Pathname:/usr
p4 = p2.relative_path_from(p3)  # Pathname:lib/ruby/1.8
pwd = Pathname.pwd              # Pathname:/home/gavin
pwd.absolute?                   # true
p5 = Pathname.new "."           # Pathname:.
p5 = p5 + "music/../articles"   # Pathname:music/../articles
p5.cleanpath                    # Pathname:articles
p5.realpath                     # Pathname:/home/gavin/articles
p5.children                     # [Pathname:/home/gavin/articles/linux, ...]

Breakdown of functionality

Core methods

These methods are effectively manipulating a String, because that’s all a path is. None of these access the file system except for mountpoint?, children, each_child, realdirpath and realpath.

File status predicate methods

These methods are a facade for FileTest:

File property and manipulation methods

These methods are a facade for File:

Directory methods

These methods are a facade for Dir:

Utilities

These methods are a mixture of Find, FileUtils, and others:

Method documentation

As the above section shows, most of the methods in Pathname are facades. The documentation for these methods generally just says, for instance, “See FileTest.writable?”, as you should be familiar with the original method anyway, and its documentation (e.g. through ri) will contain more information. In some cases, a brief description will follow.