rdoc 2.0.0 → 2.1.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 (52) hide show
  1. data.tar.gz.sig +1 -0
  2. data/History.txt +30 -0
  3. data/Manifest.txt +18 -6
  4. data/Rakefile +52 -0
  5. data/lib/rdoc.rb +69 -69
  6. data/lib/rdoc/code_objects.rb +331 -112
  7. data/lib/rdoc/generator.rb +172 -144
  8. data/lib/rdoc/generator/html.rb +45 -18
  9. data/lib/rdoc/generator/html/frameless.rb +795 -0
  10. data/lib/rdoc/generator/html/hefss.rb +11 -11
  11. data/lib/rdoc/generator/html/html.rb +81 -87
  12. data/lib/rdoc/generator/html/kilmer.rb +10 -10
  13. data/lib/rdoc/generator/html/one_page_html.rb +9 -9
  14. data/lib/rdoc/generator/ri.rb +5 -8
  15. data/lib/rdoc/generator/texinfo.rb +84 -0
  16. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  17. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  18. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  19. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  20. data/lib/rdoc/known_classes.rb +69 -0
  21. data/lib/rdoc/markup.rb +3 -3
  22. data/lib/rdoc/markup/attribute_manager.rb +0 -9
  23. data/lib/rdoc/markup/fragments.rb +1 -1
  24. data/lib/rdoc/markup/preprocess.rb +10 -6
  25. data/lib/rdoc/markup/to_html.rb +55 -8
  26. data/lib/rdoc/markup/to_html_crossref.rb +21 -5
  27. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  28. data/lib/rdoc/options.rb +37 -14
  29. data/lib/rdoc/parser.rb +109 -0
  30. data/lib/rdoc/parser/c.rb +656 -0
  31. data/lib/rdoc/parser/f95.rb +1835 -0
  32. data/lib/rdoc/{parsers/parse_rb.rb → parser/ruby.rb} +1436 -1191
  33. data/lib/rdoc/parser/simple.rb +38 -0
  34. data/lib/rdoc/rdoc.rb +48 -32
  35. data/lib/rdoc/ri.rb +5 -1
  36. data/lib/rdoc/ri/descriptions.rb +8 -5
  37. data/lib/rdoc/ri/driver.rb +148 -49
  38. data/lib/rdoc/stats.rb +94 -4
  39. data/test/test_rdoc_info_formatting.rb +175 -0
  40. data/test/test_rdoc_info_sections.rb +136 -0
  41. data/test/test_rdoc_markup_to_html.rb +30 -0
  42. data/test/test_rdoc_markup_to_html_crossref.rb +18 -0
  43. data/test/{test_rdoc_c_parser.rb → test_rdoc_parser_c.rb} +8 -11
  44. data/test/test_rdoc_parser_ruby.rb +539 -0
  45. data/test/test_rdoc_ri_default_display.rb +17 -16
  46. data/test/test_rdoc_ri_driver.rb +92 -0
  47. metadata +54 -12
  48. metadata.gz.sig +0 -0
  49. data/lib/rdoc/parsers/parse_c.rb +0 -775
  50. data/lib/rdoc/parsers/parse_f95.rb +0 -1841
  51. data/lib/rdoc/parsers/parse_simple.rb +0 -40
  52. data/lib/rdoc/parsers/parserfactory.rb +0 -99
