2009-07-16 12 views

Respuesta

17

La función Dir#tmpdir en el núcleo Ruby (no stdlib con la que se vinculó) debe ser multiplataforma.

Para usar esta función necesita require 'tmpdir'.

+3

Eso le da a la ruta temporal global del sistema operativo, pero no a la propia ruta dedicada y vacía de su aplicación. – Mike

+1

De acuerdo con Mike, no creo que esta sea una respuesta correcta a la pregunta anterior. Lo que necesitamos es similar a Tempfile (http://ruby-doc.org/stdlib/libdoc/tempfile/rdoc/files/tempfile_rb.html), pero para los dirs; idealmente los archivos temporales de soporte de archivos temporales. – inger

+0

sí, esta respuesta es falsa. Otros son más correctos, p. el mío en http://stackoverflow.com/questions/1139265/what-is-the-best-way-to-get-a-temporary-directory-in-ruby-on-rails/8823618#8823618 – AlexChaffee

0

Empecé a hacer frente a esto mediante el secuestro Tempfile, ver a continuación. Debería limpiarse a sí mismo como lo hace Tempfile, pero no siempre ... Todavía tiene que eliminar archivos en el tempdir. De todos modos, comparto esto aquí, podría ser útil como punto de partida.

require 'tempfile' 
class Tempdir < Tempfile 
    require 'tmpdir' 
    def initialize(basename, tmpdir = Dir::tmpdir) 
    super 
    p = self.path 
    File.delete(p) 
    Dir.mkdir(p) 
    end 
    def unlink # copied from tempfile.rb 
    # keep this order for thread safeness 
    begin 
     Dir.unlink(@tmpname) if File.exist?(@tmpname) 
     @@cleanlist.delete(@tmpname) 
     @data = @tmpname = nil 
     ObjectSpace.undefine_finalizer(self) 
    rescue Errno::EACCES 
     # may not be able to unlink on Windows; just ignore 
    end 
    end 
end 

Esto se puede utilizar de la misma manera como archivo temporal, por ejemplo:

Tempdir.new('foo') 

Todos los métodos de archivo temporal, y, a su vez, del archivo debería funcionar. Solo lo probé brevemente, entonces no hay garantías.

0

Mira la librería Ruby stemp: http://ruby-stemp.rubyforge.org/rdoc/

Si haces algo como esto:

dirname = STemp.mkdtemp("#{Dir.tmpdir}/directory-name-template-XXXXXXXX") 

nombredir será una cadena que apunta a un directorio que está garantizado que no existía previamente. Puedes definir para qué quieres que empiece el nombre del directorio. Las X se reemplazan con caracteres aleatorios.

EDITAR: alguien mencionó que esto no funcionó para ellos en 1.9, entonces YMMV.

2
require 'tmpdir' # not needed if you are loading Rails 
tmp_dir = File.join(Dir::tmpdir, "my_app_#{Time.now.to_i}_#{rand(100)}") 
Dir.mkdir(tmp_dir) 

Trabaja para mí.

+0

te refieres a trabajos con cierta probabilidad :) – Alexey

11

Un general aprox estoy usando ahora:

def in_tmpdir 
    path = File.expand_path "#{Dir.tmpdir}/#{Time.now.to_i}#{rand(1000)}/" 
    FileUtils.mkdir_p path 
    yield path 
ensure 
    FileUtils.rm_rf(path) if File.exists?(path) 
end 

Así que en su código puede:

in_tmpdir do |tmpdir| 
    puts "My tmp dir: #{tmpdir}" 
    # work with files in the dir 
end 

El directorio temporal se eliminará automáticamente cuando el método terminará.

+1

Muy buen enfoque, +1 – klaffenboeck

+3

