class RDoc::RDoc
def self.add_generator(klass)
def self.add_generator(klass) name = klass.name.sub(/^RDoc::Generator::/, '').downcase GENERATORS[name] = klass end
def self.current
def self.current @current end
def self.current=(rdoc)
def self.current=(rdoc) @current = rdoc end
def document(argv)
def document(argv) RDoc::TopLevel.reset RDoc::Parser::C.reset @options = RDoc::Options.new @options.parse argv if @options.pipe then handle_pipe exit end @exclude = @options.exclude @last_modified = setup_output_dir @options.op_dir, @options.force_update start_time = Time.now file_info = parse_files @options.files @options.title = "RDoc Documentation" if file_info.empty? $stderr.puts "\nNo newer files." unless @options.quiet else gen_klass = @options.generator unless @options.quiet then $stderr.puts "\nGenerating #{gen_klass.name.sub(/^.*::/, '')}..." end @generator = gen_klass.for @options pwd = Dir.pwd Dir.chdir @options.op_dir do begin self.class.current = self @generator.generate file_info update_output_dir ".", start_time, @last_modified ensure self.class.current = nil end end end unless @options.quiet or not @stats then puts @stats.print end end
def error(msg)
def error(msg) raise RDoc::Error, msg end
def gather_files files
def gather_files files files = ["."] if files.empty? file_list = normalized_file_list files, true, @exclude file_list = file_list.uniq file_list = remove_unparseable file_list end
def handle_pipe
def handle_pipe @html = RDoc::Markup::ToHtml.new out = @html.convert $stdin.read $stdout.write out end
def initialize
def initialize @current = nil @exclude = nil @generator = nil @last_modified = {} @old_siginfo = nil @options = nil @stats = nil end
def install_siginfo_handler
def install_siginfo_handler return unless Signal.list.include? 'INFO' @old_siginfo = trap 'INFO' do puts @current if @current end end
def list_files_in_directory dir
def list_files_in_directory dir files = Dir.glob File.join(dir, "*") normalized_file_list files, false, @options.exclude end
def normalized_file_list(relative_files, force_doc = false,
def normalized_file_list(relative_files, force_doc = false, exclude_pattern = nil) file_list = [] relative_files.each do |rel_file_name| next if exclude_pattern && exclude_pattern =~ rel_file_name stat = File.stat rel_file_name rescue next case type = stat.ftype when "file" then next if last_modified = @last_modified[rel_file_name] and stat.mtime.to_i <= last_modified.to_i if force_doc or RDoc::Parser.can_parse(rel_file_name) then file_list << rel_file_name.sub(/^\.\//, '') @last_modified[rel_file_name] = stat.mtime end when "directory" then next if rel_file_name == "CVS" || rel_file_name == ".svn" dot_doc = File.join rel_file_name, RDoc::DOT_DOC_FILENAME if File.file? dot_doc then file_list << parse_dot_doc_file(rel_file_name, dot_doc) else file_list << list_files_in_directory(rel_file_name) end else raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}" end end file_list.flatten end
def output_flag_file(op_dir)
def output_flag_file(op_dir) File.join op_dir, "created.rid" end
def parse_dot_doc_file in_dir, filename
def parse_dot_doc_file in_dir, filename # read and strip comments patterns = File.read(filename).gsub(/#.*/, '') result = [] patterns.split.each do |patt| candidates = Dir.glob(File.join(in_dir, patt)) result.concat normalized_file_list(candidates) end result end
def parse_file filename
def parse_file filename @stats.add_file filename content = read_file_contents filename return unless content top_level = RDoc::TopLevel.new filename parser = RDoc::Parser.for top_level, filename, content, @options, @stats return unless parser parser.scan rescue => e $stderr.puts <<-EOF fore reporting this, could you check that the file you're documenting mpiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if d invalid programs. e internal error was: (#{e.class}) #{e.message} EOF $stderr.puts e.backtrace.join("\n\t") if $RDOC_DEBUG raise e nil end
def parse_files files
def parse_files files file_list = gather_files files return [] if file_list.empty? file_info = [] @stats = RDoc::Stats.new file_list.size, @options.verbosity @stats.begin_adding file_info = file_list.map do |filename| @current = filename parse_file filename end.compact @stats.done_adding file_info end
def read_file_contents(filename)
def read_file_contents(filename) content = open filename, "rb" do |f| f.read end if defined? Encoding then if /coding[=:]\s*([^\s;]+)/i =~ content[%r"\A(?:#!.*\n)?.*\n"] if enc = ::Encoding.find($1) content.force_encoding(enc) end end end content rescue Errno::EISDIR, Errno::ENOENT nil end
def remove_siginfo_handler
def remove_siginfo_handler return unless Signal.list.key? 'INFO' handler = @old_siginfo || 'DEFAULT' trap 'INFO', handler end
def remove_unparseable files
def remove_unparseable files files.reject do |file| file =~ /\.(?:class|eps|erb|scpt\.txt|ttf|yml)$/i end end
def setup_output_dir(dir, force)
def setup_output_dir(dir, force) flag_file = output_flag_file dir last = {} if File.exist? dir then error "#{dir} exists and is not a directory" unless File.directory? dir begin open flag_file do |io| unless force then Time.parse io.gets io.each do |line| file, time = line.split "\t", 2 time = Time.parse(time) rescue next last[file] = time end end end rescue SystemCallError, TypeError error <<-ERROR rectory #{dir} already exists, but it looks like it isn't an RDoc directory. cause RDoc doesn't want to risk destroying any of your existing files, u'll need to specify a different output directory name (using the --op <dir> tion) ERROR end else FileUtils.mkdir_p dir end last end
def update_output_dir(op_dir, time, last = {})
def update_output_dir(op_dir, time, last = {}) open output_flag_file(op_dir), "w" do |f| f.puts time.rfc2822 last.each do |n, t| f.puts "#{n}\t#{t.rfc2822}" end end end