class LoadTracer::StaticChecker

Public Class Methods

new(path) click to toggle source
# File lib/load_tracer/static_checker.rb, line 7
def initialize(path)
  @path = path
end
parse_file(path) click to toggle source
# File lib/load_tracer/static_checker.rb, line 3
def self.parse_file(path)
  new(path).trace
end

Public Instance Methods

trace(format: nil) click to toggle source
# File lib/load_tracer/static_checker.rb, line 11
def trace(format: nil)
  @dependencies = Hash.new { |hash, key| hash[key] = [] }
  @reverse_dependencies = Hash.new { |hash, key| hash[key] = [] }
  @load_checked_features = Hash.new
  @not_found_features = []

  traverse(path: @path)

  report(format: format, dependencies: @dependencies, reverse_dependencies: @reverse_dependencies)
end
traverse(path:) click to toggle source
# File lib/load_tracer/static_checker.rb, line 22
def traverse(path:)
  return if @load_checked_features[path]
  return if File.extname(path) != '.rb'

  @load_checked_features[path] = true
  ast = RubyVM::AbstractSyntaxTree.parse_file(path)
  features = search_load_features(ast: ast)

  features.each do |feature|
    feature_path = find_path(feature) || find_path(File.expand_path(feature, File.dirname(path)))

    if feature_path.nil?
      @not_found_features << feature
      next
    end

    traverse(path: feature_path)

    @dependencies[path] << feature_path
    @reverse_dependencies[feature_path] << path
  end
end

Private Instance Methods

inspect(ast:) { |child| ... } click to toggle source
# File lib/load_tracer/static_checker.rb, line 47
def inspect(ast:, &block)
  ast.children.each do |child|
    next unless child.instance_of?(RubyVM::AbstractSyntaxTree::Node)

    yield child

    inspect(ast: child, &block)
  end
end
search_load_features(ast:) click to toggle source
# File lib/load_tracer/static_checker.rb, line 57
def search_load_features(ast:)
  features = []

  inspect(ast: ast) do |node|
    next if node.type != :FCALL

    method_id = node.children[0]

    next unless LOAD_METHODS.include?(method_id)

    feature = case method_id
              when :require, :require_relative, :load
                node.children[1].children[0].children[0]
              when :autoload
                node.children[1].children[1].children[0]
              end

    features << feature if feature.instance_of?(String)
  end

  features
end