class FileDiscard::Discarder
The core logic for moving files to an appropriate trash directory.
Public Class Methods
new(home, home_trash, mountpoint_trash_fmt)
click to toggle source
# File lib/file_discard.rb, line 96 def initialize(home, home_trash, mountpoint_trash_fmt) home = pathname_for(home).expand_path @home_trash = home.join(home_trash) @home_mountpoint = mountpoint_of home @mountpoint_trash_fmt = mountpoint_trash_fmt end
Public Instance Methods
discard(obj, options = {})
click to toggle source
Request that obj
be moved to the trash.
options
- a hash of any of the following:
-
:force - if greater than one, permanently remove
obj
-
:directory - allow an empty directory to be discarded
-
:recursive - allow a directory to be discarded even if not empty
-
:verbose - report the move operation
May raise:
-
Errno::EINVAL -
obj
is “.” or “..” which are not allowed to be discarded -
Errno::EISDIR -
obj
is a directory -
Errno::ENOTEMPTY -
obj
is a directory with children -
Errno::ENOENT -
obj
does not exist on the file system -
TrashMissing
- the trash directory for the mountpoint associated withobj
did not exist
# File lib/file_discard.rb, line 118 def discard(obj, options = {}) pn = pathname_for obj if pn.directory? SPECIAL_DIRS.include?(pn.basename.to_s) and raise Errno::EINVAL.new(SPECIAL_DIRS.join(' and ') << ' may not be removed') unless options[:recursive] options[:directory] or raise Errno::EISDIR.new(pn.to_s) pn.children.any? and raise Errno::ENOTEMPTY.new(pn.to_s) end end if options.key?(:force) && options[:force] > 1 FileUtils.rm_rf(pn, {verbose: options[:verbose] || false}) return end trash = find_trash_for pn unless trash.exist? FileDiscard.create_trash_when_missing or raise TrashMissing.new(trash.to_s) begin trash.mkpath rescue Errno::EACCES raise TrashNotPermitted.new("Unable to create #{trash.to_s}") end end move_options = options.has_key?(:verbose) ? {verbose: options[:verbose]} : {} move(pn, trash, move_options) end
Private Instance Methods
find_trash_for(pn)
click to toggle source
# File lib/file_discard.rb, line 154 def find_trash_for(pn) pn_path = pn.expand_path if pn_path.symlink? # Use the containing directory's real path for symbolic links, not the target of the link pd = pn_path.dirname.realpath else pd = pn_path.realpath.dirname end mp = mountpoint_of(pd) return @home_trash if mp == @home_mountpoint mp.join(@mountpoint_trash_fmt % Process.uid) end
mountpoint_of(pn)
click to toggle source
# File lib/file_discard.rb, line 149 def mountpoint_of(pn) pn = pn.parent until pn.mountpoint? pn end
move(src, dst, options) { |src, dst| ... }
click to toggle source
# File lib/file_discard.rb, line 177 def move(src, dst, options) src = src.expand_path dst = uniquify(dst.join(src.basename)) options[:verbose] and puts "#{src} => #{dst}" File.rename(src, dst) block_given? and yield(src, dst) end
pathname_for(obj)
click to toggle source
# File lib/file_discard.rb, line 167 def pathname_for(obj) if obj.is_a? Pathname obj elsif obj.respond_to? :to_path Pathname.new(obj.to_path) else Pathname.new(obj) end end
uniquify(pn)
click to toggle source
# File lib/file_discard.rb, line 185 def uniquify(pn) pn.exist? or return pn dn = pn.dirname ext = pn.extname base = pn.basename(ext).to_s fmt = bfmt = '%H.%M.%S' 10.times do |i| ts = Time.now.strftime(fmt) pn = dn.join("#{base} #{ts}#{ext}") pn.exist? or return pn fmt = bfmt + ".%#{i}N" # use fractional seconds, with increasing precision end raise RuntimeError.new(%{Unable to uniquify "#{base}" (last attempt: #{pn})}) end