binding_of_caller (v0.8.0)のコードリーディングをしました。Rubyのバージョンは2系以上のものを扱っていきます。

まずlib/binding_of_caller.rbの定義は以下のようになっており、Rubyのバージョンなどで読み込むファイルが変わります。Rubyの2系の場合はbinding_of_caller/mri2がrequireされます。

BindingクラスにオープンクラスによってBindingOfCaller::BindingExtensionsがincludeされます。これによりBindingオブジェクトに#of_callerや#callersが生えます。

BindingOfCaller#of_callerは以下のように定義されています。#callersを呼び出して、配列の要素を取り出しています。

#callersではdebug_inspectorのrubygemのRubyVM::DebugInspectorを使っており、Debug Inspector APIをRubyから簡単に使えるようにするライブラリになります。これによってバックトレースや各フレームのbinding、iseq(RubyVM::InstructionSequenceのインスタンス)を取得できます。

drop(1)しているのは#callersの呼び出し分を取り除くためです。#of_callerでもdrop(1)していますが、これも#of_callerの呼び出し分を取り除いています。

各バインディングのインスタンスには#frame_typeと#frame_descriptionというメソッドも生えます。これはcallersで取得した@iseq(RubyVM::InstructionSequenceのインスタンス)から情報を取得して、フレームタイプやラベルを返却しています。

ちなみにbetter_errorsのgemでは、binding_of_callerがある場合には、binding_of_callerで取得した各bindingに対してevalやframe_descriptionを使って各フレームの情報をセットしています。