Ruby で困ったこまった。大もんだ〜〜〜い

Tempfileクラスを使って、一時ファイルを作成し、そやつをrenameする方法。

  1. きっかけ

ファイルの先頭に文字列を追加したくて、『Rubyレシピブック』をぱらぱらめくると、「#163 ファイルに1行挿入する」なんて項目を見つけたので、そのままコピペ。

要するにTempfileクラスを使って一時ファイルを作成してファイルの内容をコピー。該当行にきたら挿入したいデータを追記して、一時ファイルを作成完了。最後にrenameして終了というのがこのレシピの本質。

  1. 正誤表は大事

Rubyレシピブック』に限らず、こういう本を読むときは、必ず正誤表をチェックしておこう。今回のレシピでは2件の正誤情報が報告されているので、目を通しておかないとちょっぴり痛い目にあいます。(と、あった本人が言う。)

  1. GCは気ままに生きる

ガーベージコレクタ(GC)って便利なものですよね。C++malloc - freeな関係やnew - deleteってな関係に疲れていると、「使ったらそのまんま」「後片付けはメイドさんがやってくれる」的なGCは快適そのものです。

さてさて、そろそろ本文。
Tempfileクラスを使って一時ファイルを作成した後、削除してくれるのもGCなんですが、また処理しきってないのに一時ファイルを削除しちゃうと「ファイル作っても0バイト〜」ってな状態になったりします。というわけで、GCに対して「まだこいつ生きているよ〜〜〜」って言うのが必要なんですが、どないすればええのやら・・・

でいろいろやった結果、一時ファイルに情報を書き込んだ後、一旦closeして再度openしちょります。これが有効なのかどうかは分かりませんが、これで「ファイル作っても0バイト〜」ってことはなくなりました。

  1. 最後はrenameのはずだった・・・

で、これで万事OK牧場!!って思って実行すると、こんなエラーが出てきました。

renametry.rb:18:in `rename': Permission denied - ./mytemp3124.0 or ddd.cpp (Errno::EACCES)
from renametry.rb:18

どうやらパーミッションがダメよんって言っている様なのですが、動かしている
のはWindows。なんでこんなもんが出てくるんでしょう。わけ分かりません。

さらに、よくよくメッセージを見ると「./mytemp3124.0かddd.cppのどっちかがへんだよ〜」って言ってんだけれども、どっちが悪いのかが分からん。解決の手がかりすらねぇよ。

こういうときは、問題の切り分けを行わなければいけない。まず、どっちが悪いかを見極めることにする。

まず、./mytemp3124.0の内容をファイルにコピーすることにする。これは、FileUtilsモジュールにあるcp関数を使ってみると見事に成功。

次にrenameの代わりにFileUtilsモジュールにあるmv関数を使ってみることにする。
すると、

C:/ruby/lib/ruby/1.8/fileutils.rb:585:in `unlink': Permission denied - ./mytemp3844.0 (Errno::EACCES)
from C:/ruby/lib/ruby/1.8/fileutils.rb:585:in `mv'
from C:/ruby/lib/ruby/1.8/fileutils.rb:572:in `fu_each_src_dest'
from C:/ruby/lib/ruby/1.8/fileutils.rb:845:in `fu_each_src_dest0'
from C:/ruby/lib/ruby/1.8/fileutils.rb:845:in `fu_each_src_dest'
from C:/ruby/lib/ruby/1.8/fileutils.rb:572:in `mv'
from renametry.rb:20

ってでたので、悪いのは一時ファイルの削除処理だろうと。というわけで、うまくいったcp関数でおしまいって感じ。

  1. Macでもやってみた。

MacだときっちりrenameでOK牧場。結局窓はそんな感じだ。