rdoc 2.3.0 → 2.4.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 (81) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +14 -0
  3. data/History.txt +27 -0
  4. data/Manifest.txt +29 -9
  5. data/Rakefile +2 -0
  6. data/bin/rdoc +13 -2
  7. data/lib/rdoc.rb +11 -3
  8. data/lib/rdoc/alias.rb +54 -0
  9. data/lib/rdoc/anon_class.rb +10 -0
  10. data/lib/rdoc/any_method.rb +190 -0
  11. data/lib/rdoc/attr.rb +79 -0
  12. data/lib/rdoc/cache.rb +11 -2
  13. data/lib/rdoc/class_module.rb +87 -0
  14. data/lib/rdoc/code_object.rb +152 -0
  15. data/lib/rdoc/code_objects.rb +18 -1118
  16. data/lib/rdoc/constant.rb +36 -0
  17. data/lib/rdoc/context.rb +712 -0
  18. data/lib/rdoc/diagram.rb +8 -8
  19. data/lib/rdoc/generator.rb +3 -1140
  20. data/lib/rdoc/generator/darkfish.rb +107 -133
  21. data/lib/rdoc/generator/markup.rb +194 -0
  22. data/lib/rdoc/generator/ri.rb +4 -2
  23. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +92 -113
  24. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +33 -35
  25. data/lib/rdoc/generator/template/darkfish/index.rhtml +22 -15
  26. data/lib/rdoc/ghost_method.rb +8 -0
  27. data/lib/rdoc/include.rb +39 -0
  28. data/lib/rdoc/markup/attribute_manager.rb +46 -0
  29. data/lib/rdoc/markup/formatter.rb +11 -0
  30. data/lib/rdoc/markup/fragments.rb +42 -2
  31. data/lib/rdoc/markup/inline.rb +29 -4
  32. data/lib/rdoc/markup/lines.rb +4 -0
  33. data/lib/rdoc/markup/preprocess.rb +4 -0
  34. data/lib/rdoc/markup/to_flow.rb +27 -1
  35. data/lib/rdoc/markup/to_html.rb +33 -33
  36. data/lib/rdoc/markup/to_html_crossref.rb +4 -11
  37. data/lib/rdoc/markup/to_latex.rb +31 -31
  38. data/lib/rdoc/markup/to_test.rb +3 -0
  39. data/lib/rdoc/markup/to_texinfo.rb +18 -14
  40. data/lib/rdoc/meta_method.rb +8 -0
  41. data/lib/rdoc/normal_class.rb +18 -0
  42. data/lib/rdoc/normal_module.rb +34 -0
  43. data/lib/rdoc/options.rb +26 -159
  44. data/lib/rdoc/parser/c.rb +16 -8
  45. data/lib/rdoc/parser/ruby.rb +16 -10
  46. data/lib/rdoc/parser/simple.rb +1 -1
  47. data/lib/rdoc/rdoc.rb +50 -34
  48. data/lib/rdoc/require.rb +32 -0
  49. data/lib/rdoc/ri/descriptions.rb +1 -1
  50. data/lib/rdoc/ri/driver.rb +4 -4
  51. data/lib/rdoc/ri/formatter.rb +70 -32
  52. data/lib/rdoc/single_class.rb +8 -0
  53. data/lib/rdoc/top_level.rb +232 -0
  54. data/test/test_rdoc_any_method.rb +10 -0
  55. data/test/test_rdoc_code_object.rb +80 -0
  56. data/test/test_rdoc_constant.rb +15 -0
  57. data/test/test_rdoc_context.rb +250 -0
  58. data/test/test_rdoc_include.rb +17 -0
  59. data/test/test_rdoc_markup.rb +13 -2
  60. data/test/test_rdoc_markup_to_html.rb +22 -0
  61. data/test/test_rdoc_markup_to_html_crossref.rb +50 -115
  62. data/test/test_rdoc_normal_module.rb +26 -0
  63. data/test/test_rdoc_parser_c.rb +33 -0
  64. data/test/test_rdoc_parser_ruby.rb +54 -36
  65. data/test/test_rdoc_require.rb +25 -0
  66. data/test/test_rdoc_ri_default_display.rb +2 -1
  67. data/test/test_rdoc_ri_html_formatter.rb +141 -0
  68. data/test/test_rdoc_top_level.rb +85 -0
  69. data/test/xref_data.rb +46 -0
  70. data/test/xref_test_case.rb +48 -0
  71. metadata +42 -13
  72. metadata.gz.sig +0 -0
  73. data/lib/rdoc/generator/html.rb +0 -456
  74. data/lib/rdoc/generator/html/common.rb +0 -24
  75. data/lib/rdoc/generator/html/html.rb +0 -769
  76. data/lib/rdoc/generator/html/one_page_html.rb +0 -122
  77. data/lib/rdoc/generator/xml.rb +0 -124
  78. data/lib/rdoc/generator/xml/rdf.rb +0 -113
  79. data/lib/rdoc/generator/xml/xml.rb +0 -123
  80. data/lib/rdoc/parser/f95.rb +0 -1835
  81. data/lib/rdoc/template.rb +0 -68
