rdoc 2.5.11 → 3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (113) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.document +1 -0
  3. data/History.txt +95 -0
  4. data/Manifest.txt +13 -4
  5. data/README.txt +9 -3
  6. data/Rakefile +1 -1
  7. data/lib/rdoc.rb +15 -298
  8. data/lib/rdoc/alias.rb +65 -16
  9. data/lib/rdoc/any_method.rb +27 -150
  10. data/lib/rdoc/attr.rb +36 -115
  11. data/lib/rdoc/class_module.rb +236 -22
  12. data/lib/rdoc/code_object.rb +76 -31
  13. data/lib/rdoc/constant.rb +32 -4
  14. data/lib/rdoc/context.rb +494 -222
  15. data/lib/rdoc/encoding.rb +79 -0
  16. data/lib/rdoc/erbio.rb +37 -0
  17. data/lib/rdoc/gauntlet.rb +9 -5
  18. data/lib/rdoc/generator.rb +33 -1
  19. data/lib/rdoc/generator/darkfish.rb +284 -375
  20. data/lib/rdoc/generator/markup.rb +72 -36
  21. data/lib/rdoc/generator/ri.rb +4 -4
  22. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +267 -274
  23. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +91 -91
  24. data/lib/rdoc/generator/template/darkfish/index.rhtml +45 -45
  25. data/lib/rdoc/generator/template/darkfish/rdoc.css +298 -298
  26. data/lib/rdoc/include.rb +40 -1
  27. data/lib/rdoc/known_classes.rb +1 -0
  28. data/lib/rdoc/markup.rb +467 -2
  29. data/lib/rdoc/markup/attribute_manager.rb +24 -6
  30. data/lib/rdoc/markup/blank_line.rb +11 -3
  31. data/lib/rdoc/markup/document.rb +6 -0
  32. data/lib/rdoc/markup/formatter.rb +10 -0
  33. data/lib/rdoc/markup/formatter_test_case.rb +339 -3
  34. data/lib/rdoc/markup/heading.rb +3 -0
  35. data/lib/rdoc/markup/inline.rb +11 -1
  36. data/lib/rdoc/markup/list.rb +3 -0
  37. data/lib/rdoc/markup/list_item.rb +3 -0
  38. data/lib/rdoc/markup/paragraph.rb +3 -0
  39. data/lib/rdoc/markup/parser.rb +191 -237
  40. data/lib/rdoc/markup/{preprocess.rb → pre_process.rb} +50 -29
  41. data/lib/rdoc/markup/raw.rb +4 -0
  42. data/lib/rdoc/markup/rule.rb +3 -0
  43. data/lib/rdoc/markup/text_formatter_test_case.rb +116 -0
  44. data/lib/rdoc/markup/to_ansi.rb +14 -2
  45. data/lib/rdoc/markup/to_bs.rb +8 -2
  46. data/lib/rdoc/markup/to_html.rb +84 -91
  47. data/lib/rdoc/markup/to_html_crossref.rb +77 -26
  48. data/lib/rdoc/markup/to_rdoc.rb +94 -49
  49. data/lib/rdoc/markup/to_test.rb +9 -1
  50. data/lib/rdoc/markup/verbatim.rb +6 -3
  51. data/lib/rdoc/method_attr.rb +353 -0
  52. data/lib/rdoc/normal_class.rb +11 -2
  53. data/lib/rdoc/normal_module.rb +0 -5
  54. data/lib/rdoc/options.rb +373 -82
  55. data/lib/rdoc/parser.rb +59 -23
  56. data/lib/rdoc/parser/c.rb +224 -86
  57. data/lib/rdoc/parser/ruby.rb +219 -111
  58. data/lib/rdoc/parser/ruby_tools.rb +4 -1
  59. data/lib/rdoc/parser/simple.rb +9 -4
  60. data/lib/rdoc/rdoc.rb +68 -28
  61. data/lib/rdoc/require.rb +21 -0
  62. data/lib/rdoc/ri/driver.rb +20 -10
  63. data/lib/rdoc/ri/paths.rb +2 -2
  64. data/lib/rdoc/ri/store.rb +22 -5
  65. data/lib/rdoc/ruby_lex.rb +11 -12
  66. data/lib/rdoc/ruby_token.rb +2 -2
  67. data/lib/rdoc/single_class.rb +2 -1
  68. data/lib/rdoc/stats.rb +202 -162
  69. data/lib/rdoc/stats/normal.rb +51 -0
  70. data/lib/rdoc/stats/quiet.rb +59 -0
  71. data/lib/rdoc/stats/verbose.rb +45 -0
  72. data/lib/rdoc/text.rb +133 -4
  73. data/lib/rdoc/{tokenstream.rb → token_stream.rb} +0 -2
  74. data/lib/rdoc/top_level.rb +230 -39
  75. data/test/test_attribute_manager.rb +58 -7
  76. data/test/test_rdoc_alias.rb +13 -0
  77. data/test/test_rdoc_any_method.rb +43 -2
  78. data/test/test_rdoc_attr.rb +15 -8
  79. data/test/test_rdoc_class_module.rb +133 -0
  80. data/test/test_rdoc_code_object.rb +62 -5
  81. data/test/test_rdoc_context.rb +72 -26
  82. data/test/test_rdoc_encoding.rb +145 -0
  83. data/test/test_rdoc_generator_darkfish.rb +119 -0
  84. data/test/test_rdoc_generator_ri.rb +22 -2
  85. data/test/test_rdoc_include.rb +79 -0
  86. data/test/test_rdoc_markup_attribute_manager.rb +4 -4
  87. data/test/test_rdoc_markup_parser.rb +134 -95
  88. data/test/test_rdoc_markup_pre_process.rb +7 -2
  89. data/test/test_rdoc_markup_to_ansi.rb +43 -153
  90. data/test/test_rdoc_markup_to_bs.rb +42 -156
  91. data/test/test_rdoc_markup_to_html.rb +130 -58
  92. data/test/test_rdoc_markup_to_html_crossref.rb +10 -10
  93. data/test/test_rdoc_markup_to_rdoc.rb +40 -151
  94. data/test/test_rdoc_method_attr.rb +122 -0
  95. data/test/test_rdoc_normal_class.rb +1 -1
  96. data/test/test_rdoc_normal_module.rb +6 -1
  97. data/test/test_rdoc_options.rb +237 -12
  98. data/test/test_rdoc_parser.rb +3 -22
  99. data/test/test_rdoc_parser_c.rb +203 -2
  100. data/test/test_rdoc_parser_ruby.rb +403 -89
  101. data/test/test_rdoc_parser_simple.rb +25 -1
  102. data/test/test_rdoc_rdoc.rb +44 -32
  103. data/test/test_rdoc_ri_driver.rb +29 -24
  104. data/test/test_rdoc_ri_store.rb +46 -3
  105. data/test/test_rdoc_task.rb +1 -1
  106. data/test/test_rdoc_text.rb +102 -8
  107. data/test/test_rdoc_top_level.rb +13 -4
  108. data/test/xref_data.rb +8 -0
  109. data/test/xref_test_case.rb +6 -0
  110. metadata +29 -19
  111. metadata.gz.sig +0 -0
  112. data/lib/rdoc/parser/perl.rb +0 -165
  113. data/test/test_rdoc_parser_perl.rb +0 -73
