そのため、「使用済み」が何を意味するかに関して、ここにはいくつかのあいまいさがあります。最後に b.rb (これも使用されます) が呼び出されるため、明らかに d が使用されD.new
ます。「require プロセス中以外に、そのファイルからコードが実行された」ことを意味するために「使用された」と警告する場合、次のコードは、Ruby 1.9.3 で取得できるように終了です。
require 'set'
def analyze(filename)
require_depth = 0
files = Set.new
set_trace_func( lambda do |event, file, line, id, binding, classname|
case event
when 'call'then require_depth += 1 if id == :require && classname == Kernel
when 'return' then require_depth -= 1 if id == :require && classname == Kernel
when 'line'
files << file if require_depth == 0
end
end)
load filename
set_trace_func nil
files.reject {|f| f == __FILE__ || f =~ %r{/lib/ruby/site_ruby}}
end
実行して使用しanalyse 'a.rb'
ます (関連するすべてのファイルがロード パス上にあると仮定します)。これは、何が起こっているかをリッスンするために ruby の set_trace_func を使用しています。最初の部分は、require の呼び出し中に発生するすべてを無視しようとする大まかな試みです。次に、実行されたルビのすべての行のファイル名を蓄積します。最後の行はジャンク (例えば、パッチが必要とする rubygems ファイル) を片付けるだけです。
これはテスト例では実際には機能しません: B.new が実行されるとき、b.rb からのコード行は実際には実行されません。ただし、B (および C、D など) に初期化メソッド (または呼び出されるコード行) がある場合は、目的の結果が得られるはずです。それはかなり単純化されたものであり、あらゆる種類のものにだまされる可能性があります. 特に、(たとえば) B でメソッドを呼び出したが、そのメソッドの実装が b.rb にない場合 (たとえば、attr_accessor で定義されたアクセサー)、b.rb はログに記録されません。
call イベントをより適切に使用できるかもしれませんが、set_trace_func でできることはあまりないと思います。
Ruby 2.0 を使用している場合は、 の代わりに TracePoint を使用できますset_trace_func
。セマンティクスが少し異なります。特に、メソッド呼び出しを追跡する場合は、呼び出されたクラスを簡単に取得できます。
require 'set'
def analyze(filename)
require_depth = 0
files = Set.new
classes_to_files = {}
trace = TracePoint.new(:call, :line, :return, :c_call, :class) do |tp|
case tp.event
when :class
classes_to_files[tp.self] = tp.path
when :call, :c_call then
if tp.method_id == :require && tp.defined_class == Kernel
require_depth += 1
else
if require_depth == 0
if path = classes_to_files[tp.self] || classes_to_files[tp.self.class]
files << path
end
end
end
when :return then require_depth -= 1 if tp.method_id == :require && tp.defined_class == Kernel
when :line
if require_depth == 0
files << tp.path
end
end
end
trace.enable
load filename
trace.disable
files.reject {|f| f == __FILE__ || f =~ %r{/lib/ruby/site_ruby}}
end
テスト例の a、b、c を返します。実際に実行されるコードについてしか認識していないという基本的な制限は依然としてあります。