Skip to content
2 changes: 1 addition & 1 deletion doc/file/symbolic_links.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ File.delete(linkpath)

### `rename`

Each of these methods changes the name of an entry (which need not be a symlink):
Each of these methods changes the name of an entry (which may be a symlink):

- File::rename
- Pathname#rename
Expand Down
73 changes: 66 additions & 7 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -3358,7 +3358,8 @@ lchown_internal(const char *path, void *arg)
*
* Calling process must have superuser privileges.
*
* When supported: like File::chown, but does not follow symbolic links,
* When supported: like File::chown,
* but does not follow [symbolic links](rdoc-ref:file/symbolic_links.md),
* and therefore changes the ownership of the entries given by `paths`;
* returns the number of paths given:
*
Expand Down Expand Up @@ -3614,7 +3615,8 @@ rb_file_s_utime(int argc, VALUE *argv, VALUE _)
* call-seq:
* File.lutime(atime, mtime, *paths) -> path_count
*
* Like File#utime, but does not follow symbolic links,
* Like File::utime,
* but does not follow [symbolic links](rdoc-ref:file/symbolic_links.md),
* and therefore changes the times of the entries given by `paths`,
* regardless of whether they are symbolic links;
* returns the number of `paths` given:
Expand Down Expand Up @@ -3914,13 +3916,70 @@ no_gvl_rename(void *ptr)
}

/*
* call-seq:
* File.rename(old_name, new_name) -> 0
* :markup: markdown
*
* call-seq:
* File.rename(path, new_path) -> 0
*
* Moves the entry at the given `path` to the given `new_path`.
*
* Does not follow [symbolic links](rdoc-ref:file/symbolic_links.md);
* if the entry is a symlink, the link itself is renamed.
*
* The examples below use two temporary directories:
*
* ```ruby
* src_dirpath = '/tmp/src/' # => "/tmp/src/"
* dst_dirpath = '/tmp/dst/' # => "/tmp/dst/"
* Dir.mkdir(src_dirpath)
* Dir.mkdir(dst_dirpath)
* ```
*
* The entry to be renamed may be a file:
*
* ```ruby
* src_filepath = File.join(src_dirpath, 't.tmp') # => "/tmp/src/t.tmp"
* File.write(src_filepath, 'foo')
* dst_filepath = File.join(dst_dirpath, 'u.tmp') # => "/tmp/dst/u.tmp"
* File.rename(src_filepath, dst_filepath)
* File.exist?(src_filepath) # => false
* File.exist?(dst_filepath) # => true
* File.delete(dst_filepath) # Clean up.
* ```
*
* The entry to be renamed may be a symbolic link:
*
* ```ruby
* filepath = File.join(src_dirpath, 't.tmp') # => "/tmp/src/t.tmp"
* File.write(src_filepath, 'foo')
* linkpath = File.join(src_dirpath, 'u.tmp') # => "/tmp/src/u.tmp"
* File.symlink(filepath, linkpath)
* File.readlink(linkpath) # => "/tmp/src/t.tmp"
* newpath = File.join(dst_dirpath, 'v.tmp') # => "/tmp/dst/v.tmp"
* File.rename(linkpath, newpath) # Symlink not followed.
* File.readlink(newpath) # => "/tmp/src/t.tmp"
* File.delete(filepath, newpath) # Clean up.
* ```
*
* The entry to be renamed may be a directory:
*
* Renames the given file to the new name. Raises a SystemCallError
* if the file cannot be renamed.
* ```ruby
* old_dirpath = File.join(src_dirpath, 'olddir') # => "/tmp/src/olddir"
* Dir.mkdir(old_dirpath)
* new_dirpath = File.join(dst_dirpath, 'newdir') # => "/tmp/dst/newdir"
* File.rename(old_dirpath, new_dirpath)
* File.directory?(new_dirpath) # => true
* Dir.rmdir(new_dirpath) # Clean up.
* ```
*
* Clean up:
*
* ```ruby
* FileUtils.rm_rf(src_dirpath) # => ["/tmp/src/"]
* FileUtils.rm_rf(dst_dirpath) # => ["/tmp/dst/"]
* ```
*
* File.rename("afile", "afile.bak") #=> 0
* Raises SystemCallError if the file cannot be renamed.
*/

