gitlab-rdoc 6.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.rdoc +220 -0
  3. data/CVE-2013-0256.rdoc +49 -0
  4. data/ExampleMarkdown.md +37 -0
  5. data/ExampleRDoc.rdoc +208 -0
  6. data/Gemfile +12 -0
  7. data/History.rdoc +1666 -0
  8. data/LEGAL.rdoc +50 -0
  9. data/LICENSE.rdoc +57 -0
  10. data/README.rdoc +133 -0
  11. data/RI.rdoc +57 -0
  12. data/Rakefile +101 -0
  13. data/TODO.rdoc +59 -0
  14. data/bin/console +7 -0
  15. data/bin/setup +6 -0
  16. data/exe/rdoc +44 -0
  17. data/exe/ri +12 -0
  18. data/lib/rdoc/alias.rb +112 -0
  19. data/lib/rdoc/anon_class.rb +11 -0
  20. data/lib/rdoc/any_method.rb +361 -0
  21. data/lib/rdoc/attr.rb +176 -0
  22. data/lib/rdoc/class_module.rb +802 -0
  23. data/lib/rdoc/code_object.rb +421 -0
  24. data/lib/rdoc/code_objects.rb +6 -0
  25. data/lib/rdoc/comment.rb +250 -0
  26. data/lib/rdoc/constant.rb +187 -0
  27. data/lib/rdoc/context/section.rb +232 -0
  28. data/lib/rdoc/context.rb +1266 -0
  29. data/lib/rdoc/cross_reference.rb +202 -0
  30. data/lib/rdoc/encoding.rb +136 -0
  31. data/lib/rdoc/erb_partial.rb +19 -0
  32. data/lib/rdoc/erbio.rb +42 -0
  33. data/lib/rdoc/extend.rb +10 -0
  34. data/lib/rdoc/generator/darkfish.rb +790 -0
  35. data/lib/rdoc/generator/json_index.rb +300 -0
  36. data/lib/rdoc/generator/markup.rb +160 -0
  37. data/lib/rdoc/generator/pot/message_extractor.rb +68 -0
  38. data/lib/rdoc/generator/pot/po.rb +84 -0
  39. data/lib/rdoc/generator/pot/po_entry.rb +141 -0
  40. data/lib/rdoc/generator/pot.rb +98 -0
  41. data/lib/rdoc/generator/ri.rb +31 -0
  42. data/lib/rdoc/generator/template/darkfish/.document +0 -0
  43. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +5 -0
  44. data/lib/rdoc/generator/template/darkfish/_head.rhtml +22 -0
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +19 -0
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +9 -0
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +15 -0
  48. data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +9 -0
  49. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +15 -0
  50. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +15 -0
  51. data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +12 -0
  52. data/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml +11 -0
  53. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +12 -0
  54. data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +11 -0
  55. data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +14 -0
  56. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +11 -0
  57. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +18 -0
  58. data/lib/rdoc/generator/template/darkfish/class.rhtml +172 -0
  59. data/lib/rdoc/generator/template/darkfish/css/fonts.css +167 -0
  60. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +639 -0
  61. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf +0 -0
  62. data/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf +0 -0
  63. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf +0 -0
  64. data/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf +0 -0
  65. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
  66. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
  67. data/lib/rdoc/generator/template/darkfish/images/add.png +0 -0
  68. data/lib/rdoc/generator/template/darkfish/images/arrow_up.png +0 -0
  69. data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
  70. data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
  71. data/lib/rdoc/generator/template/darkfish/images/bug.png +0 -0
  72. data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
  73. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
  74. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
  75. data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
  76. data/lib/rdoc/generator/template/darkfish/images/delete.png +0 -0
  77. data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
  78. data/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif +0 -0
  79. data/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png +0 -0
  80. data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
  81. data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
  82. data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
  83. data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
  84. data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
  85. data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
  86. data/lib/rdoc/generator/template/darkfish/images/tag_blue.png +0 -0
  87. data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
  88. data/lib/rdoc/generator/template/darkfish/images/transparent.png +0 -0
  89. data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
  90. data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
  91. data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
  92. data/lib/rdoc/generator/template/darkfish/index.rhtml +22 -0
  93. data/lib/rdoc/generator/template/darkfish/js/darkfish.js +84 -0
  94. data/lib/rdoc/generator/template/darkfish/js/search.js +110 -0
  95. data/lib/rdoc/generator/template/darkfish/page.rhtml +18 -0
  96. data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +18 -0
  97. data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +62 -0
  98. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +58 -0
  99. data/lib/rdoc/generator/template/json_index/.document +1 -0
  100. data/lib/rdoc/generator/template/json_index/js/navigation.js +105 -0
  101. data/lib/rdoc/generator/template/json_index/js/searcher.js +229 -0
  102. data/lib/rdoc/generator.rb +51 -0
  103. data/lib/rdoc/ghost_method.rb +7 -0
  104. data/lib/rdoc/i18n/locale.rb +102 -0
  105. data/lib/rdoc/i18n/text.rb +126 -0
  106. data/lib/rdoc/i18n.rb +10 -0
  107. data/lib/rdoc/include.rb +10 -0
  108. data/lib/rdoc/known_classes.rb +73 -0
  109. data/lib/rdoc/markdown/entities.rb +2132 -0
  110. data/lib/rdoc/markdown/literals.kpeg +23 -0
  111. data/lib/rdoc/markdown/literals.rb +417 -0
  112. data/lib/rdoc/markdown.kpeg +1237 -0
  113. data/lib/rdoc/markdown.rb +16685 -0
  114. data/lib/rdoc/markup/attr_changer.rb +23 -0
  115. data/lib/rdoc/markup/attr_span.rb +36 -0
  116. data/lib/rdoc/markup/attribute_manager.rb +409 -0
  117. data/lib/rdoc/markup/attributes.rb +71 -0
  118. data/lib/rdoc/markup/blank_line.rb +28 -0
  119. data/lib/rdoc/markup/block_quote.rb +15 -0
  120. data/lib/rdoc/markup/document.rb +165 -0
  121. data/lib/rdoc/markup/formatter.rb +266 -0
  122. data/lib/rdoc/markup/hard_break.rb +32 -0
  123. data/lib/rdoc/markup/heading.rb +79 -0
  124. data/lib/rdoc/markup/include.rb +43 -0
  125. data/lib/rdoc/markup/indented_paragraph.rb +48 -0
  126. data/lib/rdoc/markup/list.rb +102 -0
  127. data/lib/rdoc/markup/list_item.rb +100 -0
  128. data/lib/rdoc/markup/paragraph.rb +29 -0
  129. data/lib/rdoc/markup/parser.rb +575 -0
  130. data/lib/rdoc/markup/pre_process.rb +296 -0
  131. data/lib/rdoc/markup/raw.rb +70 -0
  132. data/lib/rdoc/markup/regexp_handling.rb +41 -0
  133. data/lib/rdoc/markup/rule.rb +21 -0
  134. data/lib/rdoc/markup/table.rb +47 -0
  135. data/lib/rdoc/markup/to_ansi.rb +94 -0
  136. data/lib/rdoc/markup/to_bs.rb +77 -0
  137. data/lib/rdoc/markup/to_html.rb +444 -0
  138. data/lib/rdoc/markup/to_html_crossref.rb +176 -0
  139. data/lib/rdoc/markup/to_html_snippet.rb +285 -0
  140. data/lib/rdoc/markup/to_joined_paragraph.rb +47 -0
  141. data/lib/rdoc/markup/to_label.rb +75 -0
  142. data/lib/rdoc/markup/to_markdown.rb +192 -0
  143. data/lib/rdoc/markup/to_rdoc.rb +362 -0
  144. data/lib/rdoc/markup/to_table_of_contents.rb +89 -0
  145. data/lib/rdoc/markup/to_test.rb +70 -0
  146. data/lib/rdoc/markup/to_tt_only.rb +121 -0
  147. data/lib/rdoc/markup/verbatim.rb +84 -0
  148. data/lib/rdoc/markup.rb +867 -0
  149. data/lib/rdoc/meta_method.rb +7 -0
  150. data/lib/rdoc/method_attr.rb +419 -0
  151. data/lib/rdoc/mixin.rb +121 -0
  152. data/lib/rdoc/normal_class.rb +93 -0
  153. data/lib/rdoc/normal_module.rb +74 -0
  154. data/lib/rdoc/options.rb +1285 -0
  155. data/lib/rdoc/parser/c.rb +1225 -0
  156. data/lib/rdoc/parser/changelog.rb +335 -0
  157. data/lib/rdoc/parser/markdown.rb +24 -0
  158. data/lib/rdoc/parser/rd.rb +23 -0
  159. data/lib/rdoc/parser/ripper_state_lex.rb +590 -0
  160. data/lib/rdoc/parser/ruby.rb +2327 -0
  161. data/lib/rdoc/parser/ruby_tools.rb +167 -0
  162. data/lib/rdoc/parser/simple.rb +61 -0
  163. data/lib/rdoc/parser/text.rb +12 -0
  164. data/lib/rdoc/parser.rb +277 -0
  165. data/lib/rdoc/rd/block_parser.rb +1056 -0
  166. data/lib/rdoc/rd/block_parser.ry +639 -0
  167. data/lib/rdoc/rd/inline.rb +72 -0
  168. data/lib/rdoc/rd/inline_parser.rb +1208 -0
  169. data/lib/rdoc/rd/inline_parser.ry +593 -0
  170. data/lib/rdoc/rd.rb +100 -0
  171. data/lib/rdoc/rdoc.rb +579 -0
  172. data/lib/rdoc/require.rb +52 -0
  173. data/lib/rdoc/ri/driver.rb +1572 -0
  174. data/lib/rdoc/ri/formatter.rb +6 -0
  175. data/lib/rdoc/ri/paths.rb +171 -0
  176. data/lib/rdoc/ri/store.rb +7 -0
  177. data/lib/rdoc/ri/task.rb +71 -0
  178. data/lib/rdoc/ri.rb +21 -0
  179. data/lib/rdoc/rubygems_hook.rb +246 -0
  180. data/lib/rdoc/servlet.rb +451 -0
  181. data/lib/rdoc/single_class.rb +26 -0
  182. data/lib/rdoc/stats/normal.rb +58 -0
  183. data/lib/rdoc/stats/quiet.rb +60 -0
  184. data/lib/rdoc/stats/verbose.rb +46 -0
  185. data/lib/rdoc/stats.rb +462 -0
  186. data/lib/rdoc/store.rb +979 -0
  187. data/lib/rdoc/task.rb +329 -0
  188. data/lib/rdoc/text.rb +304 -0
  189. data/lib/rdoc/token_stream.rb +119 -0
  190. data/lib/rdoc/tom_doc.rb +263 -0
  191. data/lib/rdoc/top_level.rb +289 -0
  192. data/lib/rdoc/version.rb +8 -0
  193. data/lib/rdoc.rb +201 -0
  194. data/man/ri.1 +247 -0
  195. data/rdoc.gemspec +249 -0
  196. metadata +279 -0
