lib/rubysl/tempfile/tempfile.rb in rubysl-tempfile-2.0.0 vs lib/rubysl/tempfile/tempfile.rb in rubysl-tempfile-2.0.1

- old
+ new

@@ -1,9 +1,9 @@ # # tempfile - manipulates temporary files # -# $Id: tempfile.rb 31768 2011-05-28 23:31:24Z yugui $ +# $Id$ # require 'delegate' require 'tmpdir' require 'thread' @@ -37,11 +37,11 @@ # When a Tempfile object is garbage collected, or when the Ruby interpreter # exits, its associated temporary file is automatically deleted. This means # that's it's unnecessary to explicitly delete a Tempfile after use, though # it's good practice to do so: not explicitly deleting unused Tempfiles can # potentially leave behind large amounts of tempfiles on the filesystem -# until they're garbage collected. The existance of these temp files can make +# until they're garbage collected. The existence of these temp files can make # it harder to determine a new Tempfile filename. # # Therefore, one should always call #unlink or close in an ensure block, like # this: # @@ -77,11 +77,10 @@ # # Tempfile itself however may not be entirely thread-safe. If you access the # same Tempfile object from multiple threads then you should protect it with a # mutex. class Tempfile < DelegateClass(File) - MAX_TRY = 10 # :nodoc: include Dir::Tmpname # call-seq: # new(basename, [tmpdir = Dir.tmpdir], [options]) # @@ -125,32 +124,29 @@ # === Exceptions # # If Tempfile.new cannot find a unique filename within a limited # number of tries, then it will raise an exception. def initialize(basename, *rest) + if block_given? + warn "Tempfile.new doesn't call the given block." + end @data = [] @clean_proc = Remover.new(@data) ObjectSpace.define_finalizer(self, @clean_proc) create(basename, *rest) do |tmpname, n, opts| - lock = tmpname + '.lock' mode = File::RDWR|File::CREAT|File::EXCL perm = 0600 if opts mode |= opts.delete(:mode) || 0 opts[:perm] = perm perm = nil else opts = perm end - self.class.mkdir(lock) - begin - @data[1] = @tmpfile = File.open(tmpname, mode, opts) - @data[0] = @tmpname = tmpname - ensure - self.class.rmdir(lock) - end + @data[1] = @tmpfile = File.open(tmpname, mode, opts) + @data[0] = @tmpname = tmpname @mode = mode & ~(File::CREAT|File::EXCL) perm or opts.freeze @opts = opts end @@ -163,14 +159,17 @@ @tmpfile = File.open(@tmpname, @mode, @opts) @data[1] = @tmpfile __setobj__(@tmpfile) end - def _close # :nodoc: - @tmpfile.close if @tmpfile - @tmpfile = nil - @data[1] = nil if @data + def _close # :nodoc: + begin + @tmpfile.close if @tmpfile + ensure + @tmpfile = nil + @data[1] = nil if @data + end end protected :_close # Closes the file. If +unlink_now+ is true, then the file will be unlinked # (deleted) after closing. Of course, you can choose to later call #unlink @@ -189,11 +188,10 @@ # Closes and unlinks (deletes) the file. Has the same effect as called # <tt>close(true)</tt>. def close! _close unlink - ObjectSpace.undefine_finalizer(self) end # Unlinks (deletes) the file from the filesystem. One should always unlink # the file after using it, as is explained in the "Explicit close" good # practice section in the Tempfile overview: @@ -226,22 +224,22 @@ # file.close! # Closes the file handle. If the file wasn't unlinked # # because #unlink failed, then this method will attempt # # to do so again. # end def unlink - # keep this order for thread safeness return unless @tmpname begin - if File.exist?(@tmpname) - File.unlink(@tmpname) - end - # remove tmpname from remover - @data[0] = @data[2] = nil - @tmpname = nil + File.unlink(@tmpname) + rescue Errno::ENOENT rescue Errno::EACCES # may not be able to unlink on Windows; just ignore + return end + # remove tmpname from remover + @data[0] = @data[1] = nil + @tmpname = nil + ObjectSpace.undefine_finalizer(self) end alias delete unlink # Returns the full path name of the temporary file. # This will be nil if #unlink has been called. @@ -262,31 +260,37 @@ end end alias length size # :stopdoc: + def inspect + "#<#{self.class}:#{path}>" + end + class Remover def initialize(data) @pid = $$ @data = data end def call(*args) - if @pid == $$ - path, tmpfile = *@data + return if @pid != $$ - STDERR.print "removing ", path, "..." if $DEBUG + path, tmpfile = *@data - tmpfile.close if tmpfile + STDERR.print "removing ", path, "..." if $DEBUG - # keep this order for thread safeness - if path - File.unlink(path) if File.exist?(path) - end + tmpfile.close if tmpfile - STDERR.print "done\n" if $DEBUG + if path + begin + File.unlink(path) + rescue Errno::ENOENT + end end + + STDERR.print "done\n" if $DEBUG end end # :startdoc: class << self @@ -294,11 +298,11 @@ # # If no block is given, this is a synonym for Tempfile.new. # # If a block is given, then a Tempfile object will be constructed, # and the block is run with said object as argument. The Tempfile - # oject will be automatically closed after the block terminates. + # object will be automatically closed after the block terminates. # The call returns the value of the block. # # In any case, all arguments (+*args+) will be passed to Tempfile.new. # # Tempfile.open('foo', '/home/temp') do |f| @@ -314,25 +318,64 @@ # end def open(*args) tempfile = new(*args) if block_given? - begin - yield(tempfile) - ensure - tempfile.close - end + begin + yield(tempfile) + ensure + tempfile.close + end else - tempfile + tempfile end end + end +end - def mkdir(*args) - Dir.mkdir(*args) +# Creates a temporally file as usual File object (not Tempfile). +# It don't use finalizer and delegation. +# +# If no block is given, this is similar to Tempfile.new except +# creating File instead of Tempfile. +# The created file is not removed automatically. +# You should use File.unlink to remove it. +# +# If a block is given, then a File object will be constructed, +# and the block is invoked with the object as the argument. +# The File object will be automatically closed and +# the temporally file is removed after the block terminates. +# The call returns the value of the block. +# +# In any case, all arguments (+*args+) will be treated as Tempfile.new. +# +# Tempfile.create('foo', '/home/temp') do |f| +# ... do something with f ... +# end +# +def Tempfile.create(basename, *rest) + tmpfile = nil + Dir::Tmpname.create(basename, *rest) do |tmpname, n, opts| + mode = File::RDWR|File::CREAT|File::EXCL + perm = 0600 + if opts + mode |= opts.delete(:mode) || 0 + opts[:perm] = perm + perm = nil + else + opts = perm end - def rmdir(*args) - Dir.rmdir(*args) + tmpfile = File.open(tmpname, mode, opts) + end + if block_given? + begin + yield tmpfile + ensure + tmpfile.close if !tmpfile.closed? + File.unlink tmpfile end + else + tmpfile end end if __FILE__ == $0 # $DEBUG = true