rdoc 2.0.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 (62) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/Rakefile +10 -0
  5. data/bin/rdoc +22 -0
  6. data/bin/ri +6 -0
  7. data/lib/rdoc.rb +277 -0
  8. data/lib/rdoc/code_objects.rb +776 -0
  9. data/lib/rdoc/diagram.rb +338 -0
  10. data/lib/rdoc/dot.rb +249 -0
  11. data/lib/rdoc/generator.rb +1048 -0
  12. data/lib/rdoc/generator/chm.rb +113 -0
  13. data/lib/rdoc/generator/chm/chm.rb +98 -0
  14. data/lib/rdoc/generator/html.rb +370 -0
  15. data/lib/rdoc/generator/html/hefss.rb +414 -0
  16. data/lib/rdoc/generator/html/html.rb +704 -0
  17. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  18. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  19. data/lib/rdoc/generator/ri.rb +229 -0
  20. data/lib/rdoc/generator/xml.rb +120 -0
  21. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  22. data/lib/rdoc/generator/xml/xml.rb +111 -0
  23. data/lib/rdoc/markup.rb +473 -0
  24. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  25. data/lib/rdoc/markup/formatter.rb +14 -0
  26. data/lib/rdoc/markup/fragments.rb +337 -0
  27. data/lib/rdoc/markup/inline.rb +101 -0
  28. data/lib/rdoc/markup/lines.rb +152 -0
  29. data/lib/rdoc/markup/preprocess.rb +71 -0
  30. data/lib/rdoc/markup/to_flow.rb +185 -0
  31. data/lib/rdoc/markup/to_html.rb +353 -0
  32. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  33. data/lib/rdoc/markup/to_latex.rb +328 -0
  34. data/lib/rdoc/markup/to_test.rb +50 -0
  35. data/lib/rdoc/options.rb +616 -0
  36. data/lib/rdoc/parsers/parse_c.rb +775 -0
  37. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  38. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  39. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  40. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  41. data/lib/rdoc/rdoc.rb +277 -0
  42. data/lib/rdoc/ri.rb +4 -0
  43. data/lib/rdoc/ri/cache.rb +188 -0
  44. data/lib/rdoc/ri/descriptions.rb +150 -0
  45. data/lib/rdoc/ri/display.rb +274 -0
  46. data/lib/rdoc/ri/driver.rb +452 -0
  47. data/lib/rdoc/ri/formatter.rb +616 -0
  48. data/lib/rdoc/ri/paths.rb +102 -0
  49. data/lib/rdoc/ri/reader.rb +106 -0
  50. data/lib/rdoc/ri/util.rb +81 -0
  51. data/lib/rdoc/ri/writer.rb +68 -0
  52. data/lib/rdoc/stats.rb +25 -0
  53. data/lib/rdoc/template.rb +64 -0
  54. data/lib/rdoc/tokenstream.rb +33 -0
  55. data/test/test_rdoc_c_parser.rb +261 -0
  56. data/test/test_rdoc_markup.rb +613 -0
  57. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  58. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  59. data/test/test_rdoc_ri_default_display.rb +295 -0
  60. data/test/test_rdoc_ri_formatter.rb +318 -0
  61. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  62. metadata +134 -0
