class Pathname
pathname.rb
Object-Oriented Pathname Class
- Author
-
Tanaka Akira <akr@m17n.org>
- Documentation
-
Author and Gavin Sinclair
For documentation, see class Pathname.
A Pathname object contains a string directory path or filepath; it does not represent a corresponding actual file or directory – which in fact may or may not exist.
A Pathname object is immutable (except for method freeze).
A pathname may be relative or absolute:
Pathname.new('lib') # => #<Pathname:lib> Pathname.new('/usr/local/bin') # => #<Pathname:/usr/local/bin>
About the Examples
Many examples here use these variables:
# English text with newlines. text = <<~EOT First line Second line Fourth line Fifth line EOT # Japanese text. japanese = 'こんにちは' # Binary data. data = "\u9990\u9991\u9992\u9993\u9994" # Text file. File.write('t.txt', text) # File with Japanese text. File.write('t.ja', japanese) # File with binary data. f = File.new('t.dat', 'wb:UTF-16') f.write(data) f.close
Convenience Methods
The class provides all functionality from class File and module FileTest, along with some functionality from class Dir and module FileUtils.
Here’s an example string path and corresponding Pathname object:
path = 'lib/fileutils.rb' pn = Pathname.new(path) # => #<Pathname:lib/fileutils.rb>
Each of these method pairs (Pathname vs. File) gives exactly the same result:
pn.size # => 83777 File.size(path) # => 83777 pn.directory? # => false File.directory?(path) # => false pn.read.size # => 81074 File.read(path).size# # => 81074
Each of these method pairs gives similar results, but each Pathname method returns a more versatile Pathname object, instead of a string:
pn.dirname # => #<Pathname:lib> File.dirname(path) # => "lib" pn.basename # => #<Pathname:fileutils.rb> File.basename(path) # => "fileutils.rb" pn.split # => [#<Pathname:lib>, #<Pathname:fileutils.rb>] File.split(path) # => ["lib", "fileutils.rb"]
Each of these methods takes a block:
pn.open do |file| p file end File.open(path) do |file| p file end
The outputs for each:
#<File:lib/fileutils.rb (closed)> #<File:lib/fileutils.rb (closed)>
Each of these methods takes a block:
pn.each_line do |line| p line break end File.foreach(path) do |line| p line break end
The outputs for each:
"# frozen_string_literal: true\n" "# frozen_string_literal: true\n"
More Methods
Here is a sampling of other available methods:
p1 = Pathname.new('/usr/lib') # => #<Pathname:/usr/lib> p1.absolute? # => true p2 = p1 + 'ruby/4.0' # => #<Pathname:/usr/lib/ruby/4.0> p3 = p1.parent # => #<Pathname:/usr> p4 = p2.relative_path_from(p3) # => #<Pathname:lib/ruby/4.0> p4.absolute? # => false p5 = Pathname.new('.') # => #<Pathname:.> p6 = p5 + 'usr/../var' # => #<Pathname:usr/../var> p6.cleanpath # => #<Pathname:var> p6.realpath # => #<Pathname:/var> p6.children.take(2) # => [#<Pathname:usr/../var/local>, #<Pathname:usr/../var/spool>]
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:
-
each_entry(&block)
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.
Constants
- VERSION
-
The version string.
Public Class Methods
Source
# File pathname_builtin.rb, line 2509 def Pathname.getwd() self.new(Dir.getwd) end
Returns a new Pathname object containing the path to the current working directory (equivalent to Pathname.new(Dir.getwd)):
Pathname.getwd # => #<Pathname:/home>
(String | Array[String] pattern, ?Integer flags) → Array[Pathname]
(String | Array[String] pattern, ?Integer flags) { (Pathname) → untyped } → nil
Source
# File pathname_builtin.rb, line 2478 def Pathname.glob(*args, **kwargs) # :yield: pathname if block_given? Dir.glob(*args, **kwargs) {|f| yield self.new(f) } else Dir.glob(*args, **kwargs).map {|f| self.new(f) } end end
Selects filesystem entries based on the given keyword arguments base, flags, and sort; see Filename Globbing.
With no block given, returns an array of pathnames, each based on a selected filesystem entry.
With a block given, calls the block with pathnames, each based on a selected filesytem entry.
# File lib/pathname.rb, line 154 def self.mktmpdir require 'tmpdir' unless defined?(Dir.mktmpdir) if block_given? Dir.mktmpdir do |dir| dir = self.new(dir) yield dir end else self.new(Dir.mktmpdir) end end
Creates:
-
A temporary directory via
Dir.mktmpdir. -
A Pathname object that contains the path to that directory.
With no block given, returns the created pathname; the caller should delete the created directory when it is no longer needed (FileUtils.rm_r is a convenient method for the deletion):
pathname = Pathname.mktmpdir dirpath = pathname.to_s Dir.exist?(dirpath) # => true # Do something with the directory. require 'fileutils' FileUtils.rm_r(dirpath)
With a block given, calls the block with the created pathname; on block exit, automatically deletes the created directory and all its contents; returns the block’s exit value:
pathname = Pathname.mktmpdir do |p| # Do something with the directory. p end Dir.exist?(pathname.to_s) # => false
(string | Pathname) → void
Source
# File pathname_builtin.rb, line 243 def initialize(path) @path = File.path(path).dup rescue TypeError => e raise e.class, "Pathname.new requires a String, #to_path or #to_str", cause: nil end
Returns a new Pathname object based on the given path, via File.path(path).dup. the path may be a String, a File, a Dir, or another Pathname; see File.path:
Pathname.new('.') # => #<Pathname:.> Pathname.new('/usr/bin') # => #<Pathname:/usr/bin> Pathname.new(File.new('LEGAL')) # => #<Pathname:LEGAL> Pathname.new(Dir.new('.')) # => #<Pathname:.> Pathname.new(Pathname.new('.')) # => #<Pathname:.>
Public Instance Methods
# File pathname_builtin.rb, line 767 def +(other) other = Pathname.new(other) unless Pathname === other Pathname.new(plus(@path, other.path)) end
Returns a new Pathname object based on the content of self and other; argument other may be a String, a File, a Dir, or another Pathname:
pn = Pathname('foo') # => #<Pathname:foo> pn + 'bar' # => #<Pathname:foo/bar> pn + File.new('LEGAL') # => #<Pathname:foo/LEGAL> pn + Dir.new('lib') # => #<Pathname:foo/lib> pn + Pathname('bar') # => #<Pathname:foo/bar>
When other specifies a relative path (see relative?), it is combined with self to form a new pathname:
Pathname('/a/b') + 'c' # => #<Pathname:/a/b/c>
Extra component separators ('/') are removed:
Pathname('/a/b/') + 'c' # => #<Pathname:/a/b/c>
Extra current-directory components ('.') are removed:
Pathname('a') + '.' # => #<Pathname:a> Pathname('.') + 'a' # => #<Pathname:a> Pathname('.') + '.' # => #<Pathname:.>
Parent-directory components ('..') are:
-
Resolved, when possible:
Pathname('a') + '..' # => #<Pathname:.> Pathname('a/b') + '..' # => #<Pathname:a> Pathname('/') + '../a' # => #<Pathname:/a> Pathname('a') + '../b' # => #<Pathname:b> Pathname('a/b') + '../c' # => #<Pathname:a/c> Pathname('a//b/c') + '../d//e' # => #<Pathname:a//b/d//e>
-
Removed, when not needed:
Pathname('/') + '..' # => #<Pathname:/>
-
Retained, when needed:
Pathname('..') + '..' # => #<Pathname:../..> Pathname('..') + '../a' # => #<Pathname:../../a>
When other specifies an absolute path (see absolute?), equivalent to Pathname(other.to_s):
Pathname('/a') + '/b/c' # => #<Pathname:/b/c>
Occurrences of '/', '.', and '..' are preserved:
Pathname('/a') + '//b//c/./../d' # => #<Pathname://b//c/./../d>
This method does not access the file system, so other need not represent an existing (or even a valid) file or directory path:
Pathname('/var') + 'nosuch:ever' # => #<Pathname:/var/nosuch:ever>
static VALUE
path_cmp(VALUE self, VALUE other)
{
VALUE s1, s2;
char *p1, *p2;
char *e1, *e2;
if (!rb_obj_is_kind_of(other, rb_cPathname))
return Qnil;
s1 = get_strpath(self);
s2 = get_strpath(other);
p1 = RSTRING_PTR(s1);
p2 = RSTRING_PTR(s2);
e1 = p1 + RSTRING_LEN(s1);
e2 = p2 + RSTRING_LEN(s2);
while (p1 < e1 && p2 < e2) {
int c1, c2;
c1 = (unsigned char)*p1++;
c2 = (unsigned char)*p2++;
if (c1 == '/') c1 = '\0';
if (c2 == '/') c2 = '\0';
if (c1 != c2) {
if (c1 < c2)
return INT2FIX(-1);
else
return INT2FIX(1);
}
}
if (p1 < e1)
return INT2FIX(1);
if (p2 < e2)
return INT2FIX(-1);
return INT2FIX(0);
}
Compares the contents of self and other as strings; see String#<=>.
Returns:
-
-1ifself‘s string is smaller thanother’s string. -
0if the two are equal. -
1ifself‘s string is larger thanother’s string. -
nilifotheris not a Pathname.
Examples:
Pathname('a') <=> Pathname('b') # => -1 Pathname('a') <=> Pathname('ab') # => -1 Pathname('a') <=> Pathname('a') # => 0 Pathname('b') <=> Pathname('a') # => 1 Pathname('ab') <=> Pathname('a') # => 1 Pathname('ab') <=> 'a' # => nil
Two pathnames that are different may refer to the same entry in the filesystem:
Pathname('lib') <=> Pathname('./lib') # => 1
(untyped) → bool
Source
# File pathname_builtin.rb, line 273 def ==(other) return false unless Pathname === other other.path == @path end
Returns whether the stored paths in self and other are equal:
pn = Pathname('lib') pn == Pathname('lib') # => true pn == Pathname('./lib') # => false
Returns false if other is not a pathname:
pn == 'lib' # => false
() → bool
Source
static VALUE
path_absolute_p(VALUE self)
{
VALUE path = get_strpath(self);
const char *ptr = RSTRING_PTR(path);
long len = RSTRING_LEN(path);
if (len < 1) return Qfalse;
if (drive_letter) {
if (len >= 2 && ISALPHA(ptr[0]) && (ptr[1] == ':')) return Qtrue;
}
return RBOOL(isdirsep(ptr[0]));
}
Returns whether self contains an absolute path:
Pathname('/home').absolute? # => true Pathname('lib').absolute? # => false
The result is OS-dependent for some paths:
Pathname('C:/').absolute? # => true # On Windows. Pathname('C:/').absolute? # => false # Elsewhere.
() { (Pathname) → untyped } → nil
() → Enumerator[Pathname, nil]
Source
# File pathname_builtin.rb, line 695 def ascend return to_enum(__method__) unless block_given? path = @path yield self while r = chop_basename(path) path, = r break if path.empty? yield self.class.new(del_trailing_separator(path)) end end
With a block given, yields self, then a new pathname for each successive dirname in the stored path; see File.dirname:
Pathname('/path/to/some/file.rb').ascend {|dirname| p dirname} #<Pathname:/path/to/some/file.rb> #<Pathname:/path/to/some> #<Pathname:/path/to> #<Pathname:/path> #<Pathname:/>
With no block given, returns a new Enumerator.
() → Time
Source
# File pathname_builtin.rb, line 1249 def atime() File.atime(@path) end
Returns a Time object containing the access time of the entry represented by self, as reported by the filesystem; see File System Access Time:
# Pathname for a (non-existent) directory. dir_pn = Pathname('doc/foo') # => #<Pathname:doc/foo> # Create directory; establishes atime for directory. dir_pn.mkdir dir_pn.atime # => 2026-06-17 10:10:20.801115774 -0500 # Pathname for a (non-existent) file in the directory. file_pn = dir_pn.join('t.tmp') # => #<Pathname:doc/foo/t.tmp> # Create file; establishes atime for file, updates atime for directory. file_pn.write('foo') file_pn.atime # => 2026-06-17 10:11:40.987171568 -0500 dir_pn.atime # => 2026-06-17 10:11:40.96617277 -0500 # Write file; updates atime for file,but not directory. file_pn.write('bar') file_pn.atime # => 2026-06-17 10:13:22.062904563 -0500 dir_pn.atime # => 2026-06-17 10:11:40.96617277 -0500 # Read file; may update atime for file, but not directory. file_pn.read file_pn.atime # => 2026-06-17 10:13:22.062904563 -0500 dir_pn.atime # => 2026-06-17 10:11:40.96617277 -0500 # Clean up. file_pn.delete dir_pn.rmdir
# File pathname_builtin.rb, line 1860 def basename(...) self.class.new(File.basename(@path, ...)) end
Returns a new Pathname object containing all or part of the last entry of the path represented by self. Entries are delimited by the value of constant File::SEPARATOR and, if non-nil, the value of constant File::ALT_SEPARATOR.
When suffix is the empty string '', returns all of the last entry:
Pathname.new('foo/bar/baz/bat.txt').basename # => #<Pathname:bat.txt> Pathname.new('foo/bar/baz').basename # => #<Pathname:baz> File::SEPARATOR # => "/" Pathname.new('foo/bar.txt////').basename # => #<Pathname:bar.txt> File::ALT_SEPARATOR # => "\\" # On Windows. Pathname.new('foo/bar.txt//\\\\//').basename # => #<Pathname:bar.txt>
When suffix is '.*', the last filename extension, if any, is removed:
Pathname.new('foo/bar.txt').basename('.*') # => #<Pathname:bar> Pathname.new('foo/bar.txt.old').basename('.*') # => #<Pathname:bar.txt> Pathname.new('foo/bar').basename('.*') # => #<Pathname:bar>
When suffix is any string other than '' or '.*', the matching trailing substring, if any, is removed:
Pathname.new('foo/bar.txt').basename('.txt') # => #<Pathname:bar> Pathname.new('foo/bar.txt').basename('txt') # => #<Pathname:bar.> Pathname.new('foo/bar.txt').basename('*') # => #<Pathname:bar.txt> Pathname.new('foo/bar.txt').basename('.') # => #<Pathname:bar.txt>
# File pathname_builtin.rb, line 1087 def binread(...) File.binread(@path, ...) end
Behaves like read, except that the file is opened in binary mode with ASCII-8BIT encoding.
(String, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?invalid: :replace ?, ?undef: :replace ?, ?replace: String, ?fallback: Hash[String, String] | Proc | Method, ?xml: :text | :attr, ?universal_newline: true, ?cr_newline: true, ?crlf_newline: true) → Integer
Source
# File pathname_builtin.rb, line 1213 def binwrite(...) File.binwrite(@path, ...) end
Behaves like write, except that the file is opened in binary mode with ASCII-8BIT encoding.
() → Time
Source
# File pathname_builtin.rb, line 1282 def birthtime() File.birthtime(@path) end
Returns a new Time object containing the create time of the entry represented by self; see File System Timestamps:
# A directory and its Pathname. dir_path = 'doc/foo' dir_pn = Pathname(dir_path) # Create directory; directory birthtime established. dir_pn.mkdir dir_pn.birthtime # => 2026-06-16 17:06:10.779192552 -0500 # A file therein and its Pathname. file_path = dir_pn.join('t.tmp') file_pn = Pathname(file_path) # Create file; file birthtime established; directory birthtime not updated. file_pn.write('foo') dir_pn.birthtime # => 2026-06-16 17:06:10.779192552 -0500 file_pn.birthtime # => 2026-06-16 17:07:59.339330622 -0500 # Modify file; neither birthtime updated. file_pn.write('bar') dir_pn.birthtime # => 2026-06-16 17:06:10.779192552 -0500 file_pn.birthtime # => 2026-06-16 17:07:59.339330622 -0500 # Clean up. dir_pn.rmtree
() → bool
Source
# File pathname_builtin.rb, line 2039 def blockdev?() FileTest.blockdev?(@path) end
Returns whether self represents a path to a block device (i.e., a direct-access device):
Pathname('/dev/nvme0n1').blockdev? # => true Pathname('/dev/loop0').blockdev? # => true Pathname('/dev/tty').blockdev? # => false Pathname('/dev/null').blockdev? # => false Pathname('nosuch').blockdev? # => false Pathname($stdin).blockdev? # => false
The returned value is OS-dependent; on Windows, almost always false.
() → bool
Source
# File pathname_builtin.rb, line 2059 def chardev?() FileTest.chardev?(@path) end
Returns whether self represents a path to a character device (i.e., a sequential-access device):
Pathname('/dev/tty').chardev? # => true Pathname('/dev/null').chardev? # => true Pathname('/dev/nvme0n1').chardev? # => false Pathname('/dev/loop0').chardev? # => false Pathname($stdin).chardev? # => false Pathname('nosuch').chardev? # => false
The returned value is OS-dependent; on Windows, almost always false.
# File pathname_builtin.rb, line 867 def children(with_directory=true) with_directory = false if @path == '.' result = Dir.children(@path) if with_directory result.map! {|e| self.class.new(File.join(@path, e))} else result.map! {|e| self.class.new(e)} end result end
Returns an array of pathnames; each represents a child of the entry represented by self, which must be an existing directory in the underlying file system.
With with_dirnames given as true (the default), each pathname contains the full entry:
Pathname('lib').children.size # => 72 Pathname('lib').children.take(3) # => [#<Pathname:lib/bundled_gems.rb>, #<Pathname:lib/bundler>, #<Pathname:lib/bundler.rb>]
With with_dirnames given as false, each pathname contains only the basename of the entry:
Pathname('lib').children(false).take(3) # => [#<Pathname:bundled_gems.rb>, #<Pathname:bundler>, #<Pathname:bundler.rb>]
Note that entries . and .. in directory are not actually children, and so are never included in the result.
# File pathname_builtin.rb, line 1390 def chmod(mode) File.chmod(mode, @path) end
Changes the mode (i.e., permissions) of the entry represented by self; see File Permissions:
# Pathname for a (non-existent) directory. dir_pn = Pathname('doc/foo') # => #<Pathname:doc/foo> # Create the directory and fetch its mode. dir_pn.mkdir dir_pn.stat.mode.to_s(8) # => "40775" # Change the directory mode and fetch the new mode. dir_pn.chmod(0777) dir_pn.stat.mode.to_s(8) # => "40777" # Pathname for a (non-existent) file in the directory. file_pn = dir_pn.join('t.tmp') # => #<Pathname:doc/foo/t.tmp> # Create the file and fetch its mode. file_pn.write('foo') file_pn.stat.mode.to_s(8) # => "100664" # Change the file mode and fetch its new mode. file_pn.chmod(0777) file_pn.stat.mode.to_s(8) # => "100777" # Clean up. file_pn.delete dir_pn.rmdir
# File pathname_builtin.rb, line 1467 def chown(owner, group) File.chown(owner, group, @path) end
Changes the owner and group of an entry (directory or file):
# Super user; all privileges. Process.uid # => 0 Process.gid # => 0 # Pathname for a (non-existent) directory. dir_pn = Pathname('doc/foo') # => #<Pathname:doc/foo> # Create the directory; fetch original owner and group. dir_pn.mkdir dir_stat = dir_pn.stat dir_stat.uid # => 0 dir_stat.gid # => 0 # Change owner; fetch current owner and group. dir_pn.chown(1000, 1000) dir_stat = dir_pn.stat dir_stat.uid # => 1000 dir_stat.gid # => 1000 Pathname for a (non-existent) file in the directory. file_pn = dir_pn.join('t.tmp') # => #<Pathname:doc/foo/t.tmp> # Create the directory; fetch original owner and group. file_pn.write('foo') file_stat = file_pn.stat file_stat.uid # => 0 file_stat.gid # => 0 # Change owner; fetch current owner and group. file_pn.chown(1000, 1000) file_stat = file_pn.stat file_stat.uid # => 1000 file_stat.gid # => 1000 # Clean up. file_pn.delete dir_pn.rmdir
Notes:
-
On Windows, the owner and group are not changed.
-
Only a process with superuser privileges can change the owner of an entry.
-
The owner of an entry can change its group to any group to which the owner belongs.
-
A +nil+ or +-1+ owner or group id is ignored.
-
The method follows symbolic links to the target entry.
(?boolish consider_symlink) → Pathname
Source
# File pathname_builtin.rb, line 487 def cleanpath(consider_symlink=false) if consider_symlink cleanpath_conservative else cleanpath_aggressive end end
Returns a new Pathname object, “cleaned” of unnecessary separators, single-dot entries, and double-dot entries.
When self is empty, returns a pathname with a single-dot entry:
Pathname('').cleanpath # => #<Pathname:.>
Separators
A lone separator is preserved:
Pathname('/').cleanpath # => #<Pathname:/>
Multiple trailing separators are removed:
Pathname('foo/////').cleanpath # => #<Pathname:foo> Pathname('foo/').cleanpath # => #<Pathname:foo>
Multiple embedded separators are reduced to a single separator:
Pathname('foo///bar').cleanpath # => #<Pathname:foo/bar>
Multiple leading separators are reduced:
# On Windows, where File.dirname('//') == '//'. Pathname('/////foo').cleanpath # => #<Pathname://foo> Pathname('/////').cleanpath # => #<Pathname://> # Otherwise, where File.dirname('//') == '/'. Pathname('/////foo').cleanpath # => #<Pathname:/foo> Pathname('/////').cleanpath # => #<Pathname:/>
Single-Dot Entries
A lone single-dot entry is preserved:
Pathname('.').cleanpath # => #<Pathname:.>
A non-lone single-dot entry, regardless of its location, is removed:
Pathname('foo/././././bar').cleanpath # => #<Pathname:foo/bar> Pathname('./foo/./././bar').cleanpath # => #<Pathname:foo/bar> Pathname('foo/./././bar/./').cleanpath # => #<Pathname:foo/bar>
Double-Dot Entries
A lone double-dot entry is preserved:
Pathname('..').cleanpath # => #<Pathname:..>
When a non-lone double-dot entry is preceded by a named entry, both are removed:
Pathname('foo/..').cleanpath # => #<Pathname:.> Pathname('foo/../bar').cleanpath # => #<Pathname:bar> Pathname('foo/../bar/..').cleanpath # => #<Pathname:.> Pathname('foo/bar/./../..').cleanpath # => #<Pathname:.>
When a non-lone double-dot entry is not preceded by a named entry, it is preserved:
Pathname('../..').cleanpath # => #<Pathname:../..>
A non-lone meaningless double-dot entry is removed:
Pathname('/..').cleanpath # => #<Pathname:/> Pathname('/../..').cleanpath # => #<Pathname:/>
Symbolic Links
If the path may contain symbolic links, consider give optional argument symlinks as true; the method then uses a more conservative algorithm that avoids breaking symbolic links. This may preserve more double-dot entries than are absolutely necessary, but without accessing the filesystem, this can’t be avoided.
Examples:
Pathname('a/').cleanpath # => #<Pathname:a> Pathname('a/').cleanpath(true) # => #<Pathname:a/> Pathname('a/.').cleanpath # => #<Pathname:a> Pathname('a/.').cleanpath(true) # => #<Pathname:a/.> Pathname('a/./').cleanpath # => #<Pathname:a> Pathname('a/./').cleanpath(true) # => #<Pathname:a/.> Pathname('a/b/.').cleanpath # => #<Pathname:a/b> Pathname('a/b/.').cleanpath(true) # => #<Pathname:a/b/.> Pathname('a/../.').cleanpath # => #<Pathname:.> Pathname('a/../.').cleanpath(true) # => #<Pathname:a/..> Pathname('a/b/../../../../c/../d').cleanpath # => #<Pathname:../../d> Pathname('a/b/../../../../c/../d').cleanpath(true) # => #<Pathname:a/b/../../../../c/../d>
() → Time
Source
# File pathname_builtin.rb, line 1322 def ctime() File.ctime(@path) end
On Windows, returns the birthtime.
On other systems, returns a new Time object containing the time of the most recent metadata change to the entry represented by self; see File System Timestamps:
# A directory and its Pathname. dir_path = 'doc/foo' dir_pn = Pathname(dir_path) # Create directory; directory ctime established. dir_pn.mkdir dir_pn.ctime # => 2026-06-16 16:44:15.86720572 -0500 # A file therein and its Pathname. file_path = dir_pn.join('t.tmp') file_pn = Pathname(file_path) # Create file; file ctime established; directory ctime updated. file_pn.write('foo') file_pn.ctime # => 2026-06-16 16:46:00.734974872 -0500 dir_pn.ctime # => 2026-06-16 16:46:00.734974872 -0500 # Write file; file ctime updated; directory ctime not updated. file_pn.write('bar') file_pn.ctime # => 2026-06-16 16:49:11.421204188 -0500 dir_pn.ctime # => 2026-06-16 16:46:00.734974872 -0500 # Read file; neither ctime updated. file_pn.read file_pn.ctime # => 2026-06-16 16:49:11.421204188 -0500 dir_pn.ctime # => 2026-06-16 16:46:00.734974872 -0500 # Clean up. dir_pn.rmtree
() { (Pathname) → untyped } → nil
() → Enumerator[Pathname, nil]
Source
# File pathname_builtin.rb, line 671 def descend return to_enum(__method__) unless block_given? vs = [] ascend {|v| vs << v } vs.reverse_each {|v| yield v } nil end
With a block given, yields a new pathname for each successive dirname in the stored path; see File.dirname:
# Absolute path. Pathname('/path/to/some/file.rb').descend {|pn| p pn } # #<Pathname:/> # #<Pathname:/path> # #<Pathname:/path/to> # #<Pathname:/path/to/some> # #<Pathname:/path/to/some/file.rb> # Relative path. Pathname('path/to/some/file.rb').descend {|pn| p pn } # #<Pathname:path> # #<Pathname:path/to> # #<Pathname:path/to/some> # #<Pathname:path/to/some/file.rb>
With no block given, returns a new Enumerator.
() → bool
Source
# File pathname_builtin.rb, line 2171 def directory?() FileTest.directory?(@path) end
Returns whether the entry represented by self is a directory:
Pathname('/etc').directory? # => true Pathname('lib').directory? # => true Pathname('README.md').directory? # => false Pathname('nosuch').directory? # => false
() → Pathname
Source
# File pathname_builtin.rb, line 1863 def dirname() self.class.new(File.dirname(@path)) end
See File.dirname. Returns all but the last component of the path.
(?boolish with_directory) { (Pathname) → void } → Array[Pathname]
(?boolish with_directory) → Enumerator[Pathname, Array[Pathname]]
Source
# File pathname_builtin.rb, line 911 def each_child(with_directory=true, &b) children(with_directory).each(&b) end
With a block given and with_dirnames given as true (the default), yields a new pathname for each child of the entry represented by self; returns an array of those pathnames:
Pathname('include').each_child {|child| p child } # #<Pathname:include/ruby> # #<Pathname:include/ruby.h> # => [#<Pathname:include/ruby>, #<Pathname:include/ruby.h>]
With a block given and with_dirnames given as false, yields a new pathname for each child of the entry represented by self with its dirname omitted; returns an array of those pathnames:
Pathname('include').each_child(false) {|child| p child } # #<Pathname:ruby> # #<Pathname:ruby.h> # => [#<Pathname:ruby>, #<Pathname:ruby.h>]
Note that entries '.' and '..' are not children.
With no block given, returns a new Enumerator.
Source
# File pathname_builtin.rb, line 2555 def each_entry(&block) # :yield: pathname return to_enum(__method__) unless block_given? Dir.foreach(@path) {|f| yield self.class.new(f) } end
With a block given, yields a new pathname for each entry in the entry represented by self; returns nil:
Pathname('include').each_entry {|entry| p entry } # #<Pathname:ruby> # #<Pathname:..> # #<Pathname:ruby.h> # #<Pathname:.> # => nil
With no block given, returns a new Enumerator.
() { (String) → untyped } → nil
() → Enumerator[String, nil]
Source
# File pathname_builtin.rb, line 638 def each_filename # :yield: filename return to_enum(__method__) unless block_given? _, names = split_names(@path) names.each {|filename| yield filename } nil end
With a block given, yields each component of the string path:
Pathname('/foo/bar/baz').each_filename {|filename| p filename } => nil
Output:
"foo" "bar" "baz"
With no block given, returns a new Enumerator.
(?String sep, ?Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) { (String) → untyped } → nil
(Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) { (String) → untyped } → nil
(?String sep, ?Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) → Enumerator[String, nil]
(Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) → Enumerator[String, nil]
Source
# File pathname_builtin.rb, line 1018 def each_line(...) # :yield: line File.foreach(@path, ...) end
With a block given, calls the block with each line from the file represented by self; returns nil:
lines = [] Pathname('COPYING').each_line {|line| lines << line } lines.take(3) # => # ["{日本語}[rdoc-ref:COPYING.ja]\n", # "\n", # "Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.\n"]
The lines are read using IO.foreach, all arguments and options are passed to that method; see details at IO.foreach.
With no block given, returns a new Enumerator.
() → bool
Source
# File pathname_builtin.rb, line 2086 def empty? if FileTest.directory?(@path) Dir.empty?(@path) else File.empty?(@path) end end
Returns whether the entry represented by self exists and is empty:
dir_pn = Pathname('example_dir') dir_pn.empty? # => false # Dir does not exist. dir_pn.mkdir dir_pn.empty? # => true # Dir exists and is empty. file_pn = Pathname('example_dir/example.txt') file_pn.empty? # => false # File does not exist. file_pn.write('') file_pn.empty? # => true # File exists and is empty. dir_pn.empty? # => false # Dir exists and is not empty. file_pn.write('foo') file_pn.empty? # => false # File exists and is not empty. file_pn.delete dir_pn.delete
Source
# File pathname_builtin.rb, line 2532 def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
Returns an array of pathnames, one for each entry in the directory represented by self:
Pathname('.').entries.take(5) # => # [#<Pathname:.>, # #<Pathname:..>, # #<Pathname:gc.rb>, # #<Pathname:yjit.rb>, # #<Pathname:iseq.h>]
() → bool
Source
# File pathname_builtin.rb, line 2107 def executable?() FileTest.executable?(@path) end
Returns whether the entry represented by self is executable; calls FileTest.executable? with argument self.to_s:
Pathname('bin/gem').executable? # => true Pathname('README.md').executable? # => false
() → bool
Source
# File pathname_builtin.rb, line 2126 def executable_real?() FileTest.executable_real?(@path) end
Returns whether the entry represented by self is executable by the real user and group id of the current process; calls FileTest.executable_real? with argument self.to_s:
pn = Pathname('example') pn.write('') pn.executable_real? # => false pn.chmod(0100) pn.executable_real? # => true
() → bool
Source
# File pathname_builtin.rb, line 2141 def exist?() FileTest.exist?(@path) end
Returns whether the entry represented by self exists:
Pathname('.').exist? # => true Pathname('README.md').exist? # => true Pathname('nosuch').exist? # => false
Source
# File pathname_builtin.rb, line 1940 def expand_path(...) self.class.new(File.expand_path(@path, ...)) end
Returns a new pathname containing the absolute path for self.
Evaluates a relative path with respect to the directory given by dirpath:
Dir.chdir('/snap') # Default dirpath. Pathname('README').expand_path # => #<Pathname:/snap/README> Pathname('bin').expand_path # => #<Pathname:/snap/bin> Pathname('bin/../var').expand_path # => #<Pathname:/snap/var> # Cleaned. # Other dirpath. Pathname('../zip').expand_path('/usr/bin/ruby') # => #<Pathname:/usr/bin/zip> Dir.chdir('/usr/bin') Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap>
Evaluates an absolute path without respect to dirpath:
Pathname('/snap').expand_path # => #<Pathname:/snap> Pathname('/snap').expand_path.expand_path('nosuch') # => #<Pathname:/snap> Pathname('/snap/../snap').expand_path # => #<Pathname:/snap> # Cleaned.
More examples:
Dir.chdir('/usr/bin') Pathname('../../snap').expand_path(__FILE__) # => #<Pathname:/usr/snap> Pathname('../../snap').expand_path # => #<Pathname:/snap>
Source
# File pathname_builtin.rb, line 1901 def extname() File.extname(@path) end
Returns the filename extension of self – usually the portion of the string path beginning from the last period:
Pathname('t.rb').extname # => ".rb" Pathname('foo.bar.t.rb').extname # => ".rb" Pathname('foo/bar/t.rb').extname # => ".rb" Pathname('nosuch.txt').extname # => ".txt" # Path need not exist.
Returns the entire string when there is no period:
Pathname('foo').extname # => ""
Returns an empty string when the only period is the first character:
Pathname('.irbrc').extname # => ""
Returns an empty string or '.' when path ends with a period:
Pathname('foo.').extname # => "" # On Windows. Pathname('foo.').extname # => "." # Elsewhere. Pathname('foo....').extname # => "" # On Windows. Pathname('foo....').extname # => "." # Elsewhere.
() → bool
Source
# File pathname_builtin.rb, line 2174 def file?() FileTest.file?(@path) end
See FileTest.file?.
# File lib/pathname.rb, line 83 def find(ignore_error: true) # :yield: pathname return to_enum(__method__, ignore_error: ignore_error) unless block_given? require 'find' if @path == '.' Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) } else Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) } end end
With a block given, performs a depth-first traversal of the path in self; calls the block with each found path:
paths = [] Pathname('lib').find {|path| paths << path } paths.size # => 909 paths.take(3) # => # [#<Pathname:lib>, # #<Pathname:lib/English.gemspec>, # #<Pathname:lib/English.rb>]
When self contains '.', the found paths omit the leading './':
paths = [] Dir.chdir('lib') do Pathname('.').find {|path| paths << path } end paths.take(3) # # => # [#<Pathname:.>, # #<Pathname:English.gemspec>, # #<Pathname:English.rb>]
This method calls method Find.find; therefore method Find.prune may be used in the block:
files = [] Pathname('.').find do |path| Find.prune if File.basename(path) == 'test' next unless File.file?(path) && File.extname(path) == '.rb' files << path end files.size # => 6690 files.take(3) # # => # [#<Pathname:KNOWNBUGS.rb>, # #<Pathname:array.rb>, # #<Pathname:ast.rb>]
Raises an exception if the path in self cannot be read.
When keyword argument ignore_error is given as true (the default), certain exceptions during traversal are ignored (i.e., silently rescued): Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL; when given as false, no exceptions are rescued.
Note that these exceptions may be ignored only in Pathname#find traversal code; an exception raised before traversal begins, or raised while in the block is not ignored. Each of the calls below raises an Errno::ENOENT exception that is not ignored:
Pathname('nosuch').find { } Pathname('lib').find {|entry| raise Errno::ENOENT }
With no block given, returns a new Enumerator.
# File pathname_builtin.rb, line 1522 def fnmatch(pattern, ...) File.fnmatch(pattern, @path, ...) end
Returns whether string pattern matches against the string path in self, under the control of the given flags; see Filename Matching.
Source
# File pathname_builtin.rb, line 1525 def fnmatch?(pattern, ...) File.fnmatch?(pattern, @path, ...) end
See File.fnmatch? (same as fnmatch).
() → Pathname
Source
# File pathname_builtin.rb, line 254 def freeze super @path.freeze self end
Freezes self, preventing further modifications; see Frozen Objects.
Object#freeze
() → String
Source
# File pathname_builtin.rb, line 1548 def ftype() File.ftype(@path) end
Returns the string type of the object at the path in self:
Pathname('README.md').ftype # => "file" Pathname('lib').ftype # => "directory" Pathname('/dev/null').ftype # => "characterSpecial" Pathname('/dev/loop0').ftype # => "blockSpecial" File.mkfifo('/tmp/pipe', 0666) Pathname('/tmp/pipe').ftype # => "fifo" File.symlink('lib', 'lib_link') Pathname('lib_link').ftype # => "link" require 'socket' UNIXServer.new('/tmp/socket') Pathname('/tmp/socket').ftype # => "socket"
Returns 'unknown' if the type cannot be determined.
(String | Array[String] pattern, ?Integer flags) → Array[Pathname]
(String | Array[String] pattern, ?Integer flags) { (Pathname) → untyped } → nil
Source
# File pathname_builtin.rb, line 2493 def glob(*args, **kwargs) # :yield: pathname if block_given? Dir.glob(*args, **kwargs, base: @path) {|f| yield self + f } else Dir.glob(*args, **kwargs, base: @path).map {|f| self + f } end end
() → bool
Source
# File pathname_builtin.rb, line 2155 def grpowned?() FileTest.grpowned?(@path) end
Returns whether the filesystem entry for the path stored in self exists, and the effective group id of the calling process is the owner of the entry:
Pathname('README.md').grpowned? # => true Pathname('lib').grpowned? # => true Pathname('/etc/passwd').grpowned? # => false Pathname('nosuch').grpowned? # => false
Returns false on Windows.
# File pathname_builtin.rb, line 827 def join(*args) return self if args.empty? result = args.pop result = Pathname.new(result) unless Pathname === result return result if result.absolute? args.reverse_each {|arg| arg = Pathname.new(arg) unless Pathname === arg result = arg + result return result if result.absolute? } self + result end
Joins the string-converted given objects to the string path in self; returns a new pathname containing the joined string:
Pathname('foo').join # => #<Pathname:foo> Pathname('foo').join('bar') # => #<Pathname:foo/bar> Pathname('foo').join('bar', 'baz') # => #<Pathname:foo/bar/baz> Pathname('foo').join(Pathname('bar')) # => #<Pathname:foo/bar>
# File pathname_builtin.rb, line 1414 def lchmod(mode) File.lchmod(mode, @path) end
Not supported on some platforms (raises Errno:: ENOTSUP).
When supported: like Pathname::chmod, but does not follow symbolic links, and therefore changes the mode of the entry specified by self:
File.write('t.tmp', '') File.symlink('t.tmp', 'link') File.stat('t.tmp').mode.to_s(8) # => "100664" File.stat('link').mode.to_s(8) # => "100664" Pathname('link').lchmod(0777) File.stat('t.tmp').mode.to_s(8) # => "100664" File.stat('link').mode.to_s(8) # => "100777" File.delete('t.tmp') File.delete('link')
# File pathname_builtin.rb, line 1512 def lchown(owner, group) File.lchown(owner, group, @path) end
Not supported on some platforms (raises exception).
Calling process must have superuser privileges.
When supported: like Pathname#chown, but does not follow symbolic links, and therefore changes the ownership of the entry at the path in self:
# Super user; all privileges. Process.uid # => 0 Process.gid # => 0 # Create regular file and symbolic link to it. File.write('t.tmp', '') File.symlink('t.tmp', 'link') # Capture original statuses. fstat0 = File.stat('t.tmp') # Method ::stat; status of file. lstat0 = File.lstat('link') # Method ::lstat; status of link. # Original user ids and group ids. fstat0.uid # => 0 fstat0.gid # => 0 lstat0.uid # => 0 lstat0.gid # => 0 # Change ids for link. Pathname('link').lchown(1000, 1000) # Capture new statuses. fstat1 = File.stat('t.tmp') lstat1 = File.lstat('link') # User id and group id for file not changed. fstat1.uid # => 0 fstat1.gid # => 0 # User id and group id for link changed. p lstat1.uid # => 1000 p lstat1.gid # => 1000 # Clean up. File.delete('t.tmp') File.delete('link')
() → ::File::Stat
Source
# File pathname_builtin.rb, line 1682 def lstat() File.lstat(@path) end
Returns a File::Stat object for the path in self; does not follow symbolic links, and therefore returns the stat object for that path, regardless of whether it is a symbolic link:
File.write('t.tmp', '') sleep(1) File.symlink('t.tmp', 'link') pn = Pathname('link') # => #<Pathname:link> # Method stat: follows link to 't.tmp'. pn.stat.ctime # => 2026-06-13 15:02:46.562620885 -0500 # Method lstat; does not follow link. pn.lstat.ctime # => 2026-06-13 15:02:47.563619647 -0500 File.delete('t.tmp') File.delete('link')
# File pathname_builtin.rb, line 1824 def lutime(atime, mtime) File.lutime(atime, mtime, @path) end
Like Pathname#utime, but does not follow symbolic links, and therefore changes the times of the entry in self, regardless of whether it is a symbolic link:
# Create a file and a link to it. file_path = 't.tmp' link_path = 'link' File.write(file_path, '') File.symlink(file_path, link_path) # Take snapshots of both. file_stat = File.stat(file_path) link_stat = File.lstat(link_path) # Fetch access times and modification times of both. file_stat.atime # => 2026-06-15 11:03:29.600373255 -0500 file_stat.mtime # => 2026-06-15 11:03:22.247352211 -0500 link_stat.atime # => 2026-06-15 11:03:29.251372254 -0500 link_stat.mtime # => 2026-06-15 11:03:26.66436484 -0500 # Update access time and modification time of the link. pn = Pathname(link_path) time = Time.now # => 2026-06-15 11:08:07.384287523 -0500 pn.lutime(time, time) # Take fresh snapshots of both. file_stat = File.stat(file_path) link_stat = File.lstat(link_path) # Fetch access time and modification time of file (not changed). file_stat.atime # => 2026-06-15 11:03:29.600373255 -0500 file_stat.mtime # => 2026-06-15 11:03:22.247352211 -0500 # Fetch access time and modification time of link (changed). link_stat.atime # => 2026-06-15 11:08:29.847301399 -0500 link_stat.mtime # => 2026-06-15 11:08:07.384287523 -0500 # Clean up. File.delete(file_path) File.delete(link_path)
Arguments atime and mtime may be Time objects (as above).
Either or both may be integers; when an integer i is passed, Time.new(i) is used.
Either or both may be nil, in which case Time.now is used.
# File pathname_builtin.rb, line 1572 def make_link(old) File.link(old, @path) end
Not available on some systems.
Creates a new entry at the path in self for the existing entry at path using a hard link:
File.write('doc/t.tmp', 'foo') Pathname('lib/u.tmp').make_link('doc/t.tmp') File.read('lib/u.tmp') # => "foo" File.write('lib/u.tmp', 'bar') File.read('doc/t.tmp') # => "bar" File.delete('doc/t.tmp') File.read('lib/u.tmp') # => "bar" File.delete('lib/u.tmp')
Raises an exception if the entry at the path in self exists.
# File pathname_builtin.rb, line 1703 def make_symlink(old) File.symlink(old, @path) end
Creates a symbolic link at the path in self to the entry at path:
# Create Pathnames. file_pn = Pathname('doc/extension.rdoc') # => #<Pathname:doc/extension.rdoc> target_pn = Pathname('..').join(file_pn) # => #<Pathname:../doc/extension.rdoc> link_pn = Pathname('lib/u.tmp') # => #<Pathname:lib/u.tmp> # Create link and verify. link_pn.make_symlink(target_pn) file_pn.read == link_pn.read # => true link_pn.delete # Clean up.
# File pathname_builtin.rb, line 2579 def mkdir(...) Dir.mkdir(@path, ...) end
Creates a directory in the underlying file system at the path in self, with the given permissions; see File Permissions:
Dir.mkdir('foo') File.stat(Dir.new('foo')).mode.to_s(8) # => "40775" Dir.mkdir('bar', 0644) File.stat(Dir.new('bar')).mode.to_s(8) # => "40644" Dir.rmdir('foo') Dir.rmdir('bar')
Argument permissions is ignored on Windows.
() → self
Source
# File pathname_builtin.rb, line 324 def mkpath(mode: nil) path = @path == '/' ? @path : @path.chomp('/') stack = [] until File.directory?(path) || (parent = File.dirname(path)) == path stack.push path path = parent end stack.reverse_each do |dir| dir = dir == '/' ? dir : dir.chomp('/') if mode Dir.mkdir dir, mode File.chmod mode, dir else Dir.mkdir dir end rescue SystemCallError raise unless File.directory?(dir) end self end
Creates a directory at the path in self; creates intermediate directories as needed:
pn = Pathname('foo/bar/baz') pn.directory? # => false pn.mkpath # Creates directories 'foo', 'foo/bar', 'foo/bar/baz'. pn.directory? # => true pn.rmtree # Clean up.
Directories are created with the given permissions; see File Permissions. The permissions for already-existing directories are not changed.
() → bool
Source
# File pathname_builtin.rb, line 583 def mountpoint? begin stat1 = self.lstat stat2 = self.parent.lstat stat1.dev != stat2.dev || stat1.ino == stat2.ino rescue Errno::ENOENT false end end
Returns whether the path in self points to a mountpoint:
Pathname('/').mountpoint? # => true Pathname('/etc').mountpoint? # => false Pathname('nosuch').mountpoint? # => false
() → Time
Source
# File pathname_builtin.rb, line 1355 def mtime() File.mtime(@path) end
Returns a Time object containing the time of the most recent modification to the entry represented by self; see File System Timestamps:
# A directory and its Pathname. dir_path = 'doc/foo' dir_pn = Pathname(dir_path) # Create directory; directory mtime established. dir_pn.mkdir dir_pn.mtime # => 2026-06-28 16:38:02.675780521 -0500 # A file therein and its Pathname. file_path = dir_pn.join('t.tmp') file_pn = Pathname(file_path) # Create file; file mtime established; directory mtime updated. file_pn.write('foo') dir_pn.mtime # => 2026-06-28 16:41:23.107750483 -0500 file_pn.mtime # => 2026-06-28 16:41:23.107750483 -0500 # Modify file; file mtime updated; directory mtime unchanged. file_pn.write('bar') dir_pn.mtime # => 2026-06-28 16:41:23.107750483 -0500 file_pn.mtime # => 2026-06-28 16:42:48.869163049 -0500 # Clean up. dir_pn.rmtree
(?string | int mode, ?int perm, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?path: path, ?invalid: :replace | nil, ?undef: :replace | nil, ?replace: String | nil, ?fallback: Hash[string, string] | ^(String) → string | Method | nil, ?xml: :text | :attr | nil, ?cr_newline: bool, ?crlf_newline: bool, ?universal_newline: bool) → File
[T] (?string | int mode, ?int perm, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?path: path, ?invalid: :replace | nil, ?undef: :replace | nil, ?replace: String | nil, ?fallback: Hash[string, string] | ^(String) → string | Method | nil, ?xml: :text | :attr | nil, ?cr_newline: bool, ?crlf_newline: bool, ?universal_newline: bool) { (File) → T } → T
Source
# File pathname_builtin.rb, line 1575 def open(...) # :yield: file File.open(@path, ...) end
See File.open. Opens the file for reading or writing.
Source
# File pathname_builtin.rb, line 2626 def opendir(&block) # :yield: dir Dir.open(@path, &block) end
Creates a Dir object dir for the directory at the path represented by self; opens dir.
With a block given, calls the block with dir; on block exit, closes dir and returns the block’s return value:
pn = Pathname('.') pn.opendir {|dir| dir.entries.take(3) } # => ["README.md", "html", ".git"]
With no block given, returns the open directory dir:
dir = pn.opendir # => #<Dir:.> dir.entries.take(3) # => ["README.md", "html", ".git"] dir.close
() → bool
Source
# File pathname_builtin.rb, line 2237 def owned?() FileTest.owned?(@path) end
Returns whether the entry at the path represented by self exists and is owned by the user of the current process:
pn = Pathname('doc/t.tmp') pn.write('foo') pn.owned? # => true pn.delete pn = Pathname('doc/tmp') pn.mkdir pn.owned? # => true pn.rmdir Pathname('/etc').owned? # => false
Source
# File pathname_builtin.rb, line 566 def parent self + '..' end
Returns a new pathname representing the parent directory of the entry represented by self:
pn = Pathname('/etc/passwd') # => #<Pathname:/etc/passwd> pn.parent # => #<Pathname:/etc>
() → bool
Source
# File pathname_builtin.rb, line 2192 def pipe?() FileTest.pipe?(@path) end
Returns whether the path in +self+ points to a pipe:
path = '/tmp/foo' File.mkfifo(path) pn = Pathname(path) # => #<Pathname:/tmp/foo> pn.pipe? # => true Pathname('.').pipe? # => false pn.delete # Clean up.
(?Integer length, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish) → String
Source
# File pathname_builtin.rb, line 1079 def read(...) File.read(@path, ...) end
Reads and returns some or all of the content of the file whose path is self.to_s.
With no arguments given, reads in text mode and returns the entire content of the file:
Pathname.new('t.txt').read # => "First line\nSecond line\n\nFourth line\nFifth line\n" Pathname.new('t.ja').read # => "こんにちは" Pathname.new('t.dat').read # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
On Windows, text mode can terminate reading and leave bytes in the file unread when encountering certain special bytes. Consider using binread if all bytes in the file should be read.
With argument length given, returns length bytes if available:
Pathname.new('t.txt').read(7) # => "First l" Pathname.new('t.ja').read(7) # => "\xE3\x81\x93\xE3\x82\x93\xE3" Pathname.new('t.dat').read(7) # => "\xFE\xFF\x99\x90\x99\x91\x99"
Returns all bytes if length is larger than the files size:
Pathname.new('t.txt').read(700) # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n" Pathname.new('t.ja').read(700) # => "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF" Pathname.new('t.dat').read(700) # => "\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
With arguments length and offset given, returns length bytes if available, beginning at the given offset:
Pathname.new('t.txt').read(10, 2) # => "rst line\r\n" Pathname.new('t.ja').read(10, 2) # => "\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1" Pathname.new('t.dat').read(10, 2) # => "\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"
Returns nil if offset is past the end of the file:
Pathname.new('t.txt').read(10, 200) # => nil
Optional keyword arguments opts specify:
() → bool
Source
# File pathname_builtin.rb, line 2257 def readable?() FileTest.readable?(@path) end
Returns whether the path in self points to an entry that is readable by the owner and group of the current process:
pn = Pathname('/tmp/secret.txt') pn.write('foo') pn.readable? # => true pn.chmod(0o000) pn.readable? # => false pn.delete # Clean up. Pathname('nosuch').readable? # => false
() → bool
Source
# File pathname_builtin.rb, line 2291 def readable_real?() FileTest.readable_real?(@path) end
readable_real? -> true or false
Like readable?, but checks against the real user and group ids instead of the effective ids.
(?String sep, ?Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) → Array[String]
(Integer limit, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish, ?chomp: boolish) → Array[String]
Source
# File pathname_builtin.rb, line 1143 def readlines(...) File.readlines(@path, ...) end
Returns an array of all lines read from the source at the path in self, which must be the path to a file.
Examples here use a file defined at IO Example Files.
With no arguments given, parses lines from the file at the given path, as determined by the default line separator, and returns those lines in an array:
pn = Pathname('t.txt') ppn.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
With argument sep given, parses lines as determined by that line separator (see IO Line Separator):
pn.readlines('li') # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"] pn.readlines('') # Special "paragraphs" separator value. # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"] pn.readlines(nil) # Special "slurp" separator value. # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
With argument limit given, parses lines as determined by the default line separator and the given line-length limit (see IO Line Separator and IO Line Limit):
pn.readlines(7) # => ["First l", "ine\n", "Second ", "line\n", "\n", "Fourth ", "line\n", "Fifth l", "ine\n"]
With arguments sep and limit given, combines the two behaviors (see IO Line Separator and Line Limit).
Optional keyword arguments options specify:
() → untyped
Source
# File pathname_builtin.rb, line 1596 def readlink() self.class.new(File.readlink(@path)) end
Returns a new pathname containing the string path to the entry referenced by self:
# Create Pathnames. file_pn = Pathname('doc/extension.rdoc') # => #<Pathname:doc/extension.rdoc> target_pn = Pathname('..').join(file_pn) # => #<Pathname:../doc/extension.rdoc> link_pn = Pathname('lib/u.tmp') # => #<Pathname:lib/u.tmp> link_pn.make_symlink(target_pn) link_pn.readlink # => #<Pathname:../doc/extension.rdoc> link_pn.delete
# File pathname_builtin.rb, line 2015 def realdirpath(...) self.class.new(File.realdirpath(@path, ...)) end
Returns a new pathname containing the real (absolute) pathname of the path in self; the new path is the path in the actual filesystem, and does not contain useless dot-entries ('.' or '..') or symbolic links:
Pathname('/etc/./passwd/../../var').realdirpath # => #<Pathname:/var>
Only the last component of the new path may be nonexistent:
Pathname('/etc/./passwd/../../var/nosuch').realdirpath # => #<Pathname:/var/nosuch> Pathname('/etc/./passwd/../../var/nosuch/nosuch').realdirpath # Raises Errno::ENOENT: No such file or directory.
Method realpath is similar, but requires all components to exist.
# File pathname_builtin.rb, line 1986 def realpath(...) self.class.new(File.realpath(@path, ...)) end
Returns a new pathname containing the real (absolute) pathname of the path in self; the new path is the path in the actual filesystem, and does not contain useless dot-entries ('.' or '..') or symbolic links:
Pathname('/etc/./passwd/../../var').realpath # => #<Pathname:/var>
All components of the new path must exist:
Pathname('/etc/./passwd/../../var/nosuch').realpath # Raises Errno::ENOENT: No such file or directory.
Method realdirpath is similar, but does not require the last component to exist.
() → bool
Source
# File pathname_builtin.rb, line 612 def relative? !absolute? end
Returns whether self contains a relative path:
Pathname('lib').relative? # => true Pathname('/home').relative? # => false
The result is OS-dependent for some paths:
Pathname('C:/').relative? # => false # On Windows. Pathname('C:/').relative? # => true # Elsewhere.
# File pathname_builtin.rb, line 951 def relative_path_from(base_directory) base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname dest_directory = self.cleanpath.path base_directory = base_directory.cleanpath.path dest_prefix = dest_directory dest_names = [] while r = chop_basename(dest_prefix) dest_prefix, basename = r dest_names.unshift basename if basename != '.' end base_prefix = base_directory base_names = [] while r = chop_basename(base_prefix) base_prefix, basename = r base_names.unshift basename if basename != '.' end unless same_paths?(dest_prefix, base_prefix) raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}" end while !dest_names.empty? && !base_names.empty? && same_paths?(dest_names.first, base_names.first) dest_names.shift base_names.shift end if base_names.include? '..' raise ArgumentError, "base_directory has ..: #{base_directory.inspect}" end base_names.fill('..') relpath_names = base_names + dest_names if relpath_names.empty? Pathname.new('.') else Pathname.new(File.join(*relpath_names)) end end
Returns a pathname containing the relative filesystem path from the given source to the path in self; source must be a directory path or a pathname containing a directory path:
Pathname('.').relative_path_from('doc/language') # => #<Pathname:../..> Pathname('doc/language').relative_path_from('.') # => #<Pathname:doc/language> Pathname('doc').relative_path_from('doc/language') # => #<Pathname:..>
The paths need not exist:
Pathname('nosuch').relative_path_from('nosuch/foo/bar/baz') # => #<Pathname:../../..>
The two paths must be either both absolute or both relative:
Pathname('/var').relative_path_from('/etc') # => #<Pathname:../var> Pathname('/var').relative_path_from('doc') # Raises ArgumentError Pathname('doc').relative_path_from('/etc') # Raises ArgumentError
Raises an exception if there is no such relative path:
Pathname('foo').relative_path_from('..') # Raises ArgumentError
(Pathname | string new_name) → 0
Source
# File pathname_builtin.rb, line 1639 def rename(to) File.rename(@path, to) end
Renames the entry at the path in self to the entry given in new_name, which may be either a path or another pathname:
# Create source and destination pathnames and directories. pn_srcdir = Pathname('/tmp/src') # => #<Pathname:/tmp/src> pn_srcdir.mkdir pn_dstdir = Pathname('/tmp/dst') # => #<Pathname:/tmp/dst> pn_dstdir.mkdir # Create source file pathname and file. pn_srcfile = pn_srcdir.join('t.tmp') # => #<Pathname:/tmp/src/t.tmp> pn_srcfile.write('foo') # Create destination file pathname. pn_dstfile = pn_dstdir.join('u.tmp') # => #<Pathname:/tmp/dst/u.tmp> # Rename source file as destination file. pn_srcfile.rename(pn_dstfile) pn_srcfile.exist? # => false pn_dstfile.exist? # => true
Works for directories, too:
pn_dstdir.rename('/tmp/foo') pn_dstdir.exist? # => false Pathname('/tmp/foo').exist? # => true
Clean up.
pn_srcdir.rmtree Pathname('/tmp/foo').rmtree
Raises SystemCallError if the entry cannot be renamed.
() → 0
Source
# File pathname_builtin.rb, line 2598 def rmdir() Dir.rmdir(@path) end
Deletes the directory at the path in +self+; returns 0:
pn = Pathname('doc/foo') pn.mkdir pn.rmdir
Raises an exception if the directory is not empty, or if the path does not point to a directory.
Use method rmtree to delete the entire filetree at the path.
Source
# File lib/pathname.rb, line 115 def rmtree(noop: nil, verbose: nil, secure: nil) # The name "rmtree" is borrowed from File::Path of Perl. # File::Path provides "mkpath" and "rmtree". require 'fileutils' FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure) self end
Deletes the entire filetree at the path in self; returns 0:
dir_pn = Pathname('foo/bar/baz') # => #<Pathname:foo/bar/baz> dir_pn.mkpath # Create 'baz' and intermediate directories. file_pn = dir_pn.join('t.tmp') # => #<Pathname:foo/bar/baz/t.tmp> file_pn.write('foo') # Create file at nested directory 'baz'. Pathname('foo').rmtree # Delete the entire tree at directory 'foo'. Pathname('foo').exist? # => false
Use method rmdir to delete a single (empty) directory.
() → bool
Source
static VALUE
path_root_p(VALUE self)
{
VALUE path = get_strpath(self);
if (RSTRING_LEN(path) == 0) return Qfalse;
const char *ptr = RSTRING_PTR(path), *end = RSTRING_END(path);
rb_encoding *enc = rb_enc_get(path);
const char *base = rb_enc_path_skip_prefix_root(ptr, end, enc);
return RBOOL(base == end);
}
Returns whether the path in self points to a root directory.
On a non-Windows system, a root directory path is one whose name begins with one or more slash characters (‘’/‘):
Pathname('/').root? # => true Pathname('////').root? # => true Pathname('/usr').root? # => false Pathname('foo').root? # => false
Does not resolve dot directories:
Pathname('/usr/.').root? # => false Pathname('/usr/..').root? # => false
On a Windows system, a root directory path is one whose name begins as above, or with a device letter followed by a colon character (':') and one or more slash characters (‘’/‘):
Pathname('/').root? # => true Pathname('////').root? # => true Pathname('C:/').root? # => true Pathname('C:////').root? # => true Pathname('c:/').root? # => true Pathname('H:/').root? # => true Pathname('C:/m').root? # => false Pathname('C:').root? # => false
() → bool
Source
# File pathname_builtin.rb, line 2339 def setgid?() FileTest.setgid?(@path) end
Returns whether the setgid bit is set in the permissions for the entry at the path in self:
# Create a file and get its permissions and setgid? setting. pn = Pathname('doc/t.tmp') pn.write('foo') mode = pn.stat.mode.to_s(8) # => "100664" pn.setgid? # => false # Set the bit. pn.chmod(0o2644) mode = pn.stat.mode.to_s(8) # => "102644" pn.setgid? # => true pn.delete # Clean up.
On Windows, the bit is never set; the method always returns false.
() → bool
Source
# File pathname_builtin.rb, line 2315 def setuid?() FileTest.setuid?(@path) end
Returns whether the setuid bit is set in the permissions for the entry at the path in self:
# Create a file and get its permissions and setuid? setting. pn = Pathname('doc/t.tmp') pn.write('foo') mode = pn.stat.mode.to_s(8) # => "100664" pn.setuid? # => false # Set the bit. pn.chmod(0o4644) mode = pn.stat.mode.to_s(8) # => "104644" pn.setuid? # => true pn.delete # Clean up.
On Windows, the bit is never set; the method always returns false.
() → Integer
Source
# File pathname_builtin.rb, line 2359 def size() FileTest.size(@path) end
Returns the size of the entry at the path in self:
Pathname('README.md').size # => 3469 Pathname('doc').size # => 4096 pn = Pathname('doc/t.tmp') pn.write('') pn.size # => 0 pd.delete # Clean up.
Raises an exception if the entry does not exist.
Source
# File pathname_builtin.rb, line 2384 def size?() FileTest.size?(@path) end
If the file or directory entry at the path in self exists, returns its size if non-zero, or nil if zero:
pn = Pathname('doc/t.tmp') pn.write('foo') pn.size? # => 3 pn.write('') pn.size? # => nil
Returns nil if the entry does not exist:
pn.delete pn.size? # => nil
() → untyped
Source
# File pathname_builtin.rb, line 2215 def socket?() FileTest.socket?(@path) end
Returns whether the path in self points to a socket entry:
require 'socket' path = 'doc/socket' server = UNIXServer.new(path) # => #<UNIXServer:doc/socket> pn = Pathname(path) # => #<Pathname:doc/socket> pn.socket? # => true server.close pn.unlink Pathname('README.md').socket? # => false Pathname('nosuch').socket? # => false
Returns false on Windows.
# File pathname_builtin.rb, line 1956 def split() array = File.split(@path) raise TypeError, 'wrong argument type nil (expected Array)' unless Array === array array.map {|f| self.class.new(f) } end
Returns a 2-element array containing dirname and basename:
Pathname('lib/pathname.rb').split # => [#<Pathname:lib>, #<Pathname:pathname.rb>] Pathname('README.md').split # => [#<Pathname:.>, #<Pathname:README.md>] Pathname('').split # => [#<Pathname:.>, #<Pathname:>] Pathname('nosuch/foo/bar').split # => [#<Pathname:nosuch/foo>, #<Pathname:bar>]
Source
# File pathname_builtin.rb, line 1655 def stat() File.stat(@path) end
Returns a File::Stat object for the entry at the path in self:
Pathname('README.md').stat.inspect => "#<File::Stat dev=0x10302, ino=22941341, mode=0100664, nlink=1, uid=1000, gid=1000, rdev=0x0, size=3469, blksize=4096, blocks=8, atime=2026-07-10 15:24:17.476506084 -0500, mtime=2026-07-07 10:23:27.320088262 -0500, ctime=2026-07-07 10:23:27.320088262 -0500>" Pathname('doc').stat.inspect => "#<File::Stat dev=0x10302, ino=22941930, mode=040775, nlink=22, uid=1000, gid=1000, rdev=0x0, size=4096, blksize=4096, blocks=8, atime=2026-07-11 10:05:20.480330738 -0500, mtime=2026-07-11 10:05:06.34333645 -0500, ctime=2026-07-11 10:05:06.34333645 -0500>"
() → untyped
Source
# File pathname_builtin.rb, line 2405 def sticky?() FileTest.sticky?(@path) end
Returns whether the sticky bit is set for the entry at the path in self:
pn = Pathname('t.tmp') pn.write('foo') pn.stat.mode.to_s(8) # => "100664" pn.sticky? # => false pn.chmod(0o1644) pn.stat.mode.to_s(8) # => "101644" pn.sticky? # => true pn.delete
Returns false on Windows.
(Regexp | string pattern, string | Hash[String, String] replacement) → Pathname
(Regexp | string pattern) { (String match) → string } → Pathname
Source
static VALUE
path_sub(int argc, VALUE *argv, VALUE self)
{
VALUE str = get_strpath(self);
if (rb_block_given_p()) {
str = rb_block_call(str, id_sub, argc, argv, 0, 0);
}
else {
str = rb_funcallv(str, id_sub, argc, argv);
}
return rb_class_new_instance(1, &str, rb_obj_class(self));
}
Returns a new pathname whose path is the path in self, after the specified substitutions.
Argument pattern may be a string or a Regexp; argument replacement may be a string or a hash.
Varying types for the argument values makes this method very versatile.
Below are some simple examples; for many more related examples (using strings, not pathnames), see Substitution Methods.
With arguments pattern and string replacement given, replaces the first matching substring with the given replacement string:
pn = Pathname('abracadabra.txt') # => #<Pathname:abracadabra.txt> pn.sub('bra', 'xyzzy') # => #<Pathname:axyzzycadabra.txt> pn.sub(/bra/, 'xyzzy') # => #<Pathname:axyzzycadabra.txt> pn.sub('nope', 'xyzzy') # => #<Pathname:abracadabra.txt>
With arguments pattern and hash replacement given, replaces the first matching substring with a value from the given replacement hash, or removes it:
h = {'a' => 'A', 'b' => 'B', 'c' => 'C'} pn.sub('b', h) # => #<Pathname:aBracadabra.txt> pn.sub(/b/, h) # => #<Pathname:aBracadabra.txt> pn.sub(/d/, h) # => #<Pathname:abracaabra.txt> # 'd' removed.
With argument pattern and a block given, calls the block with the first matching substring; replaces that substring with the block’s return value:
pn.sub('b') {|match| match.upcase } # => #<Pathname:aBracadabra.txt> pn.sub(/X/) {|match| match.upcase } # => #<Pathname:abracadabra.txt>
(string replacement) → Pathname
Source
static VALUE
path_sub_ext(VALUE self, VALUE repl)
{
VALUE path = get_strpath(self);
long len = RSTRING_LEN(path);
const char *ptr = RSTRING_PTR(path);
const char *ext = ruby_enc_find_extname(ptr, &len, rb_enc_get(path));
if (len > 0) {
RUBY_ASSERT(ext, "should point the last dot");
path = rb_str_subseq(path, 0, ext - ptr);
}
else {
/* no dot or dotted file */
path = rb_str_dup(path);
}
path = rb_str_append(path, repl);
return rb_class_new_instance(1, &path, rb_obj_class(self));
}
Returns a new pathname whose path is the path in self, after specified changes:
Pathname('t.tmp').sub_ext('.txt') # => #<Pathname:t.txt> # Extension replaced. Pathname('temp').sub_ext('.txt') # => #<Pathname:temp.txt> # Extension added. Pathname('t.tmp').sub_ext('') # => #<Pathname:t> # Extension removed.
() → untyped
Source
# File pathname_builtin.rb, line 2426 def symlink?() FileTest.symlink?(@path) end
Returns whether the entry at the path in self is a symbolic link:
# Create Pathnames. file_pn = Pathname('doc/extension.rdoc') # => #<Pathname:doc/extension.rdoc> target_pn = Pathname('..').join(file_pn) # => #<Pathname:../doc/extension.rdoc> link_pn = Pathname('lib/u.tmp') # => #<Pathname:lib/u.tmp> link_pn.symlink? # => false # Create link. link_pn.make_symlink(target_pn) link_pn.symlink? # => true link_pn.delete # Clean up.
# File pathname_builtin.rb, line 1169 def sysopen(...) File.sysopen(@path, ...) end
Opens the file at the path in self with the given mode and permissions; returns the integer file descriptor.
If the file is to be readable, it must exist; if the file is to be writable and does not exist, it is created with the given permissions:
pn = Pathname('doc/t.tmp') pn.write('foo') fd = pn.sysopen # => 5 IO.new(fd).close fd = pn.sysopen('w') # => 5 IO.new(fd).close fd = pn.sysopen('r', 0o644) # => 5 IO.new(fd).close pn.delete
Source
# File pathname_builtin.rb, line 295 def to_s @path.dup end
Returns a copy of the string path in self:
Pathname('nosuch/foo/bar').to_s # => "nosuch/foo/bar"
(Integer length) → 0
Source
# File pathname_builtin.rb, line 1729 def truncate(length) File.truncate(@path, length) end
Adjusts the size of file at the path in self to the given size; returns 0:
pn.write('0123456789') pn.size # => 10 pn.truncate(5) pn.size # => 5 pn.read # => "01234"
Pads on the right with null characters if necessary:
pn.truncate(10) pn.size # => 10 pn.read # => "01234\u0000\u0000\u0000\u0000\u0000"
() → Integer
Source
# File pathname_builtin.rb, line 2646 def unlink() Dir.unlink @path rescue Errno::ENOTDIR File.unlink @path end
Removes the entry represented by self; returns 0 if a directory, 1 if a file:
Pathname(Pathname.mktmpdir).unlink # => 0 Pathname(Tempfile.create).unlink # => 1
# File pathname_builtin.rb, line 1772 def utime(atime, mtime) File.utime(atime, mtime, @path) end
For the entry at the path in self, updates its access time to the given atime and its modification time to the given mtime; each given time may be a Time object, an integer representing a time, or nil (meaning Time.now):
pn = Pathname('doc/t.tmp') pn.write('foo') pn.stat.atime # => 1969-12-31 18:00:00 -0600 pn.stat.mtime # => 2026-07-11 16:12:15.832556524 -0500 pn.utime(0, 0) pn.stat.atime # => 1969-12-31 18:00:00 -0600 pn.stat.mtime # => 1969-12-31 18:00:00 -0600 pn.utime(nil, nil) pn.stat.atime # => 2026-07-11 16:13:06.982646673 -0500 pn.stat.mtime # => 2026-07-11 16:13:04.983530291 -0500 time = Time.now # => 2026-07-11 16:13:40.190110708 -0500 pn.utime(time, time) pn.stat.atime # => 2026-07-11 16:13:51.99317823 -0500 pn.stat.mtime # => 2026-07-11 16:13:40.190110708 -0500
Follows symbolic links:
link_pn = Pathname('link') link_pn.make_symlink(pn) link_pn.stat.atime # => 2026-07-11 16:13:51.99317823 -0500 link_pn.stat.mtime # => 2026-07-11 16:13:40.190110708 -0500 link_pn.utime(0, 0) pn.stat.atime # => 1969-12-31 18:00:00 -0600 pn.stat.mtime # => 1969-12-31 18:00:00 -0600 pn.delete link_pn.delete
() → (Integer | nil)
Source
# File pathname_builtin.rb, line 2281 def world_readable?() File.world_readable?(@path) end
If the entry at the path in self is readable by others, returns the integer permissions for the entry:
Pathname('/etc/passwd').world_readable?.to_s(8) # => "644"
Otherwise, returns nil:
pn = Pathname('doc/t.tmp') pn.write('foo') pn.chmod(0o0) pn.world_readable? # => nil pn.delete
() → (Integer | nil)
Source
# File pathname_builtin.rb, line 2453 def world_writable?() File.world_writable?(@path) end
If the entry at the path in self is writable by others, returns the integer permissions for the entry:
Pathname('/tmp').world_writable?.to_s(8) # => "777"
Otherwise, returns nil:
pn = Pathname('doc/t.tmp') pn.write('foo') pn.chmod(0o0) pn.world_writable? # => nil pn.delete
() → bool
Source
# File pathname_builtin.rb, line 2429 def writable?() FileTest.writable?(@path) end
See FileTest.writable?.
() → bool
Source
# File pathname_builtin.rb, line 2456 def writable_real?() FileTest.writable_real?(@path) end
(String content, ?Integer offset, ?mode: Integer | String, ?flags: Integer, ?external_encoding: encoding, ?internal_encoding: encoding, ?encoding: encoding, ?textmode: boolish, ?binmode: boolish, ?autoclose: boolish) → Integer
Source
# File pathname_builtin.rb, line 1206 def write(...) File.write(@path, ...) end
Opens the file at self.to_s, writes the given data to it, and closes the file; returns the number of bytes written.
With only argument data given, writes the given data to the file:
path = 't.tmp' pn = Pathname.new(path) pn.write('foo') # => 3 File.read(path) # => "foo"
If offset is zero (the default), the file is overwritten:
pn.write('bar') File.read(path) # => "bar"
If offset in within the file content, the file is partly overwritten:
pn.write('foobarbaz') pn.write('BAR', 3) File.read(path) # => "fooBARbaz"
If offset is outside the file content, the file is padded with null characters "\u0000":
pn.write('bat', 12) File.read(path) # => "fooBARbaz\u0000\u0000\u0000bat"
Optional keyword arguments opts specify:
() → bool
Source
# File pathname_builtin.rb, line 2459 def zero?() FileTest.zero?(@path) end
See FileTest.zero?.
Private Instance Methods
(untyped path) → untyped
Source
static VALUE
add_trailing_separator(VALUE self, VALUE path)
{
if (RSTRING_LEN(check_strpath(path)) <= 0) return path;
rb_encoding *enc = rb_enc_get(path);
const char *name = RSTRING_PTR(path);
const char *end = RSTRING_END(path);
const char *top = rb_enc_path_skip_prefix(name, end, enc);
if (top < end && isdirsep(end[-1])) {
if (end[-1] == '/' || rb_enc_prev_char(top, end, end, enc) == end - 1)
return path;
}
return rb_str_cat_cstr(rb_str_dup(path), "/");
}
add_trailing_separator(path) -> path
(untyped path) → untyped
Source
static VALUE
chop_basename(VALUE self, VALUE path)
{
long baselen, alllen = RSTRING_LEN(check_strpath(path));
if (alllen <= 0) return Qnil;
rb_encoding *enc = rb_enc_get(path);
const char *name = RSTRING_PTR(path);
const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
if (baselen < 1) return Qnil;
if (baselen == 1 && isdirsep(*base)) return Qnil;
RUBY_ASSERT(base >= name);
RUBY_ASSERT(base <= RSTRING_END(path));
VALUE dir = rb_str_subseq(path, 0, base - name);
VALUE basename = rb_enc_str_new(base, alllen, enc);
RB_GC_GUARD(path);
return rb_assoc_new(dir, basename);
}
chop_basename(path) -> [pre-basename, basename] or nil
(untyped path) → untyped
Source
static VALUE
has_trailing_separator(VALUE self, VALUE path)
{
long baselen, alllen = RSTRING_LEN(check_strpath(path));
if (alllen <= 0) return Qfalse;
rb_encoding *enc = rb_enc_get(path);
const char *name = RSTRING_PTR(path);
const char *base = ruby_enc_find_basename(name, &baselen, &alllen, enc);
if (baselen < 1) return Qfalse;
if (baselen == 1 && isdirsep(*base)) return Qfalse;
return RBOOL(base + alllen < RSTRING_END(path));
}
has_trailing_separator?(path) -> bool
(untyped path) → untyped
Source
static VALUE
split_names(VALUE self, VALUE path)
{
rb_encoding *enc = rb_enc_get(check_strpath(path));
const char *beg = RSTRING_PTR(path), *ptr = beg;
const char *end = RSTRING_END(path);
const char *root = rb_enc_path_skip_prefix_root(ptr, end, enc);
VALUE pre = rb_str_subseq(path, 0, root - ptr);
VALUE names = rb_ary_new();
while (ptr < end) {
const char *next = rb_enc_path_next(ptr, end, enc);
if (next > ptr) rb_ary_push(names, rb_str_subseq(path, ptr - beg, next - ptr));
ptr = next;
while (ptr < end && isdirsep(*ptr)) ++ptr;
}
return rb_assoc_new(pre, names);
}
split_names(path) -> prefix, [name, …]