#!/usr/local/bin/ruby

require 'rdoc/ri/ri_driver'

class Symbol
  def to_proc
    proc{|obj, *p| obj.__send__(self, *p)}
  end
end

module RI
  class ClassEntry
    attr_reader :class_methods, :instance_methods
  end
end

if ARGV.first == "-r"
  ARGV.shift; reverse = true
else
  reverse = false
end

paths = nil

if ENV['RI']
  options = RI::Options.instance
  options.parse(ENV['RI'].split)
  paths = options.paths
end

paths ||= RI::Paths::PATH

cache = RI::RiCache.new(paths)

def format_full_name(str)
  if str.index(?#)
    str
  else
    s = str.split(/::/)
    m = s.pop
    s.join("::") + "." + m
  end
end

class Info
  def initialize(toplevel)
    @toplevel = toplevel
    @info = []
  end
  
  def visit_method(entry)
    m = File.open(entry.path_name){|f| RI::Description.deserialize(f)}
    full_name = format_full_name(m.full_name)
    
    params = m.params.split("\n").map{|param|
      if param[0] == ?(
        param
      elsif param.index(full_name)
        param.gsub(/#{Regexp.quote(full_name)}/, "")
      elsif param.index(m.name)
        param.gsub(/^.*?#{Regexp.quote(m.name)}/, "")
      else
        nil
      end
    }.compact.map{|param|
      param.gsub(/\sor\s/, "/").gsub(/ (?!block)/, "").gsub(/[=-]>nil$/, "")
    }

    @info << Desc.new(full_name, params)
  end

  def visit_class(node)
    node.instance_methods.each(&method(:visit_method))
    node.class_methods.each(&method(:visit_method))
    node.classes_and_modules.each(&method(:visit_class))
  end

  def display_info
    visit_class(@toplevel)
    @info.sort_by{|i| i.full_name}.each{|i|
      print i.full_name, "\t", i.params.join("\t"), "\n"
    }
  end
  
  Desc = Struct.new(:full_name, :params)
end

class RevInfo
  def initialize(toplevel)
    @toplevel = toplevel
    @info = Hash.new{|h, k| h[k] = Array.new}
  end

  def visit_method(node)
    @info[node.name] << format_full_name(node.full_name)
  end
  
  def visit_class(node)
    node.instance_methods.each(&method(:visit_method))
    node.class_methods.each(&method(:visit_method))
    node.classes_and_modules.each(&method(:visit_class))
  end
  
  def display_info
    visit_class(@toplevel)
    @info.sort_by{|name, methods| name}.each{|name, methods|
      print name, "\t", methods.join("\t"), "\n"
    }
  end
end


if reverse
  RevInfo.new(cache.toplevel).display_info
else
  Info.new(cache.toplevel).display_info
end
