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.

Files changed (62) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/Rakefile +10 -0
  5. data/bin/rdoc +22 -0
  6. data/bin/ri +6 -0
  7. data/lib/rdoc.rb +277 -0
  8. data/lib/rdoc/code_objects.rb +776 -0
  9. data/lib/rdoc/diagram.rb +338 -0
  10. data/lib/rdoc/dot.rb +249 -0
  11. data/lib/rdoc/generator.rb +1048 -0
  12. data/lib/rdoc/generator/chm.rb +113 -0
  13. data/lib/rdoc/generator/chm/chm.rb +98 -0
  14. data/lib/rdoc/generator/html.rb +370 -0
  15. data/lib/rdoc/generator/html/hefss.rb +414 -0
  16. data/lib/rdoc/generator/html/html.rb +704 -0
  17. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  18. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  19. data/lib/rdoc/generator/ri.rb +229 -0
  20. data/lib/rdoc/generator/xml.rb +120 -0
  21. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  22. data/lib/rdoc/generator/xml/xml.rb +111 -0
  23. data/lib/rdoc/markup.rb +473 -0
  24. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  25. data/lib/rdoc/markup/formatter.rb +14 -0
  26. data/lib/rdoc/markup/fragments.rb +337 -0
  27. data/lib/rdoc/markup/inline.rb +101 -0
  28. data/lib/rdoc/markup/lines.rb +152 -0
  29. data/lib/rdoc/markup/preprocess.rb +71 -0
  30. data/lib/rdoc/markup/to_flow.rb +185 -0
  31. data/lib/rdoc/markup/to_html.rb +353 -0
  32. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  33. data/lib/rdoc/markup/to_latex.rb +328 -0
  34. data/lib/rdoc/markup/to_test.rb +50 -0
  35. data/lib/rdoc/options.rb +616 -0
  36. data/lib/rdoc/parsers/parse_c.rb +775 -0
  37. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  38. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  39. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  40. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  41. data/lib/rdoc/rdoc.rb +277 -0
  42. data/lib/rdoc/ri.rb +4 -0
  43. data/lib/rdoc/ri/cache.rb +188 -0
  44. data/lib/rdoc/ri/descriptions.rb +150 -0
  45. data/lib/rdoc/ri/display.rb +274 -0
  46. data/lib/rdoc/ri/driver.rb +452 -0
  47. data/lib/rdoc/ri/formatter.rb +616 -0
  48. data/lib/rdoc/ri/paths.rb +102 -0
  49. data/lib/rdoc/ri/reader.rb +106 -0
  50. data/lib/rdoc/ri/util.rb +81 -0
  51. data/lib/rdoc/ri/writer.rb +68 -0
  52. data/lib/rdoc/stats.rb +25 -0
  53. data/lib/rdoc/template.rb +64 -0
  54. data/lib/rdoc/tokenstream.rb +33 -0
  55. data/test/test_rdoc_c_parser.rb +261 -0
  56. data/test/test_rdoc_markup.rb +613 -0
  57. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  58. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  59. data/test/test_rdoc_ri_default_display.rb +295 -0
  60. data/test/test_rdoc_ri_formatter.rb +318 -0
  61. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  62. 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(/->/, '&rarr;')
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 = "&nbsp;&nbsp;::" * 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
+