Acabo de descubrir que este comportamiento ya está implementado en [Dir.mktmpdir] (http://ruby-doc.org/stdlib-1.9.3/libdoc/ tmpdir/rdoc/Dir.html # method-c-mktmpdir) – fguillen

+1

Para mí, el nombre 'in_tmpdir' sugiere que' pwd' cambia en el contexto del bloque. Sugeriría usar 'Dir.chdir (ruta, & bloque)' en lugar de simplemente ceder la ruta. – tfischbach

0

Actualización: gem install files, entonces

require "files" 
dir = Files do 
    file "hello.txt", "stuff" 
end 

ver más abajo para más ejemplos.


Aquí hay otra solución, inspirada en algunas otras respuestas. Este es adecuado para su inclusión en una prueba (por ejemplo, rspec o spec_helper.rb). Crea un directorio temporal basado en el nombre del archivo incluido, lo almacena en una variable de instancia para que persista durante la prueba (pero no se comparte entre las pruebas), y lo elimina al salir (u opcionalmente no, si desea verificar su contenido después de la prueba).

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 

(También es posible usar Dir.mktmpdir (que ha estado presente desde Rubí 1.8.7) en lugar de Dir.mkdir pero encuentro la API de ese método confuso, por no mencionar el algoritmo de nombres.)

Uso ejemplo (y otro método de prueba útil):

def write name, contents = "contents of #{name}" 
    path = "#{temp_dir}/#{name}" 
    File.open(path, "w") do |f| 
    f.write contents 
    end 
    File.new path 
end 

describe "#write" do 
    before do 
    @hello = write "hello.txt" 
    @goodbye = write "goodbye.txt", "farewell" 
    end 

    it "uses temp_dir" do 
    File.dirname(@hello).should == temp_dir 
    File.dirname(@goodbye).should == temp_dir 
    end 

    it "writes a default value" do 
    File.read(@hello).should == "contents of hello.txt" 
    end 

    it "writes a given value" do 
    # since write returns a File instance, we can call read on it 
    @goodbye.read.should == "farewell" 
    end 
end 

actualización: he utilizado este código de dar un impulso a una joya que estoy llamando files WHI ch tiene la intención de que sea super fácil crear directorios y archivos de forma temporal (p. prueba unitaria) uso. Ver https://github.com/alexch/files y https://rubygems.org/gems/files. Por ejemplo:

require "files" 

files = Files do  # creates a temporary directory inside Dir.tmpdir 
    file "hello.txt"   # creates file "hello.txt" containing "contents of hello.txt" 
    dir "web" do    # creates directory "web" 
    file "snippet.html", # creates file "web/snippet.html"... 
     "<h1>Fix this!</h1>" # ...containing "<h1>Fix this!</h1>" 
    dir "img" do   # creates directory "web/img" 
     file File.new("data/hello.png")   # containing a copy of hello.png 
     file "hi.png", File.new("data/hello.png") # and a copy of hello.png named hi.png 
    end 
    end 
end       # returns a string with the path to the directory 
42

El objeto Dir tiene un método mktmpdir que crea un directorio temporal:

require 'tmpdir' # Not needed if you are using rails. 

Dir.mktmpdir do |dir| 
    puts "My new temp dir: #{dir}" 
end 

El directorio temporal se eliminará después de la ejecución del bloque.

+1

Aunque supongo que esto requiere que puedas caber tu código en un bloque ... Me gusta :) – rogerdpack

+8

de [ruby-doc.org] (http://ruby-doc.org/stdlib-2.0.0 /libdoc/tmpdir/rdoc/Dir.html#method-c-mktmpdir) _Si no se proporciona un bloque, se devuelve la ruta del directorio. En este caso, :: mktmpdir no elimina el directorio._ – thinkOfaNumber

+1

¿Cómo no puedes colocar tu código en un bloque? Si es demasiado grande crea una clase/método/etc. y luego llámalo desde el bloque –

0

Ruby tiene Dir # mktmpdir, así que simplemente úselo.

require 'tempfile' 
Dir.mktmpdir('prefix_unique_to_your_program') do 
    ### your work here ### 
end 

Ver http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tmpdir/rdoc/Dir.html

o construir su propio uso de archivo temporal archivo temporal es de procesos y subprocesos único, por lo que sólo tiene que utilizar para construir una rápida tempdir.

require 'tempfile' 
Tempfile.open('prefix_unique_to_your_program') do |tmp| 
    tmp_dir = tmp.path + "_dir" 
    begin 
    FileUtils.mkdir_p(tmp_dir) 

    ### your work here ### 
    ensure 
    FileUtils.rm_rf(tmp_dir) 
    end 
end 

Ver http://www.ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/Tempfile.html para las opciones sufijo/prefijo opcional.

0

Puede usar Dir.mktmpdir.

El uso de un bloque eliminará el directorio temporal cuando se cierre.

Dir.mktmpdir do |dir| 
    File.open("#{dir}/foo", 'w') { |f| f.write('foo') } 
end 

O si necesita varios directorios temporales de existir al mismo tiempo, por ejemplo

context 'when there are duplicate tasks' do 
    it 'raises an DuplicateTask error' do 
    begin 
     tmp_dir1 = Dir.mktmpdir('foo') 
     tmp_dir2 = Dir.mktmpdir('bar') 

     File.new("#{tmp_dir1}/task_name", 'w+') 
     File.new("#{tmp_dir2}/task_name", 'w+') 

     expect { subject.filepath('task_name') }.to raise_error(TaskFinder::DuplicateTask) 
    ensure 
     FileUtils.remove_entry tmp_dir1 
     FileUtils.remove_entry tmp_dir2 
    end 
    end 
end 

Dir.mktmpdir crea un directorio temporal en virtud Dir.tmpdir (Tendrá que require 'tmpdir' para ver lo que se evalúe como)

Si desea utilizar su propia ruta, Dir.mktmpdir toma un segundo argumento opcional tmpdir si se proporciona un valor nulo. P.ej.

Dir.mktmpdir(nil, "/var/tmp") { |dir| "dir is '/var/tmp/d...'" } 
Cuestiones relacionadas