Any nice way to get a temporary directory?


#1

I’d like to be able to obtain a temporary directory in the same way I
can easily obtain a temporary file, but there doesn’t seem to be a
function for this. Currently, I’m creating a temp file, getting it’s
name, unlinking it, and then creating a dir with the same name. But
this is ugly, and in theory subject to a race condition. Is there a
better way of doing this?

Thanks,
Ken


#2

Could you call Dir.mkdir with the result of Dir.tmpdir plus the name of
the
directory that you want to create?

Regards,
Craig


#3

There is, sadly, no Dir.tmpdir function in Ruby.

Ken


#4

Ah, thank you. Sorry for my previous mistake.

Ken


#5

On Thu, Oct 23, 2008 at 4:45 PM, Kenneth McDonald
removed_email_address@domain.invalid wrote:

There is, sadly, no Dir.tmpdir function in Ruby.

There is, actually. You have to require ‘tmpdir’ and then you’ll have
it.


Avdi

Home: http://avdi.org
Developer Blog: http://avdi.org/devblog/
Twitter: http://twitter.com/avdi
Journal: http://avdi.livejournal.com


#6

On Thu, Oct 23, 2008 at 5:49 PM, Kenneth McDonald
removed_email_address@domain.invalid wrote:

Ah, thank you. Sorry for my previous mistake.

No problem. Considering there is almost no documentation for the
‘tmpdir’ library, and nothing to hint that requiring a special library
will magically make new methods appear on an existing class, this is
definitely one of Ruby’s better-kept secrets :slight_smile:


Avdi

Home: http://avdi.org
Developer Blog: http://avdi.org/devblog/
Twitter: http://twitter.com/avdi
Journal: http://avdi.livejournal.com


#7

On Oct 23, 2008, at 2:24 PM, Kenneth McDonald wrote:

I’d like to be able to obtain a temporary directory in the same way
I can easily obtain a temporary file, but there doesn’t seem to be a
function for this. Currently, I’m creating a temp file, getting it’s
name, unlinking it, and then creating a dir with the same name. But
this is ugly, and in theory subject to a race condition. Is there a
better way of doing this?

Thanks,
Ken

this keeps backwards compact, but also lets you do

Dir.tmpdir do

 puts "in tmpdir #{ Dir.pwd }"

end

the tmpdir will be created for you and cleaned up too

class Dir
module Tmpdir
require ‘tmpdir’
require ‘socket’
require ‘fileutils’

 unless defined?(Super)
   Super = Dir.send(:method, :tmpdir)
   class << Dir
     remove_method :tmpdir
   end
 end

 class Error < ::StandardError; end

 Hostname = Socket.gethostname || 'localhost'
 Pid = Process.pid
 Ppid = Process.ppid

 def tmpdir *args, &block
   options = Hash === args.last ? args.pop : {}

   dirname = Super.call(*args)

   return dirname unless block

   turd = options['turd'] || options[:turd]

   basename = [
     Hostname,
     Ppid,
     Pid,
     Thread.current.object_id.abs,
     rand
   ].join('-')

   pathname = File.join dirname, basename

   made = false

   42.times do
     begin
       FileUtils.mkdir_p pathname
       break(made = true)
     rescue Object
       sleep rand
       :retry
     end
   end

   raise Error, "failed to make tmpdir in #{ dirname.inspect }"

unless made

   begin
     return Dir.chdir(pathname, &block)
   ensure
     unless turd
       FileUtils.rm_rf(pathname) if made
     end
   end
 end

end

extend Tmpdir
end

a @ http://codeforpeople.com/


#8

Hi,

At Fri, 24 Oct 2008 05:24:20 +0900,
Kenneth McDonald wrote in [ruby-talk:318458]:

I’d like to be able to obtain a temporary directory in the same way I
can easily obtain a temporary file, but there doesn’t seem to be a
function for this. Currently, I’m creating a temp file, getting it’s
name, unlinking it, and then creating a dir with the same name. But
this is ugly, and in theory subject to a race condition. Is there a
better way of doing this?

Dir.mktmpdir is available in lib/tmpdir.rb since 1.8.7.


#9

Nobuyoshi N. wrote in post #741896:

Hi,

At Fri, 24 Oct 2008 05:24:20 +0900,
Kenneth McDonald wrote in [ruby-talk:318458]:

I’d like to be able to obtain a temporary directory in the same way I
can easily obtain a temporary file, but there doesn’t seem to be a
function for this. Currently, I’m creating a temp file, getting it’s
name, unlinking it, and then creating a dir with the same name. But
this is ugly, and in theory subject to a race condition. Is there a
better way of doing this?

Dir.mktmpdir is available in lib/tmpdir.rb since 1.8.7.

Sorry for the zombie post, but I had this question and rolled my own
solution. My code is on StackOverflow along with some usage examples and
other answers here:

http://stackoverflow.com/questions/1139265/what-is-the-best-way-to-get-a-temporary-directory-in-ruby-on-rails

Mine is suitable for inclusion in a test (e.g. rspec or spec_helper.rb).
It makes a temporary dir based on the name of the including file, stores
it in an instance variable so it persists for the duration of the test
(but is not shared between tests), and deletes it on exit (or optionally
doesn’t, if you want to check its contents after the test run).

def temp_dir options = {:remove => true}
@temp_dir ||= begin
require ‘tmpdir’
require ‘fileutils’
called_from = File.basename caller.first.split(’:’).first, “.rb”
path = File.join(Dir::tmpdir,
“#{called_from}#{Time.now.to_i}#{rand(1000)}”)
Dir.mkdir(path)
at_exit {FileUtils.rm_rf(path) if File.exists?(path)} if
options[:remove]
File.new path
end
end

I don’t like Dir.mktmpdir since I find the API of that method confusing,
not to mention the naming algorithm, and it doesn’t have the right
deletion timing options – I want the dir to stick around for a while,
but mktmpdir only lets you delete it immediately at the end of a block,
or never.

  • Alex