まつもと ゆきひろです.

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

とすれば目的が達成できそうに思います.ちょっと遅いかも知れま
せんけど.

                                まつもと ゆきひろ /:|)