From 95ed2bc24312699cfce9bb6f9bc1418b15718bb1 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Wed, 24 Aug 2011 18:09:33 +0100 Subject: Add rdoc 2.4.3 to vendor/gems --- vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb | 375 ++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb (limited to 'vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb') diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb new file mode 100644 index 000000000..b854988ac --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb @@ -0,0 +1,375 @@ +require 'rdoc' + +require 'rdoc/parser' + +# Simple must come first +require 'rdoc/parser/simple' +require 'rdoc/parser/ruby' +require 'rdoc/parser/c' +require 'rdoc/parser/perl' + +require 'rdoc/stats' +require 'rdoc/options' + +require 'rdoc/diagram' + +require 'find' +require 'fileutils' +require 'time' +require 'thread' + +## +# 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. + +class RDoc::RDoc + + ## + # Generator instance used for creating output + + attr_accessor :generator + + ## + # RDoc options + + attr_reader :options + + ## + # Accessor for statistics. Available after each call to parse_files + + attr_reader :stats + + ## + # This is the list of supported output generators + + GENERATORS = {} + + ## + # Add +klass+ that can generate output after parsing + + def self.add_generator(klass) + name = klass.name.sub(/^RDoc::Generator::/, '').downcase + GENERATORS[name] = klass + end + + ## + # Active RDoc::RDoc instance + + def self.current + @current + end + + ## + # Sets the active RDoc::RDoc instance + + def self.current=(rdoc) + @current = rdoc + end + + def initialize + @generator = nil + @options = nil + @stats = nil + end + + ## + # Report an error message and exit + + def error(msg) + raise RDoc::Error, msg + end + + ## + # Turns RDoc from stdin into HTML + + def handle_pipe + @html = RDoc::Markup::ToHtml.new + + out = @html.convert $stdin.read + + $stdout.write out + 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 + + def setup_output_dir(op_dir, force) + flag_file = output_flag_file op_dir + + if File.exist? op_dir then + unless File.directory? op_dir then + error "'#{op_dir}' exists, and is not a directory" + end + begin + created = File.read(flag_file) + rescue SystemCallError + error "\nDirectory #{op_dir} already exists, but it looks like it\n" + + "isn't an RDoc directory. Because RDoc doesn't want to risk\n" + + "destroying any of your existing files, you'll need to\n" + + "specify a different output directory name (using the\n" + + "--op option).\n\n" + else + last = (Time.parse(created) unless force rescue nil) + end + else + FileUtils.mkdir_p(op_dir) + end + last + end + + ## + # Update the flag file in an output directory. + + def update_output_dir(op_dir, time) + File.open(output_flag_file(op_dir), "w") { |f| f.puts time.rfc2822 } + end + + ## + # Return the path name of the flag file in an output directory. + + def output_flag_file(op_dir) + File.join op_dir, "created.rid" + end + + ## + # The .document file contains a list of file and directory name patterns, + # representing candidates for documentation. It may also contain comments + # (starting with '#') + + def parse_dot_doc_file(in_dir, filename, options) + # 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(options, candidates)) + end + + result + 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 explicitly. + + def normalized_file_list(options, 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" + next if @last_created and stat.mtime < @last_created + + if force_doc or RDoc::Parser.can_parse(rel_file_name) then + file_list << rel_file_name.sub(/^\.\//, '') + end + when "directory" + 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) + file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options)) + else + file_list.concat(list_files_in_directory(rel_file_name, options)) + end + else + raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}" + end + end + + file_list + 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. + + def list_files_in_directory(dir, options) + files = Dir.glob File.join(dir, "*") + + normalized_file_list options, files, false, options.exclude + end + + ## + # Parse each file on the command line, recursively entering directories. + + def parse_files(options) + files = options.files + files = ["."] if files.empty? + + file_list = normalized_file_list(options, files, true, options.exclude) + + return [] if file_list.empty? + + jobs = SizedQueue.new(@options.threads * 3) + workers = [] + file_info = [] + file_info_lock = Mutex.new + + Thread.abort_on_exception = true + @stats = RDoc::Stats.new(file_list.size, options.verbosity) + @stats.begin_adding @options.threads + + # Create worker threads. + @options.threads.times do + thread = Thread.new do + while (filename = jobs.pop) + @stats.add_file(filename) + content = read_file_contents(filename) + top_level = RDoc::TopLevel.new filename + + parser = RDoc::Parser.for(top_level, filename, content, options, + @stats) + result = parser.scan + + file_info_lock.synchronize do + file_info << result + end + end + end + workers << thread + end + + # Feed filenames to the parser worker threads... + file_list.each do |filename| + jobs << filename + end + workers.size.times do + jobs << nil + end + + # ...and wait until they're done. + workers.each do |thread| + thread.join + end + + @stats.done_adding + + file_info + 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 + + def document(argv) + RDoc::TopLevel.reset + + @options = RDoc::Options.new + @options.parse argv + + if @options.pipe then + handle_pipe + exit + end + + @last_created = setup_output_dir @options.op_dir, @options.force_update + + start_time = Time.now + + file_info = parse_files @options + + @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 + + begin + self.class.current = self + + RDoc::Diagram.new(file_info, @options).draw if @options.diagram + @generator.generate file_info + update_output_dir ".", start_time + ensure + self.class.current = nil + Dir.chdir pwd + end + end + + unless @options.quiet or not @stats then + puts + @stats.print + end + end + + private + + def read_file_contents(filename) + content = if RUBY_VERSION >= '1.9' then + File.open(filename, "r:ascii-8bit") { |f| f.read } + else + File.read filename + end + + if defined? Encoding then + if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/] + if enc = ::Encoding.find($1) + content.force_encoding(enc) + end + end + end + + content + end + +end + +if Gem.respond_to? :find_files then + rdoc_extensions = Gem.find_files 'rdoc/discover' + + rdoc_extensions.each do |extension| + begin + load extension + rescue => e + warn "error loading #{extension.inspect}: #{e.message} (#{e.class})" + end + end +end + +# require built-in generators after discovery in case they've been replaced +require 'rdoc/generator/darkfish' +require 'rdoc/generator/ri' + -- cgit v1.2.3