From: keiju@... (=?ISO-2022-JP?B?GyRCQFBETTc9PHkbKEI=?=) Date: 2009-11-27T23:09:57+09:00 Subject: [ruby-dev:39803] Re: バグ? ブロック引数で to_ary が呼ばれる必要のない場面で呼ばれる けいじゅ@いしつかです. In [ruby-dev:39800] the message: "[ruby-dev:39800] Re: バグ? ブロック 引数で to_ary が呼ばれる必要のない場面で呼ばれる", on Nov/27 22:32(JST) Yukihiro Matsumoto writes: >まつもと ゆきひろです >呼ばれる必要はないと思います。 ですよねぇ. >|ただ, 簡単な再現スクリプトを作ってもこの現象は再現しませんので, 何か特 >|殊な条件が重なると発生するようです... >うーん、直しようがない。 ですよねぇぇ... >これなんですけど、確かに直接呼ぶんですけど、rescueしてるはず >です。ので、例外が発生するのはやっぱりおかしいです。大規模な >プログラムで小規模な再現パターンを抽出できないと言うのは同情 >しますが、それでもあまりに情報がないので対処しようがありませ >ん。せめて「to_ary がないと怒られてしまう」ではなくて、どんな >エラーメッセージなのか、できるだけ生のメッセージをいただくと >かいうわけにはいきませんでしょうか。 あー. すいません. こんな感じです: CONT#1 bjob.rb[214] BHere#rescue in create_nodes: undefined method `to_ary' for # -- peer side -- /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/backend/bjob.rb:304:in `call' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/backend/bjob.rb:304:in `each_export_by' / >あと、r25556だと、methog_missingが定義してあるかどうかで挙動 >が変わります(定義されてないと例外処理をショートカットする)。 >そのへんも織り込むと再現パターンを作れないでしょうか。 おー. すばらしいヒントです. to_aryがないと例外が出ているのは, リモート オブジェクトで, method_missingを定義してありました. おかげで再現スクリプトができました. ちょっと入り組んでいますが... 元の コードからスケルトンを抜き出して作ったので... これを実行すると問題の例外が発生します. (2)をコメントアウトし(1)に入れ 替えると例外が起らなくなります. -- class A def create_nodes BO.assign_ntasks(self, "dummy1") do |ntask, mapper, opts={}| create_and_add_node(ntask, mapper, opts) end end def create_and_add_node(ntask, mapper, opts={}) node = create_node(ntask) {|node| } end def create_node(ntask, *params, &block) block.call("dummy2") end def each_assigned_filter(&block) # loop do block.call D.new # end end def each_export_by(njob, mapper, &block) # block.call njob.export, :foo=>:bar #(1) block.call njob.export #(2) end end class B def assign_ntasks(target_bjob, create_node_mutex, &block) target_bjob.each_assigned_filter do |input_filter| @c = C.new(input_filter, self, target_bjob) assign_ntask(&block) end end def assign_ntask(&block) @c.assign_ntask(&block) end def assign_new_processor(bjob, &block) create_processor("dummy9", bjob, &block) end def create_processor(node, bjob, &block) yield "dummy10" end end class C def initialize(a, b, d) @a = a @b = b @d = d @cx = CX.new(self) end attr_reader :a, :b, :d def assign_ntask(&block) @cx.assign_ntask(&block) end end class CX def initialize(c) @c = c end def assign_ntask(&block) @c.d.each_export_by(@c.a, self) do |export, opts={}| p export p opts @c.b.assign_new_processor("dummy5") do |processor| block.call("dummy6", "dummy7", opts) end end end end class D def export E.new end end class E def method_missing(method, *args, &block) raise NoMethodError, method end end BO = B.new A.new.create_nodes __ ---------------------------------------------------->> 石塚 圭樹 <<--- ---------------------------------->> e-mail: keiju@ishitsuka.com <<---