rdoc-f95 0.0.1

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