diff options
Diffstat (limited to 'lib/tempfile.rb')
-rw-r--r-- | lib/tempfile.rb | 97 |
1 files changed, 69 insertions, 28 deletions
diff --git a/lib/tempfile.rb b/lib/tempfile.rb index 8a6bcc3e14..1d7b80a74d 100644 --- a/lib/tempfile.rb +++ b/lib/tempfile.rb @@ -57,7 +57,7 @@ require 'tmpdir' # Note that Tempfile.create returns a File instance instead of a Tempfile, which # also avoids the overhead and complications of delegation. # -# Tempfile.open('foo') do |file| +# Tempfile.create('foo') do |file| # # ...do something with file... # end # @@ -88,6 +88,9 @@ require 'tmpdir' # mutex. class Tempfile < DelegateClass(File) + # The version + VERSION = "0.2.1" + # Creates a file in the underlying file system; # returns a new \Tempfile object based on that file. # @@ -104,7 +107,7 @@ class Tempfile < DelegateClass(File) # - Directory is the system temporary directory (system-dependent). # - Generated filename is unique in that directory. # - Permissions are <tt>0600</tt>; - # see {File Permissions}[https://docs.ruby-lang.org/en/master/File.html#label-File+Permissions]. + # see {File Permissions}[rdoc-ref:File@File+Permissions]. # - Mode is <tt>'w+'</tt> (read/write mode, positioned at the end). # # The underlying file is removed when the \Tempfile object dies @@ -136,12 +139,12 @@ class Tempfile < DelegateClass(File) # Tempfile.new('foo', '.') # => #<Tempfile:./foo20220505-17839-xfstr8> # # Keyword arguments +mode+ and +options+ are passed directly to method - # {File.open}[https://docs.ruby-lang.org/en/master/File.html#method-c-open]: + # {File.open}[rdoc-ref:File.open]: # # - The value given with +mode+ must be an integer, # and may be expressed as the logical OR of constants defined in - # {File::Constants}[https://docs.ruby-lang.org/en/master/File/Constants.html]. - # - For +options+, see {Open Options}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Open+Options]. + # {File::Constants}[rdoc-ref:File::Constants]. + # - For +options+, see {Open Options}[rdoc-ref:IO@Open+Options]. # # Related: Tempfile.create. # @@ -150,26 +153,50 @@ class Tempfile < DelegateClass(File) @unlinked = false @mode = mode|File::RDWR|File::CREAT|File::EXCL + @finalizer_obj = Object.new + tmpfile = nil ::Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts| opts[:perm] = 0600 - @tmpfile = File.open(tmpname, @mode, **opts) + tmpfile = File.open(tmpname, @mode, **opts) @opts = opts.freeze end - ObjectSpace.define_finalizer(self, Remover.new(@tmpfile)) + ObjectSpace.define_finalizer(@finalizer_obj, Remover.new(tmpfile.path)) + ObjectSpace.define_finalizer(self, Closer.new(tmpfile)) + + super(tmpfile) + end + + def initialize_dup(other) # :nodoc: + initialize_copy_iv(other) + super(other) + ObjectSpace.define_finalizer(self, Closer.new(__getobj__)) + end + + def initialize_clone(other) # :nodoc: + initialize_copy_iv(other) + super(other) + ObjectSpace.define_finalizer(self, Closer.new(__getobj__)) + end - super(@tmpfile) + private def initialize_copy_iv(other) # :nodoc: + @unlinked = other.unlinked + @mode = other.mode + @opts = other.opts + @finalizer_obj = other.finalizer_obj end # Opens or reopens the file with mode "r+". def open _close + ObjectSpace.undefine_finalizer(self) mode = @mode & ~(File::CREAT|File::EXCL) - @tmpfile = File.open(@tmpfile.path, mode, **@opts) - __setobj__(@tmpfile) + __setobj__(File.open(__getobj__.path, mode, **@opts)) + ObjectSpace.define_finalizer(self, Closer.new(__getobj__)) + __getobj__ end def _close # :nodoc: - @tmpfile.close + __getobj__.close end protected :_close @@ -226,13 +253,13 @@ class Tempfile < DelegateClass(File) def unlink return if @unlinked begin - File.unlink(@tmpfile.path) + File.unlink(__getobj__.path) rescue Errno::ENOENT rescue Errno::EACCES # may not be able to unlink on Windows; just ignore return end - ObjectSpace.undefine_finalizer(self) + ObjectSpace.undefine_finalizer(@finalizer_obj) @unlinked = true end alias delete unlink @@ -240,43 +267,57 @@ class Tempfile < DelegateClass(File) # Returns the full path name of the temporary file. # This will be nil if #unlink has been called. def path - @unlinked ? nil : @tmpfile.path + @unlinked ? nil : __getobj__.path end # Returns the size of the temporary file. As a side effect, the IO # buffer is flushed before determining the size. def size - if !@tmpfile.closed? - @tmpfile.size # File#size calls rb_io_flush_raw() + if !__getobj__.closed? + __getobj__.size # File#size calls rb_io_flush_raw() else - File.size(@tmpfile.path) + File.size(__getobj__.path) end end alias length size # :stopdoc: def inspect - if @tmpfile.closed? + if __getobj__.closed? "#<#{self.class}:#{path} (closed)>" else "#<#{self.class}:#{path}>" end end + alias to_s inspect - class Remover # :nodoc: + protected + + attr_reader :unlinked, :mode, :opts, :finalizer_obj + + class Closer # :nodoc: def initialize(tmpfile) - @pid = Process.pid @tmpfile = tmpfile end def call(*args) + @tmpfile.close + end + end + + class Remover # :nodoc: + def initialize(path) + @pid = Process.pid + @path = path + end + + def call(*args) return if @pid != Process.pid - $stderr.puts "removing #{@tmpfile.path}..." if $DEBUG + $stderr.puts "removing #{@path}..." if $DEBUG - @tmpfile.close begin - File.unlink(@tmpfile.path) + File.unlink(@path) rescue Errno::ENOENT end @@ -344,11 +385,11 @@ end # # With no block given and no arguments, creates and returns file whose: # -# - Class is {File}[https://docs.ruby-lang.org/en/master/File.html] (not \Tempfile). +# - Class is {File}[rdoc-ref:File] (not \Tempfile). # - Directory is the system temporary directory (system-dependent). # - Generated filename is unique in that directory. # - Permissions are <tt>0600</tt>; -# see {File Permissions}[https://docs.ruby-lang.org/en/master/File.html#label-File+Permissions]. +# see {File Permissions}[rdoc-ref:File@File+Permissions]. # - Mode is <tt>'w+'</tt> (read/write mode, positioned at the end). # # With no block, the file is not removed automatically, @@ -380,12 +421,12 @@ end # Tempfile.create('foo', '.') # => #<File:./foo20220505-9795-1emu6g8> # # Keyword arguments +mode+ and +options+ are passed directly to method -# {File.open}[https://docs.ruby-lang.org/en/master/File.html#method-c-open]: +# {File.open}[rdoc-ref:File.open]: # # - The value given with +mode+ must be an integer, # and may be expressed as the logical OR of constants defined in -# {File::Constants}[https://docs.ruby-lang.org/en/master/File/Constants.html]. -# - For +options+, see {Open Options}[https://docs.ruby-lang.org/en/master/IO.html#class-IO-label-Open+Options]. +# {File::Constants}[rdoc-ref:File::Constants]. +# - For +options+, see {Open Options}[rdoc-ref:IO@Open+Options]. # # With a block given, creates the file as above, passes it to the block, # and returns the block's value; |