voloko-sdoc 0.1.2 → 0.1.3

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