@@ -0,0 +1,656 @@
1
+ require 'rdoc/parser'
2
+ require 'rdoc/known_classes'
3
+
4
+ ##
5
+ # We attempt to parse C extension files. Basically we look for
6
+ # the standard patterns that you find in extensions: <tt>rb_define_class,
7
+ # rb_define_method</tt> and so on. We also try to find the corresponding
8
+ # C source for the methods and extract comments, but if we fail
9
+ # we don't worry too much.
10
+ #
11
+ # The comments associated with a Ruby method are extracted from the C
12
+ # comment block associated with the routine that _implements_ that
13
+ # method, that is to say the method whose name is given in the
14
+ # <tt>rb_define_method</tt> call. For example, you might write:
15
+ #
16
+ # /*
17
+ # * Returns a new array that is a one-dimensional flattening of this
18
+ # * array (recursively). That is, for every element that is an array,
19
+ # * extract its elements into the new array.
20
+ # *
21
+ # * s = [ 1, 2, 3 ] #=> [1, 2, 3]
22
+ # * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
23
+ # * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
24
+ # * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
25
+ # */
26
+ # static VALUE
27
+ # rb_ary_flatten(ary)
28
+ # VALUE ary;
29
+ # {
30
+ # ary = rb_obj_dup(ary);
31
+ # rb_ary_flatten_bang(ary);
32
+ # return ary;
33
+ # }
34
+ #
35
+ # ...
36
+ #
37
+ # void
38
+ # Init_Array()
39
+ # {
40
+ # ...
41
+ # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
42
+ #
43
+ # Here RDoc will determine from the rb_define_method line that there's a
44
+ # method called "flatten" in class Array, and will look for the implementation
45
+ # in the method rb_ary_flatten. It will then use the comment from that
46
+ # method in the HTML output. This method must be in the same source file
47
+ # as the rb_define_method.
48
+ #
49
+ # C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc
50
+ # integrates C and Ruby source into one tree
51
+ #
52
+ # The comment blocks may include special directives:
53
+ #
54
+ # [Document-class: <i>name</i>]
55
+ # This comment block is documentation for the given class. Use this
56
+ # when the <tt>Init_xxx</tt> method is not named after the class.
57
+ #
58
+ # [Document-method: <i>name</i>]
59
+ # This comment documents the named method. Use when RDoc cannot
60
+ # automatically find the method from it's declaration
61
+ #
62
+ # [call-seq: <i>text up to an empty line</i>]
63
+ # Because C source doesn't give descripive names to Ruby-level parameters,
64
+ # you need to document the calling sequence explicitly
65
+ #
66
+ # In addition, RDoc assumes by default that the C method implementing a
67
+ # Ruby function is in the same source file as the rb_define_method call.
68
+ # If this isn't the case, add the comment:
69
+ #
70
+ # rb_define_method(....); // in: filename
71
+ #
72
+ # As an example, we might have an extension that defines multiple classes
73
+ # in its Init_xxx method. We could document them using
74
+ #
75
+ # /*
76
+ # * Document-class: MyClass
77
+ # *
78
+ # * Encapsulate the writing and reading of the configuration
79
+ # * file. ...
80
+ # */
81
+ #
82
+ # /*
83
+ # * Document-method: read_value
84
+ # *
85
+ # * call-seq:
86
+ # * cfg.read_value(key) -> value
87
+ # * cfg.read_value(key} { |key| } -> value
88
+ # *
89
+ # * Return the value corresponding to +key+ from the configuration.
90
+ # * In the second form, if the key isn't found, invoke the
91
+ # * block and return its value.
92
+ # */
93
+
94
+ class RDoc::Parser::C < RDoc::Parser
95
+
96
+ parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
97
+
98
+ @@enclosure_classes = {}
99
+ @@known_bodies = {}
100
+
101
+ ##
102
+ # Prepare to parse a C file
103
+
104
+ def initialize(top_level, file_name, content, options, stats)
105
+ super
106
+
107
+ @known_classes = RDoc::KNOWN_CLASSES.dup
108
+ @content = handle_tab_width handle_ifdefs_in(@content)
109
+ @classes = Hash.new
110
+ @file_dir = File.dirname(@file_name)
111
+ end
112
+
113
+ def do_aliases
114
+ @content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do
115
+ |var_name, new_name, old_name|
116
+ class_name = @known_classes[var_name] || var_name
117
+ class_obj = find_class(var_name, class_name)
118
+
119
+ as = class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "")
120
+
121
+ @stats.add_alias as
122
+ end
123
+ end
124
+
125
+ def do_classes
126
+ @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do
127
+ |var_name, class_name|
128
+ handle_class_module(var_name, "module", class_name, nil, nil)
129
+ end
130
+
131
+ # The '.' lets us handle SWIG-generated files
132
+ @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s*
133
+ \(
134
+ \s*"(\w+)",
135
+ \s*(\w+)\s*
136
+ \)/mx) do |var_name, class_name, parent|
137
+ handle_class_module(var_name, "class", class_name, parent, nil)
138
+ end
139
+
140
+ @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
141
+ |var_name, class_name, parent|
142
+ parent = nil if parent == "0"
143
+ handle_class_module(var_name, "class", class_name, parent, nil)
144
+ end
145
+
146
+ @content.scan(/(\w+)\s* = \s*rb_define_module_under\s*
147
+ \(
148
+ \s*(\w+),
149
+ \s*"(\w+)"
150
+ \s*\)/mx) do |var_name, in_module, class_name|
151
+ handle_class_module(var_name, "module", class_name, nil, in_module)
152
+ end
153
+
154
+ @content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s*
155
+ \(
156
+ \s*(\w+),
157
+ \s*"(\w+)",
158
+ \s*(\w+)\s*
159
+ \s*\)/mx) do |var_name, in_module, class_name, parent|
160
+ handle_class_module(var_name, "class", class_name, parent, in_module)
161
+ end
162
+ end
163
+
164
+ def do_constants
165
+ @content.scan(%r{\Wrb_define_
166
+ (
167
+ variable |
168
+ readonly_variable |
169
+ const |
170
+ global_const |
171
+ )
172
+ \s*\(
173
+ (?:\s*(\w+),)?
174
+ \s*"(\w+)",
175
+ \s*(.*?)\s*\)\s*;
176
+ }xm) do |type, var_name, const_name, definition|
177
+ var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
178
+ handle_constants(type, var_name, const_name, definition)
179
+ end
180
+ end
181
+
182
+ ##
183
+ # Look for includes of the form:
184
+ #
185
+ # rb_include_module(rb_cArray, rb_mEnumerable);
186
+
187
+ def do_includes
188
+ @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
189
+ if cls = @classes[c]
190
+ m = @known_classes[m] || m
191
+ cls.add_include RDoc::Include.new(m, "")
192
+ end
193
+ end
194
+ end
195
+
196
+ def do_methods
197
+ @content.scan(%r{rb_define_
198
+ (
199
+ singleton_method |
200
+ method |
201
+ module_function |
202
+ private_method
203
+ )
204
+ \s*\(\s*([\w\.]+),
205
+ \s*"([^"]+)",
206
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
207
+ \s*(-?\w+)\s*\)
208
+ (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
209
+ }xm) do
210
+ |type, var_name, meth_name, meth_body, param_count, source_file|
211
+
212
+ # Ignore top-object and weird struct.c dynamic stuff
213
+ next if var_name == "ruby_top_self"
214
+ next if var_name == "nstr"
215
+ next if var_name == "envtbl"
216
+ next if var_name == "argf" # it'd be nice to handle this one
217
+
218
+ var_name = "rb_cObject" if var_name == "rb_mKernel"
219
+ handle_method(type, var_name, meth_name,
220
+ meth_body, param_count, source_file)
221
+ end
222
+
223
+ @content.scan(%r{rb_define_attr\(
224
+ \s*([\w\.]+),
225
+ \s*"([^"]+)",
226
+ \s*(\d+),
227
+ \s*(\d+)\s*\);
228
+ }xm) do |var_name, attr_name, attr_reader, attr_writer|
229
+ #var_name = "rb_cObject" if var_name == "rb_mKernel"
230
+ handle_attr(var_name, attr_name,
231
+ attr_reader.to_i != 0,
232
+ attr_writer.to_i != 0)
233
+ end
234
+
235
+ @content.scan(%r{rb_define_global_function\s*\(
236
+ \s*"([^"]+)",
237
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
238
+ \s*(-?\w+)\s*\)
239
+ (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
240
+ }xm) do |meth_name, meth_body, param_count, source_file|
241
+ handle_method("method", "rb_mKernel", meth_name,
242
+ meth_body, param_count, source_file)
243
+ end
244
+
245
+ @content.scan(/define_filetest_function\s*\(
246
+ \s*"([^"]+)",
247
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
248
+ \s*(-?\w+)\s*\)/xm) do
249
+ |meth_name, meth_body, param_count|
250
+
251
+ handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count)
252
+ handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count)
253
+ end
254
+ end
255
+
256
+ def find_attr_comment(attr_name)
257
+ if @content =~ %r{((?>/\*.*?\*/\s+))
258
+ rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi
259
+ $1
260
+ elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m
261
+ $1
262
+ else
263
+ ''
264
+ end
265
+ end
266
+
267
+ ##
268
+ # Find the C code corresponding to a Ruby method
269
+
270
+ def find_body(meth_name, meth_obj, body, quiet = false)
271
+ case body
272
+ when %r"((?>/\*.*?\*/\s*))(?:static\s+)?VALUE\s+#{meth_name}
273
+ \s*(\([^)]*\))\s*\{.*?^\}"xm
274
+ comment, params = $1, $2
275
+ body_text = $&
276
+
277
+ remove_private_comments(comment) if comment
278
+
279
+ # see if we can find the whole body
280
+
281
+ re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}'
282
+ if Regexp.new(re, Regexp::MULTILINE).match(body)
283
+ body_text = $&
284
+ end
285
+
286
+ # The comment block may have been overridden with a 'Document-method'
287
+ # block. This happens in the interpreter when multiple methods are
288
+ # vectored through to the same C method but those methods are logically
289
+ # distinct (for example Kernel.hash and Kernel.object_id share the same
290
+ # implementation
291
+
292
+ override_comment = find_override_comment(meth_obj.name)
293
+ comment = override_comment if override_comment
294
+
295
+ find_modifiers(comment, meth_obj) if comment
296
+
297
+ # meth_obj.params = params
298
+ meth_obj.start_collecting_tokens
299
+ meth_obj.add_token(RDoc::RubyToken::Token.new(1,1).set_text(body_text))
300
+ meth_obj.comment = mangle_comment(comment)
301
+ when %r{((?>/\*.*?\*/\s*))^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
302
+ comment = $1
303
+ find_body($2, meth_obj, body, true)
304
+ find_modifiers(comment, meth_obj)
305
+ meth_obj.comment = mangle_comment(comment) + meth_obj.comment
306
+ when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m
307
+ unless find_body($1, meth_obj, body, true)
308
+ warn "No definition for #{meth_name}" unless @options.quiet
309
+ return false
310
+ end
311
+ else
312
+
313
+ # No body, but might still have an override comment
314
+ comment = find_override_comment(meth_obj.name)
315
+
316
+ if comment
317
+ find_modifiers(comment, meth_obj)
318
+ meth_obj.comment = mangle_comment(comment)
319
+ else
320
+ warn "No definition for #{meth_name}" unless @options.quiet
321
+ return false
322
+ end
323
+ end
324
+ true
325
+ end
326
+
327
+ def find_class(raw_name, name)
328
+ unless @classes[raw_name]
329
+ if raw_name =~ /^rb_m/
330
+ container = @top_level.add_module RDoc::NormalModule, name
331
+ else
332
+ container = @top_level.add_class RDoc::NormalClass, name, nil
333
+ end
334
+
335
+ container.record_location @top_level
336
+ @classes[raw_name] = container
337
+ end
338
+ @classes[raw_name]
339
+ end
340
+
341
+ ##
342
+ # Look for class or module documentation above Init_+class_name+(void),
343
+ # in a Document-class +class_name+ (or module) comment or above an
344
+ # rb_define_class (or module). If a comment is supplied above a matching
345
+ # Init_ and a rb_define_class the Init_ comment is used.
346
+ #
347
+ # /*
348
+ # * This is a comment for Foo
349
+ # */
350
+ # Init_Foo(void) {
351
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
352
+ # }
353
+ #
354
+ # /*
355
+ # * Document-class: Foo
356
+ # * This is a comment for Foo
357
+ # */
358
+ # Init_foo(void) {
359
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
360
+ # }
361
+ #
362
+ # /*
363
+ # * This is a comment for Foo
364
+ # */
365
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
366
+
367
+ def find_class_comment(class_name, class_meth)
368
+ comment = nil
369
+ if @content =~ %r{((?>/\*.*?\*/\s+))
370
+ (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi
371
+ comment = $1
372
+ elsif @content =~ %r{Document-(class|module):\s#{class_name}\s*?\n((?>.*?\*/))}m
373
+ comment = $2
374
+ else
375
+ if @content =~ /rb_define_(class|module)/m then
376
+ class_name = class_name.split("::").last
377
+ comments = []
378
+ @content.split(/(\/\*.*?\*\/)\s*?\n/m).each_with_index do |chunk, index|
379
+ comments[index] = chunk
380
+ if chunk =~ /rb_define_(class|module).*?"(#{class_name})"/m then
381
+ comment = comments[index-1]
382
+ break
383
+ end
384
+ end
385
+ end
386
+ end
387
+ class_meth.comment = mangle_comment(comment) if comment
388
+ end
389
+
390
+ ##
391
+ # Finds a comment matching +type+ and +const_name+ either above the
392
+ # comment or in the matching Document- section.
393
+
394
+ def find_const_comment(type, const_name)
395
+ if @content =~ %r{((?>^\s*/\*.*?\*/\s+))
396
+ rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi
397
+ $1
398
+ elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m
399
+ $1
400
+ else
401
+ ''
402
+ end
403
+ end
404
+
405
+ ##
406
+ # If the comment block contains a section that looks like:
407
+ #
408
+ # call-seq:
409
+ # Array.new
410
+ # Array.new(10)
411
+ #
412
+ # use it for the parameters.
413
+
414
+ def find_modifiers(comment, meth_obj)
415
+ if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or
416
+ comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '')
417
+ meth_obj.document_self = false
418
+ end
419
+ if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or
420
+ comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '')
421
+ seq = $1
422
+ seq.gsub!(/^\s*\*\s*/, '')
423
+ meth_obj.call_seq = seq
424
+ end
425
+ end
426
+
427
+ def find_override_comment(meth_name)
428
+ name = Regexp.escape(meth_name)
429
+ if @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m
430
+ $1
431
+ end
432
+ end
433
+
434
+ def handle_attr(var_name, attr_name, reader, writer)
435
+ rw = ''
436
+ if reader
437
+ #@stats.num_methods += 1
438
+ rw << 'R'
439
+ end
440
+ if writer
441
+ #@stats.num_methods += 1
442
+ rw << 'W'
443
+ end
444
+
445
+ class_name = @known_classes[var_name]
446
+
447
+ return unless class_name
448
+
449
+ class_obj = find_class(var_name, class_name)
450
+
451
+ if class_obj
452
+ comment = find_attr_comment(attr_name)
453
+ unless comment.empty?
454
+ comment = mangle_comment(comment)
455
+ end
456
+ att = RDoc::Attr.new '', attr_name, rw, comment
457
+ class_obj.add_attribute(att)
458
+ end
459
+ end
460
+
461
+ def handle_class_module(var_name, class_mod, class_name, parent, in_module)
462
+ parent_name = @known_classes[parent] || parent
463
+
464
+ if in_module
465
+ enclosure = @classes[in_module] || @@enclosure_classes[in_module]
466
+ unless enclosure
467
+ if enclosure = @known_classes[in_module]
468
+ handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"),
469
+ enclosure, nil, nil)
470
+ enclosure = @classes[in_module]
471
+ end
472
+ end
473
+ unless enclosure
474
+ warn("Enclosing class/module '#{in_module}' for " +
475
+ "#{class_mod} #{class_name} not known")
476
+ return
477
+ end
478
+ else
479
+ enclosure = @top_level
480
+ end
481
+
482
+ if class_mod == "class" then
483
+ cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
484
+ @stats.add_class cm
485
+ else
486
+ cm = enclosure.add_module RDoc::NormalModule, class_name
487
+ @stats.add_module cm
488
+ end
489
+
490
+ cm.record_location(enclosure.toplevel)
491
+
492
+ find_class_comment(cm.full_name, cm)
493
+ @classes[var_name] = cm
494
+ @@enclosure_classes[var_name] = cm
495
+ @known_classes[var_name] = cm.full_name
496
+ end
497
+
498
+ ##
499
+ # Adds constant comments. By providing some_value: at the start ofthe
500
+ # comment you can override the C value of the comment to give a friendly
501
+ # definition.
502
+ #
503
+ # /* 300: The perfect score in bowling */
504
+ # rb_define_const(cFoo, "PERFECT", INT2FIX(300);
505
+ #
506
+ # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc.
507
+ # Values may include quotes and escaped colons (\:).
508
+
509
+ def handle_constants(type, var_name, const_name, definition)
510
+ #@stats.num_constants += 1
511
+ class_name = @known_classes[var_name]
512
+
513
+ return unless class_name
514
+
515
+ class_obj = find_class(var_name, class_name)
516
+
517
+ unless class_obj
518
+ warn("Enclosing class/module '#{const_name}' for not known")
519
+ return
520
+ end
521
+
522
+ comment = find_const_comment(type, const_name)
523
+
524
+ # In the case of rb_define_const, the definition and comment are in
525
+ # "/* definition: comment */" form. The literal ':' and '\' characters
526
+ # can be escaped with a backslash.
527
+ if type.downcase == 'const' then
528
+ elements = mangle_comment(comment).split(':')
529
+ if elements.nil? or elements.empty? then
530
+ con = RDoc::Constant.new(const_name, definition,
531
+ mangle_comment(comment))
532
+ else
533
+ new_definition = elements[0..-2].join(':')
534
+ if new_definition.empty? then # Default to literal C definition
535
+ new_definition = definition
536
+ else
537
+ new_definition.gsub!("\:", ":")
538
+ new_definition.gsub!("\\", '\\')
539
+ end
540
+ new_definition.sub!(/\A(\s+)/, '')
541
+ new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}"
542
+ con = RDoc::Constant.new(const_name, new_definition,
543
+ mangle_comment(new_comment))
544
+ end
545
+ else
546
+ con = RDoc::Constant.new const_name, definition, mangle_comment(comment)
547
+ end
548
+
549
+ class_obj.add_constant(con)
550
+ end
551
+
552
+ ##
553
+ # Removes #ifdefs that would otherwise confuse us
554
+
555
+ def handle_ifdefs_in(body)
556
+ body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
557
+ end
558
+
559
+ def handle_method(type, var_name, meth_name, meth_body, param_count,
560
+ source_file = nil)
561
+ class_name = @known_classes[var_name]
562
+
563
+ return unless class_name
564
+
565
+ class_obj = find_class(var_name, class_name)
566
+
567
+ if class_obj
568
+ if meth_name == "initialize"
569
+ meth_name = "new"
570
+ type = "singleton_method"
571
+ end
572
+ meth_obj = RDoc::AnyMethod.new("", meth_name)
573
+ meth_obj.singleton =
574
+ %w{singleton_method module_function}.include?(type)
575
+
576
+ @stats.add_method meth_obj
577
+
578
+ p_count = (Integer(param_count) rescue -1)
579
+
580
+ if p_count < 0
581
+ meth_obj.params = "(...)"
582
+ elsif p_count == 0
583
+ meth_obj.params = "()"
584
+ else
585
+ meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")"
586
+ end
587
+
588
+ if source_file
589
+ file_name = File.join(@file_dir, source_file)
590
+ body = (@@known_bodies[source_file] ||= File.read(file_name))
591
+ else
592
+ body = @content
593
+ end
594
+ if find_body(meth_body, meth_obj, body) and meth_obj.document_self
595
+ class_obj.add_method(meth_obj)
596
+ end
597
+ end
598
+ end
599
+
600
+ def handle_tab_width(body)
601
+ if /\t/ =~ body
602
+ tab_width = @options.tab_width
603
+ body.split(/\n/).map do |line|
604
+ 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
605
+ line
606
+ end .join("\n")
607
+ else
608
+ body
609
+ end
610
+ end
611
+
612
+ ##
613
+ # Remove the /*'s and leading asterisks from C comments
614
+
615
+ def mangle_comment(comment)
616
+ comment.sub!(%r{/\*+}) { " " * $&.length }
617
+ comment.sub!(%r{\*+/}) { " " * $&.length }
618
+ comment.gsub!(/^[ \t]*\*/m) { " " * $&.length }
619
+ comment
620
+ end
621
+
622
+ ##
623
+ # Removes lines that are commented out that might otherwise get picked up
624
+ # when scanning for classes and methods
625
+
626
+ def remove_commented_out_lines
627
+ @content.gsub!(%r{//.*rb_define_}, '//')
628
+ end
629
+
630
+ def remove_private_comments(comment)
631
+ comment.gsub!(/\/?\*--(.*?)\/?\*\+\+/m, '')
632
+ comment.sub!(/\/?\*--.*/m, '')
633
+ end
634
+
635
+ ##
636
+ # Extract the classes/modules and methods from a C file and return the
637
+ # corresponding top-level object
638
+
639
+ def scan
640
+ remove_commented_out_lines
641
+ do_classes
642
+ do_constants
643
+ do_methods
644
+ do_includes
645
+ do_aliases
646
+ @top_level
647
+ end
648
+
649
+ def warn(msg)
650
+ $stderr.puts
651
+ $stderr.puts msg
652
+ $stderr.flush
653
+ end
654
+
655
+ end
656
+