@@ -0,0 +1,13 @@
1
+ === 2.0.0 / 2008-04-10
2
+
3
+ * 3 Major Enhancements:
4
+ * Renamespaced everything RDoc under the RDoc module.
5
+ * New `ri` implementation.
6
+ * Reads from a cache in ~/.ri/ for enhanced speed.
7
+ * RubyGems aware, only searches latest gem versions.
8
+ * Now up to over 100 tests and 200 assertions.
9
+ * 4 Minor Enhancements:
10
+ * Switched to an ERb-based TemplatePage, see RDoc::TemplatePage.
11
+ * Class/module ri now displays attribute and constant comments.
12
+ * Cross-references can be disabled with a leading \.
13
+ * Relaxed parsing for some RDoc inline markup.
@@ -0,0 +1,61 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/rdoc
6
+ bin/ri
7
+ lib/rdoc.rb
8
+ lib/rdoc/code_objects.rb
9
+ lib/rdoc/diagram.rb
10
+ lib/rdoc/dot.rb
11
+ lib/rdoc/generator.rb
12
+ lib/rdoc/generator/chm.rb
13
+ lib/rdoc/generator/chm/chm.rb
14
+ lib/rdoc/generator/html.rb
15
+ lib/rdoc/generator/html/hefss.rb
16
+ lib/rdoc/generator/html/html.rb
17
+ lib/rdoc/generator/html/kilmer.rb
18
+ lib/rdoc/generator/html/one_page_html.rb
19
+ lib/rdoc/generator/ri.rb
20
+ lib/rdoc/generator/xml.rb
21
+ lib/rdoc/generator/xml/rdf.rb
22
+ lib/rdoc/generator/xml/xml.rb
23
+ lib/rdoc/markup.rb
24
+ lib/rdoc/markup/attribute_manager.rb
25
+ lib/rdoc/markup/formatter.rb
26
+ lib/rdoc/markup/fragments.rb
27
+ lib/rdoc/markup/inline.rb
28
+ lib/rdoc/markup/lines.rb
29
+ lib/rdoc/markup/preprocess.rb
30
+ lib/rdoc/markup/to_flow.rb
31
+ lib/rdoc/markup/to_html.rb
32
+ lib/rdoc/markup/to_html_crossref.rb
33
+ lib/rdoc/markup/to_latex.rb
34
+ lib/rdoc/markup/to_test.rb
35
+ lib/rdoc/options.rb
36
+ lib/rdoc/parsers/parse_c.rb
37
+ lib/rdoc/parsers/parse_f95.rb
38
+ lib/rdoc/parsers/parse_rb.rb
39
+ lib/rdoc/parsers/parse_simple.rb
40
+ lib/rdoc/parsers/parserfactory.rb
41
+ lib/rdoc/rdoc.rb
42
+ lib/rdoc/ri.rb
43
+ lib/rdoc/ri/cache.rb
44
+ lib/rdoc/ri/descriptions.rb
45
+ lib/rdoc/ri/display.rb
46
+ lib/rdoc/ri/driver.rb
47
+ lib/rdoc/ri/formatter.rb
48
+ lib/rdoc/ri/paths.rb
49
+ lib/rdoc/ri/reader.rb
50
+ lib/rdoc/ri/util.rb
51
+ lib/rdoc/ri/writer.rb
52
+ lib/rdoc/stats.rb
53
+ lib/rdoc/template.rb
54
+ lib/rdoc/tokenstream.rb
55
+ test/test_rdoc_c_parser.rb
56
+ test/test_rdoc_markup.rb
57
+ test/test_rdoc_markup_attribute_manager.rb
58
+ test/test_rdoc_ri_attribute_formatter.rb
59
+ test/test_rdoc_ri_default_display.rb
60
+ test/test_rdoc_ri_formatter.rb
61
+ test/test_rdoc_ri_overstrike_formatter.rb
@@ -0,0 +1,34 @@
1
+ = RDoc
2
+
3
+ * http://rubyforge.org/projects/rdoc/
4
+
5
+ == DESCRIPTION:
6
+
7
+ RDoc is an application that produces documentation for one or more Ruby source
8
+ files. RDoc includes the `rdoc` and `ri` tools for generating and displaying
9
+ online documentation.
10
+
11
+ At this point in time, RDoc 2.x is a work in progress and may incur further
12
+ API changes beyond what has been made to the RDoc 1.0.1. Command-line tools
13
+ are largely unaffected, but internal APIs may shift rapidly.
14
+
15
+ == SYNOPSIS:
16
+
17
+ gem 'rdoc'
18
+ require 'rdoc/rdoc'
19
+ # ... see RDoc
20
+
21
+ == BUGS:
22
+
23
+ If you found a bug, please report it at the RDoc project's tracker on
24
+ RubyForge:
25
+
26
+ http://rubyforge.org/tracker/?group_id=627
27
+
28
+ == LICENSE:
29
+
30
+ RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers,
31
+ portions (c) 2007-2008 Eric Hodel. It is free software, and may be
32
+ redistributed under the terms specified in the README file of the Ruby
33
+ distribution.
34
+
@@ -0,0 +1,10 @@
1
+ require 'hoe'
2
+
3
+ $:.unshift 'lib'
4
+ require 'rdoc'
5
+
6
+ Hoe.new "rdoc", RDoc::VERSION do |rdoc|
7
+ rdoc.developer 'Eric Hodel', 'drbrain@segment7.net'
8
+ rdoc.developer 'Dave Thomas', ''
9
+ end
10
+
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # RDoc: Documentation tool for source code
4
+ # (see lib/rdoc/rdoc.rb for more information)
5
+ #
6
+ # Copyright (c) 2003 Dave Thomas
7
+ # Released under the same terms as Ruby
8
+ #
9
+ # $Revision: 15033 $
10
+
11
+ require 'rdoc/rdoc'
12
+
13
+ begin
14
+ r = RDoc::RDoc.new
15
+ r.document ARGV
16
+ rescue Interrupt
17
+ $stderr.puts
18
+ $stderr.puts "Interrupted"
19
+ rescue RDoc::Error => e
20
+ $stderr.puts e.message
21
+ exit 1
22
+ end
data/bin/ri ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr//bin/env ruby
2
+
3
+ require 'rdoc/ri/driver'
4
+
5
+ RDoc::RI::Driver.run ARGV
6
+
@@ -0,0 +1,277 @@
1
+ $DEBUG_RDOC = nil
2
+
3
+ ##
4
+ # = RDOC - Ruby Documentation System
5
+ #
6
+ # This package contains RDoc and RDoc::Markup. RDoc is an application that
7
+ # produces documentation for one or more Ruby source files. We work similarly
8
+ # to JavaDoc, parsing the source, and extracting the definition for classes,
9
+ # modules, and methods (along with includes and requires). We associate with
10
+ # these optional documentation contained in the immediately preceding comment
11
+ # block, and then render the result using a pluggable output formatter.
12
+ # RDoc::Markup is a library that converts plain text into various output
13
+ # formats. The markup library is used to interpret the comment blocks that
14
+ # RDoc uses to document methods, classes, and so on.
15
+ #
16
+ # == Roadmap
17
+ #
18
+ # * If you want to use RDoc to create documentation for your Ruby source files,
19
+ # read on.
20
+ # * If you want to include extensions written in C, see RDoc::C_Parser
21
+ # * For information on the various markups available in comment blocks, see
22
+ # RDoc::Markup.
23
+ # * If you want to drive RDoc programatically, see RDoc::RDoc.
24
+ # * If you want to use the library to format text blocks into HTML, have a look
25
+ # at RDoc::Markup.
26
+ # * If you want to try writing your own HTML output template, see
27
+ # RDoc::Generator::HTML
28
+ #
29
+ # == Summary
30
+ #
31
+ # Once installed, you can create documentation using the 'rdoc' command
32
+ # (the command is 'rdoc.bat' under Windows)
33
+ #
34
+ # % rdoc [options] [names...]
35
+ #
36
+ # Type "rdoc --help" for an up-to-date option summary.
37
+ #
38
+ # A typical use might be to generate documentation for a package of Ruby
39
+ # source (such as rdoc itself).
40
+ #
41
+ # % rdoc
42
+ #
43
+ # This command generates documentation for all the Ruby and C source
44
+ # files in and below the current directory. These will be stored in a
45
+ # documentation tree starting in the subdirectory 'doc'.
46
+ #
47
+ # You can make this slightly more useful for your readers by having the
48
+ # index page contain the documentation for the primary file. In our
49
+ # case, we could type
50
+ #
51
+ # % rdoc --main rdoc.rb
52
+ #
53
+ # You'll find information on the various formatting tricks you can use
54
+ # in comment blocks in the documentation this generates.
55
+ #
56
+ # RDoc uses file extensions to determine how to process each file. File names
57
+ # ending +.rb+ and <tt>.rbw</tt> are assumed to be Ruby source. Files
58
+ # ending +.c+ are parsed as C files. All other files are assumed to
59
+ # contain just Markup-style markup (with or without leading '#' comment
60
+ # markers). If directory names are passed to RDoc, they are scanned
61
+ # recursively for C and Ruby source files only.
62
+ #
63
+ # = Markup
64
+ #
65
+ # For information on how to make lists, hyperlinks, etc. with RDoc, see
66
+ # RDoc::Markup.
67
+ #
68
+ # Comment blocks can be written fairly naturally, either using '#' on
69
+ # successive lines of the comment, or by including the comment in
70
+ # an =begin/=end block. If you use the latter form, the =begin line must be
71
+ # flagged with an RDoc tag:
72
+ #
73
+ # =begin rdoc
74
+ # Documentation to be processed by RDoc.
75
+ #
76
+ # ...
77
+ # =end
78
+ #
79
+ # RDoc stops processing comments if it finds a comment line containing
80
+ # a <tt>--</tt>. This can be used to separate external from internal
81
+ # comments, or to stop a comment being associated with a method, class, or
82
+ # module. Commenting can be turned back on with a line that starts with a
83
+ # <tt>++</tt>.
84
+ #
85
+ # ##
86
+ # # Extract the age and calculate the date-of-birth.
87
+ # #--
88
+ # # FIXME: fails if the birthday falls on February 29th
89
+ # #++
90
+ # # The DOB is returned as a Time object.
91
+ #
92
+ # def get_dob(person)
93
+ # # ...
94
+ # end
95
+ #
96
+ # Names of classes, source files, and any method names containing an
97
+ # underscore or preceded by a hash character are automatically hyperlinked
98
+ # from comment text to their description.
99
+ #
100
+ # Method parameter lists are extracted and displayed with the method
101
+ # description. If a method calls +yield+, then the parameters passed to yield
102
+ # will also be displayed:
103
+ #
104
+ # def fred
105
+ # ...
106
+ # yield line, address
107
+ #
108
+ # This will get documented as:
109
+ #
110
+ # fred() { |line, address| ... }
111
+ #
112
+ # You can override this using a comment containing ':yields: ...' immediately
113
+ # after the method definition
114
+ #
115
+ # def fred # :yields: index, position
116
+ # # ...
117
+ #
118
+ # yield line, address
119
+ #
120
+ # which will get documented as
121
+ #
122
+ # fred() { |index, position| ... }
123
+ #
124
+ # +:yields:+ is an example of a documentation directive. These appear
125
+ # immediately after the start of the document element they are modifying.
126
+ #
127
+ # == Directives
128
+ #
129
+ # [+:nodoc:+ / +:nodoc:+ all]
130
+ # Don't include this element in the documentation. For classes
131
+ # and modules, the methods, aliases, constants, and attributes
132
+ # directly within the affected class or module will also be
133
+ # omitted. By default, though, modules and classes within that
134
+ # class of module _will_ be documented. This is turned off by
135
+ # adding the +all+ modifier.
136
+ #
137
+ # module MyModule # :nodoc:
138
+ # class Input
139
+ # end
140
+ # end
141
+ #
142
+ # module OtherModule # :nodoc: all
143
+ # class Output
144
+ # end
145
+ # end
146
+ #
147
+ # In the above code, only class +MyModule::Input+ will be documented.
148
+ # :nodoc: is global across all files the class or module appears in, so use
149
+ # :stopdoc:/:startdoc: to only omit documentation for a particular set of
150
+ # methods, etc.
151
+ #
152
+ # [+:doc:+]
153
+ # Force a method or attribute to be documented even if it wouldn't otherwise
154
+ # be. Useful if, for example, you want to include documentation of a
155
+ # particular private method.
156
+ #
157
+ # [+:notnew:+]
158
+ # Only applicable to the +initialize+ instance method. Normally RDoc
159
+ # assumes that the documentation and parameters for #initialize are
160
+ # actually for the ::new method, and so fakes out a ::new for the class.
161
+ # The :notnew: modifier stops this. Remember that #initialize is protected,
162
+ # so you won't see the documentation unless you use the -a command line
163
+ # option.
164
+ #
165
+ # Comment blocks can contain other directives:
166
+ #
167
+ # [<tt>:section: title</tt>]
168
+ # Starts a new section in the output. The title following +:section:+ is
169
+ # used as the section heading, and the remainder of the comment containing
170
+ # the section is used as introductory text. Subsequent methods, aliases,
171
+ # attributes, and classes will be documented in this section. A :section:
172
+ # comment block may have one or more lines before the :section: directive.
173
+ # These will be removed, and any identical lines at the end of the block are
174
+ # also removed. This allows you to add visual cues such as:
175
+ #
176
+ # # ----------------------------------------
177
+ # # :section: My Section
178
+ # # This is the section that I wrote.
179
+ # # See it glisten in the noon-day sun.
180
+ # # ----------------------------------------
181
+ #
182
+ # [+:call-seq:+]
183
+ # Lines up to the next blank line in the comment are treated as the method's
184
+ # calling sequence, overriding the default parsing of method parameters and
185
+ # yield arguments.
186
+ #
187
+ # [+:include:+ _filename_]
188
+ # \Include the contents of the named file at this point. The file will be
189
+ # searched for in the directories listed by the +--include+ option, or in
190
+ # the current directory by default. The contents of the file will be
191
+ # shifted to have the same indentation as the ':' at the start of the
192
+ # :include: directive.
193
+ #
194
+ # [+:title:+ _text_]
195
+ # Sets the title for the document. Equivalent to the <tt>--title</tt>
196
+ # command line parameter. (The command line parameter overrides any :title:
197
+ # directive in the source).
198
+ #
199
+ # [+:enddoc:+]
200
+ # Document nothing further at the current level.
201
+ #
202
+ # [+:main:+ _name_]
203
+ # Equivalent to the <tt>--main</tt> command line parameter.
204
+ #
205
+ # [+:stopdoc:+ / +:startdoc:+]
206
+ # Stop and start adding new documentation elements to the current container.
207
+ # For example, if a class has a number of constants that you don't want to
208
+ # document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the
209
+ # last. If you don't specifiy a +:startdoc:+ by the end of the container,
210
+ # disables documentation for the entire class or module.
211
+ #
212
+ # = Other stuff
213
+ #
214
+ # RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net>
215
+ #
216
+ # Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc.
217
+ #
218
+ # == Credits
219
+ #
220
+ # * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding
221
+ # work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby
222
+ # parser for irb and the rtags package.
223
+ #
224
+ # * Code to diagram classes and modules was written by Sergey A Yanovitsky
225
+ # (Jah) of Enticla.
226
+ #
227
+ # * Charset patch from MoonWolf.
228
+ #
229
+ # * Rich Kilmer wrote the kilmer.rb output template.
230
+ #
231
+ # * Dan Brickley led the design of the RDF format.
232
+ #
233
+ # == License
234
+ #
235
+ # RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It
236
+ # is free software, and may be redistributed under the terms specified
237
+ # in the README file of the Ruby distribution.
238
+ #
239
+ # == Warranty
240
+ #
241
+ # This software is provided "as is" and without any express or implied
242
+ # warranties, including, without limitation, the implied warranties of
243
+ # merchantibility and fitness for a particular purpose.
244
+
245
+ module RDoc
246
+
247
+ ##
248
+ # Exception thrown by any rdoc error.
249
+
250
+ class Error < RuntimeError; end
251
+
252
+ RDocError = Error # :nodoc:
253
+
254
+ ##
255
+ # RDoc version you are using
256
+
257
+ VERSION = "2.0.0"
258
+
259
+ ##
260
+ # Name of the dotfile that contains the description of files to be processed
261
+ # in the current directory
262
+
263
+ DOT_DOC_FILENAME = ".document"
264
+
265
+ GENERAL_MODIFIERS = %w[nodoc].freeze
266
+
267
+ CLASS_MODIFIERS = GENERAL_MODIFIERS
268
+
269
+ ATTR_MODIFIERS = GENERAL_MODIFIERS
270
+
271
+ CONSTANT_MODIFIERS = GENERAL_MODIFIERS
272
+
273
+ METHOD_MODIFIERS = GENERAL_MODIFIERS +
274
+ %w[arg args yield yields notnew not-new not_new doc]
275
+
276
+ end
277
+
@@ -0,0 +1,776 @@
1
+ # We represent the various high-level code constructs that appear
2
+ # in Ruby programs: classes, modules, methods, and so on.
3
+
4
+ require 'rdoc/tokenstream'
5
+
6
+ module RDoc
7
+
8
+ ##
9
+ # We contain the common stuff for contexts (which are containers)
10
+ # and other elements (methods, attributes and so on)
11
+
12
+ class CodeObject
13
+
14
+ attr_accessor :parent
15
+
16
+ # We are the model of the code, but we know that at some point
17
+ # we will be worked on by viewers. By implementing the Viewable
18
+ # protocol, viewers can associated themselves with these objects.
19
+
20
+ attr_accessor :viewer
21
+
22
+ # are we done documenting (ie, did we come across a :enddoc:)?
23
+
24
+ attr_accessor :done_documenting
25
+
26
+ # Which section are we in
27
+
28
+ attr_accessor :section
29
+
30
+ # do we document ourselves?
31
+
32
+ attr_reader :document_self
33
+
34
+ def document_self=(val)
35
+ @document_self = val
36
+ if !val
37
+ remove_methods_etc
38
+ end
39
+ end
40
+
41
+ # set and cleared by :startdoc: and :enddoc:, this is used to toggle
42
+ # the capturing of documentation
43
+ def start_doc
44
+ @document_self = true
45
+ @document_children = true
46
+ end
47
+
48
+ def stop_doc
49
+ @document_self = false
50
+ @document_children = false
51
+ end
52
+
53
+ # do we document ourselves and our children
54
+
55
+ attr_reader :document_children
56
+
57
+ def document_children=(val)
58
+ @document_children = val
59
+ if !val
60
+ remove_classes_and_modules
61
+ end
62
+ end
63
+
64
+ # Do we _force_ documentation, even is we wouldn't normally show the entity
65
+ attr_accessor :force_documentation
66
+
67
+ # Default callbacks to nothing, but this is overridden for classes
68
+ # and modules
69
+ def remove_classes_and_modules
70
+ end
71
+
72
+ def remove_methods_etc
73
+ end
74
+
75
+ def initialize
76
+ @document_self = true
77
+ @document_children = true
78
+ @force_documentation = false
79
+ @done_documenting = false
80
+ end
81
+
82
+ # Access the code object's comment
83
+ attr_reader :comment
84
+
85
+ # Update the comment, but don't overwrite a real comment with an empty one
86
+ def comment=(comment)
87
+ @comment = comment unless comment.empty?
88
+ end
89
+
90
+ # There's a wee trick we pull. Comment blocks can have directives that
91
+ # override the stuff we extract during the parse. So, we have a special
92
+ # class method, attr_overridable, that lets code objects list
93
+ # those directives. Wehn a comment is assigned, we then extract
94
+ # out any matching directives and update our object
95
+
96
+ def self.attr_overridable(name, *aliases)
97
+ @overridables ||= {}
98
+
99
+ attr_accessor name
100
+
101
+ aliases.unshift name
102
+ aliases.each do |directive_name|
103
+ @overridables[directive_name.to_s] = name
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+ # A Context is something that can hold modules, classes, methods,
110
+ # attributes, aliases, requires, and includes. Classes, modules, and
111
+ # files are all Contexts.
112
+
113
+ class Context < CodeObject
114
+ attr_reader :name, :method_list, :attributes, :aliases, :constants
115
+ attr_reader :requires, :includes, :in_files, :visibility
116
+
117
+ attr_reader :sections
118
+
119
+ class Section
120
+ attr_reader :title, :comment, :sequence
121
+
122
+ @@sequence = "SEC00000"
123
+
124
+ def initialize(title, comment)
125
+ @title = title
126
+ @@sequence.succ!
127
+ @sequence = @@sequence.dup
128
+ @comment = nil
129
+ set_comment(comment)
130
+ end
131
+
132
+ private
133
+
134
+ # Set the comment for this section from the original comment block
135
+ # If the first line contains :section:, strip it and use the rest. Otherwise
136
+ # remove lines up to the line containing :section:, and look for
137
+ # those lines again at the end and remove them. This lets us write
138
+ #
139
+ # # ---------------------
140
+ # # :SECTION: The title
141
+ # # The body
142
+ # # ---------------------
143
+
144
+ def set_comment(comment)
145
+ return unless comment
146
+
147
+ if comment =~ /^.*?:section:.*$/
148
+ start = $`
149
+ rest = $'
150
+ if start.empty?
151
+ @comment = rest
152
+ else
153
+ @comment = rest.sub(/#{start.chomp}\Z/, '')
154
+ end
155
+ else
156
+ @comment = comment
157
+ end
158
+ @comment = nil if @comment.empty?
159
+ end
160
+ end
161
+
162
+
163
+ def initialize
164
+ super()
165
+
166
+ @in_files = []
167
+
168
+ @name ||= "unknown"
169
+ @comment ||= ""
170
+ @parent = nil
171
+ @visibility = :public
172
+
173
+ @current_section = Section.new(nil, nil)
174
+ @sections = [ @current_section ]
175
+
176
+ initialize_methods_etc
177
+ initialize_classes_and_modules
178
+ end
179
+
180
+ # map the class hash to an array externally
181
+ def classes
182
+ @classes.values
183
+ end
184
+
185
+ # map the module hash to an array externally
186
+ def modules
187
+ @modules.values
188
+ end
189
+
190
+ # Change the default visibility for new methods
191
+ def ongoing_visibility=(vis)
192
+ @visibility = vis
193
+ end
194
+
195
+ # Given an array +methods+ of method names, set the
196
+ # visibility of the corresponding AnyMethod object
197
+
198
+ def set_visibility_for(methods, vis, singleton=false)
199
+ count = 0
200
+ @method_list.each do |m|
201
+ if methods.include?(m.name) && m.singleton == singleton
202
+ m.visibility = vis
203
+ count += 1
204
+ end
205
+ end
206
+
207
+ return if count == methods.size || singleton
208
+
209
+ # perhaps we need to look at attributes
210
+
211
+ @attributes.each do |a|
212
+ if methods.include?(a.name)
213
+ a.visibility = vis
214
+ count += 1
215
+ end
216
+ end
217
+ end
218
+
219
+ # Record the file that we happen to find it in
220
+ def record_location(toplevel)
221
+ @in_files << toplevel unless @in_files.include?(toplevel)
222
+ end
223
+
224
+ # Return true if at least part of this thing was defined in +file+
225
+ def defined_in?(file)
226
+ @in_files.include?(file)
227
+ end
228
+
229
+ def add_class(class_type, name, superclass)
230
+ add_class_or_module(@classes, class_type, name, superclass)
231
+ end
232
+
233
+ def add_module(class_type, name)
234
+ add_class_or_module(@modules, class_type, name, nil)
235
+ end
236
+
237
+ def add_method(a_method)
238
+ puts "Adding #@visibility method #{a_method.name} to #@name" if $DEBUG_RDOC
239
+ a_method.visibility = @visibility
240
+ add_to(@method_list, a_method)
241
+ end
242
+
243
+ def add_attribute(an_attribute)
244
+ add_to(@attributes, an_attribute)
245
+ end
246
+
247
+ def add_alias(an_alias)
248
+ meth = find_instance_method_named(an_alias.old_name)
249
+ if meth
250
+ new_meth = 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
+ new_meth.comment = "Alias for \##{meth.name}"
255
+ meth.add_alias(new_meth)
256
+ add_method(new_meth)
257
+ else
258
+ add_to(@aliases, an_alias)
259
+ end
260
+ end
261
+
262
+ def add_include(an_include)
263
+ add_to(@includes, an_include)
264
+ end
265
+
266
+ def add_constant(const)
267
+ add_to(@constants, const)
268
+ end
269
+
270
+ # Requires always get added to the top-level (file) context
271
+ def add_require(a_require)
272
+ if self.kind_of? TopLevel
273
+ add_to(@requires, a_require)
274
+ else
275
+ parent.add_require(a_require)
276
+ end
277
+ end
278
+
279
+ def add_class_or_module(collection, class_type, name, superclass=nil)
280
+ cls = collection[name]
281
+ if cls
282
+ puts "Reusing class/module #{name}" if $DEBUG_RDOC
283
+ else
284
+ cls = class_type.new(name, superclass)
285
+ puts "Adding class/module #{name} to #@name" if $DEBUG_RDOC
286
+ # collection[name] = cls if @document_self && !@done_documenting
287
+ collection[name] = cls if !@done_documenting
288
+ cls.parent = self
289
+ cls.section = @current_section
290
+ end
291
+ cls
292
+ end
293
+
294
+ def add_to(array, thing)
295
+ array << thing if @document_self && !@done_documenting
296
+ thing.parent = self
297
+ thing.section = @current_section
298
+ end
299
+
300
+ # If a class's documentation is turned off after we've started
301
+ # collecting methods etc., we need to remove the ones
302
+ # we have
303
+
304
+ def remove_methods_etc
305
+ initialize_methods_etc
306
+ end
307
+
308
+ def initialize_methods_etc
309
+ @method_list = []
310
+ @attributes = []
311
+ @aliases = []
312
+ @requires = []
313
+ @includes = []
314
+ @constants = []
315
+ end
316
+
317
+ # and remove classes and modules when we see a :nodoc: all
318
+ def remove_classes_and_modules
319
+ initialize_classes_and_modules
320
+ end
321
+
322
+ def initialize_classes_and_modules
323
+ @classes = {}
324
+ @modules = {}
325
+ end
326
+
327
+ # Find a named module
328
+ def find_module_named(name)
329
+ return self if self.name == name
330
+ res = @modules[name] || @classes[name]
331
+ return res if res
332
+ find_enclosing_module_named(name)
333
+ end
334
+
335
+ # find a module at a higher scope
336
+ def find_enclosing_module_named(name)
337
+ parent && parent.find_module_named(name)
338
+ end
339
+
340
+ # Iterate over all the classes and modules in
341
+ # this object
342
+
343
+ def each_classmodule
344
+ @modules.each_value {|m| yield m}
345
+ @classes.each_value {|c| yield c}
346
+ end
347
+
348
+ def each_method
349
+ @method_list.each {|m| yield m}
350
+ end
351
+
352
+ def each_attribute
353
+ @attributes.each {|a| yield a}
354
+ end
355
+
356
+ def each_constant
357
+ @constants.each {|c| yield c}
358
+ end
359
+
360
+ # Return the toplevel that owns us
361
+
362
+ def toplevel
363
+ return @toplevel if defined? @toplevel
364
+ @toplevel = self
365
+ @toplevel = @toplevel.parent until TopLevel === @toplevel
366
+ @toplevel
367
+ end
368
+
369
+ # allow us to sort modules by name
370
+ def <=>(other)
371
+ name <=> other.name
372
+ end
373
+
374
+ # Look up the given symbol. If method is non-nil, then
375
+ # we assume the symbol references a module that
376
+ # contains that method
377
+ def find_symbol(symbol, method=nil)
378
+ result = nil
379
+ case symbol
380
+ when /^::(.*)/
381
+ result = toplevel.find_symbol($1)
382
+ when /::/
383
+ modules = symbol.split(/::/)
384
+ unless modules.empty?
385
+ module_name = modules.shift
386
+ result = find_module_named(module_name)
387
+ if result
388
+ modules.each do |name|
389
+ result = result.find_module_named(name)
390
+ break unless result
391
+ end
392
+ end
393
+ end
394
+ else
395
+ # if a method is specified, then we're definitely looking for
396
+ # a module, otherwise it could be any symbol
397
+ if method
398
+ result = find_module_named(symbol)
399
+ else
400
+ result = find_local_symbol(symbol)
401
+ if result.nil?
402
+ if symbol =~ /^[A-Z]/
403
+ result = parent
404
+ while result && result.name != symbol
405
+ result = result.parent
406
+ end
407
+ end
408
+ end
409
+ end
410
+ end
411
+ if result && method
412
+ if !result.respond_to?(:find_local_symbol)
413
+ #p result.name
414
+ #p method
415
+ fail
416
+ end
417
+ result = result.find_local_symbol(method)
418
+ end
419
+ result
420
+ end
421
+
422
+ def find_local_symbol(symbol)
423
+ res = find_method_named(symbol) ||
424
+ find_constant_named(symbol) ||
425
+ find_attribute_named(symbol) ||
426
+ find_module_named(symbol)
427
+ end
428
+
429
+ # Handle sections
430
+
431
+ def set_current_section(title, comment)
432
+ @current_section = Section.new(title, comment)
433
+ @sections << @current_section
434
+ end
435
+
436
+ private
437
+
438
+ # Find a named method, or return nil
439
+ def find_method_named(name)
440
+ @method_list.find {|meth| meth.name == name}
441
+ end
442
+
443
+ # Find a named instance method, or return nil
444
+ def find_instance_method_named(name)
445
+ @method_list.find {|meth| meth.name == name && !meth.singleton}
446
+ end
447
+
448
+ # Find a named constant, or return nil
449
+ def find_constant_named(name)
450
+ @constants.find {|m| m.name == name}
451
+ end
452
+
453
+ # Find a named attribute, or return nil
454
+ def find_attribute_named(name)
455
+ @attributes.find {|m| m.name == name}
456
+ end
457
+
458
+ end
459
+
460
+ ##
461
+ # A TopLevel context is a source file
462
+
463
+ class TopLevel < Context
464
+ attr_accessor :file_stat
465
+ attr_accessor :file_relative_name
466
+ attr_accessor :file_absolute_name
467
+ attr_accessor :diagram
468
+
469
+ @@all_classes = {}
470
+ @@all_modules = {}
471
+
472
+ def self.reset
473
+ @@all_classes = {}
474
+ @@all_modules = {}
475
+ end
476
+
477
+ def initialize(file_name)
478
+ super()
479
+ @name = "TopLevel"
480
+ @file_relative_name = file_name
481
+ @file_absolute_name = file_name
482
+ @file_stat = File.stat(file_name)
483
+ @diagram = nil
484
+ end
485
+
486
+ def full_name
487
+ nil
488
+ end
489
+
490
+ ##
491
+ # Adding a class or module to a TopLevel is special, as we only want one
492
+ # copy of a particular top-level class. For example, if both file A and
493
+ # file B implement class C, we only want one ClassModule object for C.
494
+ # This code arranges to share classes and modules between files.
495
+
496
+ def add_class_or_module(collection, class_type, name, superclass)
497
+ cls = collection[name]
498
+
499
+ if cls
500
+ puts "Reusing class/module #{name}" if $DEBUG_RDOC
501
+ else
502
+ if class_type == NormalModule
503
+ all = @@all_modules
504
+ else
505
+ all = @@all_classes
506
+ end
507
+
508
+ cls = all[name]
509
+
510
+ if !cls
511
+ cls = class_type.new(name, superclass)
512
+ all[name] = cls unless @done_documenting
513
+ end
514
+
515
+ puts "Adding class/module #{name} to #{@name}" if $DEBUG_RDOC
516
+
517
+ collection[name] = cls unless @done_documenting
518
+
519
+ cls.parent = self
520
+ end
521
+
522
+ cls
523
+ end
524
+
525
+ def self.all_classes_and_modules
526
+ @@all_classes.values + @@all_modules.values
527
+ end
528
+
529
+ def self.find_class_named(name)
530
+ @@all_classes.each_value do |c|
531
+ res = c.find_class_named(name)
532
+ return res if res
533
+ end
534
+ nil
535
+ end
536
+
537
+ def find_local_symbol(symbol)
538
+ find_class_or_module_named(symbol) || super
539
+ end
540
+
541
+ def find_class_or_module_named(symbol)
542
+ @@all_classes.each_value {|c| return c if c.name == symbol}
543
+ @@all_modules.each_value {|m| return m if m.name == symbol}
544
+ nil
545
+ end
546
+
547
+ ##
548
+ # Find a named module
549
+
550
+ def find_module_named(name)
551
+ find_class_or_module_named(name) || find_enclosing_module_named(name)
552
+ end
553
+
554
+ end
555
+
556
+ # ClassModule is the base class for objects representing either a
557
+ # class or a module.
558
+
559
+ class ClassModule < Context
560
+
561
+ attr_reader :superclass
562
+ attr_accessor :diagram
563
+
564
+ def initialize(name, superclass = nil)
565
+ @name = name
566
+ @diagram = nil
567
+ @superclass = superclass
568
+ @comment = ""
569
+ super()
570
+ end
571
+
572
+ # Return the fully qualified name of this class or module
573
+ def full_name
574
+ if @parent && @parent.full_name
575
+ @parent.full_name + "::" + @name
576
+ else
577
+ @name
578
+ end
579
+ end
580
+
581
+ def http_url(prefix)
582
+ path = full_name.split("::")
583
+ File.join(prefix, *path) + ".html"
584
+ end
585
+
586
+ # Return +true+ if this object represents a module
587
+ def is_module?
588
+ false
589
+ end
590
+
591
+ # to_s is simply for debugging
592
+ def to_s
593
+ res = self.class.name + ": " + @name
594
+ res << @comment.to_s
595
+ res << super
596
+ res
597
+ end
598
+
599
+ def find_class_named(name)
600
+ return self if full_name == name
601
+ @classes.each_value {|c| return c if c.find_class_named(name) }
602
+ nil
603
+ end
604
+ end
605
+
606
+ # Anonymous classes
607
+ class AnonClass < ClassModule
608
+ end
609
+
610
+ # Normal classes
611
+ class NormalClass < ClassModule
612
+ end
613
+
614
+ # Singleton classes
615
+ class SingleClass < ClassModule
616
+ end
617
+
618
+ # Module
619
+ class NormalModule < ClassModule
620
+ def is_module?
621
+ true
622
+ end
623
+ end
624
+
625
+ ##
626
+ # AnyMethod is the base class for objects representing methods
627
+
628
+ class AnyMethod < CodeObject
629
+ attr_accessor :name
630
+ attr_accessor :visibility
631
+ attr_accessor :block_params
632
+ attr_accessor :dont_rename_initialize
633
+ attr_accessor :singleton
634
+ attr_reader :text
635
+
636
+ # list of other names for this method
637
+ attr_reader :aliases
638
+
639
+ # method we're aliasing
640
+ attr_accessor :is_alias_for
641
+
642
+ attr_overridable :params, :param, :parameters, :parameter
643
+
644
+ attr_accessor :call_seq
645
+
646
+ include TokenStream
647
+
648
+ def initialize(text, name)
649
+ super()
650
+ @text = text
651
+ @name = name
652
+ @token_stream = nil
653
+ @visibility = :public
654
+ @dont_rename_initialize = false
655
+ @block_params = nil
656
+ @aliases = []
657
+ @is_alias_for = nil
658
+ @comment = ""
659
+ @call_seq = nil
660
+ end
661
+
662
+ def <=>(other)
663
+ @name <=> other.name
664
+ end
665
+
666
+ def to_s
667
+ res = self.class.name + ": " + @name + " (" + @text + ")\n"
668
+ res << @comment.to_s
669
+ res
670
+ end
671
+
672
+ def param_seq
673
+ p = params.gsub(/\s*\#.*/, '')
674
+ p = p.tr("\n", " ").squeeze(" ")
675
+ p = "(" + p + ")" unless p[0] == ?(
676
+
677
+ if (block = block_params)
678
+ # If this method has explicit block parameters, remove any
679
+ # explicit &block
680
+ $stderr.puts p
681
+ p.sub!(/,?\s*&\w+/)
682
+ $stderr.puts p
683
+
684
+ block.gsub!(/\s*\#.*/, '')
685
+ block = block.tr("\n", " ").squeeze(" ")
686
+ if block[0] == ?(
687
+ block.sub!(/^\(/, '').sub!(/\)/, '')
688
+ end
689
+ p << " {|#{block}| ...}"
690
+ end
691
+ p
692
+ end
693
+
694
+ def add_alias(method)
695
+ @aliases << method
696
+ end
697
+ end
698
+
699
+ # Represent an alias, which is an old_name/ new_name pair associated
700
+ # with a particular context
701
+ class Alias < CodeObject
702
+ attr_accessor :text, :old_name, :new_name, :comment
703
+
704
+ def initialize(text, old_name, new_name, comment)
705
+ super()
706
+ @text = text
707
+ @old_name = old_name
708
+ @new_name = new_name
709
+ self.comment = comment
710
+ end
711
+
712
+ def to_s
713
+ "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
714
+ end
715
+ end
716
+
717
+ # Represent a constant
718
+ class Constant < CodeObject
719
+ attr_accessor :name, :value
720
+
721
+ def initialize(name, value, comment)
722
+ super()
723
+ @name = name
724
+ @value = value
725
+ self.comment = comment
726
+ end
727
+ end
728
+
729
+ # Represent attributes
730
+ class Attr < CodeObject
731
+ attr_accessor :text, :name, :rw, :visibility
732
+
733
+ def initialize(text, name, rw, comment)
734
+ super()
735
+ @text = text
736
+ @name = name
737
+ @rw = rw
738
+ @visibility = :public
739
+ self.comment = comment
740
+ end
741
+
742
+ def to_s
743
+ "attr: #{self.name} #{self.rw}\n#{self.comment}"
744
+ end
745
+
746
+ def <=>(other)
747
+ self.name <=> other.name
748
+ end
749
+ end
750
+
751
+ # a required file
752
+
753
+ class Require < CodeObject
754
+ attr_accessor :name
755
+
756
+ def initialize(name, comment)
757
+ super()
758
+ @name = name.gsub(/'|"/, "") #'
759
+ self.comment = comment
760
+ end
761
+
762
+ end
763
+
764
+ # an included module
765
+ class Include < CodeObject
766
+ attr_accessor :name
767
+
768
+ def initialize(name, comment)
769
+ super()
770
+ @name = name
771
+ self.comment = comment
772
+ end
773
+
774
+ end
775
+
776
+ end