From: SASADA Koichi Date: 2012-05-29T01:00:40+09:00 Subject: [ruby-dev:45687] Re: [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller()  ささだです.  添削ありがとうございます. (2012/05/28 23:28), Kouhei Sutou wrote: > 動かしていないし他のところも見ていなくて字面だけですが、思っ > たことをつらつらと書きます。  ありがとうございました.  もしあれば,この機能なんて使わないから要らないよ,とか,こういう場面で 使いたいからこういうインターフェースがいい,とかの意見も頂ければ幸いです. >> FrameInfo#basename: name without decorations. >> FrameInfo#filename: file name. >> FrameInfo#filepath: full filepath. > > この3つの名前がわかりづらいと思います。 > basenameというのはファイルのパスの文脈で使われることが多いと > 思うのですが、ここでは違った文脈で使っているように見えます。 > さらに同じクラスがファイルのパスについての情報も持っているの > でさらにわかりづらくなっていると思います。 > > あと、filenameとfilepathでどんな違いを表現しているかがわかり > づらいと思います。想像力を働かせるとfilepathが/a/b/c.rbで > filenameがc.rbかなぁと思いました。 > (あっているかどうかはわかりません。) > > あと、あと、decorationsっていうのはこの文脈でよく使われる単語 > なのかがよくわかりませんでした。(使われているものならよいと > 思います。)  ChangeLog なので,マニュアルにするほど気合い入れて書いてませんでした. すみません(英語で面倒だったというのが大きいか).  真面目に書きます. >> FrameInfo#basename: name without decorations.  1.times{ raise } とすると, t.rb:3:in `block in
': unhandled exception from t.rb:2:in `times' from t.rb:2:in `
' となります.この,"block in
" が FileInfo#name になります.フレー ムの情報の名前ですね."block in" を decoration と言っていました."
" という情報に修飾しているためです.  このとき,basename が "
" になります.  仰るとおり,パスの文脈で使われる basename とわかりづらいですね.もし, 他に適当な名前があるといいなと思います(もしくは不要でしょうか). >> FrameInfo#filename: file name. >> FrameInfo#filepath: full filepath.  filename は require で渡した名前(多分)で相対パスの可能性があ り,filepath はフルパスです.通常,filename を caller やバックトレースで 返します.  filepath は require_relative で利用するために保存している内部情報であ り,内部(C)の変数名をそのままにしていました.外に出す必要は無いかもし れません.もしくは,あって便利なら名前を変えるとか. >> FrameInfo#line_no: line number. > > (個人的にはline_noの方が好きですが)IO#linenoに合わせて > linenoの方がいいかもしれません。  なるほど,IO#lineno があるんですね.そうしますか. >> RubyVM::FrameInfo.caller(n, lev) returns array of FrameInfo objects.  あ,lev と n の順番が逆だ. > かっこわるいなぁと思いました。 > (あと、nって何?って思いました。)  lev 上から n 個取ってくる. > FrameInfoのcallerというのがピンとこないからかもしれません。 > 「caller」っていうものを取ってくるならこれでもいいかもしれま > せんが、そんな感じはしませんでした。  同意します.ほんとうにダメな名前だと思います. > RubyVM.framesとかbacktraceとかでいいんじゃないかと思いました。  次の2つの理由で,冗長な名前にしました. 1) frame って言われて何かわからない(caller がわかるかというと謎) 2) Kernel::backtrace ってメソッドをすでに定義してるかも,と思って避けた  ただ,例えば backtrace でいいよ,ということであれば,そうしたい気もし ます. > あと、FrameInfoじゃなくてFrameじゃダメですかねぇ。 > (大きくですぎていそうな気はします。) > Infoっていうのがなんか野暮ったいです。  Info がださいのは同意します.  ただ,Frame だと,フレームのすべての情報,つまり変数情報(a=1)なども 含まれそうです.  これらの機能やら名前やらは,とりあえず作ったものを突っ込んだので,適切 な名前なり機能なりに変えてもらうのは全く構いません.また,機能が不適切で あれば(もしくは,名前や機能の議論なく突っ込んだことが不適切であれば) revert してもいいと思っています. ----  テストまで添削してもらってありがとうございます. > + def test_caller_frame_info > + fis = RubyVM::FrameInfo.caller(0); cs = caller(0) > > fisとかcsのsってstackのsですか? > ピンときませんでした。 > と思ったんですが、複数形のsですか。  yes.迷ったら複数形で s をつけています. > + assert_equal(cs.size, fis.size) > + fis.zip(cs).each{|fi, s| > + assert_match(/#{fi.name}/, s) > + assert_match(/#{fi.filename}/, s) > + assert_match(/#{fi.line_no}/, s) > + } > > ↑という風に書くよりも、↓という風に書いたほうがテストが失敗 > したときにわかりやすくなると思います。(動かしていないのでちゃ > んと動くかはわかりません。) > ↑だと、sizeが違うとすぐに失敗して「どのくらい数が違うか」ま > ではわかりますが、「どのように違うか」はわかりません。でも、 > ↓のように書くと数が違うときでも「どのように違うか」までわか > ります。 > > parsed_cs = cs.map{|c| > filename, line_no, other = c.split(/:/, 3) > if /in `(.+?)'/ =~ other > name = $1 > else > name = nil > end > [filename, line_no, name] > } > assert_equal(parsed_cs, fis.map{|fi| [fi.filename, fi.line_no, fi.name]}) > > + end >  なるほど.失敗したときのことをあまり気にせず書いていました.  いや,失敗したらデバッグ始めるのでおもむろに p などを入れ始めるという.  今後,気を付けます. -- // SASADA Koichi at atdot dot net