lib/load_tracer.rb in load_tracer-0.1.0 vs lib/load_tracer.rb in load_tracer-0.2.0

- old
+ new

@@ -1,27 +1,25 @@ require 'binding_of_caller' +require 'load_tracer/formatter/default' +require 'load_tracer/formatter/dot' require 'load_tracer/version' module Kernel unless defined?(__original_require__) alias __original_require__ require - private :__original_require__ end unless defined?(__original_require_relative__) alias __original_require_relative__ require_relative - private :__original_require_relative__ end unless defined?(__original_load__) alias __original_load__ load - private :__original_load__ end unless defined?(__original_autoload__) alias __original_autoload__ autoload - private :__original_autoload__ end def require(feature) __original_require__(feature) end @@ -42,67 +40,62 @@ class LoadTracer FileSpec = Struct.new(:name, :path, :dependencies, :reverse_dependencies, keyword_init: true) LOAD_METHODS = %i(require require_relative load autoload) - def self.trace + def self.trace(format: nil) instance = new instance.tracer.enable { yield } - instance.report + instance.report(format: format) end def initialize @dependencies = Hash.new { |hash, key| hash[key] = [] } @reverse_dependencies = Hash.new { |hash, key| hash[key] = [] } + @not_found_features = [] end def tracer - TracePoint.new(:call) do |tp| + TracePoint.new(:return) do |tp| next unless LOAD_METHODS.include?(tp.method_id) next if tp.defined_class != ::Kernel next if tp.path != __FILE__ case tp.event - when :call + when :return bl = caller_locations[1] - feature = get_feature(tp) + + if bl.absolute_path.nil? + bl = find_caller_of_internal_library(feature) + end + path = find_path(feature) || find_path(File.expand_path(feature, File.dirname(bl.path))) - raise LoadError.new("cannot load such file -- #{feature}") if path.nil? + if path.nil? + @not_found_features << feature + next + end - @dependencies[bl.path] << path - @reverse_dependencies[path] << bl.path + @dependencies[bl.absolute_path] << path + @reverse_dependencies[path] << bl.absolute_path end end end - def report - file_specs = @dependencies.map do |path, deps| - FileSpec.new( - name: File.basename(path), - path: path, - dependencies: deps, + def report(format:) + case format + when :dot + DotFormatter.export( + dependencies: @dependencies ) + else + DefaultFormatter.export( + dependencies: @dependencies, + reverse_dependencies: @reverse_dependencies + ) end - - @reverse_dependencies.each do |path, rdeps| - fs = file_specs.find { |fs| fs.path == path } - - if fs.nil? - file_specs << FileSpec.new( - name: File.basename(path), - path: path, - dependencies: [], - reverse_dependencies: rdeps - ) - else - fs.reverse_dependencies = rdeps - end - end - - file_specs end private def get_feature(tp) @@ -118,7 +111,12 @@ def find_path(feature) RubyVM.resolve_feature_path(feature).last rescue LoadError nil + end + + def find_caller_of_internal_library(feature) + index = caller_locations.find_index { |bl| bl.base_label == feature && bl.path == '<internal:prelude>' } + caller_locations[index + 1] end end