Class RDoc::RDoc
In: rdoc.rb
doc-tmp/rdoc/rdoc.rb
Parent: Object

Encapsulate the production of rdoc documentation. Basically you can use this as you would invoke rdoc from the command line:

   rdoc = RDoc::RDoc.new
   rdoc.document(args)

where args is an array of strings, each corresponding to an argument you‘d give rdoc on the command line. See rdoc/rdoc.rb for details.

Methods

Public Class methods

[Source]

    # File doc-tmp/rdoc/rdoc.rb, line 84
84:     def initialize
85:       @stats = Stats.new
86:     end

[Source]

    # File rdoc.rb, line 84
84:     def initialize
85:       @stats = Stats.new
86:     end

Public Instance methods

Format up one or more files according to the given arguments.

For simplicity, argv is an array of strings, equivalent to the strings that would be passed on the command line. (This isn‘t a coincidence, as we do pass in ARGV when running interactively). For a list of options, see rdoc/rdoc.rb. By default, output will be stored in a directory called doc below the current directory, so make sure you‘re somewhere writable before invoking.

Throws: RDoc::Error on error

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 256
256:     def document(argv)
257:       TopLevel::reset
258: 
259:       options = Options.new GENERATORS
260:       options.parse argv
261: 
262:       @last_created = nil
263: 
264:       unless options.all_one_file
265:         @last_created = setup_output_dir(options.op_dir, options.force_update)
266:       end
267: 
268:       start_time = Time.now
269: 
270:       file_info = parse_files(options)
271: 
272:       if file_info.empty?
273:         $stderr.puts "\nNo newer files." unless options.quiet
274:       else
275:         gen = options.generator
276: 
277:         $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet
278: 
279:         require gen.file_name
280: 
281:         gen_class = ::RDoc::Generator.const_get gen.class_name
282:         gen = gen_class.for(options)
283: 
284:         pwd = Dir.pwd
285: 
286:         Dir.chdir(options.op_dir)  unless options.all_one_file
287: 
288:         begin
289:           Diagram.new(file_info, options).draw if options.diagram
290:           gen.generate(file_info)
291:           update_output_dir(".", start_time)
292:         ensure
293:           Dir.chdir(pwd)
294:         end
295:       end
296: 
297:       unless options.quiet
298:         puts
299:         @stats.print
300:       end
301:     end

Format up one or more files according to the given arguments.

For simplicity, argv is an array of strings, equivalent to the strings that would be passed on the command line. (This isn‘t a coincidence, as we do pass in ARGV when running interactively). For a list of options, see rdoc/rdoc.rb. By default, output will be stored in a directory called doc below the current directory, so make sure you‘re somewhere writable before invoking.

Throws: RDoc::Error on error

[Source]

     # File rdoc.rb, line 256
256:     def document(argv)
257:       TopLevel::reset
258: 
259:       options = Options.new GENERATORS
260:       options.parse argv
261: 
262:       @last_created = nil
263: 
264:       unless options.all_one_file
265:         @last_created = setup_output_dir(options.op_dir, options.force_update)
266:       end
267: 
268:       start_time = Time.now
269: 
270:       file_info = parse_files(options)
271: 
272:       if file_info.empty?
273:         $stderr.puts "\nNo newer files." unless options.quiet
274:       else
275:         gen = options.generator
276: 
277:         $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet
278: 
279:         require gen.file_name
280: 
281:         gen_class = ::RDoc::Generator.const_get gen.class_name
282:         gen = gen_class.for(options)
283: 
284:         pwd = Dir.pwd
285: 
286:         Dir.chdir(options.op_dir)  unless options.all_one_file
287: 
288:         begin
289:           Diagram.new(file_info, options).draw if options.diagram
290:           gen.generate(file_info)
291:           update_output_dir(".", start_time)
292:         ensure
293:           Dir.chdir(pwd)
294:         end
295:       end
296: 
297:       unless options.quiet
298:         puts
299:         @stats.print
300:       end
301:     end

Report an error message and exit

[Source]

    # File rdoc.rb, line 91
91:     def error(msg)
92:       raise ::RDoc::Error, msg
93:     end

Report an error message and exit

[Source]

    # File doc-tmp/rdoc/rdoc.rb, line 91
91:     def error(msg)
92:       raise ::RDoc::Error, msg
93:     end

