gitlab-rdoc 6.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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