@@ -5,6 +5,13 @@ require 'rdoc/code_object'
5
5
 
6
6
  class RDoc::Constant < RDoc::CodeObject
7
7
 
8
+ ##
9
+ # If this constant is an alias for a module or class,
10
+ # this is the RDoc::ClassModule it is an alias for.
11
+ # +nil+ otherwise.
12
+
13
+ attr_accessor :is_alias_for
14
+
8
15
  ##
9
16
  # The constant's name
10
17
 
@@ -22,6 +29,7 @@ class RDoc::Constant < RDoc::CodeObject
22
29
  super()
23
30
  @name = name
24
31
  @value = value
32
+ @is_alias_for = nil
25
33
  self.comment = comment
26
34
  end
27
35
 
@@ -34,17 +42,28 @@ class RDoc::Constant < RDoc::CodeObject
34
42
  [parent_name, name] <=> [other.parent_name, other.name]
35
43
  end
36
44
 
45
+ ##
46
+ # Constants are equal when their #parent and #name is the same
47
+
37
48
  def == other
38
49
  self.class == other.class and
39
50
  @parent == other.parent and
40
51
  @name == other.name
41
52
  end
42
53
 
54
+ ##
55
+ # A constant is documented if it has a comment, or is an alias
56
+ # for a documented class or module.
57
+
58
+ def documented?
59
+ super or is_alias_for && is_alias_for.documented?
60
+ end
61
+
43
62
  def inspect # :nodoc:
44
- "#<%s:0x%x %s::%s>" % [
45
- self.class, object_id,
46
- parent_name, @name,
47
- ]
63
+ "#<%s:0x%x %s::%s>" % [
64
+ self.class, object_id,
65
+ parent_name, @name,
66
+ ]
48
67
  end
49
68
 
50
69
  ##
@@ -54,5 +73,14 @@ class RDoc::Constant < RDoc::CodeObject
54
73
  "#{@parent.path}##{@name}"
55
74
  end
56
75
 
76
+ def to_s # :nodoc:
77
+ parent_name = parent ? parent.full_name : '(unknown)'
78
+ if is_alias_for
79
+ "constant #{parent_name}::#@name -> #{is_alias_for}"
80
+ else
81
+ "constant #{parent_name}::#@name"
82
+ end
83
+ end
84
+
57
85
  end
58
86
 
@@ -15,17 +15,12 @@ class RDoc::Context < RDoc::CodeObject
15
15
  TYPES = %w[class instance]
16
16
 
17
17
  ##
18
- # Method visibilities
19
-
20
- VISIBILITIES = [:public, :protected, :private]
21
-
22
- ##
23
- # Aliased methods
18
+ # Class/module aliases
24
19
 
25
20
  attr_reader :aliases
26
21
 
27
22
  ##
28
- # attr* methods
23
+ # All attr* methods
29
24
 
30
25
  attr_reader :attributes
31
26
 
@@ -37,7 +32,7 @@ class RDoc::Context < RDoc::CodeObject
37
32
  ##
38
33
  # Current section of documentation
39
34
 
40
- attr_reader :current_section
35
+ attr_accessor :current_section
41
36
 
42
37
  ##
43
38
  # Files this context is found in
@@ -70,19 +65,37 @@ class RDoc::Context < RDoc::CodeObject
70
65
  attr_reader :sections
71
66
 
72
67
  ##
73
- # Aliases that haven't been resolved to a method
68
+ # Hash <tt>old_name => [aliases]</tt>, for aliases
69
+ # that haven't (yet) been resolved to a method/attribute.
70
+ # (Not to be confused with the aliases of the context.)
74
71
 
75
72
  attr_accessor :unmatched_alias_lists
76
73
 
74
+ ##
75
+ # Aliases that could not eventually be resolved.
76
+
77
+ attr_reader :external_aliases
78
+
77
79
  ##
78
80
  # Current visibility of this context
79
81
 
80
- attr_reader :visibility
82
+ attr_accessor :visibility
83
+
84
+ ##
85
+ # Hash of registered methods. Attributes are also registered here,
86
+ # twice if they are RW.
87
+
88
+ attr_reader :methods_hash
89
+
90
+ ##
91
+ # Hash of registered constants.
92
+
93
+ attr_reader :constants_hash
81
94
 
