rubyにはメソッドのソースを取得する method_source というgemがあるのですが、これのクラスバージョンもあったら便利かも?と思って書いてみました。
class_sources.rb
module ClassSource
@lines_for_file = {}
@locations = Hash.new { |h, k| h[k] = [] }
@pos_stack = []
TracePoint.trace(:class, :end) do |tp|
next if tp.self == ClassSource
@lines_for_file[tp.path] ||= File.readlines(tp.path)
case tp.event
when :class
@pos_stack << tp.lineno - 1
when :end
from, to = @pos_stack.pop, tp.lineno - 1
content = @lines_for_file[tp.path][from..to].join
@locations[tp.self] << { path: tp.path, from: from, to: to, content: content }
end
end
def self.locations(klass)
@locations[klass]
end
end
class Object
def source_locations
ClassSource.locations(self)
end
end
class A
def say
"hi"
end
end
A.source_locations.each do |data|
puts "#{data[:path]}##{data[:from]}"
puts "-" * 30
puts data[:content]
puts "-" * 30
end
出力
class_sources.rb#30
------------------------------
class A
def say
'hi'
end
end
------------------------------
TracePoint が実行される前のクラス定義は無視されてしまうのが難点です。