ruby/lib/rdoc/ri/ri_cache.rb

177 строки
4.5 KiB
Ruby
Исходник Обычный вид История

module RI
class ClassEntry
attr_reader :name
attr_reader :path_name
def initialize(path_name, name, in_class)
@path_name = path_name
@name = name
@in_class = in_class
@class_methods = []
@instance_methods = []
@inferior_classes = []
end
# read in our methods and any classes
# and modules in our namespace. Methods are
# stored in files called name-c|i.yaml,
# where the 'name' portion is the external
# form of the method name and the c|i is a class|instance
# flag
def load_from(dir)
Dir.foreach(dir) do |name|
next if name =~ /^\./
# convert from external to internal form, and
# extract the instance/class flag
if name =~ /^(.*?)-(c|i).yaml$/
external_name = $1
is_class_method = $2 == "c"
internal_name = RiWriter.external_to_internal(external_name)
list = is_class_method ? @class_methods : @instance_methods
path = File.join(dir, name)
list << MethodEntry.new(path, internal_name, is_class_method, self)
else
full_name = File.join(dir, name)
if File.directory?(full_name)
inf_class = ClassEntry.new(full_name, name, self)
inf_class.load_from(full_name)
@inferior_classes << inf_class
end
end
end
end
# Return a list of any classes or modules that we contain
# that match a given string
def contained_modules_matching(name)
@inferior_classes.find_all {|c| c.name[name]}
end
def classes_and_modules
@inferior_classes
end
# Return an exact match to a particular name
def contained_class_named(name)
@inferior_classes.find {|c| c.name == name}
end
# return the list of local methods matching name
# We're split into two because we need distinct behavior
# when called from the _toplevel_
def methods_matching(name, is_class_method)
local_methods_matching(name, is_class_method)
end
# Find methods matching 'name' in ourselves and in
# any classes we contain
def recursively_find_methods_matching(name, is_class_method)
res = local_methods_matching(name, is_class_method)
@inferior_classes.each do |c|
res.concat(c.recursively_find_methods_matching(name, is_class_method))
end
res
end
# Return our full name
def full_name
res = @in_class.full_name
res << "::" unless res.empty?
res << @name
end
# Return a list of all out method names
def all_method_names
res = @class_methods.map {|m| m.full_name }
@instance_methods.each {|m| res << m.full_name}
res
end
private
# Return a list of all our methods matching a given string.
# Is +is_class_methods+ if 'nil', we don't care if the method
# is a class method or not, otherwise we only return
# those methods that match
def local_methods_matching(name, is_class_method)
list = case is_class_method
when nil then @class_methods + @instance_methods
when true then @class_methods
when false then @instance_methods
else fail "Unknown is_class_method: #{is_class_method.inspect}"
end
list.find_all {|m| m.name; m.name[name]}
end
end
# A TopLevelEntry is like a class entry, but when asked to search
# for methods searches all classes, not just itself
class TopLevelEntry < ClassEntry
def methods_matching(name, is_class_method)
res = recursively_find_methods_matching(name, is_class_method)
end
def full_name
""
end
def module_named(name)
end
end
class MethodEntry
attr_reader :name
attr_reader :path_name
def initialize(path_name, name, is_class_method, in_class)
@path_name = path_name
@name = name
@is_class_method = is_class_method
@in_class = in_class
end
def full_name
res = @in_class.full_name
unless res.empty?
if @is_class_method
res << "::"
else
res << "#"
end
end
res << @name
end
end
# We represent everything know about all 'ri' files
# accessible to this program
class RiCache
attr_reader :toplevel
def initialize(dirs)
# At the top level we have a dummy module holding the
# overall namespace
@toplevel = TopLevelEntry.new('', '::', nil)
dirs.each do |dir|
@toplevel.load_from(dir)
end
end
end
end