82
95
  ##
83
96
  # A per-comment section of documentation like:
84
97
  #
85
- # # :SECTION: The title
98
+ # # :section: The title
86
99
  # # The body
87
100
 
88
101
  class Section
@@ -137,14 +150,12 @@ class RDoc::Context < RDoc::CodeObject
137
150
  end
138
151
 
139
152
  ##
140
- # Set the comment for this section from the original comment block If
153
+ # Set the comment for this section from the original comment block. If
141
154
  # the first line contains :section:, strip it and use the rest.
142
155
  # Otherwise remove lines up to the line containing :section:, and look
143
156
  # for those lines again at the end and remove them. This lets us write
144
157
  #
145
- # # blah blah blah
146
- # #
147
- # # :SECTION: The title
158
+ # # :section: The title
148
159
  # # The body
149
160
 
150
161
  def set_comment(comment)
@@ -169,7 +180,7 @@ class RDoc::Context < RDoc::CodeObject
169
180
  end
170
181
 
171
182
  ##
172
- # Creates an unnamed empty context with public visibility
183
+ # Creates an unnamed empty context with public current visibility
173
184
 
174
185
  def initialize
175
186
  super
@@ -184,16 +195,10 @@ class RDoc::Context < RDoc::CodeObject
184
195
  @current_section = Section.new self, nil, nil
185
196
  @sections = [@current_section]
186
197
 
187
- initialize_methods_etc
188
- initialize_classes_and_modules
189
- end
190
-
191
- ##
192
- # Sets the defaults for classes and modules
193
-
194
- def initialize_classes_and_modules
195
198
  @classes = {}
196
199
  @modules = {}
200
+
201
+ initialize_methods_etc
197
202
  end
198
203
 
199
204
  ##
@@ -206,10 +211,14 @@ class RDoc::Context < RDoc::CodeObject
206
211
  @requires = []
207
212
  @includes = []
208
213
  @constants = []
214
+ @external_aliases = []
209
215
 
210
216
  # This Hash maps a method name to a list of unmatched aliases (aliases of
211
217
  # a method not yet encountered).
212
218
  @unmatched_alias_lists = {}
219
+
220
+ @methods_hash = {}
221
+ @constants_hash = {}
213
222
  end
214
223
 
215
224
  ##
@@ -220,23 +229,20 @@ class RDoc::Context < RDoc::CodeObject
220
229
  end
221
230
 
222
231
  ##
223
- # Adds +an_alias+ that is automatically resolved to it's corresponding
224
- # RDoc::AnyMethod object.
232
+ # Adds +an_alias+ that is automatically resolved
225
233
 
226
234
  def add_alias an_alias
227
- old_name = an_alias.old_name
235
+ return an_alias unless @document_self
228
236
 
229
- meth = if an_alias.singleton then
230
- find_class_method_named old_name
231
- else
232
- find_instance_method_named old_name
233
- end
237
+ method_attr = find_method(an_alias.old_name, an_alias.singleton) ||
238
+ find_attribute(an_alias.old_name, an_alias.singleton)
234
239
 
235
- if meth then
236
- add_alias_impl an_alias, meth
240
+ if method_attr then
241
+ method_attr.add_alias an_alias, self
237
242
  else
238
- add_to @aliases, an_alias
239
- unmatched_alias_list = @unmatched_alias_lists[old_name] ||= []
243
+ add_to @external_aliases, an_alias
244
+ unmatched_alias_list =
245
+ @unmatched_alias_lists[an_alias.pretty_old_name] ||= []
240
246
  unmatched_alias_list.push an_alias
241
247
  end
242
248
 
@@ -244,175 +250,279 @@ class RDoc::Context < RDoc::CodeObject
244
250
  end
245
251
 
246
252
  ##
247
- # Turns +an_alias+ into an AnyMethod that points to +meth+
248
-
249
- def add_alias_impl(an_alias, meth)
250
- new_meth = RDoc::AnyMethod.new an_alias.text, an_alias.new_name
251
- new_meth.is_alias_for = meth
252
- new_meth.singleton = meth.singleton
253
- new_meth.params = meth.params
254
-
255
- new_meth.comment = an_alias.comment
256
-
257
- meth.add_alias new_meth
258
-
259
- add_method new_meth
260
-
261
- # aliases don't use ongoing visibility
262
- new_meth.visibility = meth.visibility
263
-
264
- new_meth
265
- end
253
+ # Adds +attribute+ if not already there. If it is (as method(s) or attribute),
254
+ # updates the comment if it was empty.
255
+ #
256
+ # The attribute is registered only if it defines a new method.
257
+ # For instance, <tt>attr_reader :foo</tt> will not be registered
258
+ # if method +foo+ exists, but <tt>attr_accessor :foo</tt> will be registered
259
+ # if method +foo+ exists, but <tt>foo=</tt> does not.
260
+
261
+ def add_attribute attribute
262
+ return attribute unless @document_self
263
+
264
+ # mainly to check for redefinition of an attribute as a method
265
+ # TODO find a policy for 'attr_reader :foo' + 'def foo=()'
266
+ register = false
267
+
268
+ if attribute.rw.index('R') then
269
+ key = attribute.pretty_name
270
+ known = @methods_hash[key]
271
+ if known then
272
+ known.comment = attribute.comment if known.comment.empty?
273
+ else
274
+ @methods_hash[key] = attribute
275
+ register = true
276
+ end
277
+ end
266
278
 
267
- ##
268
- # Adds +attribute+
279
+ if attribute.rw.index('W')
280
+ key = attribute.pretty_name << '='
281
+ known = @methods_hash[key]
282
+ if known then
283
+ known.comment = attribute.comment if known.comment.empty?
284
+ else
285
+ @methods_hash[key] = attribute
286
+ register = true
287
+ end
288
+ end
269
289
 
