iownbey-rdoc 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/bin/rdoc +22 -0
  5. data/bin/ri +6 -0
  6. data/lib/rdoc.rb +277 -0
  7. data/lib/rdoc/code_objects.rb +776 -0
  8. data/lib/rdoc/diagram.rb +338 -0
  9. data/lib/rdoc/dot.rb +249 -0
  10. data/lib/rdoc/generator.rb +1050 -0
  11. data/lib/rdoc/generator/chm.rb +113 -0
  12. data/lib/rdoc/generator/chm/chm.rb +98 -0
  13. data/lib/rdoc/generator/html.rb +370 -0
  14. data/lib/rdoc/generator/html/hefss.rb +414 -0
  15. data/lib/rdoc/generator/html/html.rb +704 -0
  16. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  17. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  18. data/lib/rdoc/generator/ri.rb +229 -0
  19. data/lib/rdoc/generator/texinfo.rb +84 -0
  20. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  21. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  22. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  23. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  24. data/lib/rdoc/generator/xml.rb +120 -0
  25. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  26. data/lib/rdoc/generator/xml/xml.rb +111 -0
  27. data/lib/rdoc/markup.rb +473 -0
  28. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  29. data/lib/rdoc/markup/formatter.rb +14 -0
  30. data/lib/rdoc/markup/fragments.rb +337 -0
  31. data/lib/rdoc/markup/inline.rb +101 -0
  32. data/lib/rdoc/markup/lines.rb +152 -0
  33. data/lib/rdoc/markup/preprocess.rb +71 -0
  34. data/lib/rdoc/markup/to_flow.rb +185 -0
  35. data/lib/rdoc/markup/to_html.rb +354 -0
  36. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  37. data/lib/rdoc/markup/to_latex.rb +328 -0
  38. data/lib/rdoc/markup/to_test.rb +50 -0
  39. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  40. data/lib/rdoc/options.rb +621 -0
  41. data/lib/rdoc/parsers/parse_c.rb +775 -0
  42. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  43. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  44. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  45. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  46. data/lib/rdoc/rdoc.rb +277 -0
  47. data/lib/rdoc/ri.rb +4 -0
  48. data/lib/rdoc/ri/cache.rb +188 -0
  49. data/lib/rdoc/ri/descriptions.rb +150 -0
  50. data/lib/rdoc/ri/display.rb +274 -0
  51. data/lib/rdoc/ri/driver.rb +452 -0
  52. data/lib/rdoc/ri/formatter.rb +616 -0
  53. data/lib/rdoc/ri/paths.rb +102 -0
  54. data/lib/rdoc/ri/reader.rb +106 -0
  55. data/lib/rdoc/ri/util.rb +81 -0
  56. data/lib/rdoc/ri/writer.rb +68 -0
  57. data/lib/rdoc/stats.rb +25 -0
  58. data/lib/rdoc/template.rb +64 -0
  59. data/lib/rdoc/tokenstream.rb +33 -0
  60. data/test/test_rdoc_c_parser.rb +261 -0
  61. data/test/test_rdoc_info_formatting.rb +179 -0
  62. data/test/test_rdoc_info_sections.rb +93 -0
  63. data/test/test_rdoc_markup.rb +613 -0
  64. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  65. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  66. data/test/test_rdoc_ri_default_display.rb +295 -0
  67. data/test/test_rdoc_ri_formatter.rb +318 -0
  68. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  69. metadata +142 -0