@@ -0,0 +1,1225 @@
1
+ # frozen_string_literal: true
2
+ require 'tsort'
3
+
4
+ ##
5
+ # RDoc::Parser::C attempts to parse C extension files. It looks for
6
+ # the standard patterns that you find in extensions: +rb_define_class+,
7
+ # +rb_define_method+ and so on. It tries 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
+ # +rb_define_method+ 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(VALUE ary)
28
+ # {
29
+ # ary = rb_obj_dup(ary);
30
+ # rb_ary_flatten_bang(ary);
31
+ # return ary;
32
+ # }
33
+ #
34
+ # ...
35
+ #
36
+ # void
37
+ # Init_Array(void)
38
+ # {
39
+ # ...
40
+ # rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
41
+ #
42
+ # Here RDoc will determine from the +rb_define_method+ line that there's a
43
+ # method called "flatten" in class Array, and will look for the implementation
44
+ # in the method +rb_ary_flatten+. It will then use the comment from that
45
+ # method in the HTML output. This method must be in the same source file
46
+ # as the +rb_define_method+.
47
+ #
48
+ # The comment blocks may include special directives:
49
+ #
50
+ # [Document-class: +name+]
51
+ # Documentation for the named class.
52
+ #
53
+ # [Document-module: +name+]
54
+ # Documentation for the named module.
55
+ #
56
+ # [Document-const: +name+]
57
+ # Documentation for the named +rb_define_const+.
58
+ #
59
+ # Constant values can be supplied on the first line of the comment like so:
60
+ #
61
+ # /* 300: The highest possible score in bowling */
62
+ # rb_define_const(cFoo, "PERFECT", INT2FIX(300));
63
+ #
64
+ # The value can contain internal colons so long as they are escaped with a \
65
+ #
66
+ # [Document-global: +name+]
67
+ # Documentation for the named +rb_define_global_const+
68
+ #
69
+ # [Document-variable: +name+]
70
+ # Documentation for the named +rb_define_variable+
71
+ #
72
+ # [Document-method\: +method_name+]
73
+ # Documentation for the named method. Use this when the method name is
74
+ # unambiguous.
75
+ #
76
+ # [Document-method\: <tt>ClassName::method_name</tt>]
77
+ # Documentation for a singleton method in the given class. Use this when
78
+ # the method name alone is ambiguous.
79
+ #
80
+ # [Document-method\: <tt>ClassName#method_name</tt>]
81
+ # Documentation for a instance method in the given class. Use this when the
82
+ # method name alone is ambiguous.
83
+ #
84
+ # [Document-attr: +name+]
85
+ # Documentation for the named attribute.
86
+ #
87
+ # [call-seq: <i>text up to an empty line</i>]
88
+ # Because C source doesn't give descriptive names to Ruby-level parameters,
89
+ # you need to document the calling sequence explicitly
90
+ #
91
+ # In addition, RDoc assumes by default that the C method implementing a
92
+ # Ruby function is in the same source file as the rb_define_method call.
93
+ # If this isn't the case, add the comment:
94
+ #
95
+ # rb_define_method(....); // in filename
96
+ #
97
+ # As an example, we might have an extension that defines multiple classes
98
+ # in its Init_xxx method. We could document them using
99
+ #
100
+ # /*
101
+ # * Document-class: MyClass
102
+ # *
103
+ # * Encapsulate the writing and reading of the configuration
104
+ # * file. ...
105
+ # */
106
+ #
107
+ # /*
108
+ # * Document-method: read_value
109
+ # *
110
+ # * call-seq:
111
+ # * cfg.read_value(key) -> value
112
+ # * cfg.read_value(key} { |key| } -> value
113
+ # *
114
+ # * Return the value corresponding to +key+ from the configuration.
115
+ # * In the second form, if the key isn't found, invoke the
116
+ # * block and return its value.
117
+ # */
118
+
119
+ class RDoc::Parser::C < RDoc::Parser
120
+
121
+ parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/)
122
+
123
+ include RDoc::Text
124
+
125
+ ##
126
+ # Maps C variable names to names of Ruby classes or modules
127
+
128
+ attr_reader :classes
129
+
130
+ ##
131
+ # C file the parser is parsing
132
+
133
+ attr_accessor :content
134
+
135
+ ##
136
+ # Dependencies from a missing enclosing class to the classes in
137
+ # missing_dependencies that depend upon it.
138
+
139
+ attr_reader :enclosure_dependencies
140
+
141
+ ##
142
+ # Maps C variable names to names of Ruby classes (and singleton classes)
143
+
144
+ attr_reader :known_classes
145
+
146
+ ##
147
+ # Classes found while parsing the C file that were not yet registered due to
148
+ # a missing enclosing class. These are processed by do_missing
149
+
150
+ attr_reader :missing_dependencies
151
+
152
+ ##
153
+ # Maps C variable names to names of Ruby singleton classes
154
+
155
+ attr_reader :singleton_classes
156
+
157
+ ##
158
+ # The TopLevel items in the parsed file belong to
159
+
160
+ attr_reader :top_level
161
+
162
+ ##
163
+ # Prepares for parsing a C file. See RDoc::Parser#initialize for details on
164
+ # the arguments.
165
+
166
+ def initialize top_level, file_name, content, options, stats
167
+ super
168
+
169
+ @known_classes = RDoc::KNOWN_CLASSES.dup
170
+ @content = handle_tab_width handle_ifdefs_in @content
171
+ @file_dir = File.dirname @file_name
172
+
173
+ @classes = load_variable_map :c_class_variables
174
+ @singleton_classes = load_variable_map :c_singleton_class_variables
175
+
176
+ # class_variable => { function => [method, ...] }
177
+ @methods = Hash.new { |h, f| h[f] = Hash.new { |i, m| i[m] = [] } }
178
+
179
+ # missing variable => [handle_class_module arguments]
180
+ @missing_dependencies = {}
181
+
182
+ # missing enclosure variable => [dependent handle_class_module arguments]
183
+ @enclosure_dependencies = Hash.new { |h, k| h[k] = [] }
184
+ @enclosure_dependencies.instance_variable_set :@missing_dependencies,
185
+ @missing_dependencies
186
+
187
+ @enclosure_dependencies.extend TSort
188
+
189
+ def @enclosure_dependencies.tsort_each_node &block
190
+ each_key(&block)
191
+ rescue TSort::Cyclic => e
192
+ cycle_vars = e.message.scan(/"(.*?)"/).flatten
193
+
194
+ cycle = cycle_vars.sort.map do |var_name|
195
+ delete var_name
196
+
197
+ var_name, type, mod_name, = @missing_dependencies[var_name]
198
+
199
+ "#{type} #{mod_name} (#{var_name})"
200
+ end.join ', '
201
+
202
+ warn "Unable to create #{cycle} due to a cyclic class or module creation"
203
+
204
+ retry
205
+ end
206
+
207
+ def @enclosure_dependencies.tsort_each_child node, &block
208
+ fetch(node, []).each(&block)
209
+ end
210
+ end
211
+
212
+ ##
213
+ # Scans #content for rb_define_alias
214
+
215
+ def do_aliases
216
+ @content.scan(/rb_define_alias\s*\(
217
+ \s*(\w+),
218
+ \s*"(.+?)",
219
+ \s*"(.+?)"
220
+ \s*\)/xm) do |var_name, new_name, old_name|
221
+ class_name = @known_classes[var_name]
222
+
223
+ unless class_name then
224
+ @options.warn "Enclosing class or module %p for alias %s %s is not known" % [
225
+ var_name, new_name, old_name]
226
+ next
227
+ end
228
+
229
+ class_obj = find_class var_name, class_name
230
+ comment = find_alias_comment var_name, new_name, old_name
231
+ comment.normalize
232
+ if comment.to_s.empty? and existing_method = class_obj.method_list.find { |m| m.name == old_name}
233
+ comment = existing_method.comment
234
+ end
235
+ add_alias(var_name, class_obj, old_name, new_name, comment)
236
+ end
237
+ end
238
+
239
+ ##
240
+ # Add alias, either from a direct alias definition, or from two
241
+ # method that reference the same function.
242
+
243
+ def add_alias(var_name, class_obj, old_name, new_name, comment)
244
+ al = RDoc::Alias.new '', old_name, new_name, ''
245
+ al.singleton = @singleton_classes.key? var_name
246
+ al.comment = comment
247
+ al.record_location @top_level
248
+ class_obj.add_alias al
249
+ @stats.add_alias al
250
+ al
251
+ end
252
+
253
+ ##
254
+ # Scans #content for rb_attr and rb_define_attr
255
+
256
+ def do_attrs
257
+ @content.scan(/rb_attr\s*\(
258
+ \s*(\w+),
259
+ \s*([\w"()]+),
260
+ \s*([01]),
261
+ \s*([01]),
262
+ \s*\w+\);/xm) do |var_name, attr_name, read, write|
263
+ handle_attr var_name, attr_name, read, write
264
+ end
265
+
266
+ @content.scan(%r%rb_define_attr\(
267
+ \s*([\w\.]+),
268
+ \s*"([^"]+)",
269
+ \s*(\d+),
270
+ \s*(\d+)\s*\);
271
+ %xm) do |var_name, attr_name, read, write|
272
+ handle_attr var_name, attr_name, read, write
273
+ end
274
+ end
275
+
276
+ ##
277
+ # Scans #content for boot_defclass
278
+
279
+ def do_boot_defclass
280
+ @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do
281
+ |var_name, class_name, parent|
282
+ parent = nil if parent == "0"
283
+ handle_class_module(var_name, :class, class_name, parent, nil)
284
+ end
285
+ end
286
+
287
+ ##
288
+ # Scans #content for rb_define_class, boot_defclass, rb_define_class_under
289
+ # and rb_singleton_class
290
+
291
+ def do_classes_and_modules
292
+ do_boot_defclass if @file_name == "class.c"
293
+
294
+ @content.scan(
295
+ %r(
296
+ (?<var_name>[\w\.]+)\s* =
297
+ \s*rb_(?:
298
+ define_(?:
299
+ class(?: # rb_define_class(class_name_1, parent_name_1)
300
+ \s*\(
301
+ \s*"(?<class_name_1>\w+)",
302
+ \s*(?<parent_name_1>\w+)\s*
303
+ \)
304
+ |
305
+ _under\s*\( # rb_define_class_under(class_under, class_name2, parent_name2...)
306
+ \s* (?<class_under>\w+),
307
+ \s* "(?<class_name_2>\w+)",
308
+ \s*
309
+ (?:
310
+ (?<parent_name_2>[\w\*\s\(\)\.\->]+) |
311
+ rb_path2class\("(?<path>[\w:]+)"\)
312
+ )
313
+ \s*\)
314
+ )
315
+ |
316
+ module(?: # rb_define_module(module_name_1)
317
+ \s*\(
318
+ \s*"(?<module_name_1>\w+)"\s*
319
+ \)
320
+ |
321
+ _under\s*\( # rb_define_module_under(module_under, module_name_2)
322
+ \s*(?<module_under>\w+),
323
+ \s*"(?<module_name_2>\w+)"
324
+ \s*\)
325
+ )
326
+ )
327
+ |
328
+ struct_define_without_accessor\s*\( # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...)
329
+ \s*"(?<class_name_3>\w+)",
330
+ \s*(?<parent_name_3>\w+),
331
+ \s*\w+, # Allocation function
332
+ (?:\s*"\w+",)* # Attributes
333
+ \s*NULL
334
+ \)
335
+ |
336
+ singleton_class\s*\( # rb_singleton_class(target_class_name)
337
+ \s*(?<target_class_name>\w+)
338
+ \)
339
+ )
340
+ )mx
341
+ ) do
342
+ class_name = $~[:class_name_1]
343
+ type = :class
344
+ if class_name
345
+ # rb_define_class(class_name_1, parent_name_1)
346
+ parent_name = $~[:parent_name_1]
347
+ #under = nil
348
+ else
349
+ class_name = $~[:class_name_2]
350
+ if class_name
351
+ # rb_define_class_under(class_under, class_name2, parent_name2...)
352
+ parent_name = $~[:parent_name_2] || $~[:path]
353
+ under = $~[:class_under]
354
+ else
355
+ class_name = $~[:class_name_3]
356
+ if class_name
357
+ # rb_struct_define_without_accessor(class_name_3, parent_name_3, ...)
358
+ parent_name = $~[:parent_name_3]
359
+ #under = nil
360
+ else
361
+ type = :module
362
+ class_name = $~[:module_name_1]
363
+ #parent_name = nil
364
+ if class_name
365
+ # rb_define_module(module_name_1)
366
+ #under = nil
367
+ else
368
+ class_name = $~[:module_name_2]
369
+ if class_name
370
+ # rb_define_module_under(module_under, module_name_1)
371
+ under = $~[:module_under]
372
+ else
373
+ # rb_singleton_class(target_class_name)
374
+ target_class_name = $~[:target_class_name]
375
+ handle_singleton $~[:var_name], target_class_name
376
+ next
377
+ end
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ handle_class_module($~[:var_name], type, class_name, parent_name, under)
384
+ end
385
+ end
386
+
387
+ ##
388
+ # Scans #content for rb_define_variable, rb_define_readonly_variable,
389
+ # rb_define_const and rb_define_global_const
390
+
391
+ def do_constants
392
+ @content.scan(%r%\Wrb_define_
393
+ ( variable |
394
+ readonly_variable |
395
+ const |
396
+ global_const )
397
+ \s*\(
398
+ (?:\s*(\w+),)?
399
+ \s*"(\w+)",
400
+ \s*(.*?)\s*\)\s*;
401
+ %xm) do |type, var_name, const_name, definition|
402
+ var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel"
403
+ handle_constants type, var_name, const_name, definition
404
+ end
405
+
406
+ @content.scan(%r%
407
+ \Wrb_curses_define_const
408
+ \s*\(
409
+ \s*
410
+ (\w+)
411
+ \s*
412
+ \)
413
+ \s*;%xm) do |consts|
414
+ const = consts.first
415
+
416
+ handle_constants 'const', 'mCurses', const, "UINT2NUM(#{const})"
417
+ end
418
+
419
+ @content.scan(%r%
420
+ \Wrb_file_const
421
+ \s*\(
422
+ \s*
423
+ "([^"]+)",
424
+ \s*
425
+ (.*?)
426
+ \s*
427
+ \)
428
+ \s*;%xm) do |name, value|
429
+ handle_constants 'const', 'rb_mFConst', name, value
430
+ end
431
+ end
432
+
433
+
434
+ ##
435
+ # Scans #content for rb_include_module
436
+
437
+ def do_includes
438
+ @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
439
+ next unless cls = @classes[c]
440
+ m = @known_classes[m] || m
441
+
442
+ comment = RDoc::Comment.new '', @top_level, :c
443
+ incl = cls.add_include RDoc::Include.new(m, comment)
444
+ incl.record_location @top_level
445
+ end
446
+ end
447
+
448
+ ##
449
+ # Scans #content for rb_define_method, rb_define_singleton_method,
450
+ # rb_define_module_function, rb_define_private_method,
451
+ # rb_define_global_function and define_filetest_function
452
+
453
+ def do_methods
454
+ @content.scan(%r%rb_define_
455
+ (
456
+ singleton_method |
457
+ method |
458
+ module_function |
459
+ private_method
460
+ )
461
+ \s*\(\s*([\w\.]+),
462
+ \s*"([^"]+)",
463
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(METHOD\))?(\w+)\)?,
464
+ \s*(-?\w+)\s*\)
465
+ (?:;\s*/[*/]\s+in\s+(\w+?\.(?:cpp|c|y)))?
466
+ %xm) do |type, var_name, meth_name, function, param_count, source_file|
467
+
468
+ # Ignore top-object and weird struct.c dynamic stuff
469
+ next if var_name == "ruby_top_self"
470
+ next if var_name == "nstr"
471
+
472
+ var_name = "rb_cObject" if var_name == "rb_mKernel"
473
+ handle_method(type, var_name, meth_name, function, param_count,
474
+ source_file)
475
+ end
476
+
477
+ @content.scan(%r%rb_define_global_function\s*\(
478
+ \s*"([^"]+)",
479
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
480
+ \s*(-?\w+)\s*\)
481
+ (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))?
482
+ %xm) do |meth_name, function, param_count, source_file|
483
+ handle_method("method", "rb_mKernel", meth_name, function, param_count,
484
+ source_file)
485
+ end
486
+
487
+ @content.scan(/define_filetest_function\s*\(
488
+ \s*"([^"]+)",
489
+ \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?,
490
+ \s*(-?\w+)\s*\)/xm) do |meth_name, function, param_count|
491
+
492
+ handle_method("method", "rb_mFileTest", meth_name, function, param_count)
493
+ handle_method("singleton_method", "rb_cFile", meth_name, function,
494
+ param_count)
495
+ end
496
+ end
497
+
498
+ ##
499
+ # Creates classes and module that were missing were defined due to the file
500
+ # order being different than the declaration order.
501
+
502
+ def do_missing
503
+ return if @missing_dependencies.empty?
504
+
505
+ @enclosure_dependencies.tsort.each do |in_module|
506
+ arguments = @missing_dependencies.delete in_module
507
+
508
+ next unless arguments # dependency on existing class
509
+
510
+ handle_class_module(*arguments)
511
+ end
512
+ end
513
+
514
+ ##
515
+ # Finds the comment for an alias on +class_name+ from +new_name+ to
516
+ # +old_name+
517
+
518
+ def find_alias_comment class_name, new_name, old_name
519
+ content =~ %r%((?>/\*.*?\*/\s+))
520
+ rb_define_alias\(\s*#{Regexp.escape class_name}\s*,
521
+ \s*"#{Regexp.escape new_name}"\s*,
522
+ \s*"#{Regexp.escape old_name}"\s*\);%xm
523
+
524
+ RDoc::Comment.new($1 || '', @top_level, :c)
525
+ end
526
+
527
+ ##
528
+ # Finds a comment for rb_define_attr, rb_attr or Document-attr.
529
+ #
530
+ # +var_name+ is the C class variable the attribute is defined on.
531
+ # +attr_name+ is the attribute's name.
532
+ #
533
+ # +read+ and +write+ are the read/write flags ('1' or '0'). Either both or
534
+ # neither must be provided.
535
+
536
+ def find_attr_comment var_name, attr_name, read = nil, write = nil
537
+ attr_name = Regexp.escape attr_name
538
+
539
+ rw = if read and write then
540
+ /\s*#{read}\s*,\s*#{write}\s*/xm
541
+ else
542
+ /.*?/m
543
+ end
544
+
545
+ comment = if @content =~ %r%((?>/\*.*?\*/\s+))
546
+ rb_define_attr\((?:\s*#{var_name},)?\s*
547
+ "#{attr_name}"\s*,
548
+ #{rw}\)\s*;%xm then
549
+ $1
550
+ elsif @content =~ %r%((?>/\*.*?\*/\s+))
551
+ rb_attr\(\s*#{var_name}\s*,
552
+ \s*#{attr_name}\s*,
553
+ #{rw},.*?\)\s*;%xm then
554
+ $1
555
+ elsif @content =~ %r%(/\*.*?(?:\s*\*\s*)?)
556
+ Document-attr:\s#{attr_name}\s*?\n
557
+ ((?>(.|\n)*?\*/))%x then
558
+ "#{$1}\n#{$2}"
559
+ else
560
+ ''
561
+ end
562
+
563
+ RDoc::Comment.new comment, @top_level, :c
564
+ end
565
+
566
+ ##
567
+ # Generate a Ruby-method table
568
+
569
+ def gen_body_table file_content
570
+ table = {}
571
+ file_content.scan(%r{
572
+ ((?>/\*.*?\*/\s*)?)
573
+ ((?:(?:\w+)\s+)?
574
+ (?:intern\s+)?VALUE\s+(\w+)
575
+ \s*(?:\([^)]*\))(?:[^\);]|$))
576
+ | ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+))
577
+ | ^\s*\#\s*define\s+(\w+)\s+(\w+)
578
+ }xm) do
579
+ case
580
+ when $1
581
+ table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def
582
+ when $4
583
+ table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias
584
+ when $8
585
+ table[$8] ||= [:macro_alias, $9]
586
+ end
587
+ end
588
+ table
589
+ end
590
+
591
+ ##
592
+ # Find the C code corresponding to a Ruby method
593
+
594
+ def find_body class_name, meth_name, meth_obj, file_content, quiet = false
595
+ if file_content
596
+ @body_table ||= {}
597
+ @body_table[file_content] ||= gen_body_table file_content
598
+ type, *args = @body_table[file_content][meth_name]
599
+ end
600
+
601
+ case type
602
+ when :func_def
603
+ comment = RDoc::Comment.new args[0], @top_level, :c
604
+ body = args[1]
605
+ offset, = args[2]
606
+
607
+ comment.remove_private if comment
608
+
609
+ # try to find the whole body
610
+ body = $& if /#{Regexp.escape body}[^(]*?\{.*?^\}/m =~ file_content
611
+
612
+ # The comment block may have been overridden with a 'Document-method'
613
+ # block. This happens in the interpreter when multiple methods are
614
+ # vectored through to the same C method but those methods are logically
615
+ # distinct (for example Kernel.hash and Kernel.object_id share the same
616
+ # implementation
617
+
618
+ override_comment = find_override_comment class_name, meth_obj
619
+ comment = override_comment if override_comment
620
+
621
+ comment.normalize
622
+ find_modifiers comment, meth_obj if comment
623
+
624
+ #meth_obj.params = params
625
+ meth_obj.start_collecting_tokens
626
+ tk = { :line_no => 1, :char_no => 1, :text => body }
627
+ meth_obj.add_token tk
628
+ meth_obj.comment = comment
629
+ meth_obj.line = file_content[0, offset].count("\n") + 1
630
+
631
+ body
632
+ when :macro_def
633
+ comment = RDoc::Comment.new args[0], @top_level, :c
634
+ body = args[1]
635
+ offset, = args[2]
636
+
637
+ find_body class_name, args[3], meth_obj, file_content, true
638
+
639
+ comment.normalize
640
+ find_modifiers comment, meth_obj
641
+
642
+ meth_obj.start_collecting_tokens
643
+ tk = { :line_no => 1, :char_no => 1, :text => body }
644
+ meth_obj.add_token tk
645
+ meth_obj.comment = comment
646
+ meth_obj.line = file_content[0, offset].count("\n") + 1
647
+
648
+ body
649
+ when :macro_alias
650
+ # with no comment we hope the aliased definition has it and use it's
651
+ # definition
652
+
653
+ body = find_body(class_name, args[0], meth_obj, file_content, true)
654
+
655
+ return body if body
656
+
657
+ @options.warn "No definition for #{meth_name}"
658
+ false
659
+ else # No body, but might still have an override comment
660
+ comment = find_override_comment class_name, meth_obj
661
+
662
+ if comment then
663
+ comment.normalize
664
+ find_modifiers comment, meth_obj
665
+ meth_obj.comment = comment
666
+
667
+ ''
668
+ else
669
+ @options.warn "No definition for #{meth_name}"
670
+ false
671
+ end
672
+ end
673
+ end
674
+
675
+ ##
676
+ # Finds a RDoc::NormalClass or RDoc::NormalModule for +raw_name+
677
+
678
+ def find_class(raw_name, name)
679
+ unless @classes[raw_name]
680
+ if raw_name =~ /^rb_m/
681
+ container = @top_level.add_module RDoc::NormalModule, name
682
+ else
683
+ container = @top_level.add_class RDoc::NormalClass, name
684
+ end
685
+
686
+ container.record_location @top_level
687
+ @classes[raw_name] = container
688
+ end
689
+ @classes[raw_name]
690
+ end
691
+
692
+ ##
693
+ # Look for class or module documentation above Init_+class_name+(void),
694
+ # in a Document-class +class_name+ (or module) comment or above an
695
+ # rb_define_class (or module). If a comment is supplied above a matching
696
+ # Init_ and a rb_define_class the Init_ comment is used.
697
+ #
698
+ # /*
699
+ # * This is a comment for Foo
700
+ # */
701
+ # Init_Foo(void) {
702
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
703
+ # }
704
+ #
705
+ # /*
706
+ # * Document-class: Foo
707
+ # * This is a comment for Foo
708
+ # */
709
+ # Init_foo(void) {
710
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
711
+ # }
712
+ #
713
+ # /*
714
+ # * This is a comment for Foo
715
+ # */
716
+ # VALUE cFoo = rb_define_class("Foo", rb_cObject);
717
+
718
+ def find_class_comment class_name, class_mod
719
+ comment = nil
720
+
721
+ if @content =~ %r%
722
+ ((?>/\*.*?\*/\s+))
723
+ (static\s+)?
724
+ void\s+
725
+ Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)?\)%xmi then
726
+ comment = $1.sub(%r%Document-(?:class|module):\s+#{class_name}%, '')
727
+ elsif @content =~ %r%Document-(?:class|module):\s+#{class_name}\s*?
728
+ (?:<\s+[:,\w]+)?\n((?>.*?\*/))%xm then
729
+ comment = "/*\n#{$1}"
730
+ elsif @content =~ %r%((?>/\*.*?\*/\s+))
731
+ ([\w\.\s]+\s* = \s+)?rb_define_(class|module)[\t (]*?"(#{class_name})"%xm then
732
+ comment = $1
733
+ elsif @content =~ %r%((?>/\*.*?\*/\s+))
734
+ ([\w\. \t]+ = \s+)?rb_define_(class|module)_under[\t\w, (]*?"(#{class_name.split('::').last})"%xm then
735
+ comment = $1
736
+ else
737
+ comment = ''
738
+ end
739
+
740
+ comment = RDoc::Comment.new comment, @top_level, :c
741
+ comment.normalize
742
+
743
+ look_for_directives_in class_mod, comment
744
+
745
+ class_mod.add_comment comment, @top_level
746
+ end
747
+
748
+ ##
749
+ # Generate a const table
750
+
751
+ def gen_const_table file_content
752
+ table = {}
753
+ @content.scan(%r{
754
+ ((?>^\s*/\*.*?\*/\s+))
755
+ rb_define_(\w+)\((?:\s*(?:\w+),)?\s*
756
+ "(\w+)"\s*,
757
+ .*?\)\s*;
758
+ | Document-(?:const|global|variable):\s
759
+ ((?:\w+::)*\w+)
760
+ \s*?\n((?>.*?\*/))
761
+ }mxi) do
762
+ case
763
+ when $1 then table[[$2, $3]] = $1
764
+ when $4 then table[$4] = "/*\n" + $5
765
+ end
766
+ end
767
+ table
768
+ end
769
+
770
+ ##
771
+ # Finds a comment matching +type+ and +const_name+ either above the
772
+ # comment or in the matching Document- section.
773
+
774
+ def find_const_comment(type, const_name, class_name = nil)
775
+ @const_table ||= {}
776
+ @const_table[@content] ||= gen_const_table @content
777
+ table = @const_table[@content]
778
+
779
+ comment =
780
+ table[[type, const_name]] ||
781
+ (class_name && table[class_name + "::" + const_name]) ||
782
+ table[const_name] ||
783
+ ''
784
+
785
+ RDoc::Comment.new comment, @top_level, :c
786
+ end
787
+
788
+ ##
789
+ # Handles modifiers in +comment+ and updates +meth_obj+ as appropriate.
790
+
791
+ def find_modifiers comment, meth_obj
792
+ comment.normalize
793
+ comment.extract_call_seq meth_obj
794
+
795
+ look_for_directives_in meth_obj, comment
796
+ end
797
+
798
+ ##
799
+ # Finds a <tt>Document-method</tt> override for +meth_obj+ on +class_name+
800
+
801
+ def find_override_comment class_name, meth_obj
802
+ name = Regexp.escape meth_obj.name
803
+ prefix = Regexp.escape meth_obj.name_prefix
804
+
805
+ comment = if @content =~ %r%Document-method:
806
+ \s+#{class_name}#{prefix}#{name}
807
+ \s*?\n((?>.*?\*/))%xm then
808
+ "/*#{$1}"
809
+ elsif @content =~ %r%Document-method:
810
+ \s#{name}\s*?\n((?>.*?\*/))%xm then
811
+ "/*#{$1}"
812
+ end
813
+
814
+ return unless comment
815
+
816
+ RDoc::Comment.new comment, @top_level, :c
817
+ end
818
+
819
+ ##
820
+ # Creates a new RDoc::Attr +attr_name+ on class +var_name+ that is either
821
+ # +read+, +write+ or both
822
+
823
+ def handle_attr(var_name, attr_name, read, write)
824
+ rw = ''
825
+ rw += 'R' if '1' == read
826
+ rw += 'W' if '1' == write
827
+
828
+ class_name = @known_classes[var_name]
829
+
830
+ return unless class_name
831
+
832
+ class_obj = find_class var_name, class_name
833
+
834
+ return unless class_obj
835
+
836
+ comment = find_attr_comment var_name, attr_name
837
+ comment.normalize
838
+
839
+ name = attr_name.gsub(/rb_intern(?:_const)?\("([^"]+)"\)/, '\1')
840
+
841
+ attr = RDoc::Attr.new '', name, rw, comment
842
+
843
+ attr.record_location @top_level
844
+ class_obj.add_attribute attr
845
+ @stats.add_attribute attr
846
+ end
847
+
848
+ ##
849
+ # Creates a new RDoc::NormalClass or RDoc::NormalModule based on +type+
850
+ # named +class_name+ in +parent+ which was assigned to the C +var_name+.
851
+
852
+ def handle_class_module(var_name, type, class_name, parent, in_module)
853
+ parent_name = @known_classes[parent] || parent
854
+
855
+ if in_module then
856
+ enclosure = @classes[in_module] || @store.find_c_enclosure(in_module)
857
+
858
+ if enclosure.nil? and enclosure = @known_classes[in_module] then
859
+ enc_type = /^rb_m/ =~ in_module ? :module : :class
860
+ handle_class_module in_module, enc_type, enclosure, nil, nil
861
+ enclosure = @classes[in_module]
862
+ end
863
+
864
+ unless enclosure then
865
+ @enclosure_dependencies[in_module] << var_name
866
+ @missing_dependencies[var_name] =
867
+ [var_name, type, class_name, parent, in_module]
868
+
869
+ return
870
+ end
871
+ else
872
+ enclosure = @top_level
873
+ end
874
+
875
+ if type == :class then
876
+ full_name = if RDoc::ClassModule === enclosure then
877
+ enclosure.full_name + "::#{class_name}"
878
+ else
879
+ class_name
880
+ end
881
+
882
+ if @content =~ %r%Document-class:\s+#{full_name}\s*<\s+([:,\w]+)% then
883
+ parent_name = $1
884
+ end
885
+
886
+ cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name
887
+ else
888
+ cm = enclosure.add_module RDoc::NormalModule, class_name
889
+ end
890
+
891
+ cm.record_location enclosure.top_level
892
+
893
+ find_class_comment cm.full_name, cm
894
+
895
+ case cm
896
+ when RDoc::NormalClass
897
+ @stats.add_class cm
898
+ when RDoc::NormalModule
899
+ @stats.add_module cm
900
+ end
901
+
902
+ @classes[var_name] = cm
903
+ @known_classes[var_name] = cm.full_name
904
+ @store.add_c_enclosure var_name, cm
905
+ end
906
+
907
+ ##
908
+ # Adds constants. By providing some_value: at the start of the comment you
909
+ # can override the C value of the comment to give a friendly definition.
910
+ #
911
+ # /* 300: The perfect score in bowling */
912
+ # rb_define_const(cFoo, "PERFECT", INT2FIX(300));
913
+ #
914
+ # Will override <tt>INT2FIX(300)</tt> with the value +300+ in the output
915
+ # RDoc. Values may include quotes and escaped colons (\:).
916
+
917
+ def handle_constants(type, var_name, const_name, definition)
918
+ class_name = @known_classes[var_name]
919
+
920
+ return unless class_name
921
+
922
+ class_obj = find_class var_name, class_name
923
+
924
+ unless class_obj then
925
+ @options.warn 'Enclosing class or module %p is not known' % [const_name]
926
+ return
927
+ end
928
+
929
+ comment = find_const_comment type, const_name, class_name
930
+ comment.normalize
931
+
932
+ # In the case of rb_define_const, the definition and comment are in
933
+ # "/* definition: comment */" form. The literal ':' and '\' characters
934
+ # can be escaped with a backslash.
935
+ if type.downcase == 'const' then
936
+ no_match, new_definition, new_comment = comment.text.split(/(\A.*):/)
937
+
938
+ if no_match and no_match.empty? then
939
+ if new_definition.empty? then # Default to literal C definition
940
+ new_definition = definition
941
+ else
942
+ new_definition = new_definition.gsub("\:", ":")
943
+ new_definition = new_definition.gsub("\\", '\\')
944
+ end
945
+
946
+ new_definition.sub!(/\A(\s+)/, '')
947
+
948
+ new_comment = "#{$1}#{new_comment.lstrip}"
949
+
950
+ new_comment = RDoc::Comment.new new_comment, @top_level, :c
951
+
952
+ con = RDoc::Constant.new const_name, new_definition, new_comment
953
+ else
954
+ con = RDoc::Constant.new const_name, definition, comment
955
+ end
956
+ else
957
+ con = RDoc::Constant.new const_name, definition, comment
958
+ end
959
+
960
+ con.record_location @top_level
961
+ @stats.add_constant con
962
+ class_obj.add_constant con
963
+ end
964
+
965
+ ##
966
+ # Removes #ifdefs that would otherwise confuse us
967
+
968
+ def handle_ifdefs_in(body)
969
+ body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1')
970
+ end
971
+
972
+ ##
973
+ # Adds an RDoc::AnyMethod +meth_name+ defined on a class or module assigned
974
+ # to +var_name+. +type+ is the type of method definition function used.
975
+ # +singleton_method+ and +module_function+ create a singleton method.
976
+
977
+ def handle_method(type, var_name, meth_name, function, param_count,
978
+ source_file = nil)
979
+ class_name = @known_classes[var_name]
980
+ singleton = @singleton_classes.key? var_name
981
+
982
+ @methods[var_name][function] << meth_name
983
+
984
+ return unless class_name
985
+
986
+ class_obj = find_class var_name, class_name
987
+
988
+ if existing_method = class_obj.method_list.find { |m| m.c_function == function }
989
+ add_alias(var_name, class_obj, existing_method.name, meth_name, existing_method.comment)
990
+ end
991
+
992
+ if class_obj then
993
+ if meth_name == 'initialize' then
994
+ meth_name = 'new'
995
+ singleton = true
996
+ type = 'method' # force public
997
+ end
998
+
999
+ meth_obj = RDoc::AnyMethod.new '', meth_name
1000
+ meth_obj.c_function = function
1001
+ meth_obj.singleton =
1002
+ singleton || %w[singleton_method module_function].include?(type)
1003
+
1004
+ p_count = Integer(param_count) rescue -1
1005
+
1006
+ if source_file then
1007
+ file_name = File.join @file_dir, source_file
1008
+
1009
+ if File.exist? file_name then
1010
+ file_content = File.read file_name
1011
+ else
1012
+ @options.warn "unknown source #{source_file} for #{meth_name} in #{@file_name}"
1013
+ end
1014
+ else
1015
+ file_content = @content
1016
+ end
1017
+
1018
+ body = find_body class_name, function, meth_obj, file_content
1019
+
1020
+ if body and meth_obj.document_self then
1021
+ meth_obj.params = if p_count < -1 then # -2 is Array
1022
+ '(*args)'
1023
+ elsif p_count == -1 then # argc, argv
1024
+ rb_scan_args body
1025
+ else
1026
+ "(#{(1..p_count).map { |i| "p#{i}" }.join ', '})"
1027
+ end
1028
+
1029
+
1030
+ meth_obj.record_location @top_level
1031
+ class_obj.add_method meth_obj
1032
+ @stats.add_method meth_obj
1033
+ meth_obj.visibility = :private if 'private_method' == type
1034
+ end
1035
+ end
1036
+ end
1037
+
1038
+ ##
1039
+ # Registers a singleton class +sclass_var+ as a singleton of +class_var+
1040
+
1041
+ def handle_singleton sclass_var, class_var
1042
+ class_name = @known_classes[class_var]
1043
+
1044
+ @known_classes[sclass_var] = class_name
1045
+ @singleton_classes[sclass_var] = class_name
1046
+ end
1047
+
1048
+ ##
1049
+ # Normalizes tabs in +body+
1050
+
1051
+ def handle_tab_width(body)
1052
+ if /\t/ =~ body
1053
+ tab_width = @options.tab_width
1054
+ body.split(/\n/).map do |line|
1055
+ 1 while line.gsub!(/\t+/) do
1056
+ ' ' * (tab_width * $&.length - $`.length % tab_width)
1057
+ end && $~
1058
+ line
1059
+ end.join "\n"
1060
+ else
1061
+ body
1062
+ end
1063
+ end
1064
+
1065
+ ##
1066
+ # Loads the variable map with the given +name+ from the RDoc::Store, if
1067
+ # present.
1068
+
1069
+ def load_variable_map map_name
1070
+ return {} unless files = @store.cache[map_name]
1071
+ return {} unless name_map = files[@file_name]
1072
+
1073
+ class_map = {}
1074
+
1075
+ name_map.each do |variable, name|
1076
+ next unless mod = @store.find_class_or_module(name)
1077
+
1078
+ class_map[variable] = if map_name == :c_class_variables then
1079
+ mod
1080
+ else
1081
+ name
1082
+ end
1083
+ @known_classes[variable] = name
1084
+ end
1085
+
1086
+ class_map
1087
+ end
1088
+
1089
+ ##
1090
+ # Look for directives in a normal comment block:
1091
+ #
1092
+ # /*
1093
+ # * :title: My Awesome Project
1094
+ # */
1095
+ #
1096
+ # This method modifies the +comment+
1097
+
1098
+ def look_for_directives_in context, comment
1099
+ @preprocess.handle comment, context do |directive, param|
1100
+ case directive
1101
+ when 'main' then
1102
+ @options.main_page = param
1103
+ ''
1104
+ when 'title' then
1105
+ @options.default_title = param if @options.respond_to? :default_title=
1106
+ ''
1107
+ end
1108
+ end
1109
+
1110
+ comment
1111
+ end
1112
+
1113
+ ##
1114
+ # Extracts parameters from the +method_body+ and returns a method
1115
+ # parameter string. Follows 1.9.3dev's scan-arg-spec, see README.EXT
1116
+
1117
+ def rb_scan_args method_body
1118
+ method_body =~ /rb_scan_args\((.*?)\)/m
1119
+ return '(*args)' unless $1
1120
+
1121
+ $1.split(/,/)[2] =~ /"(.*?)"/ # format argument
1122
+ format = $1.split(//)
1123
+
1124
+ lead = opt = trail = 0
1125
+
1126
+ if format.first =~ /\d/ then
1127
+ lead = $&.to_i
1128
+ format.shift
1129
+ if format.first =~ /\d/ then
1130
+ opt = $&.to_i
1131
+ format.shift
1132
+ if format.first =~ /\d/ then
1133
+ trail = $&.to_i
1134
+ format.shift
1135
+ block_arg = true
1136
+ end
1137
+ end
1138
+ end
1139
+
1140
+ if format.first == '*' and not block_arg then
1141
+ var = true
1142
+ format.shift
1143
+ if format.first =~ /\d/ then
1144
+ trail = $&.to_i
1145
+ format.shift
1146
+ end
1147
+ end
1148
+
1149
+ if format.first == ':' then
1150
+ hash = true
1151
+ format.shift
1152
+ end
1153
+
1154
+ if format.first == '&' then
1155
+ block = true
1156
+ format.shift
1157
+ end
1158
+
1159
+ # if the format string is not empty there's a bug in the C code, ignore it
1160
+
1161
+ args = []
1162
+ position = 1
1163
+
1164
+ (1...(position + lead)).each do |index|
1165
+ args << "p#{index}"
1166
+ end
1167
+
1168
+ position += lead
1169
+
1170
+ (position...(position + opt)).each do |index|
1171
+ args << "p#{index} = v#{index}"
1172
+ end
1173
+
1174
+ position += opt
1175
+
1176
+ if var then
1177
+ args << '*args'
1178
+ position += 1
1179
+ end
1180
+
1181
+ (position...(position + trail)).each do |index|
1182
+ args << "p#{index}"
1183
+ end
1184
+
1185
+ position += trail
1186
+
1187
+ if hash then
1188
+ args << "p#{position} = {}"
1189
+ end
1190
+
1191
+ args << '&block' if block
1192
+
1193
+ "(#{args.join ', '})"
1194
+ end
1195
+
1196
+ ##
1197
+ # Removes lines that are commented out that might otherwise get picked up
1198
+ # when scanning for classes and methods
1199
+
1200
+ def remove_commented_out_lines
1201
+ @content = @content.gsub(%r%//.*rb_define_%, '//')
1202
+ end
1203
+
1204
+ ##
1205
+ # Extracts the classes, modules, methods, attributes, constants and aliases
1206
+ # from a C file and returns an RDoc::TopLevel for this file
1207
+
1208
+ def scan
1209
+ remove_commented_out_lines
1210
+
1211
+ do_classes_and_modules
1212
+ do_missing
1213
+
1214
+ do_constants
1215
+ do_methods
1216
+ do_includes
1217
+ do_aliases
1218
+ do_attrs
1219
+
1220
+ @store.add_c_variables self
1221
+
1222
+ @top_level
1223
+ end
1224
+
1225
+ end