Rails: メソッド検索をsource_locationとbundle openで行う(翻訳)
Rubyは動的言語なので、すぐに使える多くの優秀なデバッグ機能やイントロスペクション(=オブジェクトを調べる)機能がRubyに備わっていることは重要です。
デバッグやコードの理解を効率的に進めるには、メソッドやコードブロックの定義場所を正確に見つけて前後のソースコードを読み取る機能が欠かせません。Rubyが提供するsource_location
メソッドは、特定のメソッドやブロックが定義されているファイルと行番号を取得できる強力なツールとなります。
🔗 Railsでメソッド定義の場所を調べる方法
以下のように#source_location
メソッドを使って場所を調べます。
"Cars".method(:singularize).source_location
#=> ["/.../activesupport-7.0.8/lib/active_support/core_ext/string/inflections.rb", 60]
次にシェルで以下のコマンドを実行して、そのgemのソースコードを自分のエディタで開きます。
bundle open activesupport
🔗 そうする理由
source_location
は、初めて扱うアプリケーションを調べる場合や、自分のよく知らないコードを調べる場合、あるいは自分が使っている機能がどのgemにあるかを調べる場合にとても有用です。
ソースコードを読むことは良い学習方法のひとつです。特に、Rails自身やさまざまなgemのようにバトルテストを経たコードを読むことは大きな学びがあります。
Railsフレームワーク作者たちのおかげで、Railsの「魔法のような」メタプログラミングを駆使したメソッドでもsource_location
で調べられます。Active Recordのclass_eval
で生成されるさまざまな関連付けメソッドは、特殊な構文を渡すことでsource_location
が引き続き使えるようになっています。もしそうなっていなければ、source_location
を呼び出しても常に(eval)
が最初の結果として表示されてしまうでしょう。
class Car < ApplicationRecord
has_many :seats
# ...
end
Car.first.method(:seats).source_location
#=> [".../activerecord-7.0.8/lib/active_record/associations/builder/association.rb", 103]
上に続いて、以下のコマンドラインで該当箇所を開きます。
bundle open activerecord
🔗 そうしない理由があるとすれば
source_location
でいろいろ実験していると、必ずしも有用な結果が得られない場合もあることに気づくかもしれません。Ruby「コア」に含まれるメソッドの多くはC言語で実装されていますが、これらのメソッド定義にはRubyコードから直接アクセスできません。そのため、そうしたコアメソッドに対してsource_location
を呼び出すとたいていnil
が返されます。
"Cars".method(:upcase).source_location
#=> nil
C拡張(RubyコードからCを呼び出す機能)を利用するメソッドの場合もsource_location
を利用できません。source_location
が利用できるのは、ソースコードがRubyで書かれているgemで定義されたメソッドに対してのみです。
source_location
は開発中やデバッグ中は非常に有用ですが、誤ってproductionコードに入れないようご注意ください。
概要
原著者の許諾を得て翻訳・公開いたします。