1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
module RI
class ClassEntry
attr_reader :name
attr_reader :path_names
def initialize(path_name, name, in_class)
@path_names = [ path_name ]
@name = name
@in_class = in_class
@class_methods = []
@instance_methods = []
@inferior_classes = []
end
# We found this class in more tha one place, so add
# in the name from there.
def add_path(path)
@path_names << path
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 = @inferior_classes.find {|c| c.name == name }
if inf_class
inf_class.add_path(full_name)
else
inf_class = ClassEntry.new(full_name, name, self)
@inferior_classes << inf_class
end
inf_class.load_from(full_name)
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
|