Return a list of the files to be processed in a directory. We know that this directory doesn‘t have a .document file, so we‘re looking for real files. However we may well contain subdirectories which must be tested for .document files.

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 200
200:     def list_files_in_directory(dir, options)
201:       files = Dir.glob File.join(dir, "*")
202: 
203:       normalized_file_list options, files, false, options.exclude
204:     end

Return a list of the files to be processed in a directory. We know that this directory doesn‘t have a .document file, so we‘re looking for real files. However we may well contain subdirectories which must be tested for .document files.

[Source]

     # File rdoc.rb, line 200
200:     def list_files_in_directory(dir, options)
201:       files = Dir.glob File.join(dir, "*")
202: 
203:       normalized_file_list options, files, false, options.exclude
204:     end

Given a list of files and directories, create a list of all the Ruby files they contain.

If force_doc is true we always add the given files, if false, only add files that we guarantee we can parse. It is true when looking at files given on the command line, false when recursing through subdirectories.

The effect of this is that if you want a file with a non-standard extension parsed, you must name it explicity.

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 167
167:     def normalized_file_list(options, relative_files, force_doc = false,
168:                              exclude_pattern = nil)
169:       file_list = []
170: 
171:       relative_files.each do |rel_file_name|
172:         next if exclude_pattern && exclude_pattern =~ rel_file_name
173:         stat = File.stat(rel_file_name)
174:         case type = stat.ftype
175:         when "file"
176:           next if @last_created and stat.mtime < @last_created
177:           file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
178:         when "directory"
179:           next if rel_file_name == "CVS" || rel_file_name == ".svn"
180:           dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
181:           if File.file?(dot_doc)
182:             file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
183:           else
184:             file_list.concat(list_files_in_directory(rel_file_name, options))
185:           end
186:         else
187:           raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
188:         end
189:       end
190: 
191:       file_list
192:     end

Given a list of files and directories, create a list of all the Ruby files they contain.

If force_doc is true we always add the given files, if false, only add files that we guarantee we can parse. It is true when looking at files given on the command line, false when recursing through subdirectories.

The effect of this is that if you want a file with a non-standard extension parsed, you must name it explicity.

[Source]

     # File rdoc.rb, line 167
167:     def normalized_file_list(options, relative_files, force_doc = false,
168:                              exclude_pattern = nil)
169:       file_list = []
170: 
171:       relative_files.each do |rel_file_name|
172:         next if exclude_pattern && exclude_pattern =~ rel_file_name
173:         stat = File.stat(rel_file_name)
174:         case type = stat.ftype
175:         when "file"
176:           next if @last_created and stat.mtime < @last_created
177:           file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
178:         when "directory"
179:           next if rel_file_name == "CVS" || rel_file_name == ".svn"
180:           dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
181:           if File.file?(dot_doc)
182:             file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
183:           else
184:             file_list.concat(list_files_in_directory(rel_file_name, options))
185:           end
186:         else
187:           raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
188:         end
189:       end
190: 
191:       file_list
192:     end

Return the path name of the flag file in an output directory.

[Source]

     # File rdoc.rb, line 133
133:     def output_flag_file(op_dir)
134:       File.join(op_dir, "created.rid")
135:     end

Return the path name of the flag file in an output directory.

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 133
133:     def output_flag_file(op_dir)
134:       File.join(op_dir, "created.rid")
135:     end

