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.
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
# 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
# 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
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.
# 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.
# 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.
# 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.
# 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.
# 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.
# 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 ’#’)
# 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 ’#’)
# 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.
# 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.
# 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
# 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
# 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.
# 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