LoginSignup
1
0

More than 5 years have passed since last update.

Dir.mktmpdir が短縮ファイル名をブロックパラメーターにするのでエラい目にあった

Last updated at Posted at 2016-07-09

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

で長い形式に変換すればよいようだ。

なんかバカバカしい気もするけど,これよりマシな方法が思いつかない。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0