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 87
87:     def initialize
88:       @stats = Stats.new
89:     end

[Source]

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

Report an error message and exit

[Source]

    # File rdoc.rb, line 94
94:     def error(msg)
95:       raise ::RDoc::Error, msg
96:     end

Report an error message and exit

[Source]

    # File doc-tmp/rdoc/rdoc.rb, line 94
94:     def error(msg)
95:       raise ::RDoc::Error, msg
96:     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 203
203:     def list_files_in_directory(dir, options)
204:       files = Dir.glob File.join(dir, "*")
205: 
206:       normalized_file_list options, files, false, options.exclude
207:     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 203
203:     def list_files_in_directory(dir, options)
204:       files = Dir.glob File.join(dir, "*")
205: 
206:       normalized_file_list options, files, false, options.exclude
207:     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 170
170:     def normalized_file_list(options, relative_files, force_doc = false,
171:                              exclude_pattern = nil)
172:       file_list = []
173: 
174:       relative_files.each do |rel_file_name|
175:         next if exclude_pattern && exclude_pattern =~ rel_file_name
176:         stat = File.stat(rel_file_name)
177:         case type = stat.ftype
178:         when "file"
179:           next if @last_created and stat.mtime < @last_created
180:           file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
181:         when "directory"
182:           next if rel_file_name == "CVS" || rel_file_name == ".svn"
183:           dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
184:           if File.file?(dot_doc)
185:             file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
186:           else
187:             file_list.concat(list_files_in_directory(rel_file_name, options))
188:           end
189:         else
190:           raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
191:         end
192:       end
193: 
194:       file_list
195:     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 170
170:     def normalized_file_list(options, relative_files, force_doc = false,
171:                              exclude_pattern = nil)
172:       file_list = []
173: 
174:       relative_files.each do |rel_file_name|
175:         next if exclude_pattern && exclude_pattern =~ rel_file_name
176:         stat = File.stat(rel_file_name)
177:         case type = stat.ftype
178:         when "file"
179:           next if @last_created and stat.mtime < @last_created
180:           file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
181:         when "directory"
182:           next if rel_file_name == "CVS" || rel_file_name == ".svn"
183:           dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
184:           if File.file?(dot_doc)
185:             file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
186:           else
187:             file_list.concat(list_files_in_directory(rel_file_name, options))
188:           end
189:         else
190:           raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
191:         end
192:       end
193: 
194:       file_list
195:     end

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

[Source]

     # File rdoc.rb, line 136
136:     def output_flag_file(op_dir)
137:       File.join(op_dir, "created.rid")
138:     end

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

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 136
136:     def output_flag_file(op_dir)
137:       File.join(op_dir, "created.rid")
138:     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 145
145:     def parse_dot_doc_file(in_dir, filename, options)
146:       # read and strip comments
147:       patterns = File.read(filename).gsub(/#.*/, '')
148: 
149:       result = []
150: 
151:       patterns.split.each do |patt|
152:         candidates = Dir.glob(File.join(in_dir, patt))
153:         result.concat(normalized_file_list(options,  candidates))
154:       end
155:       result
156:     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 145
145:     def parse_dot_doc_file(in_dir, filename, options)
146:       # read and strip comments
147:       patterns = File.read(filename).gsub(/#.*/, '')
148: 
149:       result = []
150: 
151:       patterns.split.each do |patt|
152:         candidates = Dir.glob(File.join(in_dir, patt))
153:         result.concat(normalized_file_list(options,  candidates))
154:       end
155:       result
156:     end

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

[Source]

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

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

[Source]

     # File doc-tmp/rdoc/rdoc.rb, line 212
212:     def parse_files(options)
213:       files = options.files
214:       files = ["."] if files.empty?
215: 
216:       file_list = normalized_file_list(options, files, true)
217: 
218:       return [] if file_list.empty?
219: 
220:       file_info = []
221:       width = file_list.map { |name| name.length }.max + 1
222: 
223:       file_list.each do |fn|
224:         $stderr.printf("\n%*s: ", width, fn) unless options.quiet
225: 
226:         content = if RUBY_VERSION >= '1.9' then
227:                     File.open(fn, "r:ascii-8bit") { |f| f.read }
228:                   else
229:                     File.read fn
230:                   end
231: 
232:         if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
233:           if enc = Encoding.find($1)
234:             content.force_encoding(enc)
235:           end
236:         end
237: 
238:         top_level = TopLevel.new(fn)
239:         parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
240:         file_info << parser.scan
241:         @stats.num_files += 1
242:       end
243: 
244:       file_info
245:     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 103
103:     def setup_output_dir(op_dir, force)
104:       flag_file = output_flag_file(op_dir)
105:       if File.exist?(op_dir)
106:         unless File.directory?(op_dir)
107:           error "'#{op_dir}' exists, and is not a directory"
108:         end
109:         begin
110:           created = File.read(flag_file)
111:         rescue SystemCallError
112:           error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
113:             "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
114:             "destroying any of your existing files, you'll need to\n" +
115:             "specify a different output directory name (using the\n" +
116:             "--op <dir> option).\n\n"
117:         else
118:           last = (Time.parse(created) unless force rescue nil)
119:         end
120:       else
121:         FileUtils.mkdir_p(op_dir)
122:       end
123:       last
124:     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 103
103:     def setup_output_dir(op_dir, force)
104:       flag_file = output_flag_file(op_dir)
105:       if File.exist?(op_dir)
106:         unless File.directory?(op_dir)
107:           error "'#{op_dir}' exists, and is not a directory"
108:         end
109:         begin
110:           created = File.read(flag_file)
111:         rescue SystemCallError
112:           error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
113:             "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
114:             "destroying any of your existing files, you'll need to\n" +
115:             "specify a different output directory name (using the\n" +
116:             "--op <dir> option).\n\n"
117:         else
118:           last = (Time.parse(created) unless force rescue nil)
119:         end
120:       else
121:         FileUtils.mkdir_p(op_dir)
122:       end
123:       last
124:     end

Update the flag file in an output directory.

[Source]

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

Update the flag file in an output directory.

[Source]

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

[Validate]