Forum: Ruby Any nice way to get a temporary directory?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Kenneth McDonald (Guest)
on 2008-10-24 00:26
(Received via mailing list)
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
Craig D. (Guest)
on 2008-10-24 00:44
(Received via mailing list)
Could you call Dir.mkdir with the result of Dir.tmpdir plus the name of
the
directory that you want to create?

Regards,
Craig
Kenneth McDonald (Guest)
on 2008-10-24 00:49
(Received via mailing list)
There is, sadly, no Dir.tmpdir function in Ruby.

Ken
Avdi G. (Guest)
on 2008-10-24 00:57
(Received via mailing list)
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
Kenneth McDonald (Guest)
on 2008-10-24 01:51
(Received via mailing list)
Ah, thank you. Sorry for my previous mistake.

Ken
Avdi G. (Guest)
on 2008-10-24 01:53
(Received via mailing list)
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 :-)



--
Avdi

Home: http://avdi.org
Developer Blog: http://avdi.org/devblog/
Twitter: http://twitter.com/avdi
Journal: http://avdi.livejournal.com
Ara H. (Guest)
on 2008-10-24 05:01
(Received via mailing list)
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/
Nobuyoshi N. (Guest)
on 2008-10-24 06:31
(Received via mailing list)
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.
Alex C. (Guest)
on 2012-01-11 19:43
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...

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 topic is locked and can not be replied to.