* lib/tempfile.rb: refactoring.

* use warn instead of STDERR.print
  * remove @tmpname and use @tmpfile.path
  * introduce @unlinked flag
  * Remover takes only @tmpfile
  * mode will be modified just before file reopen

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50682 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
glass 2015-05-30 01:29:48 +00:00
Родитель e214058956
Коммит 354c9747e4
2 изменённых файлов: 38 добавлений и 55 удалений

Просмотреть файл

@ -1,3 +1,12 @@
Sat May 30 10:26:09 2015 Masaki Matsushita <glass.saga@gmail.com>
* lib/tempfile.rb: refactoring.
* use warn instead of STDERR.print
* remove @tmpname and use @tmpfile.path
* introduce @unlinked flag
* Remover takes only @tmpfile
* mode will be modified just before file reopen
Sat May 30 09:02:51 2015 Eric Wong <e@80x24.org> Sat May 30 09:02:51 2015 Eric Wong <e@80x24.org>
* include/ruby/intern.h (rb_generic_ivar_table): deprecate * include/ruby/intern.h (rb_generic_ivar_table): deprecate

Просмотреть файл

@ -123,41 +123,29 @@ class Tempfile < DelegateClass(File)
# If Tempfile.new cannot find a unique filename within a limited # If Tempfile.new cannot find a unique filename within a limited
# number of tries, then it will raise an exception. # number of tries, then it will raise an exception.
def initialize(basename="", tmpdir=nil, mode: 0, **options) def initialize(basename="", tmpdir=nil, mode: 0, **options)
if block_given? warn "Tempfile.new doesn't call the given block." 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)
@mode = mode|File::RDWR|File::CREAT|File::EXCL
::Dir::Tmpname.create(basename, tmpdir, options) do |tmpname, n, opts| ::Dir::Tmpname.create(basename, tmpdir, options) do |tmpname, n, opts|
mode |= File::RDWR|File::CREAT|File::EXCL
opts[:perm] = 0600 opts[:perm] = 0600
@data[1] = @tmpfile = File.open(tmpname, mode, opts) @tmpfile = File.open(tmpname, @mode, opts)
@data[0] = @tmpname = tmpname @opts = opts.freeze
@mode = mode & ~(File::CREAT|File::EXCL)
opts.freeze
@opts = opts
end end
ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))
super(@tmpfile) super(@tmpfile)
end end
# Opens or reopens the file with mode "r+". # Opens or reopens the file with mode "r+".
def open def open
@tmpfile.close if @tmpfile _close
@tmpfile = File.open(@tmpname, @mode, @opts) mode = @mode & ~(File::CREAT|File::EXCL)
@data[1] = @tmpfile @tmpfile = File.open(@tmpfile.path, mode, @opts)
__setobj__(@tmpfile) __setobj__(@tmpfile)
end end
def _close # :nodoc: def _close # :nodoc:
begin @tmpfile.close unless @tmpfile.closed?
@tmpfile.close if @tmpfile
ensure
@tmpfile = nil
@data[1] = nil if @data
end
end end
protected :_close protected :_close
@ -168,18 +156,14 @@ class Tempfile < DelegateClass(File)
# If you don't explicitly unlink the temporary file, the removal # If you don't explicitly unlink the temporary file, the removal
# will be delayed until the object is finalized. # will be delayed until the object is finalized.
def close(unlink_now=false) def close(unlink_now=false)
if unlink_now _close
close! unlink if unlink_now
else
_close
end
end end
# Closes and unlinks (deletes) the file. Has the same effect as called # Closes and unlinks (deletes) the file. Has the same effect as called
# <tt>close(true)</tt>. # <tt>close(true)</tt>.
def close! def close!
_close close(true)
unlink
end end
# Unlinks (deletes) the file from the filesystem. One should always unlink # Unlinks (deletes) the file from the filesystem. One should always unlink
@ -216,37 +200,32 @@ class Tempfile < DelegateClass(File)
# # to do so again. # # to do so again.
# end # end
def unlink def unlink
return unless @tmpname return if @unlinked
begin begin
File.unlink(@tmpname) File.unlink(@tmpfile.path)
rescue Errno::ENOENT rescue Errno::ENOENT
rescue Errno::EACCES rescue Errno::EACCES
# may not be able to unlink on Windows; just ignore # may not be able to unlink on Windows; just ignore
return return
end end
# remove tmpname from remover
@data[0] = @data[1] = nil
@tmpname = nil
ObjectSpace.undefine_finalizer(self) ObjectSpace.undefine_finalizer(self)
@unlinked = true
end end
alias delete unlink alias delete unlink
# Returns the full path name of the temporary file. # Returns the full path name of the temporary file.
# This will be nil if #unlink has been called. # This will be nil if #unlink has been called.
def path def path
@tmpname @unlinked ? nil : @tmpfile.path
end end
# Returns the size of the temporary file. As a side effect, the IO # Returns the size of the temporary file. As a side effect, the IO
# buffer is flushed before determining the size. # buffer is flushed before determining the size.
def size def size
if @tmpfile if !@tmpfile.closed?
@tmpfile.flush @tmpfile.size # File#size calls rb_io_flush_raw()
@tmpfile.stat.size
elsif @tmpname
File.size(@tmpname)
else else
0 File.size?(@tmpfile.path)
end end
end end
alias length size alias length size
@ -261,28 +240,23 @@ class Tempfile < DelegateClass(File)
end end
class Remover class Remover
def initialize(data) def initialize(tmpfile)
@pid = $$ @pid = Process.pid
@data = data @tmpfile = tmpfile
end end
def call(*args) def call(*args)
return if @pid != $$ return if @pid != Process.pid
path, tmpfile = @data warn "removing #{@tmpfile.path}..." if $DEBUG
STDERR.print "removing ", path, "..." if $DEBUG @tmpfile.close if @tmpfile.closed?
begin
tmpfile.close if tmpfile File.unlink(@tmpfile.path)
rescue Errno::ENOENT
if path
begin
File.unlink(path)
rescue Errno::ENOENT
end
end end
STDERR.print "done\n" if $DEBUG warn "done" if $DEBUG
end end
end end