[ruby-list:318] Re: Reqest for Find and BUG report
From:
matz@... (Yukihiro Matsumoto)
Date:
1996-07-19 08:28:00 UTC
List:
ruby-list #318
まつもと ゆきひろです.
In message "[ruby-list:316] Reqest for Find and BUG report"
on 96/07/19, Keiju ISHITSUKA <keiju@shljapan.co.jp> writes:
|
|けいじゅ@SHLジャパンです.
|
|Findモジュールという便利なものがあるというので, 調べていたのですが, プ
|ログラムがなっていません. もっと良いものに修正して下さい.
あんまりいっぺんにいろんなことが書いてあるので,びっくりして
しまいそうですが,一つずつ答えます.
|理由1:
| [1]でオープンしたディレクトリがクローズしていない. ちゃんとクローズ
| して下さい. このままだとディレクトリをファイルオープンのlimit分だけ
| 開くと動かなくなります.
まったくです.GCで回収されたディレクトリオブジェクトはクロー
ズされますが,問題が残ることには変わりありませんね.
|理由2:
| findpath で, 全部のファイルの配列を作ってから ここのファイルに対して,
| ブロックを評価していますが, これはちょっとひどいと思います. ファイル
| を1つ見つけたらその場でブロックを評価するようにして下さい.
これも全くです.
|というわけで, 以下のような定義はいかがでしょう?
|
|module Find
| extend Find
|
| def find(*path)
| ary = path.clone
| while not (file = ary.shift).nil?
| yield file
| if File.directory? file and not File.symlink? file then
| d = Dir.open(file)
| for f in d
| next if f =~ /^\.\.?$/
| if file == "/" then
| f = "/" + f
| else
| f = file + "/" + f
| end
| ary.push f
| end
| d.close
| end
| end
| end
| module_function :find
|end
わかりました.これを元にしたものに変更します.直すとしたら
* 「extend Find」は歴史的な名残なので外す
* 「not (file = ary.shift).nil?」は「file = ary.shift」に
するくらいですかね.
|ここで, バグレポート:
|
|Findを実行すると, ディレクトリがシンポリックリンクの時もその中にはいっ
|てしまって無限ループにはいってしまうことがあります. それを避けるために:
|
| File.symlink? file
|
|で判断するようにしたのですが, どうもバグっているようです. 調べて下さい.
確かにバグっているようです.ちょっと調べてみます.
|あと,
|
| test ?s, file
|
|もおかしいようです(1024が帰ります).
?sはサイズです.シンボリックリンクは?lです.もっともバグって
いることには変わり無いですけど.
|今度は質問: コマンドのfindでは, ツリーの探索を途中で辞めたりできるよう
|になっていますよね. それをruby版Findで実現することは可能なのでしょうか?
|例えば,
|
|Find.find(dir){|file| if cond then File.prune end}
|
|などのようにですね.
止めるといいますとイテレータの実行を中断するだけで良いんです
か? それならbreakを使ってください.-pruneみたいにこの枝の探
索は打ち切るが,他の枝の検索を続けるというのはちょっと面倒だ
と思います.が,方法はあります(下記参照).
|上記のプログラムですと yield file を行なった時に, その外側の while を
|nextできれば良いのですが... それは無理ですよね(?_?
rubyにはcatch/throwがありますので,それを使えば可能かも知れ
ませんねえ.
File#findのwhileループのすぐ内側に
catch(:prune) {
}
を置いて
def prune
throw :prune, nil
end
とすれば目的が達成できそうに思います.ちょっと遅いかも知れま
せんけど.
まつもと ゆきひろ /:|)