270
- def add_attribute(attribute)
271
- add_to @attributes, attribute
290
+ if register then
291
+ attribute.visibility = @visibility
292
+ add_to @attributes, attribute
293
+ resolve_aliases attribute
294
+ end
272
295
  end
273
296
 
274
297
  ##
275
- # Adds a class named +name+ with +superclass+.
298
+ # Adds a class named +given_name+ with +superclass+.
299
+ #
300
+ # Both +given_name+ and +superclass+ may contain '::', and are
301
+ # interpreted relative to the +self+ context. This allows handling correctly
302
+ # examples like these:
303
+ # class RDoc::Gauntlet < Gauntlet
304
+ # module Mod
305
+ # class Object # implies < ::Object
306
+ # class SubObject < Object # this is _not_ ::Object
276
307
  #
277
308
  # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module
278
- # unless it later sees <tt>class Container</tt>. add_class automatically
279
- # upgrades +name+ to a class in this case.
309
+ # unless it later sees <tt>class Container</tt>. +add_class+ automatically
310
+ # upgrades +given_name+ to a class in this case.
311
+
312
+ def add_class class_type, given_name, superclass = '::Object'
313
+ # superclass +nil+ is passed by the C parser in the following cases:
314
+ # - registering Object in 1.8 (correct)
315
+ # - registering BasicObject in 1.9 (correct)
316
+ # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c)
317
+ #
318
+ # If we later find a superclass for a registered class with a nil
319
+ # superclass, we must honor it.
320
+
321
+ # find the name & enclosing context
322
+ if given_name =~ /^:+(\w+)$/ then
323
+ full_name = $1
324
+ enclosing = top_level
325
+ name = full_name.split(/:+/).last
326
+ else
327
+ full_name = child_name given_name
328
+
329
+ if full_name =~ /^(.+)::(\w+)$/ then
330
+ name = $2
331
+ ename = $1
332
+ enclosing = RDoc::TopLevel.classes_hash[ename] ||
333
+ RDoc::TopLevel.modules_hash[ename]
334
+ # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
335
+ unless enclosing then
336
+ # try the given name at top level (will work for the above example)
337
+ enclosing = RDoc::TopLevel.classes_hash[given_name] || RDoc::TopLevel.modules_hash[given_name]
338
+ return enclosing if enclosing
339
+ # not found: create the parent(s)
340
+ names = ename.split('::')
341
+ enclosing = self
342
+ names.each do |n|
343
+ enclosing = enclosing.classes_hash[n] ||
344
+ enclosing.modules_hash[n] ||
345
+ enclosing.add_module(RDoc::NormalModule, n)
346
+ end
347
+ end
348
+ else
349
+ name = full_name
350
+ enclosing = self
351
+ end
352
+ end
280
353
 
281
- def add_class(class_type, name, superclass = 'Object')
282
- klass = add_class_or_module @classes, class_type, name, superclass
354
+ # find the superclass full name
355
+ if superclass then
356
+ if superclass =~ /^:+/ then
357
+ superclass = $' #'
358
+ else
359
+ if superclass =~ /^(\w+):+(.+)$/ then
360
+ suffix = $2
361
+ mod = find_module_named($1)
362
+ superclass = mod.full_name + '::' + suffix if mod
363
+ else
364
+ mod = find_module_named(superclass)
365
+ superclass = mod.full_name if mod
366
+ end
367
+ end
283
368
 
284
- existing = klass.superclass
285
- existing = existing.name if existing and not String === existing
369
+ # did we believe it was a module?
370
+ mod = RDoc::TopLevel.modules_hash.delete superclass
286
371
 
287
- if superclass != existing and superclass != 'Object' then
288
- klass.superclass = superclass
372
+ upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
373
+
374
+ # e.g., Object < Object
375
+ superclass = nil if superclass == full_name
289
376
  end
290
377
 
291
- # If the parser encounters Container::Item before encountering
292
- # Container, then it assumes that Container is a module. This may not
293
- # be the case, so remove Container from the module list if present and
294
- # transfer any contained classes and modules to the new class.
378
+ klass = RDoc::TopLevel.classes_hash[full_name]
379
+
380
+ if klass then
381
+ # if TopLevel, it may not be registered in the classes:
382
+ enclosing.classes_hash[name] = klass
383
+ # update the superclass if needed
384
+ if superclass then
385
+ existing = klass.superclass
386
+ existing = existing.full_name unless existing.is_a?(String) if existing
387
+ if existing.nil? ||
388
+ (existing == 'Object' && superclass != 'Object') then
389
+ klass.superclass = superclass
390
+ end
391
+ end
392
+ else
393
+ # this is a new class
394
+ mod = RDoc::TopLevel.modules_hash.delete full_name
295
395
 
296
- mod = RDoc::TopLevel.modules_hash.delete klass.full_name
396
+ if mod then
397
+ klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
297
398
 
298
- if mod then
299
- klass.classes_hash.update mod.classes_hash
300
- klass.modules_hash.update mod.modules_hash
301
- klass.method_list.concat mod.method_list
399
+ klass.superclass = superclass unless superclass.nil?
400
+ else
401
+ klass = class_type.new name, superclass
302
402
 
303
- @modules.delete klass.name
403
+ enclosing.add_class_or_module(klass, enclosing.classes_hash,
404
+ RDoc::TopLevel.classes_hash)
405
+ end
304
406
  end
305
407
 
306
- RDoc::TopLevel.classes_hash[klass.full_name] = klass
307
-
308
408
  klass
309
409
  end
310
410
 
311
411
  ##
