lib/pleasant_path/pathname.rb
# Copies 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
# copy 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 copy is aborted).
#
# *WARNING:* Due to system API limitations, the copy is performed in
# two steps, non-atomically.  First, any file or directory existing
# at the destination is deleted.  Next, the source is copied 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.
#
# @example Without a block
#   FileUtils.touch("file")
#
#   Pathname.new("file").copy_as("dir/file")
#     # == Pathname.new("dir/file")
#
#   File.exist?("file")      # == true
#   File.exist?("dir/file")  # == true
#
# @example Error on older source
#   File.write("file", "A")
#   sleep 1
#   File.write("file.new", "B")
#
#   Pathname.new("file.new").copy_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.read("file.new")  # == "B"
#   File.read("file")      # == "B"
#
# @example Abort on conflict
#   File.write("file1", "A")
#   File.write("file2", "B")
#
#   Pathname.new("file1").copy_as("file2") do |source, destination|
#     puts "#{source} not copied to #{destination} due to conflict"
#     nil
#   end                 # == Pathname.new("file1")
#
#   File.read("file1")  # == "A"
#   File.read("file2")  # == "B"
#
# @example New destination on conflict
#   File.write("file1", "A")
#   File.write("file2", "B")
#
#   Pathname.new("file1").copy_as("file2") do |source, destination|
#     destination.available_name
#   end                   # == Pathname.new("file2_1")
#
#   File.read("file1")    # == "A"
#   File.read("file2")    # == "B"
#   File.read("file2_1")  # == "A"
#
# @overload copy_as(destination)
#   @param destination [Pathname, String]
#   @return [Pathname]
#
# @overload copy_as(destination, &block)
#   @param destination [Pathname, String]
#   @yieldparam source [Pathname]
#   @yieldparam destination [Pathname]
#   @yieldreturn [Pathname, nil]
#   @return [Pathname]
Copies 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
copy 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 copy is aborted).

Due to system API limitations, the copy is performed in
two steps, non-atomically.  First, any file or directory existing
at the destination is deleted.  Next, the source is copied 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.
Copies 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 copy 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 copy is aborted ) . Due to system API limitations the copy is performed in two steps non - atomically . First any file or directory existing at the destination is deleted . Next the source is copied 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 .
def copy_as(destination)
    destination = destination.to_pathname
    if block_given? && destination.exist? && self.exist? && !File.identical?(self, destination)
      destination = yield self, destination
      destination = nil if destination == self
    end
    if destination
      destination.delete! unless File.identical?(self, destination)
      self.copy(destination.make_dirname)
    end
    destination || self
  end
def copy_as ( destination ) destination = destination . to_pathname if block_given? && destination . exist? && self . exist? && ! File . identical? ( self , destination ) destination = yield self , destination destination = nil if destination == self end if destination destination . delete! unless File . identical? ( self , destination ) self . copy ( destination . make_dirname ) end destination || self end
Copies the file or directory indicated by the Pathname to
+destination+, replacing any existing file or directory.
Copies the file or directory indicated by the Pathname to + destination + replacing any existing file or directory .
destination
example
Without a block FileUtils.touch("file") Pathname.new("file").copy_as("dir/file") # == Pathname.new("dir/file") File.exist?("file") # == true File.exist?("dir/file") # == true
Without a block FileUtils . touch ( " file " ) Pathname . new ( " file " ) . copy_as ( " dir / file " ) # == Pathname . new ( " dir / file " ) File . exist? ( " file " ) # == true File . exist? ( " dir / file " ) # == true
example
Error on older source File.write("file", "A") sleep 1 File.write("file.new", "B") Pathname.new("file.new").copy_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.read("file.new") # == "B" File.read("file") # == "B"
Error on older source File . write ( " file " " A " ) sleep 1 File . write ( " file . new " " B " ) Pathname . new ( " file . new " ) . copy_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 . read ( " file . new " ) # == " B " File . read ( " file " ) # == " B "
example
Abort on conflict File.write("file1", "A") File.write("file2", "B") Pathname.new("file1").copy_as("file2") do |source, destination| puts "#{source} not copied to #{destination} due to conflict" nil end # == Pathname.new("file1") File.read("file1") # == "A" File.read("file2") # == "B"
Abort on conflict File . write ( " file1 " " A " ) File . write ( " file2 " " B " ) Pathname . new ( " file1 " ) . copy_as ( " file2 " ) do |source destination| puts " # { source } not copied to # { destination } due to conflict " nil end # == Pathname . new ( " file1 " ) File . read ( " file1 " ) # == " A " File . read ( " file2 " ) # == " B "
example
New destination on conflict File.write("file1", "A") File.write("file2", "B") Pathname.new("file1").copy_as("file2") do |source, destination| destination.available_name end # == Pathname.new("file2_1") File.read("file1") # == "A" File.read("file2") # == "B" File.read("file2_1") # == "A"
New destination on conflict File . write ( " file1 " " A " ) File . write ( " file2 " " B " ) Pathname . new ( " file1 " ) . copy_as ( " file2 " ) do |source destination| destination . available_name end # == Pathname . new ( " file2_1 " ) File . read ( " file1 " ) # == " A " File . read ( " file2 " ) # == " B " File . read ( " file2_1 " ) # == " A "
overload
copy_as(destination) @param destination [Pathname, String] @return [Pathname]
copy_as ( destination ) @param destination [ Pathname String ] @return [ Pathname ]
overload
None