static VALUE
Expand Down
65 changes: 49 additions & 16 deletions pathname_builtin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1624,7 +1624,8 @@ def chown(owner, group) File.chown(owner, group, @path) end
#
# Calling process must have superuser privileges.
#
# When supported: like Pathname#chown, but does not follow symbolic links,
# When supported: like Pathname#chown,
# but does not follow [symbolic links](rdoc-ref:file/symbolic_links.md),
# and therefore changes the ownership of the entry at the path in `self`:
#
# ```ruby
Expand Down Expand Up @@ -1786,18 +1787,27 @@ def readlink() self.class.new(File.readlink(@path)) end
# :markup: markdown
#
# call-seq:
# rename(new_name)
# rename(new_path) -> 0
#
# Renames the entry at the path in `self` to the entry given in `new_name`,
# which may be either a path or another pathname:
# Moves the entry at the path in `self` to the given `new_path`,
# which may be either a path or another pathname.
#
# Does not follow [symbolic links](rdoc-ref:file/symbolic_links.md);
# if the entry is a symlink, the link itself is renamed.
#
# The examples below use two temporary directories:
#
# ```ruby
# # Create source and destination pathnames and directories.
# pn_srcdir = Pathname('/tmp/src') # => #<Pathname:/tmp/src>
# pn_srcdir = Pathname('/tmp/src/') # => #<Pathname:/tmp/src/>
# pn_dstdir = Pathname('/tmp/dst/') # => #<Pathname:/tmp/dst/>
# pn_srcdir.mkdir
# pn_dstdir = Pathname('/tmp/dst') # => #<Pathname:/tmp/dst>
# pn_dstdir.mkdir
# # Create source file pathname and file.
# ```
#
# The entry to be renamed may be a file:
#
# ```ruby
# # Create source pathname and file.
# pn_srcfile = pn_srcdir.join('t.tmp') # => #<Pathname:/tmp/src/t.tmp>
# pn_srcfile.write('foo')
# # Create destination file pathname.
Expand All @@ -1806,23 +1816,45 @@ def readlink() self.class.new(File.readlink(@path)) end
# pn_srcfile.rename(pn_dstfile)
# pn_srcfile.exist? # => false
# pn_dstfile.exist? # => true
# pn_srcfile # => #<Pathname:/tmp/src/t.tmp> # Not changed.
# pn_dstfile.delete # Clean up.
# ```
#
# The entry to be renames may be a symbolic link:
#
# ```ruby
# # Create source pathname and file.
# pn_srcfile = pn_srcdir.join('t.tmp') # => #<Pathname:/tmp/src/t.tmp>
# pn_srcfile.write('foo')
# # Create link pathname and link.
# pn_lnkfile = pn_dstdir.join('u.tmp') pn_lnkfile = pn_dstdir.join('u.tmp')
# pn_lnkfile.make_symlink(pn_srcfile)
# pn_lnkfile.readlink # => #<Pathname:/tmp/src/t.tmp>
# pn_renamed = Pathname('lib/v.tmp') # => #<Pathname:lib/v.tmp>
# pn_lnkfile.rename(pn_renamed) # Symlink not followed.
# pn_renamed.symlink? # => true
# pn_renamed.readlink # => #<Pathname:/tmp/src/t.tmp>
# pn_lnkfile # => #<Pathname:/tmp/dst/u.tmp> # Not changed.
# # Clean up.
# pn_renamed.delete
# pn_srcfile.delete
# ```
#
# Works for directories, too:
# The entry to be renamed may be a directory:
#
# ```ruby
# pn_dstdir.rename('/tmp/foo')
# pn_dstdir.exist? # => false
# Pathname('/tmp/foo').exist? # => true
# pn_renamed = Pathname('/tmp/foo') # => #<Pathname:/tmp/foo>
# pn_dstdir.rename(pn_renamed)
# ```
#
# Clean up.
# Clean up:
#
# ```ruby
# pn_srcdir.rmtree
# Pathname('/tmp/foo').rmtree
# pn_renamed.rmtree # => #<Pathname:/tmp/foo>
# pn_srcdir.rmtree # => #<Pathname:/tmp/src/>
# ```
#
#
# Raises SystemCallError if the entry cannot be renamed.
def rename(to) File.rename(@path, to) end

Expand Down Expand Up @@ -1972,7 +2004,8 @@ def utime(atime, mtime) File.utime(atime, mtime, @path) end
# call-seq:
# lutime(atime, mtime) -> 1
#
# Like Pathname#utime, but does not follow symbolic links,
# Like Pathname#utime,
# but does not follow [symbolic links](rdoc-ref:file/symbolic_links.md),
# and therefore changes the times of the entry in `self`,
# regardless of whether it is a symbolic link:
#
Expand Down
Loading