312
- # Instantiates a +class_type+ named +name+ and adds it the modules or
313
- # classes Hash +collection+.
314
-
315
- def add_class_or_module(collection, class_type, name, superclass = nil)
316
- full_name = child_name name
317
-
318
- mod = collection[name]
319
-
320
- if mod then
321
- mod.superclass = superclass unless mod.module?
322
- else
323
- all = if class_type == RDoc::NormalModule then
324
- RDoc::TopLevel.modules_hash
325
- else
326
- RDoc::TopLevel.classes_hash
327
- end
412
+ # Adds the class or module +mod+ to the modules or
413
+ # classes Hash +self_hash+, and to +all_hash+ (either
414
+ # <tt>TopLevel::modules_hash</tt> or <tt>TopLevel::classes_hash</tt>),
415
+ # unless #done_documenting is +true+. Sets the #parent of +mod+
416
+ # to +self+, and its #section to #current_section. Returns +mod+.
328
417
 
329
- mod = all[full_name]
418
+ def add_class_or_module mod, self_hash, all_hash
419
+ mod.section = @current_section # TODO declaring context? something is
420
+ # wrong here...
421
+ mod.parent = self
330
422
 
331
- unless mod then
332
- mod = class_type.new name, superclass
333
- else
334
- # If the class has been encountered already, check that its
335
- # superclass has been set (it may not have been, depending on the
336
- # context in which it was encountered).
337
- if class_type == RDoc::NormalClass then
338
- mod.superclass = superclass unless mod.superclass
339
- end
340
- end
341
-
342
- unless @done_documenting then
343
- all[full_name] = mod
344
- collection[name] = mod
345
- end
346
-
347
- mod.section = @current_section
348
- mod.parent = self
423
+ unless @done_documenting then
424
+ self_hash[mod.name] = mod
425
+ # this must be done AFTER adding mod to its parent, so that the full
426
+ # name is correct:
427
+ all_hash[mod.full_name] = mod
349
428
  end
350
429
 
351
430
  mod
352
431
  end
353
432
 
354
433
  ##
355
- # Adds +constant+
434
+ # Adds +constant+ if not already there. If it is, updates the comment,
435
+ # value and/or is_alias_for of the known constant if they were empty/nil.
356
436
 
357
437
  def add_constant(constant)
358
- add_to @constants, constant
438
+ return constant unless @document_self
439
+
440
+ # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code)
441
+ # (this is a #ifdef: should be handled by the C parser)
442
+ known = @constants_hash[constant.name]
443
+ if known
444
+ #$stderr.puts "\nconstant #{constant.name} already registered"
445
+ known.comment = constant.comment if known.comment.empty?
446
+ known.value = constant.value if known.value.nil? or known.value.strip.empty?
447
+ known.is_alias_for ||= constant.is_alias_for
448
+ else
449
+ @constants_hash[constant.name] = constant
450
+ add_to @constants, constant
451
+ end
359
452
  end
360
453
 
361
454
  ##
362
- # Adds included module +include+
455
+ # Adds included module +include+ which should be an RDoc::Include
363
456
 
364
457
  def add_include(include)
365
458
  add_to @includes, include
366
459
  end
367
460
 
368
461
  ##
369
- # Adds +method+
462
+ # Adds +method+ if not already there. If it is (as method or attribute),
463
+ # updates the comment if it was empty.
370
464
 
371
465
  def add_method(method)
372
- method.visibility = @visibility
373
- add_to @method_list, method
374
-
375
- unmatched_alias_list = @unmatched_alias_lists[method.name]
376
- if unmatched_alias_list then
377
- unmatched_alias_list.each do |unmatched_alias|
378
- add_alias_impl unmatched_alias, method
379
- @aliases.delete unmatched_alias
380
- end
381
-
382
- @unmatched_alias_lists.delete method.name
466
+ return method unless @document_self
467
+
468
+ # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code)
469
+ key = method.pretty_name
470
+ known = @methods_hash[key]
471
+ if known
472
+ # TODO issue stderr messages if --verbose
473
+ #$stderr.puts "\n#{display(method)} already registered as #{display(known)}"
474
+ known.comment = method.comment if known.comment.empty?
475
+ else
476
+ @methods_hash[key] = method
477
+ method.visibility = @visibility
478
+ add_to @method_list, method
479
+ resolve_aliases method
383
480
  end
384
481
  end
385
482
 
386
483
  ##
387
484
  # Adds a module named +name+. If RDoc already knows +name+ is a class then
388
- # that class is returned instead. See also #add_class
485
+ # that class is returned instead. See also #add_class.
389
486
 
390
487
  def add_module(class_type, name)
391
- return @classes[name] if @classes.key? name
488
+ mod = @classes[name] || @modules[name]
489
+ return mod if mod
392
490
 
393
- add_class_or_module @modules, class_type, name, nil
491
+ full_name = child_name name
492
+ mod = RDoc::TopLevel.modules_hash[full_name] || class_type.new(name)
493
+
494
+ add_class_or_module(mod, @modules, RDoc::TopLevel.modules_hash)
394
495
  end
395
496
 
396
497
  ##
397
- # Adds an alias from +from+ to +name+
498
+ # Adds an alias from +from+ (a class or module) to +name+.
398
499
 
399
500
  def add_module_alias from, name
400
- to_name = child_name name
501
+ return from if @done_documenting
401
502
 
402
- unless @done_documenting then
403
- if from.module? then
404
- RDoc::TopLevel.modules_hash
405
- else
406
- RDoc::TopLevel.classes_hash
407
- end[to_name] = from
503
+ to_name = child_name(name)
408
504
 