@@ -0,0 +1,40 @@
1
+ require 'rdoc'
2
+ require 'rdoc/code_objects'
3
+ require 'rdoc/markup/preprocess'
4
+
5
+ ##
6
+ # Parse a non-source file. We basically take the whole thing as one big
7
+ # comment. If the first character in the file is '#', we strip leading pound
8
+ # signs.
9
+
10
+ class RDoc::SimpleParser
11
+
12
+ ##
13
+ # Prepare to parse a plain file
14
+
15
+ def initialize(top_level, file_name, body, options, stats)
16
+ preprocess = RDoc::Markup::PreProcess.new(file_name, options.rdoc_include)
17
+
18
+ preprocess.handle(body) do |directive, param|
19
+ warn "Unrecognized directive '#{directive}' in #{file_name}"
20
+ end
21
+
22
+ @body = body
23
+ @options = options
24
+ @top_level = top_level
25
+ end
26
+
27
+ ##
28
+ # Extract the file contents and attach them to the toplevel as a comment
29
+
30
+ def scan
31
+ @top_level.comment = remove_private_comments(@body)
32
+ @top_level
33
+ end
34
+
35
+ def remove_private_comments(comment)
36
+ comment.gsub(/^--[^-].*?^\+\+/m, '').sub(/^--.*/m, '')
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,99 @@
1
+ require "rdoc/parsers/parse_simple"
2
+
3
+ module RDoc
4
+
5
+ # A parser is simple a class that implements
6
+ #
7
+ # #initialize(file_name, body, options)
8
+ #
9
+ # and
10
+ #
11
+ # #scan
12
+ #
13
+ # The initialize method takes a file name to be used, the body of the
14
+ # file, and an RDoc::Options object. The scan method is then called
15
+ # to return an appropriately parsed TopLevel code object.
16
+ #
17
+ # The ParseFactory is used to redirect to the correct parser given a filename
18
+ # extension. This magic works because individual parsers have to register
19
+ # themselves with us as they are loaded in. The do this using the following
20
+ # incantation
21
+ #
22
+ #
23
+ # require "rdoc/parsers/parsefactory"
24
+ #
25
+ # module RDoc
26
+ #
27
+ # class XyzParser
28
+ # extend ParseFactory <<<<
29
+ # parse_files_matching /\.xyz$/ <<<<
30
+ #
31
+ # def initialize(file_name, body, options)
32
+ # ...
33
+ # end
34
+ #
35
+ # def scan
36
+ # ...
37
+ # end
38
+ # end
39
+ # end
40
+ #
41
+ # Just to make life interesting, if we suspect a plain text file, we
42
+ # also look for a shebang line just in case it's a potential
43
+ # shell script
44
+
45
+
46
+
47
+ module ParserFactory
48
+
49
+ @@parsers = []
50
+
51
+ Parsers = Struct.new(:regexp, :parser)
52
+
53
+ # Record the fact that a particular class parses files that
54
+ # match a given extension
55
+
56
+ def parse_files_matching(regexp)
57
+ @@parsers.unshift Parsers.new(regexp, self)
58
+ end
59
+
60
+ # Return a parser that can handle a particular extension
61
+
62
+ def ParserFactory.can_parse(file_name)
63
+ @@parsers.find {|p| p.regexp.match(file_name) }
64
+ end
65
+
66
+ # Alias an extension to another extension. After this call,
67
+ # files ending "new_ext" will be parsed using the same parser
68
+ # as "old_ext"
69
+
70
+ def ParserFactory.alias_extension(old_ext, new_ext)
71
+ parser = ParserFactory.can_parse("xxx.#{old_ext}")
72
+ return false unless parser
73
+ @@parsers.unshift Parsers.new(Regexp.new("\\.#{new_ext}$"), parser.parser)
74
+ true
75
+ end
76
+
77
+ # Find the correct parser for a particular file name. Return a
78
+ # SimpleParser for ones that we don't know
79
+
80
+ def ParserFactory.parser_for(top_level, file_name, body, options, stats)
81
+ # If no extension, look for shebang
82
+ if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)}
83
+ shebang = $1
84
+ case shebang
85
+ when %r{env\s+ruby}, %r{/ruby}
86
+ file_name = "dummy.rb"
87
+ end
88
+ end
89
+ parser_description = can_parse(file_name)
90
+ if parser_description
91
+ parser = parser_description.parser
92
+ else
93
+ parser = SimpleParser
94
+ end
95
+
96
+ parser.new(top_level, file_name, body, options, stats)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,277 @@
1
+ require 'rdoc'
2
+
3
+ require 'rdoc/parsers/parse_rb.rb'
4
+ require 'rdoc/parsers/parse_c.rb'
5
+ require 'rdoc/parsers/parse_f95.rb'
6
+ require 'rdoc/parsers/parse_simple.rb'
7
+
8
+ require 'rdoc/stats'
9
+ require 'rdoc/options'
10
+
11
+ require 'rdoc/diagram'
12
+
13
+ require 'find'
14
+ require 'fileutils'
15
+ require 'time'
16
+
17
+ module RDoc
18
+
19
+ ##
20
+ # Encapsulate the production of rdoc documentation. Basically
21
+ # you can use this as you would invoke rdoc from the command
22
+ # line:
23
+ #
24
+ # rdoc = RDoc::RDoc.new
25
+ # rdoc.document(args)
26
+ #
27
+ # where _args_ is an array of strings, each corresponding to
28
+ # an argument you'd give rdoc on the command line. See rdoc/rdoc.rb
29
+ # for details.
30
+
31
+ class RDoc
32
+
33
+ Generator = Struct.new(:file_name, :class_name, :key)
34
+
35
+ ##
36
+ # This is the list of output generator that we support
37
+
38
+ GENERATORS = {}
39
+
40
+ $LOAD_PATH.collect do |d|
41
+ File.expand_path d
42
+ end.find_all do |d|
43
+ File.directory? "#{d}/rdoc/generator"
44
+ end.each do |dir|
45
+ Dir.entries("#{dir}/rdoc/generator").each do |gen|
46
+ next unless /(\w+)\.rb$/ =~ gen
47
+ type = $1
48
+ unless GENERATORS.has_key? type
49
+ GENERATORS[type] = Generator.new("rdoc/generator/#{gen}",
50
+ "#{type.upcase}".intern,
51
+ type)
52
+ end
53
+ end
54
+ end
55
+
56
+ def initialize
57
+ @stats = Stats.new
58
+ end
59
+
60
+ ##
61
+ # Report an error message and exit
62
+
63
+ def error(msg)
64
+ raise ::RDoc::Error, msg
65
+ end
66
+
67
+ ##
68
+ # Create an output dir if it doesn't exist. If it does exist, but doesn't
69
+ # contain the flag file <tt>created.rid</tt> then we refuse to use it, as
70
+ # we may clobber some manually generated documentation
71
+
72
+ def setup_output_dir(op_dir, force)
73
+ flag_file = output_flag_file(op_dir)
74
+ if File.exist?(op_dir)
75
+ unless File.directory?(op_dir)
76
+ error "'#{op_dir}' exists, and is not a directory"
77
+ end
78
+ begin
79
+ created = File.read(flag_file)
80
+ rescue SystemCallError
81
+ error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
82
+ "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
83
+ "destroying any of your existing files, you'll need to\n" +
84
+ "specify a different output directory name (using the\n" +
85
+ "--op <dir> option).\n\n"
86
+ else
87
+ last = (Time.parse(created) unless force rescue nil)
88
+ end
89
+ else
90
+ FileUtils.mkdir_p(op_dir)
91
+ end
92
+ last
93
+ end
94
+
95
+ ##
96
+ # Update the flag file in an output directory.
97
+
98
+ def update_output_dir(op_dir, time)
99
+ File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
100
+ end
101
+
102
+ ##
103
+ # Return the path name of the flag file in an output directory.
104
+
105
+ def output_flag_file(op_dir)
106
+ File.join(op_dir, "created.rid")
107
+ end
108
+
109
+ ##
110
+ # The .document file contains a list of file and directory name patterns,
111
+ # representing candidates for documentation. It may also contain comments
112
+ # (starting with '#')
113
+
114
+ def parse_dot_doc_file(in_dir, filename, options)
115
+ # read and strip comments
116
+ patterns = File.read(filename).gsub(/#.*/, '')
117
+
118
+ result = []
119
+
120
+ patterns.split.each do |patt|
121
+ candidates = Dir.glob(File.join(in_dir, patt))
122
+ result.concat(normalized_file_list(options, candidates))
123
+ end
124
+ result
125
+ end
126
+
127
+ ##
128
+ # Given a list of files and directories, create a list of all the Ruby
129
+ # files they contain.
130
+ #
131
+ # If +force_doc+ is true we always add the given files, if false, only
132
+ # add files that we guarantee we can parse. It is true when looking at
133
+ # files given on the command line, false when recursing through
134
+ # subdirectories.
135
+ #
136
+ # The effect of this is that if you want a file with a non-standard
137
+ # extension parsed, you must name it explicity.
138
+
139
+ def normalized_file_list(options, relative_files, force_doc = false,
140
+ exclude_pattern = nil)
141
+ file_list = []
142
+
143
+ relative_files.each do |rel_file_name|
144
+ next if exclude_pattern && exclude_pattern =~ rel_file_name
145
+ stat = File.stat(rel_file_name)
146
+ case type = stat.ftype
147
+ when "file"
148
+ next if @last_created and stat.mtime < @last_created
149
+ file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
150
+ when "directory"
151
+ next if rel_file_name == "CVS" || rel_file_name == ".svn"
152
+ dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
153
+ if File.file?(dot_doc)
154
+ file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
155
+ else
156
+ file_list.concat(list_files_in_directory(rel_file_name, options))
157
+ end
158
+ else
159
+ raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
160
+ end
161
+ end
162
+
163
+ file_list
164
+ end
165
+
166
+ ##
167
+ # Return a list of the files to be processed in a directory. We know that
168
+ # this directory doesn't have a .document file, so we're looking for real
169
+ # files. However we may well contain subdirectories which must be tested
170
+ # for .document files.
171
+
172
+ def list_files_in_directory(dir, options)
173
+ files = Dir.glob File.join(dir, "*")
174
+
175
+ normalized_file_list options, files, false, options.exclude
176
+ end
177
+
178
+ ##
179
+ # Parse each file on the command line, recursively entering directories.
180
+
181
+ def parse_files(options)
182
+ files = options.files
183
+ files = ["."] if files.empty?
184
+
185
+ file_list = normalized_file_list(options, files, true)
186
+
187
+ return [] if file_list.empty?
188
+
189
+ file_info = []
190
+ width = file_list.map { |name| name.length }.max + 1
191
+
192
+ file_list.each do |fn|
193
+ $stderr.printf("\n%*s: ", width, fn) unless options.quiet
194
+
195
+ content = if RUBY_VERSION >= '1.9' then
196
+ File.open(fn, "r:ascii-8bit") { |f| f.read }
197
+ else
198
+ File.read fn
199
+ end
200
+
201
+ if / coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
202
+ if enc = Encoding.find($1)
203
+ content.force_encoding(enc)
204
+ end
205
+ end
206
+
207
+ top_level = TopLevel.new(fn)
208
+ parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
209
+ file_info << parser.scan
210
+ @stats.num_files += 1
211
+ end
212
+
213
+ file_info
214
+ end
215
+
216
+ ##
217
+ # Format up one or more files according to the given arguments.
218
+ #
219
+ # For simplicity, _argv_ is an array of strings, equivalent to the strings
220
+ # that would be passed on the command line. (This isn't a coincidence, as
221
+ # we _do_ pass in ARGV when running interactively). For a list of options,
222
+ # see rdoc/rdoc.rb. By default, output will be stored in a directory
223
+ # called +doc+ below the current directory, so make sure you're somewhere
224
+ # writable before invoking.
225
+ #
226
+ # Throws: RDoc::Error on error
227
+
228
+ def document(argv)
229
+ TopLevel::reset
230
+
231
+ @options = Options.new GENERATORS
232
+ @options.parse argv
233
+
234
+ @last_created = nil
235
+
236
+ unless @options.all_one_file then
237
+ @last_created = setup_output_dir @options.op_dir, @options.force_update
238
+ end
239
+
240
+ start_time = Time.now
241
+
242
+ file_info = parse_files @options
243
+
244
+ if file_info.empty?
245
+ $stderr.puts "\nNo newer files." unless @options.quiet
246
+ else
247
+ @gen = @options.generator
248
+
249
+ $stderr.puts "\nGenerating #{@gen.key.upcase}..." unless @options.quiet
250
+
251
+ require @gen.file_name
252
+
253
+ gen_class = ::RDoc::Generator.const_get @gen.class_name
254
+ @gen = gen_class.for @options
255
+
256
+ pwd = Dir.pwd
257
+
258
+ Dir.chdir @options.op_dir unless @options.all_one_file
259
+
260
+ begin
261
+ Diagram.new(file_info, @options).draw if @options.diagram
262
+ @gen.generate(file_info)
263
+ update_output_dir(".", start_time)
264
+ ensure
265
+ Dir.chdir(pwd)
266
+ end
267
+ end
268
+
269
+ unless @options.quiet
270
+ puts
271
+ @stats.print
272
+ end
273
+ end
274
+ end
275
+
276
+ end
277
+
@@ -0,0 +1,4 @@
1
+ require 'rdoc'
2
+
3
+ module RDoc::RI; end
4
+
@@ -0,0 +1,188 @@
1
+ require 'rdoc/ri'
2
+
3
+ class RDoc::RI::ClassEntry
4
+
5
+ attr_reader :name
6
+ attr_reader :path_names
7
+
8
+ def initialize(path_name, name, in_class)
9
+ @path_names = [ path_name ]
10
+ @name = name
11
+ @in_class = in_class
12
+ @class_methods = []
13
+ @instance_methods = []
14
+ @inferior_classes = []
15
+ end
16
+
17
+ # We found this class in more tha one place, so add
18
+ # in the name from there.
19
+ def add_path(path)
20
+ @path_names << path
21
+ end
22
+
23
+ # read in our methods and any classes
24
+ # and modules in our namespace. Methods are
25
+ # stored in files called name-c|i.yaml,
26
+ # where the 'name' portion is the external
27
+ # form of the method name and the c|i is a class|instance
28
+ # flag
29
+
30
+ def load_from(dir)
31
+ Dir.foreach(dir) do |name|
32
+ next if name =~ /^\./
33
+
34
+ # convert from external to internal form, and
35
+ # extract the instance/class flag
36
+
37
+ if name =~ /^(.*?)-(c|i).yaml$/
38
+ external_name = $1
39
+ is_class_method = $2 == "c"
40
+ internal_name = RiWriter.external_to_internal(external_name)
41
+ list = is_class_method ? @class_methods : @instance_methods
42
+ path = File.join(dir, name)
43
+ list << MethodEntry.new(path, internal_name, is_class_method, self)
44
+ else
45
+ full_name = File.join(dir, name)
46
+ if File.directory?(full_name)
47
+ inf_class = @inferior_classes.find {|c| c.name == name }
48
+ if inf_class
49
+ inf_class.add_path(full_name)
50
+ else
51
+ inf_class = ClassEntry.new(full_name, name, self)
52
+ @inferior_classes << inf_class
53
+ end
54
+ inf_class.load_from(full_name)
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ # Return a list of any classes or modules that we contain
61
+ # that match a given string
62
+
63
+ def contained_modules_matching(name)
64
+ @inferior_classes.find_all {|c| c.name[name]}
65
+ end
66
+
67
+ def classes_and_modules
68
+ @inferior_classes
69
+ end
70
+
71
+ # Return an exact match to a particular name
72
+ def contained_class_named(name)
73
+ @inferior_classes.find {|c| c.name == name}
74
+ end
75
+
76
+ # return the list of local methods matching name
77
+ # We're split into two because we need distinct behavior
78
+ # when called from the _toplevel_
79
+ def methods_matching(name, is_class_method)
80
+ local_methods_matching(name, is_class_method)
81
+ end
82
+
83
+ # Find methods matching 'name' in ourselves and in
84
+ # any classes we contain
85
+ def recursively_find_methods_matching(name, is_class_method)
86
+ res = local_methods_matching(name, is_class_method)
87
+ @inferior_classes.each do |c|
88
+ res.concat(c.recursively_find_methods_matching(name, is_class_method))
89
+ end
90
+ res
91
+ end
92
+
93
+
94
+ # Return our full name
95
+ def full_name
96
+ res = @in_class.full_name
97
+ res << "::" unless res.empty?
98
+ res << @name
99
+ end
100
+
101
+ # Return a list of all out method names
102
+ def all_method_names
103
+ res = @class_methods.map {|m| m.full_name }
104
+ @instance_methods.each {|m| res << m.full_name}
105
+ res
106
+ end
107
+
108
+ private
109
+
110
+ # Return a list of all our methods matching a given string.
111
+ # Is +is_class_methods+ if 'nil', we don't care if the method
112
+ # is a class method or not, otherwise we only return
113
+ # those methods that match
114
+ def local_methods_matching(name, is_class_method)
115
+
116
+ list = case is_class_method
117
+ when nil then @class_methods + @instance_methods
118
+ when true then @class_methods
119
+ when false then @instance_methods
120
+ else fail "Unknown is_class_method: #{is_class_method.inspect}"
121
+ end
122
+
123
+ list.find_all {|m| m.name; m.name[name]}
124
+ end
125
+ end
126
+
127
+ ##
128
+ # A TopLevelEntry is like a class entry, but when asked to search for methods
129
+ # searches all classes, not just itself
130
+
131
+ class RDoc::RI::TopLevelEntry < RDoc::RI::ClassEntry
132
+ def methods_matching(name, is_class_method)
133
+ res = recursively_find_methods_matching(name, is_class_method)
134
+ end
135
+
136
+ def full_name
137
+ ""
138
+ end
139
+
140
+ def module_named(name)
141
+
142
+ end
143
+
144
+ end
145
+
146
+ class RDoc::RI::MethodEntry
147
+ attr_reader :name
148
+ attr_reader :path_name
149
+
150
+ def initialize(path_name, name, is_class_method, in_class)
151
+ @path_name = path_name
152
+ @name = name
153
+ @is_class_method = is_class_method
154
+ @in_class = in_class
155
+ end
156
+
157
+ def full_name
158
+ res = @in_class.full_name
159
+ unless res.empty?
160
+ if @is_class_method
161
+ res << "::"
162
+ else
163
+ res << "#"
164
+ end
165
+ end
166
+ res << @name
167
+ end
168
+ end
169
+
170
+ ##
171
+ # We represent everything know about all 'ri' files accessible to this program
172
+
173
+ class RDoc::RI::Cache
174
+
175
+ attr_reader :toplevel
176
+
177
+ def initialize(dirs)
178
+ # At the top level we have a dummy module holding the
179
+ # overall namespace
180
+ @toplevel = RDoc::RI::TopLevelEntry.new('', '::', nil)
181
+
182
+ dirs.each do |dir|
183
+ @toplevel.load_from(dir)
184
+ end
185
+ end
186
+
187
+ end
188
+