iownbey-rdoc 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+