@@ -0,0 +1,79 @@
1
+ require 'rdoc/code_object'
2
+
3
+ ##
4
+ # An attribute created by \#attr, \#attr_reader, \#attr_writer or
5
+ # \#attr_accessor
6
+
7
+ class RDoc::Attr < RDoc::CodeObject
8
+
9
+ ##
10
+ # Name of the attribute
11
+
12
+ attr_accessor :name
13
+
14
+ ##
15
+ # Is the attribute readable, writable or both?
16
+
17
+ attr_accessor :rw
18
+
19
+ ##
20
+ # Source file token stream
21
+
22
+ attr_accessor :text
23
+
24
+ ##
25
+ # public, protected, private
26
+
27
+ attr_accessor :visibility
28
+
29
+ def initialize(text, name, rw, comment)
30
+ super()
31
+ @text = text
32
+ @name = name
33
+ @rw = rw
34
+ @visibility = :public
35
+ self.comment = comment
36
+ end
37
+
38
+ ##
39
+ # Attributes are ordered by name
40
+
41
+ def <=>(other)
42
+ self.name <=> other.name
43
+ end
44
+
45
+ ##
46
+ # An HTML id-friendly representation of #name
47
+
48
+ def html_name
49
+ @name.gsub(/[^a-z]+/, '-')
50
+ end
51
+
52
+ def inspect # :nodoc:
53
+ attr = case rw
54
+ when 'RW' then :attr_accessor
55
+ when 'R' then :attr_reader
56
+ when 'W' then :attr_writer
57
+ else
58
+ " (#{rw})"
59
+ end
60
+
61
+ "#<%s:0x%x %s.%s :%s>" % [
62
+ self.class, object_id,
63
+ parent_name, attr, @name,
64
+ ]
65
+ end
66
+
67
+ ##
68
+ # URL path for this attribute
69
+
70
+ def path
71
+ "#{@parent.path}##{@name}"
72
+ end
73
+
74
+ def to_s # :nodoc:
75
+ "attr: #{self.name} #{self.rw}\n#{self.comment}"
76
+ end
77
+
78
+ end
79
+
@@ -9,24 +9,33 @@ class RDoc::Cache
9
9
 
10
10
  include Singleton
11
11
 
12
+ ##
13
+ # Creates a new, empty cache
14
+
12
15
  def initialize
13
16
  @contents = {}
14
17
  @lock = Mutex.new
15
18
  end
16
19
 
20
+ ##
17
21
  # Checks whether there's a value in the cache with key +key+. If so, then
18
- # that value will be returned. Otherwise, the given block will be run,
19
- # and its return value will be put into the cache, and returned.
22
+ # that value will be returned. Otherwise, the given block will be run, and
23
+ # its return value will be put into the cache, and returned.
24
+
20
25
  def cache(key)
21
26
  @lock.synchronize do
22
27
  @contents[key] ||= yield
23
28
  end
24
29
  end
25
30
 
31
+ ##
32
+ # Clears the contents of the cache
33
+
26
34
  def clear
27
35
  @lock.synchronize do
28
36
  @contents.clear
29
37
  end
30
38
  end
39
+
31
40
  end
32
41
 
