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