patch.diff

Masaki Matsushita, 10/12/2012 02:04 PM

Download (3.52 KB)

View differences:

lib/tempfile.rb
4 4
# $Id$
5 5
#
6 6

  
7
require 'delegate'
8 7
require 'tmpdir'
9 8
require 'thread'
10 9

  
......
78 77
# Tempfile itself however may not be entirely thread-safe. If you access the
79 78
# same Tempfile object from multiple threads then you should protect it with a
80 79
# mutex.
81
class Tempfile < DelegateClass(File)
80
class Tempfile < File
82 81
  include Dir::Tmpname
83 82

  
83
  @@tmpmap = {}
84

  
84 85
  # call-seq:
85 86
  #    new(basename, [tmpdir = Dir.tmpdir], [options])
86 87
  #
......
143 144
      else
144 145
        opts = perm
145 146
      end
146
      @data[1] = @tmpfile = File.open(tmpname, mode, opts)
147
      @data[1] = @tmpfile = super(tmpname, mode, opts)
147 148
      @data[0] = @tmpname = tmpname
148 149
      @mode = mode & ~(File::CREAT|File::EXCL)
149 150
      perm or opts.freeze
150 151
      @opts = opts
151 152
    end
153
    @@tmpmap[@tmpname] = 1
154
    @data[2] = @@tmpmap
155
  end
152 156

  
153
    super(@tmpfile)
157
  def dup
158
    @@tmpmap[@tmpname] += 1
159
    super
154 160
  end
155 161

  
156 162
  # Opens or reopens the file with mode "r+".
157 163
  def open
158
    @tmpfile.close if @tmpfile
159
    @tmpfile = File.open(@tmpname, @mode, @opts)
160
    @data[1] = @tmpfile
161
    __setobj__(@tmpfile)
162
  end
163

  
164
  def _close    # :nodoc:
165
    begin
166
      @tmpfile.close if @tmpfile
167
    ensure
168
      @tmpfile = nil
169
      @data[1] = nil if @data
170
    end
164
    opts = @opts.is_a?(Hash) ? @opts : nil
165
    @tmpfile = reopen(@tmpname, @mode, opts)
171 166
  end
172
  protected :_close
173 167

  
174 168
  # Closes the file. If +unlink_now+ is true, then the file will be unlinked
175 169
  # (deleted) after closing. Of course, you can choose to later call #unlink
......
178 172
  # If you don't explicitly unlink the temporary file, the removal
179 173
  # will be delayed until the object is finalized.
180 174
  def close(unlink_now=false)
175
    begin
176
      super() if @tmpfile
177
    ensure
178
      @tmpfile = nil
179
      @data[1] = nil if @data
180
    end
181 181
    if unlink_now
182
      close!
183
    else
184
      _close
182
      unlink
183
      ObjectSpace.undefine_finalizer(self)
185 184
    end
185
    nil
186 186
  end
187 187

  
188 188
  # Closes and unlinks (deletes) the file. Has the same effect as called
189 189
  # <tt>close(true)</tt>.
190 190
  def close!
191
    _close
192
    unlink
193
    ObjectSpace.undefine_finalizer(self)
191
    close(true)
194 192
  end
195 193

  
196 194
  # Unlinks (deletes) the file from the filesystem. One should always unlink
......
271 269
    def call(*args)
272 270
      return if @pid != $$
273 271

  
274
      path, tmpfile = *@data
272
      path, tmpfile, tmpmap = *@data
275 273

  
276 274
      STDERR.print "removing ", path, "..." if $DEBUG
277 275

  
278 276
      tmpfile.close if tmpfile
279 277

  
280
      if path
278
      if path && tmpmap.has_key?(path) && (tmpmap[path] -= 1) == 0
281 279
        begin
282 280
          File.unlink(path)
283 281
        rescue Errno::ENOENT
......
285 283
      end
286 284

  
287 285
      STDERR.print "done\n" if $DEBUG
286

  
287
    ensure
288
      tmpmap.delete(path)
288 289
    end
289 290
  end
290 291
  # :startdoc:
test/test_tempfile.rb
304 304
      assert_equal(0600, t.stat.mode & 0777)
305 305
    end
306 306
  end
307
end
308 307

  
308
  def test_dup
309
    t = tempfile("foo")
310
    t_dup = t.dup
311
    assert(t_dup.is_a?(File))
312
  end
313

  
314
  def test_duped_finalizer
315
    t = Tempfile.new("foo")
316
    path = t.path
317
    t_dup = t.dup
318
    t = nil
319
    GC.start
320
    assert(File.exist?(path))
321
  end
322
end