@@ -0,0 +1,87 @@
1
+ require 'rdoc/context'
2
+
3
+ ##
4
+ # ClassModule is the base class for objects representing either a class or a
5
+ # module.
6
+
7
+ class RDoc::ClassModule < RDoc::Context
8
+
9
+ attr_accessor :diagram
10
+
11
+ ##
12
+ # Creates a new ClassModule with +name+ with optional +superclass+
13
+
14
+ def initialize(name, superclass = 'Object')
15
+ @diagram = nil
16
+ @full_name = nil
17
+ @name = name
18
+ @superclass = superclass
19
+ super()
20
+ end
21
+
22
+ ##
23
+ # Finds a class or module with +name+ in this namespace or its descendents
24
+
25
+ def find_class_named(name)
26
+ return self if full_name == name
27
+ @classes.each_value {|c| return c if c.find_class_named(name) }
28
+ nil
29
+ end
30
+
31
+ ##
32
+ # Return the fully qualified name of this class or module
33
+
34
+ def full_name
35
+ @full_name ||= if RDoc::ClassModule === @parent then
36
+ "#{@parent.full_name}::#{@name}"
37
+ else
38
+ @name
39
+ end
40
+ end
41
+
42
+ ##
43
+ # 'module' or 'class'
44
+
45
+ def type
46
+ module? ? 'module' : 'class'
47
+ end
48
+
49
+ ##
50
+ # Does this object represent a module?
51
+
52
+ def module?
53
+ false
54
+ end
55
+
56
+ ##
57
+ # Path to this class or module
58
+
59
+ def path
60
+ http_url RDoc::RDoc.current.generator.class_dir
61
+ end
62
+
63
+ ##
64
+ # Get the superclass of this class. Attempts to retrieve the superclass
65
+ # object, returns the name if it is not known.
66
+
67
+ def superclass
68
+ raise NoMethodError, "#{full_name} is a module" if module?
69
+
70
+ RDoc::TopLevel.find_class_named(@superclass) || @superclass
71
+ end
72
+
73
+ ##
74
+ # Set the superclass of this class to +superclass+
75
+
76
+ def superclass=(superclass)
77
+ raise NoMethodError, "#{full_name} is a module" if module?
78
+
79
+ @superclass = superclass if @superclass.nil? or @superclass == 'Object'
80
+ end
81
+
82
+ def to_s # :nodoc:
83
+ "#{self.class}: #{full_name} #{@comment} #{super}"
84
+ end
85
+
86
+ end
87
+
@@ -0,0 +1,152 @@
1
+ require 'rdoc'
2
+
3
+ ##
4
+ # We contain the common stuff for contexts (which are containers) and other
5
+ # elements (methods, attributes and so on)
6
+
7
+ class RDoc::CodeObject
8
+
9
+ ##
10
+ # Our comment
11
+
12
+ attr_reader :comment
13
+
14
+ ##
15
+ # Do we document our children?
16
+
17
+ attr_reader :document_children
18
+
19
+ ##
20
+ # Do we document ourselves?
21
+
22
+ attr_reader :document_self
23
+
24
+ ##
25
+ # Are we done documenting (ie, did we come across a :enddoc:)?
26
+
27
+ attr_accessor :done_documenting
28
+
29
+ ##
30
+ # Force documentation of this CodeObject
31
+
32
+ attr_accessor :force_documentation
33
+
34
+ ##
35
+ # Our parent CodeObject
36
+
37
+ attr_accessor :parent
38
+
39
+ ##
40
+ # Which section are we in
41
+
42
+ attr_accessor :section
43
+
44
+ ##
45
+ # We are the model of the code, but we know that at some point we will be
46
+ # worked on by viewers. By implementing the Viewable protocol, viewers can
47
+ # associated themselves with these objects.
48
+
49
+ attr_accessor :viewer
50
+
51
+ ##
52
+ # There's a wee trick we pull. Comment blocks can have directives that
53
+ # override the stuff we extract during the parse. So, we have a special
54
+ # class method, attr_overridable, that lets code objects list those
55
+ # directives. When a comment is assigned, we then extract out any matching
56
+ # directives and update our object
57
+
58
+ def self.attr_overridable(name, *aliases)
59
+ @overridables ||= {}
60
+
61
+ attr_accessor name
62
+
63
+ aliases.unshift name
64
+
65
+ aliases.each do |directive_name|
66
+ @overridables[directive_name.to_s] = name
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Creates a new CodeObject that will document itself and its children
72
+
73
+ def initialize
74
+ @comment = nil
75
+ @document_children = true
76
+ @document_self = true
77
+ @done_documenting = false
78
+ @force_documentation = false
79
+ @parent = nil
80
+ end
81
+
82
+ ##
83
+ # Replaces our comment with +comment+, unless it is empty.
84
+
85
+ def comment=(comment)
86
+ @comment = comment unless comment.empty?
87
+ end
88
+
89
+ ##
90
+ # Enables or disables documentation of this CodeObject's children. Calls
91
+ # remove_classes_and_modules when disabling.
92
+
93
+ def document_children=(document_children)
94
+ @document_children = document_children
95
+ remove_classes_and_modules unless document_children
96
+ end
97
+
98
+ ##
99
+ # Enables or disables documentation of this CodeObject. Calls
100
+ # remove_methods_etc when disabling.
101
+
102
+ def document_self=(document_self)
103
+ @document_self = document_self
104
+ remove_methods_etc unless document_self
105
+ end
106
+
107
+ ##
108
+ # File name of our parent
109
+
110
+ def parent_file_name
111
+ @parent ? @parent.base_name : '(unknown)'
112
+ end
113
+
114
+ ##
115
+ # Name of our parent
116
+
117
+ def parent_name
118
+ @parent ? @parent.full_name : '(unknown)'
119
+ end
120
+
121
+ ##
122
+ # Callback called upon disabling documentation of children. See
123
+ # #document_children=
124
+
125
+ def remove_classes_and_modules
126
+ end
127
+
128
+ ##
129
+ # Callback called upon disabling documentation of ourself. See
130
+ # #document_self=
131
+
132
+ def remove_methods_etc
133
+ end
134
+
135
+ ##
136
+ # Enable capture of documentation
137
+
138
+ def start_doc
139
+ @document_self = true
140
+ @document_children = true
141
+ end
142
+
143
+ ##
144
+ # Disable capture of documentation
145
+
146
+ def stop_doc
147
+ @document_self = false
148
+ @document_children = false
149
+ end
150
+
151
+ end
152
+
@@ -1,1123 +1,23 @@
1
- # We represent the various high-level code constructs that appear
2
- # in Ruby programs: classes, modules, methods, and so on.
1
+ # We represent the various high-level code constructs that appear in Ruby
2
+ # programs: classes, modules, methods, and so on.
3
3
 
4
- require 'thread'
4
+ require 'rdoc/code_object'
5
+ require 'rdoc/context'
6
+ require 'rdoc/top_level'
5
7
 
6
- require 'rdoc/tokenstream'
8
+ require 'rdoc/class_module'
9
+ require 'rdoc/normal_class'
10
+ require 'rdoc/normal_module'
11
+ require 'rdoc/anon_class'
12
+ require 'rdoc/single_class'
7
13
 
8
- module RDoc
14
+ require 'rdoc/any_method'
15
+ require 'rdoc/alias'
16
+ require 'rdoc/ghost_method'
17
+ require 'rdoc/meta_method'
9
18
 
10
- ##
11
- # We contain the common stuff for contexts (which are containers) and other
12
- # elements (methods, attributes and so on)
19
+ require 'rdoc/attr'
20
+ require 'rdoc/constant'
21
+ require 'rdoc/require'
22
+ require 'rdoc/include'
13
23
 
