iownbey-rdoc 2.0.1

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