iownbey-rdoc 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +13 -0
- data/Manifest.txt +61 -0
- data/README.txt +34 -0
- data/bin/rdoc +22 -0
- data/bin/ri +6 -0
- data/lib/rdoc.rb +277 -0
- data/lib/rdoc/code_objects.rb +776 -0
- data/lib/rdoc/diagram.rb +338 -0
- data/lib/rdoc/dot.rb +249 -0
- data/lib/rdoc/generator.rb +1050 -0
- data/lib/rdoc/generator/chm.rb +113 -0
- data/lib/rdoc/generator/chm/chm.rb +98 -0
- data/lib/rdoc/generator/html.rb +370 -0
- data/lib/rdoc/generator/html/hefss.rb +414 -0
- data/lib/rdoc/generator/html/html.rb +704 -0
- data/lib/rdoc/generator/html/kilmer.rb +418 -0
- data/lib/rdoc/generator/html/one_page_html.rb +121 -0
- data/lib/rdoc/generator/ri.rb +229 -0
- data/lib/rdoc/generator/texinfo.rb +84 -0
- data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
- data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
- data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
- data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
- data/lib/rdoc/generator/xml.rb +120 -0
- data/lib/rdoc/generator/xml/rdf.rb +113 -0
- data/lib/rdoc/generator/xml/xml.rb +111 -0
- data/lib/rdoc/markup.rb +473 -0
- data/lib/rdoc/markup/attribute_manager.rb +274 -0
- data/lib/rdoc/markup/formatter.rb +14 -0
- data/lib/rdoc/markup/fragments.rb +337 -0
- data/lib/rdoc/markup/inline.rb +101 -0
- data/lib/rdoc/markup/lines.rb +152 -0
- data/lib/rdoc/markup/preprocess.rb +71 -0
- data/lib/rdoc/markup/to_flow.rb +185 -0
- data/lib/rdoc/markup/to_html.rb +354 -0
- data/lib/rdoc/markup/to_html_crossref.rb +86 -0
- data/lib/rdoc/markup/to_latex.rb +328 -0
- data/lib/rdoc/markup/to_test.rb +50 -0
- data/lib/rdoc/markup/to_texinfo.rb +69 -0
- data/lib/rdoc/options.rb +621 -0
- data/lib/rdoc/parsers/parse_c.rb +775 -0
- data/lib/rdoc/parsers/parse_f95.rb +1841 -0
- data/lib/rdoc/parsers/parse_rb.rb +2584 -0
- data/lib/rdoc/parsers/parse_simple.rb +40 -0
- data/lib/rdoc/parsers/parserfactory.rb +99 -0
- data/lib/rdoc/rdoc.rb +277 -0
- data/lib/rdoc/ri.rb +4 -0
- data/lib/rdoc/ri/cache.rb +188 -0
- data/lib/rdoc/ri/descriptions.rb +150 -0
- data/lib/rdoc/ri/display.rb +274 -0
- data/lib/rdoc/ri/driver.rb +452 -0
- data/lib/rdoc/ri/formatter.rb +616 -0
- data/lib/rdoc/ri/paths.rb +102 -0
- data/lib/rdoc/ri/reader.rb +106 -0
- data/lib/rdoc/ri/util.rb +81 -0
- data/lib/rdoc/ri/writer.rb +68 -0
- data/lib/rdoc/stats.rb +25 -0
- data/lib/rdoc/template.rb +64 -0
- data/lib/rdoc/tokenstream.rb +33 -0
- data/test/test_rdoc_c_parser.rb +261 -0
- data/test/test_rdoc_info_formatting.rb +179 -0
- data/test/test_rdoc_info_sections.rb +93 -0
- data/test/test_rdoc_markup.rb +613 -0
- data/test/test_rdoc_markup_attribute_manager.rb +224 -0
- data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
- data/test/test_rdoc_ri_default_display.rb +295 -0
- data/test/test_rdoc_ri_formatter.rb +318 -0
- data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
- metadata +142 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rdoc'
|
2
|
+
require 'rdoc/code_objects'
|
3
|
+
require 'rdoc/markup/preprocess'
|
4
|
+
|
5
|
+
##
|
6
|
+
# Parse a non-source file. We basically take the whole thing as one big
|
7
|
+
# comment. If the first character in the file is '#', we strip leading pound
|
8
|
+
# signs.
|
9
|
+
|
10
|
+
class RDoc::SimpleParser
|
11
|
+
|
12
|
+
##
|
13
|
+
# Prepare to parse a plain file
|
14
|
+
|
15
|
+
def initialize(top_level, file_name, body, options, stats)
|
16
|
+
preprocess = RDoc::Markup::PreProcess.new(file_name, options.rdoc_include)
|
17
|
+
|
18
|
+
preprocess.handle(body) do |directive, param|
|
19
|
+
warn "Unrecognized directive '#{directive}' in #{file_name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
@body = body
|
23
|
+
@options = options
|
24
|
+
@top_level = top_level
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Extract the file contents and attach them to the toplevel as a comment
|
29
|
+
|
30
|
+
def scan
|
31
|
+
@top_level.comment = remove_private_comments(@body)
|
32
|
+
@top_level
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove_private_comments(comment)
|
36
|
+
comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "rdoc/parsers/parse_simple"
|
2
|
+
|
3
|
+
module RDoc
|
4
|
+
|
5
|
+
# A parser is simple a class that implements
|
6
|
+
#
|
7
|
+
# #initialize(file_name, body, options)
|
8
|
+
#
|
9
|
+
# and
|
10
|
+
#
|
11
|
+
# #scan
|
12
|
+
#
|
13
|
+
# The initialize method takes a file name to be used, the body of the
|
14
|
+
# file, and an RDoc::Options object. The scan method is then called
|
15
|
+
# to return an appropriately parsed TopLevel code object.
|
16
|
+
#
|
17
|
+
# The ParseFactory is used to redirect to the correct parser given a filename
|
18
|
+
# extension. This magic works because individual parsers have to register
|
19
|
+
# themselves with us as they are loaded in. The do this using the following
|
20
|
+
# incantation
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# require "rdoc/parsers/parsefactory"
|
24
|
+
#
|
25
|
+
# module RDoc
|
26
|
+
#
|
27
|
+
# class XyzParser
|
28
|
+
# extend ParseFactory <<<<
|
29
|
+
# parse_files_matching /\.xyz$/ <<<<
|
30
|
+
#
|
31
|
+
# def initialize(file_name, body, options)
|
32
|
+
# ...
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def scan
|
36
|
+
# ...
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# Just to make life interesting, if we suspect a plain text file, we
|
42
|
+
# also look for a shebang line just in case it's a potential
|
43
|
+
# shell script
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
module ParserFactory
|
48
|
+
|
49
|
+
@@parsers = []
|
50
|
+
|
51
|
+
Parsers = Struct.new(:regexp, :parser)
|
52
|
+
|
53
|
+
# Record the fact that a particular class parses files that
|
54
|
+
# match a given extension
|
55
|
+
|
56
|
+
def parse_files_matching(regexp)
|
57
|
+
@@parsers.unshift Parsers.new(regexp, self)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a parser that can handle a particular extension
|
61
|
+
|
62
|
+
def ParserFactory.can_parse(file_name)
|
63
|
+
@@parsers.find {|p| p.regexp.match(file_name) }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Alias an extension to another extension. After this call,
|
67
|
+
# files ending "new_ext" will be parsed using the same parser
|
68
|
+
# as "old_ext"
|
69
|
+
|
70
|
+
def ParserFactory.alias_extension(old_ext, new_ext)
|
71
|
+
parser = ParserFactory.can_parse("xxx.#{old_ext}")
|
72
|
+
return false unless parser
|
73
|
+
@@parsers.unshift Parsers.new(Regexp.new("\\.#{new_ext}$"), parser.parser)
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
# Find the correct parser for a particular file name. Return a
|
78
|
+
# SimpleParser for ones that we don't know
|
79
|
+
|
80
|
+
def ParserFactory.parser_for(top_level, file_name, body, options, stats)
|
81
|
+
# If no extension, look for shebang
|
82
|
+
if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)}
|
83
|
+
shebang = $1
|
84
|
+
case shebang
|
85
|
+
when %r{env\s+ruby}, %r{/ruby}
|
86
|
+
file_name = "dummy.rb"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
parser_description = can_parse(file_name)
|
90
|
+
if parser_description
|
91
|
+
parser = parser_description.parser
|
92
|
+
else
|
93
|
+
parser = SimpleParser
|
94
|
+
end
|
95
|
+
|
96
|
+
parser.new(top_level, file_name, body, options, stats)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/rdoc/rdoc.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'rdoc'
|
2
|
+
|
3
|
+
require 'rdoc/parsers/parse_rb.rb'
|
4
|
+
require 'rdoc/parsers/parse_c.rb'
|
5
|
+
require 'rdoc/parsers/parse_f95.rb'
|
6
|
+
require 'rdoc/parsers/parse_simple.rb'
|
7
|
+
|
8
|
+
require 'rdoc/stats'
|
9
|
+
require 'rdoc/options'
|
10
|
+
|
11
|
+
require 'rdoc/diagram'
|
12
|
+
|
13
|
+
require 'find'
|
14
|
+
require 'fileutils'
|
15
|
+
require 'time'
|
16
|
+
|
17
|
+
module RDoc
|
18
|
+
|
19
|
+
##
|
20
|
+
# Encapsulate the production of rdoc documentation. Basically
|
21
|
+
# you can use this as you would invoke rdoc from the command
|
22
|
+
# line:
|
23
|
+
#
|
24
|
+
# rdoc = RDoc::RDoc.new
|
25
|
+
# rdoc.document(args)
|
26
|
+
#
|
27
|
+
# where _args_ is an array of strings, each corresponding to
|
28
|
+
# an argument you'd give rdoc on the command line. See rdoc/rdoc.rb
|
29
|
+
# for details.
|
30
|
+
|
31
|
+
class RDoc
|
32
|
+
|
33
|
+
Generator = Struct.new(:file_name, :class_name, :key)
|
34
|
+
|
35
|
+
##
|
36
|
+
# This is the list of output generator that we support
|
37
|
+
|
38
|
+
GENERATORS = {}
|
39
|
+
|
40
|
+
$LOAD_PATH.collect do |d|
|
41
|
+
File.expand_path d
|
42
|
+
end.find_all do |d|
|
43
|
+
File.directory? "#{d}/rdoc/generator"
|
44
|
+
end.each do |dir|
|
45
|
+
Dir.entries("#{dir}/rdoc/generator").each do |gen|
|
46
|
+
next unless /(\w+)\.rb$/ =~ gen
|
47
|
+
type = $1
|
48
|
+
unless GENERATORS.has_key? type
|
49
|
+
GENERATORS[type] = Generator.new("rdoc/generator/#{gen}",
|
50
|
+
"#{type.upcase}".intern,
|
51
|
+
type)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize
|
57
|
+
@stats = Stats.new
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Report an error message and exit
|
62
|
+
|
63
|
+
def error(msg)
|
64
|
+
raise ::RDoc::Error, msg
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Create an output dir if it doesn't exist. If it does exist, but doesn't
|
69
|
+
# contain the flag file <tt>created.rid</tt> then we refuse to use it, as
|
70
|
+
# we may clobber some manually generated documentation
|
71
|
+
|
72
|
+
def setup_output_dir(op_dir, force)
|
73
|
+
flag_file = output_flag_file(op_dir)
|
74
|
+
if File.exist?(op_dir)
|
75
|
+
unless File.directory?(op_dir)
|
76
|
+
error "'#{op_dir}' exists, and is not a directory"
|
77
|
+
end
|
78
|
+
begin
|
79
|
+
created = File.read(flag_file)
|
80
|
+
rescue SystemCallError
|
81
|
+
error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
|
82
|
+
"isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
|
83
|
+
"destroying any of your existing files, you'll need to\n" +
|
84
|
+
"specify a different output directory name (using the\n" +
|
85
|
+
"--op <dir> option).\n\n"
|
86
|
+
else
|
87
|
+
last = (Time.parse(created) unless force rescue nil)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
FileUtils.mkdir_p(op_dir)
|
91
|
+
end
|
92
|
+
last
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Update the flag file in an output directory.
|
97
|
+
|
98
|
+
def update_output_dir(op_dir, time)
|
99
|
+
File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Return the path name of the flag file in an output directory.
|
104
|
+
|
105
|
+
def output_flag_file(op_dir)
|
106
|
+
File.join(op_dir, "created.rid")
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# The .document file contains a list of file and directory name patterns,
|
111
|
+
# representing candidates for documentation. It may also contain comments
|
112
|
+
# (starting with '#')
|
113
|
+
|
114
|
+
def parse_dot_doc_file(in_dir, filename, options)
|
115
|
+
# read and strip comments
|
116
|
+
patterns = File.read(filename).gsub(/#.*/, '')
|
117
|
+
|
118
|
+
result = []
|
119
|
+
|
120
|
+
patterns.split.each do |patt|
|
121
|
+
candidates = Dir.glob(File.join(in_dir, patt))
|
122
|
+
result.concat(normalized_file_list(options, candidates))
|
123
|
+
end
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Given a list of files and directories, create a list of all the Ruby
|
129
|
+
# files they contain.
|
130
|
+
#
|
131
|
+
# If +force_doc+ is true we always add the given files, if false, only
|
132
|
+
# add files that we guarantee we can parse. It is true when looking at
|
133
|
+
# files given on the command line, false when recursing through
|
134
|
+
# subdirectories.
|
135
|
+
#
|
136
|
+
# The effect of this is that if you want a file with a non-standard
|
137
|
+
# extension parsed, you must name it explicity.
|
138
|
+
|
139
|
+
def normalized_file_list(options, relative_files, force_doc = false,
|
140
|
+
exclude_pattern = nil)
|
141
|
+
file_list = []
|
142
|
+
|
143
|
+
relative_files.each do |rel_file_name|
|
144
|
+
next if exclude_pattern && exclude_pattern =~ rel_file_name
|
145
|
+
stat = File.stat(rel_file_name)
|
146
|
+
case type = stat.ftype
|
147
|
+
when "file"
|
148
|
+
next if @last_created and stat.mtime < @last_created
|
149
|
+
file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
|
150
|
+
when "directory"
|
151
|
+
next if rel_file_name == "CVS" || rel_file_name == ".svn"
|
152
|
+
dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
|
153
|
+
if File.file?(dot_doc)
|
154
|
+
file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
|
155
|
+
else
|
156
|
+
file_list.concat(list_files_in_directory(rel_file_name, options))
|
157
|
+
end
|
158
|
+
else
|
159
|
+
raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
file_list
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Return a list of the files to be processed in a directory. We know that
|
168
|
+
# this directory doesn't have a .document file, so we're looking for real
|
169
|
+
# files. However we may well contain subdirectories which must be tested
|
170
|
+
# for .document files.
|
171
|
+
|
172
|
+
def list_files_in_directory(dir, options)
|
173
|
+
files = Dir.glob File.join(dir, "*")
|
174
|
+
|
175
|
+
normalized_file_list options, files, false, options.exclude
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Parse each file on the command line, recursively entering directories.
|
180
|
+
|
181
|
+
def parse_files(options)
|
182
|
+
files = options.files
|
183
|
+
files = ["."] if files.empty?
|
184
|
+
|
185
|
+
file_list = normalized_file_list(options, files, true)
|
186
|
+
|
187
|
+
return [] if file_list.empty?
|
188
|
+
|
189
|
+
file_info = []
|
190
|
+
width = file_list.map { |name| name.length }.max + 1
|
191
|
+
|
192
|
+
file_list.each do |fn|
|
193
|
+
$stderr.printf("\n%*s: ", width, fn) unless options.quiet
|
194
|
+
|
195
|
+
content = if RUBY_VERSION >= '1.9' then
|
196
|
+
File.open(fn, "r:ascii-8bit") { |f| f.read }
|
197
|
+
else
|
198
|
+
File.read fn
|
199
|
+
end
|
200
|
+
|
201
|
+
if / coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
|
202
|
+
if enc = Encoding.find($1)
|
203
|
+
content.force_encoding(enc)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
top_level = TopLevel.new(fn)
|
208
|
+
parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
|
209
|
+
file_info << parser.scan
|
210
|
+
@stats.num_files += 1
|
211
|
+
end
|
212
|
+
|
213
|
+
file_info
|
214
|
+
end
|
215
|
+
|
216
|
+
##
|
217
|
+
# Format up one or more files according to the given arguments.
|
218
|
+
#
|
219
|
+
# For simplicity, _argv_ is an array of strings, equivalent to the strings
|
220
|
+
# that would be passed on the command line. (This isn't a coincidence, as
|
221
|
+
# we _do_ pass in ARGV when running interactively). For a list of options,
|
222
|
+
# see rdoc/rdoc.rb. By default, output will be stored in a directory
|
223
|
+
# called +doc+ below the current directory, so make sure you're somewhere
|
224
|
+
# writable before invoking.
|
225
|
+
#
|
226
|
+
# Throws: RDoc::Error on error
|
227
|
+
|
228
|
+
def document(argv)
|
229
|
+
TopLevel::reset
|
230
|
+
|
231
|
+
@options = Options.new GENERATORS
|
232
|
+
@options.parse argv
|
233
|
+
|
234
|
+
@last_created = nil
|
235
|
+
|
236
|
+
unless @options.all_one_file then
|
237
|
+
@last_created = setup_output_dir @options.op_dir, @options.force_update
|
238
|
+
end
|
239
|
+
|
240
|
+
start_time = Time.now
|
241
|
+
|
242
|
+
file_info = parse_files @options
|
243
|
+
|
244
|
+
if file_info.empty?
|
245
|
+
$stderr.puts "\nNo newer files." unless @options.quiet
|
246
|
+
else
|
247
|
+
@gen = @options.generator
|
248
|
+
|
249
|
+
$stderr.puts "\nGenerating #{@gen.key.upcase}..." unless @options.quiet
|
250
|
+
|
251
|
+
require @gen.file_name
|
252
|
+
|
253
|
+
gen_class = ::RDoc::Generator.const_get @gen.class_name
|
254
|
+
@gen = gen_class.for @options
|
255
|
+
|
256
|
+
pwd = Dir.pwd
|
257
|
+
|
258
|
+
Dir.chdir @options.op_dir unless @options.all_one_file
|
259
|
+
|
260
|
+
begin
|
261
|
+
Diagram.new(file_info, @options).draw if @options.diagram
|
262
|
+
@gen.generate(file_info)
|
263
|
+
update_output_dir(".", start_time)
|
264
|
+
ensure
|
265
|
+
Dir.chdir(pwd)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
unless @options.quiet
|
270
|
+
puts
|
271
|
+
@stats.print
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
data/lib/rdoc/ri.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'rdoc/ri'
|
2
|
+
|
3
|
+
class RDoc::RI::ClassEntry
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :path_names
|
7
|
+
|
8
|
+
def initialize(path_name, name, in_class)
|
9
|
+
@path_names = [ path_name ]
|
10
|
+
@name = name
|
11
|
+
@in_class = in_class
|
12
|
+
@class_methods = []
|
13
|
+
@instance_methods = []
|
14
|
+
@inferior_classes = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# We found this class in more tha one place, so add
|
18
|
+
# in the name from there.
|
19
|
+
def add_path(path)
|
20
|
+
@path_names << path
|
21
|
+
end
|
22
|
+
|
23
|
+
# read in our methods and any classes
|
24
|
+
# and modules in our namespace. Methods are
|
25
|
+
# stored in files called name-c|i.yaml,
|
26
|
+
# where the 'name' portion is the external
|
27
|
+
# form of the method name and the c|i is a class|instance
|
28
|
+
# flag
|
29
|
+
|
30
|
+
def load_from(dir)
|
31
|
+
Dir.foreach(dir) do |name|
|
32
|
+
next if name =~ /^\./
|
33
|
+
|
34
|
+
# convert from external to internal form, and
|
35
|
+
# extract the instance/class flag
|
36
|
+
|
37
|
+
if name =~ /^(.*?)-(c|i).yaml$/
|
38
|
+
external_name = $1
|
39
|
+
is_class_method = $2 == "c"
|
40
|
+
internal_name = RiWriter.external_to_internal(external_name)
|
41
|
+
list = is_class_method ? @class_methods : @instance_methods
|
42
|
+
path = File.join(dir, name)
|
43
|
+
list << MethodEntry.new(path, internal_name, is_class_method, self)
|
44
|
+
else
|
45
|
+
full_name = File.join(dir, name)
|
46
|
+
if File.directory?(full_name)
|
47
|
+
inf_class = @inferior_classes.find {|c| c.name == name }
|
48
|
+
if inf_class
|
49
|
+
inf_class.add_path(full_name)
|
50
|
+
else
|
51
|
+
inf_class = ClassEntry.new(full_name, name, self)
|
52
|
+
@inferior_classes << inf_class
|
53
|
+
end
|
54
|
+
inf_class.load_from(full_name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a list of any classes or modules that we contain
|
61
|
+
# that match a given string
|
62
|
+
|
63
|
+
def contained_modules_matching(name)
|
64
|
+
@inferior_classes.find_all {|c| c.name[name]}
|
65
|
+
end
|
66
|
+
|
67
|
+
def classes_and_modules
|
68
|
+
@inferior_classes
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return an exact match to a particular name
|
72
|
+
def contained_class_named(name)
|
73
|
+
@inferior_classes.find {|c| c.name == name}
|
74
|
+
end
|
75
|
+
|
76
|
+
# return the list of local methods matching name
|
77
|
+
# We're split into two because we need distinct behavior
|
78
|
+
# when called from the _toplevel_
|
79
|
+
def methods_matching(name, is_class_method)
|
80
|
+
local_methods_matching(name, is_class_method)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find methods matching 'name' in ourselves and in
|
84
|
+
# any classes we contain
|
85
|
+
def recursively_find_methods_matching(name, is_class_method)
|
86
|
+
res = local_methods_matching(name, is_class_method)
|
87
|
+
@inferior_classes.each do |c|
|
88
|
+
res.concat(c.recursively_find_methods_matching(name, is_class_method))
|
89
|
+
end
|
90
|
+
res
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# Return our full name
|
95
|
+
def full_name
|
96
|
+
res = @in_class.full_name
|
97
|
+
res << "::" unless res.empty?
|
98
|
+
res << @name
|
99
|
+
end
|
100
|
+
|
101
|
+
# Return a list of all out method names
|
102
|
+
def all_method_names
|
103
|
+
res = @class_methods.map {|m| m.full_name }
|
104
|
+
@instance_methods.each {|m| res << m.full_name}
|
105
|
+
res
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# Return a list of all our methods matching a given string.
|
111
|
+
# Is +is_class_methods+ if 'nil', we don't care if the method
|
112
|
+
# is a class method or not, otherwise we only return
|
113
|
+
# those methods that match
|
114
|
+
def local_methods_matching(name, is_class_method)
|
115
|
+
|
116
|
+
list = case is_class_method
|
117
|
+
when nil then @class_methods + @instance_methods
|
118
|
+
when true then @class_methods
|
119
|
+
when false then @instance_methods
|
120
|
+
else fail "Unknown is_class_method: #{is_class_method.inspect}"
|
121
|
+
end
|
122
|
+
|
123
|
+
list.find_all {|m| m.name; m.name[name]}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# A TopLevelEntry is like a class entry, but when asked to search for methods
|
129
|
+
# searches all classes, not just itself
|
130
|
+
|
131
|
+
class RDoc::RI::TopLevelEntry < RDoc::RI::ClassEntry
|
132
|
+
def methods_matching(name, is_class_method)
|
133
|
+
res = recursively_find_methods_matching(name, is_class_method)
|
134
|
+
end
|
135
|
+
|
136
|
+
def full_name
|
137
|
+
""
|
138
|
+
end
|
139
|
+
|
140
|
+
def module_named(name)
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
class RDoc::RI::MethodEntry
|
147
|
+
attr_reader :name
|
148
|
+
attr_reader :path_name
|
149
|
+
|
150
|
+
def initialize(path_name, name, is_class_method, in_class)
|
151
|
+
@path_name = path_name
|
152
|
+
@name = name
|
153
|
+
@is_class_method = is_class_method
|
154
|
+
@in_class = in_class
|
155
|
+
end
|
156
|
+
|
157
|
+
def full_name
|
158
|
+
res = @in_class.full_name
|
159
|
+
unless res.empty?
|
160
|
+
if @is_class_method
|
161
|
+
res << "::"
|
162
|
+
else
|
163
|
+
res << "#"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
res << @name
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# We represent everything know about all 'ri' files accessible to this program
|
172
|
+
|
173
|
+
class RDoc::RI::Cache
|
174
|
+
|
175
|
+
attr_reader :toplevel
|
176
|
+
|
177
|
+
def initialize(dirs)
|
178
|
+
# At the top level we have a dummy module holding the
|
179
|
+
# overall namespace
|
180
|
+
@toplevel = RDoc::RI::TopLevelEntry.new('', '::', nil)
|
181
|
+
|
182
|
+
dirs.each do |dir|
|
183
|
+
@toplevel.load_from(dir)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|