409
- if from.module? then
410
- @modules
411
- else
412
- @classes
413
- end[name] = from
505
+ # if we already know this name, don't register an alias:
506
+ # see the metaprogramming in lib/active_support/basic_object.rb,
507
+ # where we already know BasicObject as a class when we find
508
+ # BasicObject = BlankSlate
509
+ return from if RDoc::TopLevel.find_class_or_module(to_name)
510
+
511
+ if from.module? then
512
+ RDoc::TopLevel.modules_hash[to_name] = from
513
+ @modules[name] = from
514
+ else
515
+ RDoc::TopLevel.classes_hash[to_name] = from
516
+ @classes[name] = from
414
517
  end
415
518
 
519
+ # HACK: register a constant for this alias:
520
+ # constant value and comment will be updated after,
521
+ # when the Ruby parser adds the constant
522
+ const = RDoc::Constant.new(name, nil, '')
523
+ const.is_alias_for = from
524
+ add_constant const
525
+
416
526
  from
417
527
  end
418
528
 
@@ -420,6 +530,8 @@ class RDoc::Context < RDoc::CodeObject
420
530
  # Adds +require+ to this context's top level
421
531
 
422
532
  def add_require(require)
533
+ return require unless @document_self
534
+
423
535
  if RDoc::TopLevel === self then
424
536
  add_to @requires, require
425
537
  else
@@ -431,22 +543,57 @@ class RDoc::Context < RDoc::CodeObject
431
543
  # Adds +thing+ to the collection +array+
432
544
 
433
545
  def add_to(array, thing)
434
- array << thing if @document_self and not @done_documenting
546
+ array << thing if @document_self
435
547
  thing.parent = self
436
548
  thing.section = @current_section
437
549
  end
438
550
 
551
+ ##
552
+ # Is there any content?
553
+ # This means any of: comment, aliases, methods, attributes,
554
+ # external aliases, require, constant.
555
+ # Includes are also checked unless <tt>includes == false</tt>.
556
+
557
+ def any_content(includes = true)
558
+ @any_content ||= !(
559
+ @comment.empty? &&
560
+ @method_list.empty? &&
561
+ @attributes.empty? &&
562
+ @aliases.empty? &&
563
+ @external_aliases.empty? &&
564
+ @requires.empty? &&
565
+ @constants.empty?
566
+ )
567
+ @any_content || (includes && !@includes.empty?)
568
+ end
569
+
439
570
  ##
440
571
  # Creates the full name for a child with +name+
441
572
 
442
573
  def child_name name
443
- if RDoc::TopLevel === self then
574
+ if name =~ /^:+/
575
+ $' #'
576
+ elsif RDoc::TopLevel === self then
444
577
  name
445
578
  else
446
579
  "#{self.full_name}::#{name}"
447
580
  end
448
581
  end
449
582
 
583
+ ##
584
+ # Class attributes
585
+
586
+ def class_attributes
587
+ @class_attributes ||= attributes.select { |a| a.singleton }
588
+ end
589
+
590
+ ##
591
+ # Class methods
592
+
593
+ def class_method_list
594
+ @class_method_list ||= method_list.select { |a| a.singleton }
595
+ end
596
+
450
597
  ##
451
598
  # Array of classes in this context
452
599
 
@@ -475,6 +622,14 @@ class RDoc::Context < RDoc::CodeObject
475
622
  @in_files.include?(file)
476
623
  end
477
624
 
625
+ def display(method_attr) # :nodoc:
626
+ if method_attr.is_a? RDoc::Attr
627
+ "#{method_attr.definition} #{method_attr.pretty_name}"
628
+ else
629
+ "method #{method_attr.pretty_name}"
630
+ end
631
+ end
632
+
478
633
  ##
479
634
  # Iterator for attributes
480
635
 
@@ -510,11 +665,26 @@ class RDoc::Context < RDoc::CodeObject
510
665
  @method_list.sort.each {|m| yield m}
511
666
  end
512
667
 
668
+ ##
669
+ # Finds an attribute +name+ with singleton value +singleton+.
670
+
671
+ def find_attribute(name, singleton)
672
+ name = $1 if name =~ /^(.*)=$/
673
+ @attributes.find { |a| a.name == name && a.singleton == singleton }
674
+ end
675
+
513
676
  ##
514
677
  # Finds an attribute with +name+ in this context
515
678
 
516
679
  def find_attribute_named(name)
517
- @attributes.find { |m| m.name == name }
680
+ case name
681
+ when /\A#/ then
682
+ find_attribute name[1..-1], false
683
+ when /\A::/ then
684
+ find_attribute name[2..-1], true
685
+ else
686
+ @attributes.find { |a| a.name == name }
687
+ end
518
688
  end
519
689
 
520
690
  ##
@@ -538,6 +708,27 @@ class RDoc::Context < RDoc::CodeObject
538
708
  parent && parent.find_module_named(name)
539
709
  end
540
710
 
711
+ ##
712
+ # Finds an external alias +name+ with singleton value +singleton+.
713
+
714
+ def find_external_alias(name, singleton)
715
+ @external_aliases.find { |m| m.name == name && m.singleton == singleton }
716
+ end
717
+
718
+ ##
719
+ # Finds an external alias with +name+ in this context
720
+
721
+ def find_external_alias_named(name)
722
+ case name
723
+ when /\A#/ then
724
+ find_external_alias name[1..-1], false
725
+ when /\A::/ then
726
+ find_external_alias name[2..-1], true
727
+ else
728
+ @external_aliases.find { |a| a.name == name }
729
+ end
730
+ end
731
+
541
732
  ##
542
733
  # Finds a file with +name+ in this context
543
734
 
@@ -553,26 +744,34 @@ class RDoc::Context < RDoc::CodeObject
553
744
  end
554
745
 
555
746
  ##
556
- # Finds a method, constant, attribute, module or files named +symbol+ in
557
- # this context
747
+ # Finds a method, constant, attribute, external alias, module or file
748
+ # named +symbol+ in this context.
558
749
 
