rdoc 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rdoc might be problematic. Click here for more details.
- data/History.txt +13 -0
- data/Manifest.txt +61 -0
- data/README.txt +34 -0
- data/Rakefile +10 -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 +1048 -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/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 +353 -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/options.rb +616 -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_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 +134 -0
@@ -0,0 +1,1048 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'rdoc'
|
3
|
+
require 'rdoc/options'
|
4
|
+
require 'rdoc/markup/to_html_crossref'
|
5
|
+
require 'rdoc/template'
|
6
|
+
|
7
|
+
module RDoc::Generator
|
8
|
+
|
9
|
+
##
|
10
|
+
# Name of sub-direcory that holds file descriptions
|
11
|
+
|
12
|
+
FILE_DIR = "files"
|
13
|
+
|
14
|
+
##
|
15
|
+
# Name of sub-direcory that holds class descriptions
|
16
|
+
|
17
|
+
CLASS_DIR = "classes"
|
18
|
+
|
19
|
+
##
|
20
|
+
# Name of the RDoc CSS file
|
21
|
+
|
22
|
+
CSS_NAME = "rdoc-style.css"
|
23
|
+
|
24
|
+
##
|
25
|
+
# Converts a target url to one that is relative to a given path
|
26
|
+
|
27
|
+
def self.gen_url(path, target)
|
28
|
+
from = ::File.dirname path
|
29
|
+
to, to_file = ::File.split target
|
30
|
+
|
31
|
+
from = from.split "/"
|
32
|
+
to = to.split "/"
|
33
|
+
|
34
|
+
while from.size > 0 and to.size > 0 and from[0] == to[0] do
|
35
|
+
from.shift
|
36
|
+
to.shift
|
37
|
+
end
|
38
|
+
|
39
|
+
from.fill ".."
|
40
|
+
from.concat to
|
41
|
+
from << to_file
|
42
|
+
::File.join(*from)
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Build a hash of all items that can be cross-referenced. This is used when
|
47
|
+
# we output required and included names: if the names appear in this hash,
|
48
|
+
# we can generate an html cross reference to the appropriate description.
|
49
|
+
# We also use this when parsing comment blocks: any decorated words matching
|
50
|
+
# an entry in this list are hyperlinked.
|
51
|
+
|
52
|
+
class AllReferences
|
53
|
+
@@refs = {}
|
54
|
+
|
55
|
+
def AllReferences::reset
|
56
|
+
@@refs = {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def AllReferences.add(name, html_class)
|
60
|
+
@@refs[name] = html_class
|
61
|
+
end
|
62
|
+
|
63
|
+
def AllReferences.[](name)
|
64
|
+
@@refs[name]
|
65
|
+
end
|
66
|
+
|
67
|
+
def AllReferences.keys
|
68
|
+
@@refs.keys
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Handle common markup tasks for the various Context subclasses
|
74
|
+
|
75
|
+
module MarkUp
|
76
|
+
|
77
|
+
##
|
78
|
+
# Convert a string in markup format into HTML.
|
79
|
+
|
80
|
+
def markup(str, remove_para = false)
|
81
|
+
return '' unless str
|
82
|
+
|
83
|
+
unless defined? @formatter then
|
84
|
+
@formatter = RDoc::Markup::ToHtmlCrossref.new(path, self,
|
85
|
+
@options.show_hash)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Convert leading comment markers to spaces, but only if all non-blank
|
89
|
+
# lines have them
|
90
|
+
if str =~ /^(?>\s*)[^\#]/ then
|
91
|
+
content = str
|
92
|
+
else
|
93
|
+
content = str.gsub(/^\s*(#+)/) { $1.tr '#', ' ' }
|
94
|
+
end
|
95
|
+
|
96
|
+
res = @formatter.convert content
|
97
|
+
|
98
|
+
if remove_para then
|
99
|
+
res.sub!(/^<p>/, '')
|
100
|
+
res.sub!(/<\/p>$/, '')
|
101
|
+
end
|
102
|
+
|
103
|
+
res
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Qualify a stylesheet URL; if if +css_name+ does not begin with '/' or
|
108
|
+
# 'http[s]://', prepend a prefix relative to +path+. Otherwise, return it
|
109
|
+
# unmodified.
|
110
|
+
|
111
|
+
def style_url(path, css_name=nil)
|
112
|
+
# $stderr.puts "style_url( #{path.inspect}, #{css_name.inspect} )"
|
113
|
+
css_name ||= CSS_NAME
|
114
|
+
if %r{^(https?:/)?/} =~ css_name
|
115
|
+
css_name
|
116
|
+
else
|
117
|
+
RDoc::Generator.gen_url path, css_name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Build a webcvs URL with the given 'url' argument. URLs with a '%s' in them
|
123
|
+
# get the file's path sprintfed into them; otherwise they're just catenated
|
124
|
+
# together.
|
125
|
+
|
126
|
+
def cvs_url(url, full_path)
|
127
|
+
if /%s/ =~ url
|
128
|
+
return sprintf( url, full_path )
|
129
|
+
else
|
130
|
+
return url + full_path
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# A Context is built by the parser to represent a container: contexts hold
|
138
|
+
# classes, modules, methods, require lists and include lists. ClassModule
|
139
|
+
# and TopLevel are the context objects we process here
|
140
|
+
|
141
|
+
class Context
|
142
|
+
|
143
|
+
include MarkUp
|
144
|
+
|
145
|
+
attr_reader :context
|
146
|
+
|
147
|
+
##
|
148
|
+
# Generate:
|
149
|
+
#
|
150
|
+
# * a list of RDoc::Generator::File objects for each TopLevel object
|
151
|
+
# * a list of RDoc::Generator::Class objects for each first level class or
|
152
|
+
# module in the TopLevel objects
|
153
|
+
# * a complete list of all hyperlinkable terms (file, class, module, and
|
154
|
+
# method names)
|
155
|
+
|
156
|
+
def self.build_indicies(toplevels, options)
|
157
|
+
files = []
|
158
|
+
classes = []
|
159
|
+
|
160
|
+
toplevels.each do |toplevel|
|
161
|
+
files << RDoc::Generator::File.new(toplevel, options,
|
162
|
+
RDoc::Generator::FILE_DIR)
|
163
|
+
end
|
164
|
+
|
165
|
+
RDoc::TopLevel.all_classes_and_modules.each do |cls|
|
166
|
+
build_class_list(classes, options, cls, files[0],
|
167
|
+
RDoc::Generator::CLASS_DIR)
|
168
|
+
end
|
169
|
+
|
170
|
+
return files, classes
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.build_class_list(classes, options, from, html_file, class_dir)
|
174
|
+
classes << RDoc::Generator::Class.new(from, html_file, class_dir, options)
|
175
|
+
|
176
|
+
from.each_classmodule do |mod|
|
177
|
+
build_class_list(classes, options, mod, html_file, class_dir)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def initialize(context, options)
|
182
|
+
@context = context
|
183
|
+
@options = options
|
184
|
+
|
185
|
+
# HACK ugly
|
186
|
+
@template = options.template_class
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# convenience method to build a hyperlink
|
191
|
+
|
192
|
+
def href(link, cls, name)
|
193
|
+
%{<a href="#{link}" class="#{cls}">#{name}</a>} #"
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Returns a reference to outselves to be used as an href= the form depends
|
198
|
+
# on whether we're all in one file or in multiple files
|
199
|
+
|
200
|
+
def as_href(from_path)
|
201
|
+
if @options.all_one_file
|
202
|
+
"#" + path
|
203
|
+
else
|
204
|
+
RDoc::Generator.gen_url from_path, path
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Create a list of Method objects for each method in the corresponding
|
210
|
+
# context object. If the @options.show_all variable is set (corresponding
|
211
|
+
# to the <tt>--all</tt> option, we include all methods, otherwise just the
|
212
|
+
# public ones.
|
213
|
+
|
214
|
+
def collect_methods
|
215
|
+
list = @context.method_list
|
216
|
+
|
217
|
+
unless @options.show_all then
|
218
|
+
list = list.find_all do |m|
|
219
|
+
m.visibility == :public or
|
220
|
+
m.visibility == :protected or
|
221
|
+
m.force_documentation
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
@methods = list.collect do |m|
|
226
|
+
RDoc::Generator::Method.new m, self, @options
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Build a summary list of all the methods in this context
|
232
|
+
|
233
|
+
def build_method_summary_list(path_prefix="")
|
234
|
+
collect_methods unless @methods
|
235
|
+
meths = @methods.sort
|
236
|
+
res = []
|
237
|
+
meths.each do |meth|
|
238
|
+
res << {
|
239
|
+
"name" => CGI.escapeHTML(meth.name),
|
240
|
+
"aref" => "#{path_prefix}\##{meth.aref}"
|
241
|
+
}
|
242
|
+
end
|
243
|
+
res
|
244
|
+
end
|
245
|
+
|
246
|
+
##
|
247
|
+
# Build a list of aliases for which we couldn't find a
|
248
|
+
# corresponding method
|
249
|
+
|
250
|
+
def build_alias_summary_list(section)
|
251
|
+
values = []
|
252
|
+
@context.aliases.each do |al|
|
253
|
+
next unless al.section == section
|
254
|
+
res = {
|
255
|
+
'old_name' => al.old_name,
|
256
|
+
'new_name' => al.new_name,
|
257
|
+
}
|
258
|
+
if al.comment && !al.comment.empty?
|
259
|
+
res['desc'] = markup(al.comment, true)
|
260
|
+
end
|
261
|
+
values << res
|
262
|
+
end
|
263
|
+
values
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Build a list of constants
|
268
|
+
|
269
|
+
def build_constants_summary_list(section)
|
270
|
+
values = []
|
271
|
+
@context.constants.each do |co|
|
272
|
+
next unless co.section == section
|
273
|
+
res = {
|
274
|
+
'name' => co.name,
|
275
|
+
'value' => CGI.escapeHTML(co.value)
|
276
|
+
}
|
277
|
+
res['desc'] = markup(co.comment, true) if co.comment && !co.comment.empty?
|
278
|
+
values << res
|
279
|
+
end
|
280
|
+
values
|
281
|
+
end
|
282
|
+
|
283
|
+
def build_requires_list(context)
|
284
|
+
potentially_referenced_list(context.requires) {|fn| [fn + ".rb"] }
|
285
|
+
end
|
286
|
+
|
287
|
+
def build_include_list(context)
|
288
|
+
potentially_referenced_list(context.includes)
|
289
|
+
end
|
290
|
+
|
291
|
+
##
|
292
|
+
# Build a list from an array of Context items. Look up each in the
|
293
|
+
# AllReferences hash: if we find a corresponding entry, we generate a
|
294
|
+
# hyperlink to it, otherwise just output the name. However, some names
|
295
|
+
# potentially need massaging. For example, you may require a Ruby file
|
296
|
+
# without the .rb extension, but the file names we know about may have it.
|
297
|
+
# To deal with this, we pass in a block which performs the massaging,
|
298
|
+
# returning an array of alternative names to match
|
299
|
+
|
300
|
+
def potentially_referenced_list(array)
|
301
|
+
res = []
|
302
|
+
array.each do |i|
|
303
|
+
ref = AllReferences[i.name]
|
304
|
+
# if !ref
|
305
|
+
# container = @context.parent
|
306
|
+
# while !ref && container
|
307
|
+
# name = container.name + "::" + i.name
|
308
|
+
# ref = AllReferences[name]
|
309
|
+
# container = container.parent
|
310
|
+
# end
|
311
|
+
# end
|
312
|
+
|
313
|
+
ref = @context.find_symbol(i.name)
|
314
|
+
ref = ref.viewer if ref
|
315
|
+
|
316
|
+
if !ref && block_given?
|
317
|
+
possibles = yield(i.name)
|
318
|
+
while !ref and !possibles.empty?
|
319
|
+
ref = AllReferences[possibles.shift]
|
320
|
+
end
|
321
|
+
end
|
322
|
+
h_name = CGI.escapeHTML(i.name)
|
323
|
+
if ref and ref.document_self
|
324
|
+
path = url(ref.path)
|
325
|
+
res << { "name" => h_name, "aref" => path }
|
326
|
+
else
|
327
|
+
res << { "name" => h_name }
|
328
|
+
end
|
329
|
+
end
|
330
|
+
res
|
331
|
+
end
|
332
|
+
|
333
|
+
##
|
334
|
+
# Build an array of arrays of method details. The outer array has up
|
335
|
+
# to six entries, public, private, and protected for both class
|
336
|
+
# methods, the other for instance methods. The inner arrays contain
|
337
|
+
# a hash for each method
|
338
|
+
|
339
|
+
def build_method_detail_list(section)
|
340
|
+
outer = []
|
341
|
+
|
342
|
+
methods = @methods.sort
|
343
|
+
for singleton in [true, false]
|
344
|
+
for vis in [ :public, :protected, :private ]
|
345
|
+
res = []
|
346
|
+
methods.each do |m|
|
347
|
+
if m.section == section and
|
348
|
+
m.document_self and
|
349
|
+
m.visibility == vis and
|
350
|
+
m.singleton == singleton
|
351
|
+
row = {}
|
352
|
+
if m.call_seq
|
353
|
+
row["callseq"] = m.call_seq.gsub(/->/, '→')
|
354
|
+
else
|
355
|
+
row["name"] = CGI.escapeHTML(m.name)
|
356
|
+
row["params"] = m.params
|
357
|
+
end
|
358
|
+
desc = m.description.strip
|
359
|
+
row["m_desc"] = desc unless desc.empty?
|
360
|
+
row["aref"] = m.aref
|
361
|
+
row["visibility"] = m.visibility.to_s
|
362
|
+
|
363
|
+
alias_names = []
|
364
|
+
m.aliases.each do |other|
|
365
|
+
if other.viewer # won't be if the alias is private
|
366
|
+
alias_names << {
|
367
|
+
'name' => other.name,
|
368
|
+
'aref' => other.viewer.as_href(path)
|
369
|
+
}
|
370
|
+
end
|
371
|
+
end
|
372
|
+
unless alias_names.empty?
|
373
|
+
row["aka"] = alias_names
|
374
|
+
end
|
375
|
+
|
376
|
+
if @options.inline_source
|
377
|
+
code = m.source_code
|
378
|
+
row["sourcecode"] = code if code
|
379
|
+
else
|
380
|
+
code = m.src_url
|
381
|
+
if code
|
382
|
+
row["codeurl"] = code
|
383
|
+
row["imgurl"] = m.img_url
|
384
|
+
end
|
385
|
+
end
|
386
|
+
res << row
|
387
|
+
end
|
388
|
+
end
|
389
|
+
if res.size > 0
|
390
|
+
outer << {
|
391
|
+
"type" => vis.to_s.capitalize,
|
392
|
+
"category" => singleton ? "Class" : "Instance",
|
393
|
+
"methods" => res
|
394
|
+
}
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
outer
|
399
|
+
end
|
400
|
+
|
401
|
+
##
|
402
|
+
# Build the structured list of classes and modules contained
|
403
|
+
# in this context.
|
404
|
+
|
405
|
+
def build_class_list(level, from, section, infile=nil)
|
406
|
+
res = ""
|
407
|
+
prefix = " ::" * level;
|
408
|
+
|
409
|
+
from.modules.sort.each do |mod|
|
410
|
+
next unless mod.section == section
|
411
|
+
next if infile && !mod.defined_in?(infile)
|
412
|
+
if mod.document_self
|
413
|
+
res <<
|
414
|
+
prefix <<
|
415
|
+
"Module " <<
|
416
|
+
href(url(mod.viewer.path), "link", mod.full_name) <<
|
417
|
+
"<br />\n" <<
|
418
|
+
build_class_list(level + 1, mod, section, infile)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
from.classes.sort.each do |cls|
|
423
|
+
next unless cls.section == section
|
424
|
+
next if infile && !cls.defined_in?(infile)
|
425
|
+
if cls.document_self
|
426
|
+
res <<
|
427
|
+
prefix <<
|
428
|
+
"Class " <<
|
429
|
+
href(url(cls.viewer.path), "link", cls.full_name) <<
|
430
|
+
"<br />\n" <<
|
431
|
+
build_class_list(level + 1, cls, section, infile)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
res
|
436
|
+
end
|
437
|
+
|
438
|
+
def url(target)
|
439
|
+
RDoc::Generator.gen_url path, target
|
440
|
+
end
|
441
|
+
|
442
|
+
def aref_to(target)
|
443
|
+
if @options.all_one_file
|
444
|
+
"#" + target
|
445
|
+
else
|
446
|
+
url(target)
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def document_self
|
451
|
+
@context.document_self
|
452
|
+
end
|
453
|
+
|
454
|
+
def diagram_reference(diagram)
|
455
|
+
res = diagram.gsub(/((?:src|href)=")(.*?)"/) {
|
456
|
+
$1 + url($2) + '"'
|
457
|
+
}
|
458
|
+
res
|
459
|
+
end
|
460
|
+
|
461
|
+
##
|
462
|
+
# Find a symbol in ourselves or our parent
|
463
|
+
|
464
|
+
def find_symbol(symbol, method=nil)
|
465
|
+
res = @context.find_symbol(symbol, method)
|
466
|
+
if res
|
467
|
+
res = res.viewer
|
468
|
+
end
|
469
|
+
res
|
470
|
+
end
|
471
|
+
|
472
|
+
##
|
473
|
+
# create table of contents if we contain sections
|
474
|
+
|
475
|
+
def add_table_of_sections
|
476
|
+
toc = []
|
477
|
+
@context.sections.each do |section|
|
478
|
+
if section.title
|
479
|
+
toc << {
|
480
|
+
'secname' => section.title,
|
481
|
+
'href' => section.sequence
|
482
|
+
}
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
@values['toc'] = toc unless toc.empty?
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
##
|
492
|
+
# Wrap a ClassModule context
|
493
|
+
|
494
|
+
class Class < Context
|
495
|
+
|
496
|
+
attr_reader :methods
|
497
|
+
attr_reader :path
|
498
|
+
|
499
|
+
def initialize(context, html_file, prefix, options)
|
500
|
+
super(context, options)
|
501
|
+
|
502
|
+
@html_file = html_file
|
503
|
+
@is_module = context.is_module?
|
504
|
+
@values = {}
|
505
|
+
|
506
|
+
context.viewer = self
|
507
|
+
|
508
|
+
if options.all_one_file
|
509
|
+
@path = context.full_name
|
510
|
+
else
|
511
|
+
@path = http_url(context.full_name, prefix)
|
512
|
+
end
|
513
|
+
|
514
|
+
collect_methods
|
515
|
+
|
516
|
+
AllReferences.add(name, self)
|
517
|
+
end
|
518
|
+
|
519
|
+
##
|
520
|
+
# Returns the relative file name to store this class in, which is also its
|
521
|
+
# url
|
522
|
+
|
523
|
+
def http_url(full_name, prefix)
|
524
|
+
path = full_name.dup
|
525
|
+
|
526
|
+
path.gsub!(/<<\s*(\w*)/, 'from-\1') if path['<<']
|
527
|
+
|
528
|
+
::File.join(prefix, path.split("::")) + ".html"
|
529
|
+
end
|
530
|
+
|
531
|
+
def name
|
532
|
+
@context.full_name
|
533
|
+
end
|
534
|
+
|
535
|
+
def parent_name
|
536
|
+
@context.parent.full_name
|
537
|
+
end
|
538
|
+
|
539
|
+
def index_name
|
540
|
+
name
|
541
|
+
end
|
542
|
+
|
543
|
+
def write_on(f)
|
544
|
+
value_hash
|
545
|
+
template = RDoc::TemplatePage.new(@template::BODY,
|
546
|
+
@template::CLASS_PAGE,
|
547
|
+
@template::METHOD_LIST)
|
548
|
+
template.write_html_on(f, @values)
|
549
|
+
end
|
550
|
+
|
551
|
+
def value_hash
|
552
|
+
class_attribute_values
|
553
|
+
add_table_of_sections
|
554
|
+
|
555
|
+
@values["charset"] = @options.charset
|
556
|
+
@values["style_url"] = style_url(path, @options.css)
|
557
|
+
|
558
|
+
d = markup(@context.comment)
|
559
|
+
@values["description"] = d unless d.empty?
|
560
|
+
|
561
|
+
ml = build_method_summary_list @path
|
562
|
+
@values["methods"] = ml unless ml.empty?
|
563
|
+
|
564
|
+
il = build_include_list(@context)
|
565
|
+
@values["includes"] = il unless il.empty?
|
566
|
+
|
567
|
+
@values["sections"] = @context.sections.map do |section|
|
568
|
+
|
569
|
+
secdata = {
|
570
|
+
"sectitle" => section.title,
|
571
|
+
"secsequence" => section.sequence,
|
572
|
+
"seccomment" => markup(section.comment)
|
573
|
+
}
|
574
|
+
|
575
|
+
al = build_alias_summary_list(section)
|
576
|
+
secdata["aliases"] = al unless al.empty?
|
577
|
+
|
578
|
+
co = build_constants_summary_list(section)
|
579
|
+
secdata["constants"] = co unless co.empty?
|
580
|
+
|
581
|
+
al = build_attribute_list(section)
|
582
|
+
secdata["attributes"] = al unless al.empty?
|
583
|
+
|
584
|
+
cl = build_class_list(0, @context, section)
|
585
|
+
secdata["classlist"] = cl unless cl.empty?
|
586
|
+
|
587
|
+
mdl = build_method_detail_list(section)
|
588
|
+
secdata["method_list"] = mdl unless mdl.empty?
|
589
|
+
|
590
|
+
secdata
|
591
|
+
end
|
592
|
+
|
593
|
+
@values
|
594
|
+
end
|
595
|
+
|
596
|
+
def build_attribute_list(section)
|
597
|
+
atts = @context.attributes.sort
|
598
|
+
res = []
|
599
|
+
atts.each do |att|
|
600
|
+
next unless att.section == section
|
601
|
+
if att.visibility == :public || att.visibility == :protected || @options.show_all
|
602
|
+
entry = {
|
603
|
+
"name" => CGI.escapeHTML(att.name),
|
604
|
+
"rw" => att.rw,
|
605
|
+
"a_desc" => markup(att.comment, true)
|
606
|
+
}
|
607
|
+
unless att.visibility == :public || att.visibility == :protected
|
608
|
+
entry["rw"] << "-"
|
609
|
+
end
|
610
|
+
res << entry
|
611
|
+
end
|
612
|
+
end
|
613
|
+
res
|
614
|
+
end
|
615
|
+
|
616
|
+
def class_attribute_values
|
617
|
+
h_name = CGI.escapeHTML(name)
|
618
|
+
|
619
|
+
@values["path"] = @path
|
620
|
+
@values["classmod"] = @is_module ? "Module" : "Class"
|
621
|
+
@values["title"] = "#{@values['classmod']}: #{h_name}"
|
622
|
+
|
623
|
+
c = @context
|
624
|
+
c = c.parent while c and !c.diagram
|
625
|
+
if c && c.diagram
|
626
|
+
@values["diagram"] = diagram_reference(c.diagram)
|
627
|
+
end
|
628
|
+
|
629
|
+
@values["full_name"] = h_name
|
630
|
+
|
631
|
+
parent_class = @context.superclass
|
632
|
+
|
633
|
+
if parent_class
|
634
|
+
@values["parent"] = CGI.escapeHTML(parent_class)
|
635
|
+
|
636
|
+
if parent_name
|
637
|
+
lookup = parent_name + "::" + parent_class
|
638
|
+
else
|
639
|
+
lookup = parent_class
|
640
|
+
end
|
641
|
+
|
642
|
+
parent_url = AllReferences[lookup] || AllReferences[parent_class]
|
643
|
+
|
644
|
+
if parent_url and parent_url.document_self
|
645
|
+
@values["par_url"] = aref_to(parent_url.path)
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
files = []
|
650
|
+
@context.in_files.each do |f|
|
651
|
+
res = {}
|
652
|
+
full_path = CGI.escapeHTML(f.file_absolute_name)
|
653
|
+
|
654
|
+
res["full_path"] = full_path
|
655
|
+
res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
|
656
|
+
|
657
|
+
if @options.webcvs
|
658
|
+
res["cvsurl"] = cvs_url( @options.webcvs, full_path )
|
659
|
+
end
|
660
|
+
|
661
|
+
files << res
|
662
|
+
end
|
663
|
+
|
664
|
+
@values['infiles'] = files
|
665
|
+
end
|
666
|
+
|
667
|
+
def <=>(other)
|
668
|
+
self.name <=> other.name
|
669
|
+
end
|
670
|
+
|
671
|
+
end
|
672
|
+
|
673
|
+
##
|
674
|
+
# Handles the mapping of a file's information to HTML. In reality, a file
|
675
|
+
# corresponds to a +TopLevel+ object, containing modules, classes, and
|
676
|
+
# top-level methods. In theory it _could_ contain attributes and aliases,
|
677
|
+
# but we ignore these for now.
|
678
|
+
|
679
|
+
class File < Context
|
680
|
+
|
681
|
+
attr_reader :path
|
682
|
+
attr_reader :name
|
683
|
+
|
684
|
+
def initialize(context, options, file_dir)
|
685
|
+
super(context, options)
|
686
|
+
|
687
|
+
@values = {}
|
688
|
+
|
689
|
+
if options.all_one_file
|
690
|
+
@path = filename_to_label
|
691
|
+
else
|
692
|
+
@path = http_url(file_dir)
|
693
|
+
end
|
694
|
+
|
695
|
+
@name = @context.file_relative_name
|
696
|
+
|
697
|
+
collect_methods
|
698
|
+
AllReferences.add(name, self)
|
699
|
+
context.viewer = self
|
700
|
+
end
|
701
|
+
|
702
|
+
def http_url(file_dir)
|
703
|
+
::File.join file_dir, "#{@context.file_relative_name.tr '.', '_'}.html"
|
704
|
+
end
|
705
|
+
|
706
|
+
def filename_to_label
|
707
|
+
@context.file_relative_name.gsub(/%|\/|\?|\#/) do
|
708
|
+
'%%%x' % $&[0].unpack('C')
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
def index_name
|
713
|
+
name
|
714
|
+
end
|
715
|
+
|
716
|
+
def parent_name
|
717
|
+
nil
|
718
|
+
end
|
719
|
+
|
720
|
+
def value_hash
|
721
|
+
file_attribute_values
|
722
|
+
add_table_of_sections
|
723
|
+
|
724
|
+
@values["charset"] = @options.charset
|
725
|
+
@values["href"] = path
|
726
|
+
@values["style_url"] = style_url(path, @options.css)
|
727
|
+
|
728
|
+
if @context.comment
|
729
|
+
d = markup(@context.comment)
|
730
|
+
@values["description"] = d if d.size > 0
|
731
|
+
end
|
732
|
+
|
733
|
+
ml = build_method_summary_list
|
734
|
+
@values["methods"] = ml unless ml.empty?
|
735
|
+
|
736
|
+
il = build_include_list(@context)
|
737
|
+
@values["includes"] = il unless il.empty?
|
738
|
+
|
739
|
+
rl = build_requires_list(@context)
|
740
|
+
@values["requires"] = rl unless rl.empty?
|
741
|
+
|
742
|
+
if @options.promiscuous
|
743
|
+
file_context = nil
|
744
|
+
else
|
745
|
+
file_context = @context
|
746
|
+
end
|
747
|
+
|
748
|
+
|
749
|
+
@values["sections"] = @context.sections.map do |section|
|
750
|
+
|
751
|
+
secdata = {
|
752
|
+
"sectitle" => section.title,
|
753
|
+
"secsequence" => section.sequence,
|
754
|
+
"seccomment" => markup(section.comment)
|
755
|
+
}
|
756
|
+
|
757
|
+
cl = build_class_list(0, @context, section, file_context)
|
758
|
+
@values["classlist"] = cl unless cl.empty?
|
759
|
+
|
760
|
+
mdl = build_method_detail_list(section)
|
761
|
+
secdata["method_list"] = mdl unless mdl.empty?
|
762
|
+
|
763
|
+
al = build_alias_summary_list(section)
|
764
|
+
secdata["aliases"] = al unless al.empty?
|
765
|
+
|
766
|
+
co = build_constants_summary_list(section)
|
767
|
+
@values["constants"] = co unless co.empty?
|
768
|
+
|
769
|
+
secdata
|
770
|
+
end
|
771
|
+
|
772
|
+
@values
|
773
|
+
end
|
774
|
+
|
775
|
+
def write_on(f)
|
776
|
+
value_hash
|
777
|
+
|
778
|
+
template = RDoc::TemplatePage.new(@template::BODY,
|
779
|
+
@template::FILE_PAGE,
|
780
|
+
@template::METHOD_LIST)
|
781
|
+
|
782
|
+
template.write_html_on(f, @values)
|
783
|
+
end
|
784
|
+
|
785
|
+
def file_attribute_values
|
786
|
+
full_path = @context.file_absolute_name
|
787
|
+
short_name = ::File.basename full_path
|
788
|
+
|
789
|
+
@values["title"] = CGI.escapeHTML("File: #{short_name}")
|
790
|
+
|
791
|
+
if @context.diagram then
|
792
|
+
@values["diagram"] = diagram_reference(@context.diagram)
|
793
|
+
end
|
794
|
+
|
795
|
+
@values["short_name"] = CGI.escapeHTML(short_name)
|
796
|
+
@values["full_path"] = CGI.escapeHTML(full_path)
|
797
|
+
@values["dtm_modified"] = @context.file_stat.mtime.to_s
|
798
|
+
|
799
|
+
if @options.webcvs then
|
800
|
+
@values["cvsurl"] = cvs_url @options.webcvs, @values["full_path"]
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
def <=>(other)
|
805
|
+
self.name <=> other.name
|
806
|
+
end
|
807
|
+
|
808
|
+
end
|
809
|
+
|
810
|
+
class Method
|
811
|
+
|
812
|
+
include MarkUp
|
813
|
+
|
814
|
+
attr_reader :context
|
815
|
+
attr_reader :src_url
|
816
|
+
attr_reader :img_url
|
817
|
+
attr_reader :source_code
|
818
|
+
|
819
|
+
@@seq = "M000000"
|
820
|
+
|
821
|
+
@@all_methods = []
|
822
|
+
|
823
|
+
def self.all_methods
|
824
|
+
@@all_methods
|
825
|
+
end
|
826
|
+
|
827
|
+
def self.reset
|
828
|
+
@@all_methods = []
|
829
|
+
end
|
830
|
+
|
831
|
+
def initialize(context, html_class, options)
|
832
|
+
@context = context
|
833
|
+
@html_class = html_class
|
834
|
+
@options = options
|
835
|
+
|
836
|
+
# HACK ugly
|
837
|
+
@template = options.template_class
|
838
|
+
|
839
|
+
@@seq = @@seq.succ
|
840
|
+
@seq = @@seq
|
841
|
+
@@all_methods << self
|
842
|
+
|
843
|
+
context.viewer = self
|
844
|
+
|
845
|
+
if (ts = @context.token_stream)
|
846
|
+
@source_code = markup_code(ts)
|
847
|
+
unless @options.inline_source
|
848
|
+
@src_url = create_source_code_file(@source_code)
|
849
|
+
@img_url = RDoc::Generator.gen_url path, 'source.png'
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
AllReferences.add(name, self)
|
854
|
+
end
|
855
|
+
|
856
|
+
##
|
857
|
+
# Returns a reference to outselves to be used as an href= the form depends
|
858
|
+
# on whether we're all in one file or in multiple files
|
859
|
+
|
860
|
+
def as_href(from_path)
|
861
|
+
if @options.all_one_file
|
862
|
+
"#" + path
|
863
|
+
else
|
864
|
+
RDoc::Generator.gen_url from_path, path
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
def name
|
869
|
+
@context.name
|
870
|
+
end
|
871
|
+
|
872
|
+
def section
|
873
|
+
@context.section
|
874
|
+
end
|
875
|
+
|
876
|
+
def index_name
|
877
|
+
"#{@context.name} (#{@html_class.name})"
|
878
|
+
end
|
879
|
+
|
880
|
+
def parent_name
|
881
|
+
if @context.parent.parent
|
882
|
+
@context.parent.parent.full_name
|
883
|
+
else
|
884
|
+
nil
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
def aref
|
889
|
+
@seq
|
890
|
+
end
|
891
|
+
|
892
|
+
def path
|
893
|
+
if @options.all_one_file
|
894
|
+
aref
|
895
|
+
else
|
896
|
+
@html_class.path + "#" + aref
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
900
|
+
def description
|
901
|
+
markup(@context.comment)
|
902
|
+
end
|
903
|
+
|
904
|
+
def visibility
|
905
|
+
@context.visibility
|
906
|
+
end
|
907
|
+
|
908
|
+
def singleton
|
909
|
+
@context.singleton
|
910
|
+
end
|
911
|
+
|
912
|
+
def call_seq
|
913
|
+
cs = @context.call_seq
|
914
|
+
if cs
|
915
|
+
cs.gsub(/\n/, "<br />\n")
|
916
|
+
else
|
917
|
+
nil
|
918
|
+
end
|
919
|
+
end
|
920
|
+
|
921
|
+
def params
|
922
|
+
# params coming from a call-seq in 'C' will start with the
|
923
|
+
# method name
|
924
|
+
params = @context.params
|
925
|
+
if params !~ /^\w/
|
926
|
+
params = @context.params.gsub(/\s*\#.*/, '')
|
927
|
+
params = params.tr("\n", " ").squeeze(" ")
|
928
|
+
params = "(" + params + ")" unless params[0] == ?(
|
929
|
+
|
930
|
+
if (block = @context.block_params)
|
931
|
+
# If this method has explicit block parameters, remove any
|
932
|
+
# explicit &block
|
933
|
+
|
934
|
+
params.sub!(/,?\s*&\w+/, '')
|
935
|
+
|
936
|
+
block.gsub!(/\s*\#.*/, '')
|
937
|
+
block = block.tr("\n", " ").squeeze(" ")
|
938
|
+
if block[0] == ?(
|
939
|
+
block.sub!(/^\(/, '').sub!(/\)/, '')
|
940
|
+
end
|
941
|
+
params << " {|#{block.strip}| ...}"
|
942
|
+
end
|
943
|
+
end
|
944
|
+
CGI.escapeHTML(params)
|
945
|
+
end
|
946
|
+
|
947
|
+
def create_source_code_file(code_body)
|
948
|
+
meth_path = @html_class.path.sub(/\.html$/, '.src')
|
949
|
+
FileUtils.mkdir_p(meth_path)
|
950
|
+
file_path = ::File.join meth_path, "#{@seq}.html"
|
951
|
+
|
952
|
+
template = RDoc::TemplatePage.new(@template::SRC_PAGE)
|
953
|
+
|
954
|
+
open file_path, 'w' do |f|
|
955
|
+
values = {
|
956
|
+
'title' => CGI.escapeHTML(index_name),
|
957
|
+
'code' => code_body,
|
958
|
+
'style_url' => style_url(file_path, @options.css),
|
959
|
+
'charset' => @options.charset
|
960
|
+
}
|
961
|
+
template.write_html_on(f, values)
|
962
|
+
end
|
963
|
+
|
964
|
+
RDoc::Generator.gen_url path, file_path
|
965
|
+
end
|
966
|
+
|
967
|
+
def <=>(other)
|
968
|
+
@context <=> other.context
|
969
|
+
end
|
970
|
+
|
971
|
+
##
|
972
|
+
# Given a sequence of source tokens, mark up the source code
|
973
|
+
# to make it look purty.
|
974
|
+
|
975
|
+
def markup_code(tokens)
|
976
|
+
src = ""
|
977
|
+
tokens.each do |t|
|
978
|
+
next unless t
|
979
|
+
# p t.class
|
980
|
+
# style = STYLE_MAP[t.class]
|
981
|
+
style = case t
|
982
|
+
when RubyToken::TkCONSTANT then "ruby-constant"
|
983
|
+
when RubyToken::TkKW then "ruby-keyword kw"
|
984
|
+
when RubyToken::TkIVAR then "ruby-ivar"
|
985
|
+
when RubyToken::TkOp then "ruby-operator"
|
986
|
+
when RubyToken::TkId then "ruby-identifier"
|
987
|
+
when RubyToken::TkNode then "ruby-node"
|
988
|
+
when RubyToken::TkCOMMENT then "ruby-comment cmt"
|
989
|
+
when RubyToken::TkREGEXP then "ruby-regexp re"
|
990
|
+
when RubyToken::TkSTRING then "ruby-value str"
|
991
|
+
when RubyToken::TkVal then "ruby-value"
|
992
|
+
else
|
993
|
+
nil
|
994
|
+
end
|
995
|
+
|
996
|
+
text = CGI.escapeHTML(t.text)
|
997
|
+
|
998
|
+
if style
|
999
|
+
src << "<span class=\"#{style}\">#{text}</span>"
|
1000
|
+
else
|
1001
|
+
src << text
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
add_line_numbers(src) if @options.include_line_numbers
|
1006
|
+
src
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
##
|
1010
|
+
# We rely on the fact that the first line of a source code listing has
|
1011
|
+
# # File xxxxx, line dddd
|
1012
|
+
|
1013
|
+
def add_line_numbers(src)
|
1014
|
+
if src =~ /\A.*, line (\d+)/
|
1015
|
+
first = $1.to_i - 1
|
1016
|
+
last = first + src.count("\n")
|
1017
|
+
size = last.to_s.length
|
1018
|
+
real_fmt = "%#{size}d: "
|
1019
|
+
fmt = " " * (size+2)
|
1020
|
+
src.gsub!(/^/) do
|
1021
|
+
res = sprintf(fmt, first)
|
1022
|
+
first += 1
|
1023
|
+
fmt = real_fmt
|
1024
|
+
res
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
def document_self
|
1030
|
+
@context.document_self
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
def aliases
|
1034
|
+
@context.aliases
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
def find_symbol(symbol, method=nil)
|
1038
|
+
res = @context.parent.find_symbol(symbol, method)
|
1039
|
+
if res
|
1040
|
+
res = res.viewer
|
1041
|
+
end
|
1042
|
+
res
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
end
|
1048
|
+
|