From: Kouhei Sutou <kou@...>
Date: 2012-05-28T23:28:09+09:00
Subject: [ruby-dev:45686] Re: [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller()

須藤です。

In <4FC06822.8090100@atdot.net>
  "[ruby-dev:45681] Re: [Ruby 1.9-Feature#3917][Open] [proposal] called_from() which is much faster than caller()" on Sat, 26 May 2012 14:20:47 +0900,
  SASADA Koichi <ko1@atdot.net> wrote:

> (2012/05/22 8:14), SASADA Koichi wrote:
>>  配列 ([filaneme, line, methodname])と,メソッドでアクセスするオブジェ
>> クト(frame.filename, frame.line, frame.method みたいな)だと,どちらが
>> いい,とかありますか? 例では多重代入で一発でやっていましたが.
> 
>  RubyVM::FrameInfo::caller というメソッドで,FrameInfo オブジェクトの配
> 列を取得できるようにしました.
> 
>  また,RubyVM::FrameInfo#name などの各種メソッドで,パースしなくてもと
> れるようにしました.
> 
>  が,名前とか,細かい挙動など問題があるかと思いますので,ご意見頂ければ
> 幸いです.

動かしていないし他のところも見ていなくて字面だけですが、思っ
たことをつらつらと書きます。

> 	    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っていうのはこの文脈でよく使われる単語
なのかがよくわかりませんでした。(使われているものならよいと
思います。)

> 	    FrameInfo#line_no: line number.

(個人的にはline_noの方が好きですが)IO#linenoに合わせて
linenoの方がいいかもしれません。

> 	  RubyVM::FrameInfo.caller(n, lev) returns array of FrameInfo objects.

かっこわるいなぁと思いました。
(あと、nって何?って思いました。)
FrameInfoのcallerというのがピンとこないからかもしれません。
「caller」っていうものを取ってくるならこれでもいいかもしれま
せんが、そんな感じはしませんでした。

RubyVM.framesとかbacktraceとかでいいんじゃないかと思いました。


あと、FrameInfoじゃなくてFrameじゃダメですかねぇ。
(大きくですぎていそうな気はします。)
Infoっていうのがなんか野暮ったいです。


+  def test_caller_frame_info
+    fis = RubyVM::FrameInfo.caller(0); cs = caller(0)

fisとかcsのsってstackのsですか?
ピンときませんでした。
と思ったんですが、複数形の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