The .document file contains a list of file and directory name patterns, representing candidates for documentation. It may also contain comments (starting with ’#’)

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 142
142:     def parse_dot_doc_file(in_dir, filename, options)
143:       # read and strip comments
144:       patterns = File.read(filename).gsub(/#.*/, '')
145: 
146:       result = []
147: 
148:       patterns.split.each do |patt|
149:         candidates = Dir.glob(File.join(in_dir, patt))
150:         result.concat(normalized_file_list(options,  candidates))
151:       end
152:       result
153:     end

The .document file contains a list of file and directory name patterns, representing candidates for documentation. It may also contain comments (starting with ’#’)

[Source]

     # File rdoc.rb, line 142
142:     def parse_dot_doc_file(in_dir, filename, options)
143:       # read and strip comments
144:       patterns = File.read(filename).gsub(/#.*/, '')
145: 
146:       result = []
147: 
148:       patterns.split.each do |patt|
149:         candidates = Dir.glob(File.join(in_dir, patt))
150:         result.concat(normalized_file_list(options,  candidates))
151:       end
152:       result
153:     end

Parse each file on the command line, recursively entering directories.

[Source]

     # File rdoc.rb, line 209
209:     def parse_files(options)
210:       files = options.files
211:       files = ["."] if files.empty?
212: 
213:       file_list = normalized_file_list(options, files, true)
214: 
215:       return [] if file_list.empty?
216: 
217:       file_info = []
218:       width = file_list.map { |name| name.length }.max + 1
219: 
220:       file_list.each do |fn|
221:         $stderr.printf("\n%*s: ", width, fn) unless options.quiet
222: 
223:         content = if RUBY_VERSION >= '1.9' then
224:                     File.open(fn, "r:ascii-8bit") { |f| f.read }
225:                   else
226:                     File.read fn
227:                   end
228: 
229:         if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
230:           if enc = Encoding.find($1)
231:             content.force_encoding(enc)
232:           end
233:         end
234: 
235:         top_level = TopLevel.new(fn)
236:         parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
237:         file_info << parser.scan
238:         @stats.num_files += 1
239:       end
240: 
241:       file_info
242:     end

Parse each file on the command line, recursively entering directories.

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 209
209:     def parse_files(options)
210:       files = options.files
211:       files = ["."] if files.empty?
212: 
213:       file_list = normalized_file_list(options, files, true)
214: 
215:       return [] if file_list.empty?
216: 
217:       file_info = []
218:       width = file_list.map { |name| name.length }.max + 1
219: 
220:       file_list.each do |fn|
221:         $stderr.printf("\n%*s: ", width, fn) unless options.quiet
222: 
223:         content = if RUBY_VERSION >= '1.9' then
224:                     File.open(fn, "r:ascii-8bit") { |f| f.read }
225:                   else
226:                     File.read fn
227:                   end
228: 
229:         if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
230:           if enc = Encoding.find($1)
231:             content.force_encoding(enc)
232:           end
233:         end
234: 
235:         top_level = TopLevel.new(fn)
236:         parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
237:         file_info << parser.scan
238:         @stats.num_files += 1
239:       end
240: 
241:       file_info
242:     end

Create an output dir if it doesn‘t exist. If it does exist, but doesn‘t contain the flag file created.rid then we refuse to use it, as we may clobber some manually generated documentation

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 100
100:     def setup_output_dir(op_dir, force)
101:       flag_file = output_flag_file(op_dir)
102:       if File.exist?(op_dir)
103:         unless File.directory?(op_dir)
104:           error "'#{op_dir}' exists, and is not a directory"
105:         end
106:         begin
107:           created = File.read(flag_file)
108:         rescue SystemCallError
109:           error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
110:             "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
111:             "destroying any of your existing files, you'll need to\n" +
112:             "specify a different output directory name (using the\n" +
113:             "--op <dir> option).\n\n"
114:         else
115:           last = (Time.parse(created) unless force rescue nil)
116:         end
117:       else
118:         FileUtils.mkdir_p(op_dir)
119:       end
120:       last
121:     end

Create an output dir if it doesn‘t exist. If it does exist, but doesn‘t contain the flag file created.rid then we refuse to use it, as we may clobber some manually generated documentation

[Source]

     # File rdoc.rb, line 100
100:     def setup_output_dir(op_dir, force)
101:       flag_file = output_flag_file(op_dir)
102:       if File.exist?(op_dir)
103:         unless File.directory?(op_dir)
104:           error "'#{op_dir}' exists, and is not a directory"
105:         end
106:         begin
107:           created = File.read(flag_file)
108:         rescue SystemCallError
109:           error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
110:             "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
111:             "destroying any of your existing files, you'll need to\n" +
112:             "specify a different output directory name (using the\n" +
113:             "--op <dir> option).\n\n"
114:         else
115:           last = (Time.parse(created) unless force rescue nil)
116:         end
117:       else
118:         FileUtils.mkdir_p(op_dir)
119:       end
120:       last
121:     end

Update the flag file in an output directory.

[Source]

     # File rdoc.rb, line 126
126:     def update_output_dir(op_dir, time)
127:       File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
128:     end

Update the flag file in an output directory.

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 126
126:     def update_output_dir(op_dir, time)
127:       File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
128:     end

[Validate]