# Copyright: Copyright (c) 2004 Nicolas Pouillard. All rights reserved. # Author: Nicolas Pouillard . # License: Gnu General Public License. # $LastChangedBy: ertai $ # $Id: mktemp.rb 186 2005-04-03 00:07:45Z ertai $ require 'pathname' require 'tempfile' require 'tmpdir' require 'set' require 'thread' class TempPath < Pathname @@tmps = Set.new @@mutex = Mutex.new @@progname = Pathname.new($0).basename @@tmpdir = Pathname.new(Dir.tmpdir) + "#{@@progname}.#{$$}" @@tmpdir.freeze @@initialized = false @@clean_planned = false @@auto_clean = true # You can use a temporary pathname like that: # # - # No argument are mandatory. # tmp = TempPath.new # tmp.open('w') { |f| f << 'foo' } # tmp.clean # # - # You can choose the basename and an extension. # TmpPath.new('the_base_file_name', 'rb') # # - # You can supply a block (recomended). # TmpPath.new('foo') do |tmp| # tmp.open('w') { |f| << 'foo' } # tmp.exist? == true # $tmp = tmp # end # $tmp.exist? == false # # - # You can make a temporary directory. # TmpPath.new('adirectory') do |tmpdir| # tmpdir.mkpath # $file = tmpdir + 'foo' # $file.open('w') { |f| f << 'foo' } # end # $file.exist? == false # def initialize ( base=@@progname, ext='', &block ) if base.to_s =~ /\// raise ArgumentError, "bad basename, you give me a pathname #{base}" end self.class.init ext = ".#{ext}" unless ext.empty? or ext[0] == ?. res = nil @@mutex.synchronize do id_tmp = object_id while (res = @@tmpdir + "#{base}.#{id_tmp}#{ext}").exist? \ and not @@tmps.include? res id_tmp += 1 end super(res) @@tmps << self end if block_given? begin block[self.dup] ensure clean end end end # This method remove your temporary pathname. # You do not need to call this method if you provide # a block when you create a tempfile. def clean if exist? if directory? rmtree else unlink end end end def temp? true end def self.init #:nodoc: return if @@initialized @@mutex.synchronize do return if @@initialized @@tmpdir.mkpath @@initialized = true at_exit { clean if @@auto_clean } end end # By default the autoclean is on. # But in some case (if you use your temppaths in at_exit) # You must disable the autoclean. # And manually call TempPath.clean at the very of the program. def self.clean ( &block ) @@mutex.synchronize do return if @@clean_planned @@clean_planned = true end begin block[] if block_given? ensure if @@tmpdir.exist? @@tmpdir.rmtree @@initialized = false end end end def self.auto_clean= ( aBool ) @@auto_clean = aBool end def self.tmpdir init @@tmpdir end end # class TempPath # This tempfile extension, provide the mktemp function. # # Example: # # Tempfile.mktemp('foo', 'rb') # => 'foo.111811.432.rb' # which follow this format: # => 'base.pid.uniq.ext # # Tempfile.mktemp('bar') # => 'foo.111811.134' # class Tempfile # Almost deprecated use TempPath. def self.mktemp ( base=$0, ext='', &block ) TempPath.new(base, ext, &block) end end # class Tempfile class Pathname def temp? false end end # class Pathname if defined? TEST_MODE or $0 == __FILE__ require 'test/unit' class MkTempTest < Test::Unit::TestCase def setup @list = [] end def teardown @list.each { |l| l.clean } end def test_interface assert_nothing_raised { @foo = Tempfile.mktemp('foo') } assert_nothing_raised { @foobar = Tempfile.mktemp('foo', 'bar') } assert_match(/\.#{$$}\/foo\.\d+$/, @foo.to_s) assert_match(/\.#{$$}\/foo\.\d+\.bar$/, @foobar.to_s) assert_nothing_raised { @foo.open('w') { |f| f.puts 'FooFoo' } } @list << @foo @list << @foobar end def test_many (0 .. 100).each do |i| tmp = Tempfile.mktemp('many') tmp.open('w') { |f| f.puts "i: #{i}" } assert(tmp.exist?) assert_equal("i: #{i}\n", tmp.readlines.join) @list << tmp end end def test_temp? tmp = Tempfile.mktemp('is_temp') assert(tmp.temp?, 'not tmp.temp?') assert_nothing_raised { Pathname.new(tmp.to_s).temp? } assert(!Pathname.new(tmp.to_s).temp?) end end # class MkTempTest end