#!/usr/pkg/bin/ruby193 -ws

old_classes = []; new_classes = []

ObjectSpace.each_object(Module) { |klass| old_classes << klass } if defined? $a

require 'pp'

begin; require 'rubygems'; rescue LoadError; end
require 'parse_tree'
require 'sexp_processor'

ObjectSpace.each_object(Module) { |klass| old_classes << klass } unless defined? $a

class DependencyAnalyzer < SexpProcessor

  attr_reader :dependencies
  attr_accessor :current_class

  def initialize
    super
    self.auto_shift_type = true
    @dependencies = Hash.new { |h,k| h[k] = [] }
    @current_method = nil
    @current_class = nil
  end

  def self.process(*klasses)
    analyzer = self.new
    klasses.each do |start_klass|
      analyzer.current_class = start_klass
      analyzer.process(ParseTree.new.parse_tree(start_klass))
    end

    deps = analyzer.dependencies
    deps.keys.sort_by {|k| k.to_s}.each do |dep_to|
      dep_from = deps[dep_to]
      puts "#{dep_to}: #{dep_from.uniq.sort.join(", ")}"
    end
  end

  def process_defn(exp)
    name = exp.shift
    @current_method = name
    return s(:defn, name, process(exp.shift), process(exp.shift))
  end

  def process_const(exp)
    name = exp.shift
    const = (defined?($c) ? @current_class.name : "#{@current_class}.#{@current_method}")
    is_class = ! (Object.const_get(name) rescue nil).nil?
    @dependencies[name] << const if is_class
    return s(:const, name)
  end
end

if __FILE__ == $0 then
  ARGV.each { |name| require name }
  ObjectSpace.each_object(Module) { |klass| new_classes << klass }
  new_classes.delete DependencyAnalyzer unless defined? $a
  DependencyAnalyzer.process(*(new_classes - old_classes))
end
