Feature #7148 ยป patch.diff
lib/tempfile.rb | ||
---|---|---|
# $Id$
|
||
#
|
||
require 'delegate'
|
||
require 'tmpdir'
|
||
require 'thread'
|
||
... | ... | |
# 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)
|
||
class Tempfile < File
|
||
include Dir::Tmpname
|
||
@@tmpmap = {}
|
||
# call-seq:
|
||
# new(basename, [tmpdir = Dir.tmpdir], [options])
|
||
#
|
||
... | ... | |
else
|
||
opts = perm
|
||
end
|
||
@data[1] = @tmpfile = File.open(tmpname, mode, opts)
|
||
@data[1] = @tmpfile = super(tmpname, mode, opts)
|
||
@data[0] = @tmpname = tmpname
|
||
@mode = mode & ~(File::CREAT|File::EXCL)
|
||
perm or opts.freeze
|
||
@opts = opts
|
||
end
|
||
@@tmpmap[@tmpname] = 1
|
||
@data[2] = @@tmpmap
|
||
end
|
||
super(@tmpfile)
|
||
def dup
|
||
@@tmpmap[@tmpname] += 1
|
||
super
|
||
end
|
||
# Opens or reopens the file with mode "r+".
|
||
def open
|
||
@tmpfile.close if @tmpfile
|
||
@tmpfile = File.open(@tmpname, @mode, @opts)
|
||
@data[1] = @tmpfile
|
||
__setobj__(@tmpfile)
|
||
end
|
||
def _close # :nodoc:
|
||
begin
|
||
@tmpfile.close if @tmpfile
|
||
ensure
|
||
@tmpfile = nil
|
||
@data[1] = nil if @data
|
||
end
|
||
opts = @opts.is_a?(Hash) ? @opts : nil
|
||
@tmpfile = reopen(@tmpname, @mode, opts)
|
||
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
|
||
... | ... | |
# If you don't explicitly unlink the temporary file, the removal
|
||
# will be delayed until the object is finalized.
|
||
def close(unlink_now=false)
|
||
begin
|
||
super() if @tmpfile
|
||
ensure
|
||
@tmpfile = nil
|
||
@data[1] = nil if @data
|
||
end
|
||
if unlink_now
|
||
close!
|
||
else
|
||
_close
|
||
unlink
|
||
ObjectSpace.undefine_finalizer(self)
|
||
end
|
||
nil
|
||
end
|
||
# Closes and unlinks (deletes) the file. Has the same effect as called
|
||
# <tt>close(true)</tt>.
|
||
def close!
|
||
_close
|
||
unlink
|
||
ObjectSpace.undefine_finalizer(self)
|
||
close(true)
|
||
end
|
||
# Unlinks (deletes) the file from the filesystem. One should always unlink
|
||
... | ... | |
def call(*args)
|
||
return if @pid != $$
|
||
path, tmpfile = *@data
|
||
path, tmpfile, tmpmap = *@data
|
||
STDERR.print "removing ", path, "..." if $DEBUG
|
||
tmpfile.close if tmpfile
|
||
if path
|
||
if path && tmpmap.has_key?(path) && (tmpmap[path] -= 1) == 0
|
||
begin
|
||
File.unlink(path)
|
||
rescue Errno::ENOENT
|
||
... | ... | |
end
|
||
STDERR.print "done\n" if $DEBUG
|
||
ensure
|
||
tmpmap.delete(path)
|
||
end
|
||
end
|
||
# :startdoc:
|
test/test_tempfile.rb | ||
---|---|---|
assert_equal(0600, t.stat.mode & 0777)
|
||
end
|
||
end
|
||
end
|
||
def test_dup
|
||
t = tempfile("foo")
|
||
t_dup = t.dup
|
||
assert(t_dup.is_a?(File))
|
||
end
|
||
def test_duped_finalizer
|
||
t = Tempfile.new("foo")
|
||
path = t.path
|
||
t_dup = t.dup
|
||
t = nil
|
||
GC.start
|
||
assert(File.exist?(path))
|
||
end
|
||
end
|