Method: Pathname#move_as

Defined in:
lib/pleasant_path/pathname.rb

#move_as(destination) ⇒ Pathname #move_as(destination) {|source, destination| ... } ⇒ Pathname Also known as: rename_as

Moves the file or directory indicated by the Pathname to destination, replacing any existing file or directory.

If a block is given and a file or directory does exist at the destination, the block is called with the source and destination Pathnames, and the return value of the block is used as the new destination. If the block returns the source Pathname or nil, the move is aborted.

Creates any necessary parent directories of the destination. Returns the destination as a Pathname (or the source Pathname in the case that the move is aborted).

WARNING: Due to system API limitations, the move is performed in two steps, non-atomically. First, any file or directory existing at the destination is deleted. Next, the source is moved to the destination. The second step can fail independently of the first, e.g. due to insufficient disk space, leaving the file or directory previously at the destination deleted without replacement.

Examples:

Without a block

FileUtils.touch("file")

Pathname.new("file").move_as("dir/file")
  # == Pathname.new("dir/file")

File.exist?("file")      # == false
File.exist?("dir/file")  # == true

Error on older source

FileUtils.touch("file")
sleep 1
FileUtils.touch("file.new")

Pathname.new("file.new").move_as("file") do |source, destination|
  if source.mtime < destination.mtime
    raise "cannot replace newer file #{destination} with #{source}"
  end
  destination
end                      # == Pathname.new("file")

File.exist?("file.new")  # == false
File.exist?("file")      # == true

Abort on conflict

FileUtils.touch("file1")
FileUtils.touch("file2")

Pathname.new("file1").move_as("file2") do |source, destination|
  puts "#{source} not moved to #{destination} due to conflict"
  nil
end                   # == Pathname.new("file1")

File.exist?("file1")  # == true
File.exist?("file2")  # == true

New destination on conflict

FileUtils.touch("file1")
FileUtils.touch("file2")

Pathname.new("file1").move_as("file2") do |source, destination|
  destination.available_name
end                     # == Pathname.new("file2_1")

File.exist?("file1")    # == false
File.exist?("file2")    # == true
File.exist?("file2_1")  # == true

Overloads:



521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/pleasant_path/pathname.rb', line 521

def move_as(destination)
  destination = destination.to_pathname

  if block_given? && destination.exist? && self.exist? && !File.identical?(self, destination)
    destination = (yield self, destination) || self
  end

  if destination != self
    if File.identical?(self, destination)
      # FileUtils.mv raises an ArgumentError when both paths refer to
      # the same file.  On case-insensitive file systems, this occurs
      # even when both paths have different casing.  We want to
      # disregard the ArgumentError at all times, and change the
      # filename casing when applicable.
      File.rename(self, destination)
    else
      destination.delete!
      self.move(destination.make_dirname)
    end
  end

  destination
end