Каков наилучший способ получить пустой временный каталог в Ruby on Rails? - PullRequest
28 голосов
/ 16 июля 2009

Каков наилучший способ получить временный каталог без него, используя Ruby on Rails? Мне нужно, чтобы API был кросс-платформенным. Stdlib tmpdir не будет работать.

Ответы [ 9 ]

48 голосов
/ 07 июля 2013

Объект Dir имеет метод mktmpdir , который создает временный каталог:

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

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

Временный каталог будет удален после выполнения блока.

19 голосов
/ 17 июля 2009

Функция Dir#tmpdir в ядре Ruby (не с stdlib, на которую вы ссылались) должна быть кроссплатформенной.

Для использования этой функции вам необходимо require 'tmpdir'.

13 голосов
/ 09 января 2012

Общий пример, который я сейчас использую:

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

Итак, в вашем коде вы можете:

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

Временный каталог будет удален автоматически, когда ваш метод завершится.

2 голосов
/ 24 августа 2011
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)

У меня работает.

1 голос
/ 19 ноября 2013

В Ruby есть Dir # mktmpdir, так что просто используйте его.

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

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

Или создайте свой собственный, используя Tempfile, который является уникальным процессом и потоком, так что просто используйте его для создания быстрого 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

См. http://www.ruby -doc.org / stdlib-1.9.3 / libdoc / tempfile / rdoc / Tempfile.html для дополнительных параметров суффикса / префикса.

0 голосов
/ 25 апреля 2016

Вы можете использовать Dir.mktmpdir.

Использование блока избавит от временного каталога, когда он закроется.

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

Или, если вам нужно одновременное существование нескольких временных каталогов, например,

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 создает временный каталог в Dir.tmpdir (вам нужно require 'tmpdir', чтобы увидеть, к чему это приведет).

Если вы хотите использовать свой собственный путь, Dir.mktmpdir принимает необязательный второй аргумент tmpdir , если задано ненулевое значение. Э.Г.

Dir.mktmpdir(nil, "/var/tmp") { |dir| "dir is '/var/tmp/d...'" }
0 голосов
/ 11 января 2012

Обновление: gem install files, затем

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

Дополнительные примеры приведены ниже.


Вот еще одно решение, основанное на нескольких других ответах.Этот подходит для включения в тест (например, rspec или spec_helper.rb).Он создает временный каталог на основе имени включающего файла, сохраняет его в переменной экземпляра, чтобы он сохранялся в течение всего теста (но не распределяется между тестами), и удаляет его при выходе (или, по желанию, нет,если вы хотите проверить его содержимое после запуска теста).

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

(Вы также можете использовать Dir.mktmpdir (который существует начиная с Ruby 1.8.7) вместо Dir.mkdir , но я нахожу API этого метода запутанным, не говоря уже об алгоритме именования.)

Пример использования (и другой полезный метод тестирования):

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

Обновление: я использовал этот код для запуска драгоценного камня, который я называю files, который призван упростить создание каталогов и файлов для временного (например, модульного тестирования) использования.См. https://github.com/alexch/files и https://rubygems.org/gems/files.Например:

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
0 голосов
/ 01 октября 2010

Проверьте библиотеку Ruby STemp: http://ruby -stemp.rubyforge.org / rdoc /

Если вы делаете что-то вроде этого:

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

dirname будет строкой, указывающей на каталог, который гарантированно не существует ранее. Вы можете определить, с чего вы хотите начать имя каталога. X заменяются случайными символами.

РЕДАКТИРОВАТЬ: кто-то упомянул, что это не работает для них на 1,9, поэтому YMMV.

0 голосов
/ 07 сентября 2010

Я начал заниматься этим путем захвата Tempfile, см. Ниже. Он должен очиститься, как это делает Tempfile, но пока не всегда .. Это еще, чтобы удалить файлы в tempdir. В любом случае я поделюсь этим здесь, может быть полезно в качестве отправной точки.

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

Это можно использовать так же, как Tempfile, например:

 Tempdir.new('foo')

Все методы в Tempfile и, в свою очередь, File должны работать. Просто кратко проверил, так что никаких гарантий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...