14
- class CodeObject
15
-
16
- ##
17
- # Our comment
18
-
19
- attr_reader :comment
20
-
21
- ##
22
- # Do we document our children?
23
-
24
- attr_reader :document_children
25
-
26
- ##
27
- # Do we document ourselves?
28
-
29
- attr_reader :document_self
30
-
31
- ##
32
- # Are we done documenting (ie, did we come across a :enddoc:)?
33
-
34
- attr_accessor :done_documenting
35
-
36
- ##
37
- # Our parent CodeObject
38
-
39
- attr_accessor :parent
40
-
41
- ##
42
- # Which section are we in
43
-
44
- attr_accessor :section
45
-
46
- ##
47
- # We are the model of the code, but we know that at some point we will be
48
- # worked on by viewers. By implementing the Viewable protocol, viewers can
49
- # associated themselves with these objects.
50
-
51
- attr_accessor :viewer
52
-
53
- def initialize
54
- @document_self = true
55
- @document_children = true
56
- @force_documentation = false
57
- @done_documenting = false
58
- end
59
-
60
- ##
61
- # Enables or disables documentation of this CodeObject. Calls
62
- # remove_methods_etc when disabling.
63
-
64
- def document_self=(document_self)
65
- @document_self = document_self
66
- remove_methods_etc unless document_self
67
- end
68
-
69
- ##
70
- # Enable capture of documentation
71
-
72
- def start_doc
73
- @document_self = true
74
- @document_children = true
75
- end
76
-
77
- ##
78
- # Disable capture of documentation
79
-
80
- def stop_doc
81
- @document_self = false
82
- @document_children = false
83
- end
84
-
85
- ##
86
- # Enables or disables documentation of this CodeObject's children. Calls
87
- # remove_classes_and_modules when disabling.
88
-
89
- def document_children=(document_children)
90
- @document_children = document_children
91
- remove_classes_and_modules unless document_children
92
- end
93
-
94
- ##
95
- # Force documentation of this CodeObject
96
-
97
- attr_accessor :force_documentation
98
-
99
- ##
100
- # File name of our parent
101
-
102
- def parent_file_name
103
- @parent ? @parent.file_base_name : '(unknown)'
104
- end
105
-
106
- ##
107
- # Name of our parent
108
-
109
- def parent_name
110
- @parent ? @parent.name : '(unknown)'
111
- end
112
-
113
- ##
114
- # Callback called upon disabling documentation of children. See
115
- # #document_children=
116
-
117
- def remove_classes_and_modules
118
- end
119
-
120
- ##
121
- # Callback called upon disabling documentation of ourself. See
122
- # #document_self=
123
-
124
- def remove_methods_etc
125
- end
126
-
127
- ##
128
- # Replaces our comment with +comment+, unless it is empty.
129
-
130
- def comment=(comment)
131
- @comment = comment unless comment.empty?
132
- end
133
-
134
- ##
135
- # There's a wee trick we pull. Comment blocks can have directives that
136
- # override the stuff we extract during the parse. So, we have a special
137
- # class method, attr_overridable, that lets code objects list those
138
- # directives. When a comment is assigned, we then extract out any matching
139
- # directives and update our object
140
-
141
- def self.attr_overridable(name, *aliases)
142
- @overridables ||= {}
143
-
144
- attr_accessor name
145
-
146
- aliases.unshift name
147
- aliases.each do |directive_name|
148
- @overridables[directive_name.to_s] = name
149
- end
150
- end
151
-
152
- end
153
-
154
- ##
155
- # A Context is something that can hold modules, classes, methods,
156
- # attributes, aliases, requires, and includes. Classes, modules, and files
157
- # are all Contexts.
158
-
159
- class Context < CodeObject
160
-
161
- attr_reader :aliases
162
- attr_reader :attributes
163
- attr_reader :constants
164
- attr_reader :current_section
165
- attr_reader :in_files
166
- attr_reader :includes
167
- attr_reader :method_list
168
- attr_reader :name
169
- attr_reader :requires
170
- attr_reader :sections
171
- attr_reader :visibility
172
-
173
- class Section
174
- attr_reader :title, :comment, :sequence
175
-
176
- @@sequence = "SEC00000"
177
- @@sequence_lock = Mutex.new
178
-
179
- def initialize(title, comment)
180
- @title = title
181
- @@sequence_lock.synchronize do
182
- @@sequence.succ!
183
- @sequence = @@sequence.dup
184
- end
185
- @comment = nil
186
- set_comment(comment)
187
- end
188
-
189
- def ==(other)
190
- self.class === other and @sequence == other.sequence
191
- end
192
-
193
- def inspect
194
- "#<%s:0x%x %s %p>" % [
195
- self.class, object_id,
196
- @sequence, title
197
- ]
198
- end
199
-
200
- ##
201
- # Set the comment for this section from the original comment block If
202
- # the first line contains :section:, strip it and use the rest.
203
- # Otherwise remove lines up to the line containing :section:, and look
204
- # for those lines again at the end and remove them. This lets us write
205
- #
206
- # # ---------------------
207
- # # :SECTION: The title
208
- # # The body
209
- # # ---------------------
210
-
211
- def set_comment(comment)
212
- return unless comment
213
-
214
- if comment =~ /^#[ \t]*:section:.*\n/
215
- start = $`
216
- rest = $'
217
-
218
- if start.empty?
219
- @comment = rest
220
- else
221
- @comment = rest.sub(/#{start.chomp}\Z/, '')
222
- end
223
- else
224
- @comment = comment
225
- end
226
- @comment = nil if @comment.empty?
227
- end
228
-
229
- end
230
-
231
- def initialize
232
- super
233
-
234
- @in_files = []
235
-
236
- @name ||= "unknown"
237
- @comment ||= ""
238
- @parent = nil
239
- @visibility = :public
240
-
241
- @current_section = Section.new(nil, nil)
242
- @sections = [ @current_section ]
243
-
244
- initialize_methods_etc
245
- initialize_classes_and_modules
246
- end
247
-
248
- ##
249
- # map the class hash to an array externally
250
-
251
- def classes
252
- @classes.values
253
- end
254
-
255
- ##
256
- # map the module hash to an array externally
257
-
258
- def modules
259
- @modules.values
260
- end
261
-
262
- ##
263
- # return the classes Hash (only to be used internally)
264
-
265
- def classes_hash
266
- @classes
267
- end
268
- protected :classes_hash
269
-
270
- ##
271
- # return the modules Hash (only to be used internally)
272
-
273
- def modules_hash
274
- @modules
275
- end
276
- protected :modules_hash
277
-
278
- ##
279
- # Change the default visibility for new methods
280
-
281
- def ongoing_visibility=(vis)
282
- @visibility = vis
283
- end
284
-
285
- ##
286
- # Yields Method and Attr entries matching the list of names in +methods+.
287
- # Attributes are only returned when +singleton+ is false.
288
-
289
- def methods_matching(methods, singleton = false)
290
- count = 0
291
-
292
- @method_list.each do |m|
293
- if methods.include? m.name and m.singleton == singleton then
294
- yield m
295
- count += 1
296
- end
297
- end
298
-
299
- return if count == methods.size || singleton
300
-
301
- # perhaps we need to look at attributes
302
-
303
- @attributes.each do |a|
304
- yield a if methods.include? a.name
305
- end
306
- end
307
-
308
- ##
309
- # Given an array +methods+ of method names, set the visibility of the
310
- # corresponding AnyMethod object
311
-
312
- def set_visibility_for(methods, vis, singleton = false)
313
- methods_matching methods, singleton do |m|
314
- m.visibility = vis
315
- end
316
- end
317
-
318
- ##
319
- # Record the file that we happen to find it in
320
-
321
- def record_location(toplevel)
322
- @in_files << toplevel unless @in_files.include?(toplevel)
323
- end
324
-
325
- # Return true if at least part of this thing was defined in +file+
326
- def defined_in?(file)
327
- @in_files.include?(file)
328
- end
329
-
330
- def add_class(class_type, name, superclass)
331
- klass = add_class_or_module @classes, class_type, name, superclass
332
-
333
- #
334
- # If the parser encounters Container::Item before encountering
335
- # Container, then it assumes that Container is a module. This
336
- # may not be the case, so remove Container from the module list
337
- # if present and transfer any contained classes and modules to
338
- # the new class.
339
- #
340
- mod = @modules.delete(name)
341
-
342
- if mod then
343
- klass.classes_hash.update(mod.classes_hash)
344
- klass.modules_hash.update(mod.modules_hash)
345
- klass.method_list.concat(mod.method_list)
346
- end
347
-
348
- return klass
349
- end
350
-
351
- def add_module(class_type, name)
352
- add_class_or_module(@modules, class_type, name, nil)
353
- end
354
-
355
- def add_method(a_method)
356
- a_method.visibility = @visibility
357
- add_to(@method_list, a_method)
358
-
359
- unmatched_alias_list = @unmatched_alias_lists[a_method.name]
360
- if unmatched_alias_list then
361
- unmatched_alias_list.each do |unmatched_alias|
362
- add_alias_impl unmatched_alias, a_method
363
- @aliases.delete unmatched_alias
364
- end
365
-
366
- @unmatched_alias_lists.delete a_method.name
367
- end
368
- end
369
-
370
- def add_attribute(an_attribute)
371
- add_to(@attributes, an_attribute)
372
- end
373
-
374
- def add_alias_impl(an_alias, meth)
375
- new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
376
- new_meth.is_alias_for = meth
377
- new_meth.singleton = meth.singleton
378
- new_meth.params = meth.params
379
- new_meth.comment = "Alias for \##{meth.name}"
380
- meth.add_alias(new_meth)
381
- add_method(new_meth)
382
- end
383
-
384
- def add_alias(an_alias)
385
- meth = find_instance_method_named(an_alias.old_name)
386
-
387
- if meth then
388
- add_alias_impl(an_alias, meth)
389
- else
390
- add_to(@aliases, an_alias)
391
- unmatched_alias_list = @unmatched_alias_lists[an_alias.old_name] ||= []
392
- unmatched_alias_list.push(an_alias)
393
- end
394
-
395
- an_alias
396
- end
397
-
398
- def add_include(an_include)
399
- add_to(@includes, an_include)
400
- end
401
-
402
- def add_constant(const)
403
- add_to(@constants, const)
404
- end
405
-
406
- # Requires always get added to the top-level (file) context
407
- def add_require(a_require)
408
- if TopLevel === self then
409
- add_to @requires, a_require
410
- else
411
- parent.add_require a_require
412
- end
413
- end
414
-
415
- def add_class_or_module(collection, class_type, name, superclass=nil)
416
- cls = collection[name]
417
-
418
- if cls then
419
- cls.superclass = superclass unless cls.module?
420
- puts "Reusing class/module #{name}" if $DEBUG_RDOC
421
- else
422
- cls = class_type.new(name, superclass)
423
- # collection[name] = cls if @document_self && !@done_documenting
424
- collection[name] = cls if !@done_documenting
425
- cls.parent = self
426
- cls.section = @current_section
427
- end
428
- cls
429
- end
430
-
431
- def add_to(array, thing)
432
- array << thing if @document_self and not @done_documenting
433
- thing.parent = self
434
- thing.section = @current_section
435
- end
436
-
437
- # If a class's documentation is turned off after we've started
438
- # collecting methods etc., we need to remove the ones
439
- # we have
440
-
441
- def remove_methods_etc
442
- initialize_methods_etc
443
- end
444
-
445
- def initialize_methods_etc
446
- @method_list = []
447
- @attributes = []
448
- @aliases = []
449
- @requires = []
450
- @includes = []
451
- @constants = []
452
-
453
- # This Hash maps a method name to a list of unmatched
454
- # aliases (aliases of a method not yet encountered).
455
- @unmatched_alias_lists = {}
456
- end
457
-
458
- # and remove classes and modules when we see a :nodoc: all
459
- def remove_classes_and_modules
460
- initialize_classes_and_modules
461
- end
462
-
463
- def initialize_classes_and_modules
464
- @classes = {}
465
- @modules = {}
466
- end
467
-
468
- # Find a named module
469
- def find_module_named(name)
470
- # First check the enclosed modules, then check the module itself,
471
- # then check the enclosing modules (this mirrors the check done by
472
- # the Ruby parser)
473
- res = @modules[name] || @classes[name]
474
- return res if res
475
- return self if self.name == name
476
- find_enclosing_module_named(name)
477
- end
478
-
479
- # find a module at a higher scope
480
- def find_enclosing_module_named(name)
481
- parent && parent.find_module_named(name)
482
- end
483
-
484
- # Iterate over all the classes and modules in
485
- # this object
486
-
487
- def each_classmodule
488
- @modules.each_value {|m| yield m}
489
- @classes.each_value {|c| yield c}
490
- end
491
-
492
- def each_method
493
- @method_list.each {|m| yield m}
494
- end
495
-
496
- def each_attribute
497
- @attributes.each {|a| yield a}
498
- end
499
-
500
- def each_constant
501
- @constants.each {|c| yield c}
502
- end
503
-
504
- # Return the toplevel that owns us
505
-
506
- def toplevel
507
- return @toplevel if defined? @toplevel
508
- @toplevel = self
509
- @toplevel = @toplevel.parent until TopLevel === @toplevel
510
- @toplevel
511
- end
512
-
513
- # allow us to sort modules by name
514
- def <=>(other)
515
- name <=> other.name
516
- end
517
-
518
- ##
519
- # Look up +symbol+. If +method+ is non-nil, then we assume the symbol
520
- # references a module that contains that method.
521
-
522
- def find_symbol(symbol, method = nil)
523
- result = nil
524
-
525
- case symbol
526
- when /^::(.*)/ then
527
- result = toplevel.find_symbol($1)
528
- when /::/ then
529
- modules = symbol.split(/::/)
530
-
531
- unless modules.empty? then
532
- module_name = modules.shift
533
- result = find_module_named(module_name)
534
-
535
- if result then
536
- modules.each do |name|
537
- result = result.find_module_named(name)
538
- break unless result
539
- end
540
- end
541
- end
542
-
543
- else
544
- # if a method is specified, then we're definitely looking for
545
- # a module, otherwise it could be any symbol
546
- if method
547
- result = find_module_named(symbol)
548
- else
549
- result = find_local_symbol(symbol)
550
- if result.nil?
551
- if symbol =~ /^[A-Z]/
552
- result = parent
553
- while result && result.name != symbol
554
- result = result.parent
555
- end
556
- end
557
- end
558
- end
559
- end
560
-
561
- if result and method then
562
- fail unless result.respond_to? :find_local_symbol
563
- result = result.find_local_symbol(method)
564
- end
565
-
566
- result
567
- end
568
-
569
- def find_local_symbol(symbol)
570
- res = find_method_named(symbol) ||
571
- find_constant_named(symbol) ||
572
- find_attribute_named(symbol) ||
573
- find_module_named(symbol) ||
574
- find_file_named(symbol)
575
- end
576
-
577
- # Handle sections
578
-
579
- def set_current_section(title, comment)
580
- @current_section = Section.new(title, comment)
581
- @sections << @current_section
582
- end
583
-
584
- private
585
-
586
- # Find a named method, or return nil
587
- def find_method_named(name)
588
- @method_list.find {|meth| meth.name == name}
589
- end
590
-
591
- # Find a named instance method, or return nil
592
- def find_instance_method_named(name)
593
- @method_list.find {|meth| meth.name == name && !meth.singleton}
594
- end
595
-
596
- # Find a named constant, or return nil
597
- def find_constant_named(name)
598
- @constants.find {|m| m.name == name}
599
- end
600
-
601
- # Find a named attribute, or return nil
602
- def find_attribute_named(name)
603
- @attributes.find {|m| m.name == name}
604
- end
605
-
606
- ##
607
- # Find a named file, or return nil
608
-
609
- def find_file_named(name)
610
- toplevel.class.find_file_named(name)
611
- end
612
-
613
- end
614
-
615
- ##
616
- # A TopLevel context is a source file
617
-
618
- class TopLevel < Context
619
- attr_accessor :file_stat
620
- attr_accessor :file_relative_name
621
- attr_accessor :file_absolute_name
622
- attr_accessor :diagram
623
- attr_accessor :parser
624
-
625
- @@lock = Mutex.new
626
- @@all_classes = {}
627
- @@all_modules = {}
628
- @@all_files = {}
629
-
630
- def self.reset
631
- @@lock.synchronize do
632
- @@all_classes = {}
633
- @@all_modules = {}
634
- @@all_files = {}
635
- end
636
- end
637
-
638
- def initialize(file_name)
639
- super()
640
- @name = "TopLevel"
641
- @file_relative_name = file_name
642
- @file_absolute_name = file_name
643
- @file_stat = File.stat(file_name) rescue nil # HACK for testing
644
- @diagram = nil
645
- @parser = nil
646
-
647
- @@lock.synchronize do
648
- @@all_files[file_name] = self
649
- end
650
- end
651
-
652
- def file_base_name
653
- File.basename @file_absolute_name
654
- end
655
-
656
- def full_name
657
- nil
658
- end
659
-
660
- ##
661
- # Adding a class or module to a TopLevel is special, as we only want one
662
- # copy of a particular top-level class. For example, if both file A and
663
- # file B implement class C, we only want one ClassModule object for C.
664
- # This code arranges to share classes and modules between files.
665
-
666
- def add_class_or_module(collection, class_type, name, superclass)
667
- cls = collection[name]
668
-
669
- if cls then
670
- cls.superclass = superclass unless cls.module?
671
- puts "Reusing class/module #{cls.full_name}" if $DEBUG_RDOC
672
- else
673
- all = nil
674
-
675
- @@lock.synchronize do
676
- if class_type == NormalModule then
677
- all = @@all_modules
678
- else
679
- all = @@all_classes
680
- end
681
-
682
- cls = all[name]
683
- end
684
-
685
- if !cls then
686
- cls = class_type.new name, superclass
687
- unless @done_documenting
688
- @@lock.synchronize do
689
- all[name] = cls
690
- end
691
- end
692
- else
693
- # If the class has been encountered already, check that its
694
- # superclass has been set (it may not have been, depending on
695
- # the context in which it was encountered).
696
- if class_type == NormalClass
697
- if !cls.superclass then
698
- cls.superclass = superclass
699
- end
700
- end
701
- end
702
-
703
- collection[name] = cls unless @done_documenting
704
-
705
- cls.parent = self
706
- end
707
-
708
- cls
709
- end
710
-
711
- def self.all_classes_and_modules
712
- @@lock.synchronize do
713
- @@all_classes.values + @@all_modules.values
714
- end
715
- end
716
-
717
- def self.find_class_named(name)
718
- @@lock.synchronize do
719
- @@all_classes.each_value do |c|
720
- res = c.find_class_named(name)
721
- return res if res
722
- end
723
- end
724
- nil
725
- end
726
-
727
- def self.find_file_named(name)
728
- @@lock.synchronize do
729
- @@all_files[name]
730
- end
731
- end
732
-
733
- def find_local_symbol(symbol)
734
- find_class_or_module_named(symbol) || super
735
- end
736
-
737
- def find_class_or_module_named(symbol)
738
- @@lock.synchronize do
739
- @@all_classes.each_value {|c| return c if c.name == symbol}
740
- @@all_modules.each_value {|m| return m if m.name == symbol}
741
- end
742
- nil
743
- end
744
-
745
- ##
746
- # Find a named module
747
-
748
- def find_module_named(name)
749
- find_class_or_module_named(name) || find_enclosing_module_named(name)
750
- end
751
-
752
- def inspect
753
- "#<%s:0x%x %p modules: %p classes: %p>" % [
754
- self.class, object_id,
755
- file_base_name,
756
- @modules.map { |n,m| m },
757
- @classes.map { |n,c| c }
758
- ]
759
- end
760
-
761
- end
762
-
763
- ##
764
- # ClassModule is the base class for objects representing either a class or a
765
- # module.
766
-
767
- class ClassModule < Context
768
-
769
- attr_accessor :diagram
770
-
771
- def initialize(name, superclass = nil)
772
- @name = name
773
- @diagram = nil
774
- @superclass = superclass
775
- @comment = ""
776
- super()
777
- end
778
-
779
- def find_class_named(name)
780
- return self if full_name == name
781
- @classes.each_value {|c| return c if c.find_class_named(name) }
782
- nil
783
- end
784
-
785
- ##
786
- # Return the fully qualified name of this class or module
787
-
788
- def full_name
789
- if @parent && @parent.full_name
790
- @parent.full_name + "::" + @name
791
- else
792
- @name
793
- end
794
- end
795
-
796
- def http_url(prefix)
797
- path = full_name.split("::")
798
- File.join(prefix, *path) + ".html"
799
- end
800
-
801
- ##
802
- # Does this object represent a module?
803
-
804
- def module?
805
- false
806
- end
807
-
808
- ##
809
- # Get the superclass of this class. Attempts to retrieve the superclass'
810
- # real name by following module nesting.
811
-
812
- def superclass
813
- raise NoMethodError, "#{full_name} is a module" if module?
814
-
815
- scope = self
816
-
817
- begin
818
- superclass = scope.classes.find { |c| c.name == @superclass }
819
-
820
- return superclass.full_name if superclass
821
- scope = scope.parent
822
- end until scope.nil? or TopLevel === scope
823
-
824
- @superclass
825
- end
826
-
827
- ##
828
- # Set the superclass of this class
829
-
830
- def superclass=(superclass)
831
- raise NoMethodError, "#{full_name} is a module" if module?
832
-
833
- @superclass = superclass if @superclass.nil? or @superclass == 'Object'
834
- end
835
-
836
- def to_s
837
- "#{self.class}: #{@name} #{@comment} #{super}"
838
- end
839
-
840
- end
841
-
842
- ##
843
- # Anonymous classes
844
-
845
- class AnonClass < ClassModule
846
- end
847
-
848
- ##
849
- # Normal classes
850
-
851
- class NormalClass < ClassModule
852
-
853
- def inspect
854
- superclass = @superclass ? " < #{@superclass}" : nil
855
- "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [
856
- self.class, object_id,
857
- @name, superclass, @includes, @attributes, @method_list, @aliases
858
- ]
859
- end
860
-
861
- end
862
-
863
- ##
864
- # Singleton classes
865
-
866
- class SingleClass < ClassModule
867
- end
868
-
869
- ##
870
- # Module
871
-
872
- class NormalModule < ClassModule
873
-
874
- def comment=(comment)
875
- return if comment.empty?
876
- comment = @comment << "# ---\n" << comment unless @comment.empty?
877
-
878
- super
879
- end
880
-
881
- def inspect
882
- "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [
883
- self.class, object_id,
884
- @name, @includes, @attributes, @method_list, @aliases
885
- ]
886
- end
887
-
888
- def module?
889
- true
890
- end
891
-
892
- end
893
-
894
- ##
895
- # AnyMethod is the base class for objects representing methods
896
-
897
- class AnyMethod < CodeObject
898
-
899
- attr_accessor :name
900
- attr_accessor :visibility
901
- attr_accessor :block_params
902
- attr_accessor :dont_rename_initialize
903
- attr_accessor :singleton
904
- attr_reader :text
905
-
906
- # list of other names for this method
907
- attr_reader :aliases
908
-
909
- # method we're aliasing
910
- attr_accessor :is_alias_for
911
-
912
- attr_overridable :params, :param, :parameters, :parameter
913
-
914
- attr_accessor :call_seq
915
-
916
- include TokenStream
917
-
918
- def initialize(text, name)
919
- super()
920
- @text = text
921
- @name = name
922
- @token_stream = nil
923
- @visibility = :public
924
- @dont_rename_initialize = false
925
- @block_params = nil
926
- @aliases = []
927
- @is_alias_for = nil
928
- @comment = ""
929
- @call_seq = nil
930
- end
931
-
932
- def <=>(other)
933
- @name <=> other.name
934
- end
935
-
936
- def add_alias(method)
937
- @aliases << method
938
- end
939
-
940
- def inspect
941
- alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
942
- "#<%s:0x%x %s%s%s (%s)%s>" % [
943
- self.class, object_id,
944
- parent_name,
945
- singleton ? '::' : '#',
946
- name,
947
- visibility,
948
- alias_for,
949
- ]
950
- end
951
-
952
- def param_seq
953
- params = params.gsub(/\s*\#.*/, '')
954
- params = params.tr("\n", " ").squeeze(" ")
955
- params = "(#{params})" unless p[0] == ?(
956
-
957
- if block = block_params then # yes, =
958
- # If this method has explicit block parameters, remove any explicit
959
- # &block
960
- params.sub!(/,?\s*&\w+/)
961
-
962
- block.gsub!(/\s*\#.*/, '')
963
- block = block.tr("\n", " ").squeeze(" ")
964
- if block[0] == ?(
965
- block.sub!(/^\(/, '').sub!(/\)/, '')
966
- end
967
- params << " { |#{block}| ... }"
968
- end
969
-
970
- params
971
- end
972
-
973
- def to_s
974
- res = self.class.name + ": " + @name + " (" + @text + ")\n"
975
- res << @comment.to_s
976
- res
977
- end
978
-
979
- end
980
-
981
- ##
982
- # GhostMethod represents a method referenced only by a comment
983
-
984
- class GhostMethod < AnyMethod
985
- end
986
-
987
- ##
988
- # MetaMethod represents a meta-programmed method
989
-
990
- class MetaMethod < AnyMethod
991
- end
992
-
993
- ##
994
- # Represent an alias, which is an old_name/ new_name pair associated with a
995
- # particular context
996
-
997
- class Alias < CodeObject
998
-
999
- attr_accessor :text, :old_name, :new_name, :comment
1000
-
1001
- def initialize(text, old_name, new_name, comment)
1002
- super()
1003
- @text = text
1004
- @old_name = old_name
1005
- @new_name = new_name
1006
- self.comment = comment
1007
- end
1008
-
1009
- def inspect
1010
- "#<%s:0x%x %s.alias_method %s, %s>" % [
1011
- self.class, object_id,
1012
- parent.name, @old_name, @new_name,
1013
- ]
1014
- end
1015
-
1016
- def to_s
1017
- "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
1018
- end
1019
-
1020
- end
1021
-
1022
- ##
1023
- # Represent a constant
1024
-
1025
- class Constant < CodeObject
1026
- attr_accessor :name, :value
1027
-
1028
- def initialize(name, value, comment)
1029
- super()
1030
- @name = name
1031
- @value = value
1032
- self.comment = comment
1033
- end
1034
- end
1035
-
1036
- ##
1037
- # Represent attributes
1038
-
1039
- class Attr < CodeObject
1040
- attr_accessor :text, :name, :rw, :visibility
1041
-
1042
- def initialize(text, name, rw, comment)
1043
- super()
1044
- @text = text
1045
- @name = name
1046
- @rw = rw
1047
- @visibility = :public
1048
- self.comment = comment
1049
- end
1050
-
1051
- def <=>(other)
1052
- self.name <=> other.name
1053
- end
1054
-
1055
- def inspect
1056
- attr = case rw
1057
- when 'RW' then :attr_accessor
1058
- when 'R' then :attr_reader
1059
- when 'W' then :attr_writer
1060
- else
1061
- " (#{rw})"
1062
- end
1063
-
1064
- "#<%s:0x%x %s.%s :%s>" % [
1065
- self.class, object_id,
1066
- parent_name, attr, @name,
1067
- ]
1068
- end
1069
-
1070
- def to_s
1071
- "attr: #{self.name} #{self.rw}\n#{self.comment}"
1072
- end
1073
-
1074
- end
1075
-
1076
- ##
1077
- # A required file
1078
-
1079
- class Require < CodeObject
1080
- attr_accessor :name
1081
-
1082
- def initialize(name, comment)
1083
- super()
1084
- @name = name.gsub(/'|"/, "") #'
1085
- self.comment = comment
1086
- end
1087
-
1088
- def inspect
1089
- "#<%s:0x%x require '%s' in %s>" % [
1090
- self.class,
1091
- object_id,
1092
- @name,
1093
- parent_file_name,
1094
- ]
1095
- end
1096
-
1097
- end
1098
-
1099
- ##
1100
- # An included module
1101
-
1102
- class Include < CodeObject
1103
-
1104
- attr_accessor :name
1105
-
1106
- def initialize(name, comment)
1107
- super()
1108
- @name = name
1109
- self.comment = comment
1110
-
1111
- end
1112
-
1113
- def inspect
1114
- "#<%s:0x%x %s.include %s>" % [
1115
- self.class,
1116
- object_id,
1117
- parent_name, @name,
1118
- ]
1119
- end
1120
-
1121
- end
1122
-
1123
- end