Ruby で一時ディレクトリーを作るには tmpdir ライブラリーを require して,Dir.mktmpdir
メソッドを使う。
基本は
require "tmpdir"
Dir.mktmpdir do |dirpath|
# なんとかかんとか
end
の形。ブロックパラメーター dirpath
には,文字どおり,作成された一時ディレクトリーのパスが渡されるので,ブロック内でそのパスに何かしたりできる。
ブロックの評価が終われば,一時ディレクトリーは自動的に削除されるので,後始末を考えなくていい。
しかし,Windows でちょっと困ったことが起こった。dirpath
にはいわゆる「短いファイル名」形式のパスが渡されるのだ。
「短いファイル名」とは,8.3形式 しか使えなかった MS-DOS との互換性のために編み出された,本物のファイル名(パス中のディレクトリー名も含む)を無理やり 8.3 形式に落とし込んだもの。(微妙に間違ってたらごめん)
例えばディレクトリー名「Documents and settings」が「DOCUME~1」になったりする。Windows の Ruby では,どちらでアクセスしても構わない。
ところが面白いことに,そのパスを使って Dir.glob
した結果は,「短いファイル名」形式でなく「長いファイル名」形式だ。
たとえば,
require "tmpdir"
Dir.mktmpdir do |dir|
p dir
IO.write(dir + "/foo.txt", "hoge")
p Dir.glob(dir + "/*")
end
とやると,最初の p
では短い形式,二番目の p
では長い形式で表示される。
これの何が困るのか。
パス名を Pathname 化して relative_path_from
で一時ディレクトリーからの相対パスを得ようとしたとき,短い形式と長い形式では同じディレクトリーとみなしてくれないから ../../../../
みたいので始まる長ったらしいパスになる。
どうやって解決したのか。
some_dir
が短い形式のディレクトリーパスだとして,
Dir.glob(some_dir).first
で長い形式に変換すればよいようだ。
なんかバカバカしい気もするけど,これよりマシな方法が思いつかない。