559
750
  def find_local_symbol(symbol)
560
751
  find_method_named(symbol) or
561
752
  find_constant_named(symbol) or
562
753
  find_attribute_named(symbol) or
754
+ find_external_alias_named(symbol) or
563
755
  find_module_named(symbol) or
564
756
  find_file_named(symbol)
565
757
  end
566
758
 
759
+ ##
760
+ # Finds a method named +name+ with singleton value +singleton+.
761
+
762
+ def find_method(name, singleton)
763
+ @method_list.find { |m| m.name == name && m.singleton == singleton }
764
+ end
765
+
567
766
  ##
568
767
  # Finds a instance or module method with +name+ in this context
569
768
 
570
769
  def find_method_named(name)
571
770
  case name
572
771
  when /\A#/ then
573
- find_instance_method_named name[1..-1]
772
+ find_method name[1..-1], false
574
773
  when /\A::/ then
575
- find_class_method_named name[2..-1]
774
+ find_method name[2..-1], true
576
775
  else
577
776
  @method_list.find { |meth| meth.name == name }
578
777
  end
@@ -589,51 +788,42 @@ class RDoc::Context < RDoc::CodeObject
589
788
  end
590
789
 
591
790
  ##
592
- # Look up +symbol+. If +method+ is non-nil, then we assume the symbol
593
- # references a module that contains that method.
791
+ # Look up +symbol+, first as a module, then as a local symbol.
792
+
793
+ def find_symbol(symbol)
794
+ find_symbol_module(symbol) || find_local_symbol(symbol)
795
+ end
796
+
797
+ ##
798
+ # Look up a module named +symbol+.
594
799
 
595
- def find_symbol(symbol, method = nil)
800
+ def find_symbol_module(symbol)
596
801
  result = nil
597
802
 
803
+ # look for a class or module 'symbol'
598
804
  case symbol
599
- when /^::([A-Z].*)/ then
600
- result = top_level.find_symbol($1)
601
- when /::/ then
602
- modules = symbol.split(/::/)
603
-
604
- unless modules.empty? then
605
- module_name = modules.shift
606
- result = find_module_named(module_name)
607
-
608
- if result then
609
- modules.each do |name|
610
- result = result.find_module_named name
611
- break unless result
612
- end
613
- end
805
+ when /^::/ then
806
+ result = RDoc::TopLevel.find_class_or_module(symbol)
807
+ when /^(\w+):+(.+)$/
808
+ suffix = $2
809
+ top = $1
810
+ searched = self
811
+ loop do
812
+ mod = searched.find_module_named(top)
813
+ break unless mod
814
+ result = RDoc::TopLevel.find_class_or_module(mod.full_name + '::' + suffix)
815
+ break if result || searched.is_a?(RDoc::TopLevel)
816
+ searched = searched.parent
614
817
  end
615
- end
616
-
617
- unless result then
618
- # if a method is specified, then we're definitely looking for
619
- # a module, otherwise it could be any symbol
620
- if method then
621
- result = find_module_named symbol
622
- else
623
- result = find_local_symbol symbol
624
- if result.nil? then
625
- if symbol =~ /^[A-Z]/ then
626
- result = parent
627
- while result && result.name != symbol do
628
- result = result.parent
629
- end
630
- end
631
- end
818
+ else
819
+ searched = self
820
+ loop do
821
+ result = searched.find_module_named(symbol)
822
+ break if result || searched.is_a?(RDoc::TopLevel)
823
+ searched = searched.parent
632
824
  end
633
825
  end
634
826
 
635
- result = result.find_local_symbol method if result and method
636
-
637
827
  result
638
828
  end
639
829
 
@@ -644,27 +834,53 @@ class RDoc::Context < RDoc::CodeObject
644
834
  '(unknown)'
645
835
  end
646
836
 
837
+ ##
838
+ # Does this context and its methods and constants all have documentation?
839
+ #
840
+ # (Yes, fully documented doesn't mean everything.)
841
+
842
+ def fully_documented?
843
+ documented? and
844
+ attributes.all? { |a| a.documented? } and
845
+ method_list.all? { |m| m.documented? } and
846
+ constants.all? { |c| c.documented? }
847
+ end
848
+
647
849
  ##
648
850
  # URL for this with a +prefix+
649
851
 
650
852
  def http_url(prefix)
651
- path = full_name
853
+ path = name_for_path
652
854
  path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</
653
855
  path = [prefix] + path.split('::')
654
856
 
655
857
  File.join(*path.compact) + '.html'
656
858
  end
657
859
 
860
+ ##
861
+ # Instance attributes
862
+
863
+ def instance_attributes
864
+ @instance_attributes ||= attributes.reject { |a| a.singleton }
865
+ end
866
+
867
+ ##
868
+ # Instance methods
869
+
870
+ def instance_method_list
871
+ @instance_method_list ||= method_list.reject { |a| a.singleton }
872
+ end
873
+
658
874
  ##
659
875
  # Breaks method_list into a nested hash by type (class or instance) and
660
- # visibility (public, protected private)
876
+ # visibility (public, protected, private)
661
877
 
662
878
  def methods_by_type
663
879
  methods = {}
664
880
 
665
881
  TYPES.each do |type|
666
882
  visibilities = {}
667
- VISIBILITIES.each do |vis|
883
+ RDoc::VISIBILITIES.each do |vis|
668
884
  visibilities[vis] = []
669
885
  end
670
886
 
@@ -679,23 +895,11 @@ class RDoc::Context < RDoc::CodeObject
679
895
  end
680
896
 
681
897
  ##
682
- # Yields Method and Attr entries matching the list of names in +methods+.
683
- # Attributes are only returned when +singleton+ is false.
898
+ # Yields AnyMethod and Attr entries matching the list of names in +methods+.
684
899
 
