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?
On Thu, Oct 23, 2008 at 5:49 PM, Kenneth McDonald [email protected] 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
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
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.
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:
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
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.