Ruby 3.1 でオブジェクトが生成された箇所が表示できるようになった
Ruby 3.1 の小ネタです。
Ruby 3.1 で objspace/trace
というライブラリが追加されました。
このライブラリを require
すると p
で出力するときに『オブジェクトが生成された箇所』が一緒に表示されるようになります。
# このライブラリを require するとオブジェクトが生成された場所がトレースされるようになる # require した後に生成されたオブジェクトが対象となる require "objspace/trace" obj = Object.new # p する時に obj が生成された場所が表示される p obj # => #<Object:0x00007fce8b2ea778> @ /path/to/test.rb:5 # こういうのも表示される str = 42.to_s p str # => "42" @ /path/to/test.rb:11 # クラス内で生成されたオブジェクトも取得できる class X attr_accessor :value def initialize @value = "hoge" end def hoge self.value = "bar" end end x = X.new p x.value # => "hoge" @ /path/to/test.rb:22 x.hoge p x.value # => "hoge" @ /path/to/test.rb:26
こんな感じで各オブジェクトが生成された場所が生成されます。
また objspace/trace
を使っている場合は objspace/trace is enabled
が表示されます。
注意点
objspace/trace
はあくまでも『オブジェクトが生成された場所』が表示されるのであって『変数が定義された場所ではない』という注意点があります。
なので、例えば次のように定数を変数に代入している場合は『定数が定義された位置』が表示されるようになります。
require "objspace/trace" C = Object.new obj = C # これは obj 変数が定義された場所ではなくて C が定義された場所が出力される p obj # => #<Object:0x00007f6e1111e438> @ /path/to/test.rb:3
他には数値や nil
などの値も表示されなかったり
require "objspace/trace" obj = 1 + 2 p obj obj2 = "42".to_i p obj2 obj3 = nil p obj3
# frozen_string_literal: true
している場合は文字列リテラルの生成位置も表示されません。
require "objspace/trace" str = "homu" # これは表示される p str # => "homu" @ /path/to/test.rb:3
require "objspace/trace" str = "homu" # これは表示される p str # => "homu" @ /path/to/test.rb:3
# frozen_string_literal: true require "objspace/trace" str = "homu" # これは表示されない p str # => "homu" # リテラル以外で生成された文字列は表示される str2 = str + str p str2 # => "homuhomu" @ /path/to/test.rb:12
おまけ
メタプロ的に定義されている場合でも問題なく取得できた。
require "objspace/trace" # 動的に生成している場合でも位置情報は取得できる eval(<<~EOS, binding, __FILE__, __LINE__ + 1) @value = "hoge" def hoge @value end EOS p hoge # => "hoge" @ /path/to/test.rb:5 # 動的に変数を定義した場合も取得できる bind = binding bind.local_variable_set(:value, "mami") p bind.local_variable_get(:value) # => "mami" @ /path/to/test.rb:14