685
900
  def methods_matching(methods, singleton = false)
686
- count = 0
687
-
688
- @method_list.each do |m|
689
- if methods.include? m.name and m.singleton == singleton then
690
- yield m
691
- count += 1
692
- end
693
- end
694
-
695
- return if count == methods.size || singleton
696
-
697
- @attributes.each do |a|
698
- yield a if methods.include? a.name
901
+ (@method_list + @attributes).each do |m|
902
+ yield m if methods.include?(m.name) and m.singleton == singleton
699
903
  end
700
904
  end
701
905
 
@@ -713,6 +917,14 @@ class RDoc::Context < RDoc::CodeObject
713
917
  @modules
714
918
  end
715
919
 
920
+ ##
921
+ # Name to use to generate the url.
922
+ # <tt>#full_name</tt> by default.
923
+
924
+ def name_for_path
925
+ full_name
926
+ end
927
+
716
928
  ##
717
929
  # Changes the visibility for new methods to +visibility+
718
930
 
@@ -721,35 +933,63 @@ class RDoc::Context < RDoc::CodeObject
721
933
  end
722
934
 
723
935
  ##
724
- # Record which file +top_level+ is in
936
+ # Record +top_level+ as a file +self+ is in.
725
937
 
726
938
  def record_location(top_level)
727
939
  @in_files << top_level unless @in_files.include?(top_level)
728
940
  end
729
941
 
730
942
  ##
731
- # If a class's documentation is turned off after we've started collecting
732
- # methods etc., we need to remove the ones we have
733
-
734
- def remove_methods_etc
735
- initialize_methods_etc
943
+ # Should we remove this context from the documentation?
944
+ #
945
+ # The answer is yes if:
946
+ # * #received_nodoc is +true+
947
+ # * #any_content is +false+ (not counting includes)
948
+ # * All #includes are modules (not a string), and their module has
949
+ # <tt>#remove_from_documentation? == true</tt>
950
+ # * All classes and modules have <tt>#remove_from_documentation? == true</tt>
951
+
952
+ def remove_from_documentation?
953
+ @remove_from_documentation ||=
954
+ @received_nodoc &&
955
+ !any_content(false) &&
956
+ @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } &&
957
+ classes_and_modules.all? { |cm| cm.remove_from_documentation? }
736
958
  end
737
959
 
738
960
  ##
739
- # Given an array +methods+ of method names, set the visibility of each to
740
- # +visibility+
961
+ # Removes methods and attributes with a visibility less than +min_visibility+.
962
+ #--
963
+ # TODO mark the visibility of attributes in the template (if not public?)
741
964
 
742
- def set_visibility_for(methods, visibility, singleton = false)
743
- methods_matching methods, singleton do |m|
744
- m.visibility = visibility
965
+ def remove_invisible(min_visibility)
966
+ return if min_visibility == :private
967
+ remove_invisible_in @method_list, min_visibility
968
+ remove_invisible_in @attributes, min_visibility
969
+ end
970
+
971
+ def remove_invisible_in(array, min_visibility) # :nodoc:
972
+ if min_visibility == :public
973
+ array.reject! { |e| e.visibility != :public }
974
+ else
975
+ array.reject! { |e| e.visibility == :private }
745
976
  end
746
977
  end
747
978
 
748
979
  ##
749
- # Removes classes and modules when we see a :nodoc: all
980
+ # Tries to resolve unmatched aliases when a method
981
+ # or attribute has just been added.
750
982
 
751
- def remove_classes_and_modules
752
- initialize_classes_and_modules
983
+ def resolve_aliases(added)
984
+ # resolve any pending unmatched aliases
985
+ key = added.pretty_name
986
+ unmatched_alias_list = @unmatched_alias_lists[key]
987
+ return unless unmatched_alias_list
988
+ unmatched_alias_list.each do |unmatched_alias|
989
+ added.add_alias unmatched_alias, self
990
+ @external_aliases.delete unmatched_alias
991
+ end
992
+ @unmatched_alias_lists.delete key
753
993
  end
754
994
 
755
995
  ##
@@ -760,8 +1000,25 @@ class RDoc::Context < RDoc::CodeObject
760
1000
  @sections << @current_section
761
1001
  end
762
1002
 
1003
+ ##
1004
+ # Given an array +methods+ of method names, set the visibility of each to
1005
+ # +visibility+
1006
+
1007
+ def set_visibility_for(methods, visibility, singleton = false)
1008
+ methods_matching methods, singleton do |m|
1009
+ m.visibility = visibility
1010
+ end
1011
+ end
1012
+
1013
+ def to_s # :nodoc:
1014
+ "#{self.class.name} #{self.full_name}"
1015
+ end
1016
+
763
1017
  ##
764
1018
  # Return the TopLevel that owns us
1019
+ #--
1020
+ # FIXME we can be 'owned' by several TopLevel (see #record_location &
1021
+ # #in_files)
765
1022
 
766
1023
  def top_level
767
1024
  return @top_level if defined? @top_level
@@ -770,5 +1027,20 @@ class RDoc::Context < RDoc::CodeObject
770
1027
  @top_level
771
1028
  end
772
1029
 
1030
+ ##
1031
+ # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+
1032
+
1033
+ def upgrade_to_class mod, class_type, enclosing
1034
+ enclosing.modules_hash.delete mod.name
1035
+
1036
+ klass = RDoc::ClassModule.from_module class_type, mod
1037
+
1038
+ # if it was there, then we keep it even if done_documenting
1039
+ RDoc::TopLevel.classes_hash[mod.full_name] = klass
1040
+ enclosing.classes_hash[mod.name] = klass
1041
+
1042
+ klass
1043
+ end
1044
+
773
1045
  end
774
1046