lib/yard/cli/yardoc.rb in yard-0.4.0 vs lib/yard/cli/yardoc.rb in yard-0.5.0

- old
+ new

@@ -1,23 +1,25 @@ -require 'optparse' +require 'digest/sha1' +require 'fileutils' module YARD module CLI - class Yardoc + class Yardoc < Base # The configuration filename to load extra options from DEFAULT_YARDOPTS_FILE = ".yardopts" # @return [Hash] the hash of options passed to the template. # @see Templates::Engine#render attr_reader :options # @return [Array<String>] list of Ruby source files to process attr_accessor :files - # @return [Boolean] whether to reparse the source files even if the - # .yardoc already exists. - attr_accessor :reload + # @return [Boolean] whether to use the existing yardoc db if the + # .yardoc already exists. Also makes use of file checksums to + # parse only changed files. + attr_accessor :use_cache # @return [Boolean] whether to generate output attr_accessor :generate # The options file name (defaults to {DEFAULT_YARDOPTS_FILE}) @@ -28,65 +30,93 @@ # @see #run def self.run(*args) new.run(*args) end # Creates a new instance of the commandline utility def initialize - @options = SymbolHash[ + @options = SymbolHash.new(false) + @options.update( :format => :html, :template => :default, :markup => :rdoc, - :serializer => YARD::Serializers::FileSystemSerializer.new, + :serializer => YARD::Serializers::FileSystemSerializer.new, + :default_return => "Object", + :hide_void_return => false, + :no_highlight => false, :files => [], :visibilities => [:public], :verifier => nil - ] + ) @files = [] - @reload = true + @use_cache = false @generate = true @options_file = DEFAULT_YARDOPTS_FILE end # Runs the commandline utility, parsing arguments and generating # output if set. # # @param [Array<String>] args the list of arguments - # @return [nil] + # @return [void] def run(*args) args += support_rdoc_document_file! optparse(*yardopts) optparse(*args) - Registry.load(files, reload) + Registry.load if use_cache + YARD.parse(files) + Registry.save(use_cache) + if generate - Templates::Engine.generate(all_objects, options) + if use_cache + objects = all_objects + Registry.all # load all + objects.each do |object| + opts = options.merge(:object => object, :type => :layout) + Templates::Engine.render(opts) + end + else + Templates::Engine.generate(all_objects, options) + end end true end # The list of all objects to process. Override this method to change # which objects YARD should generate documentation for. # # @return [Array<CodeObjects::Base>] a list of code objects to process def all_objects - Registry.all(:root, :module, :class) + types = [:root, :module, :class] + if use_cache + Registry.paths(false).map do |path| + obj = Registry.at(path) + if types.include?(obj.type) + obj + else + nil + end + end.compact + else + Registry.all(*types) + end end # Parses the .yardopts file for default yard options - # @return [nil] + # @return [void] def yardopts - IO.read(options_file).split(/\s+/) + IO.read(options_file).shell_split rescue Errno::ENOENT [] end private # Reads a .document file in the directory to get source file globs - # @return [nil] + # @return [void] def support_rdoc_document_file! - IO.read(".document").split(/\s+/) + IO.read(".document").gsub(/^[ \t]*#.+/m, '').split(/\s+/) rescue Errno::ENOENT [] end # Adds a set of extra documentation files to be processed @@ -105,11 +135,11 @@ # @example Parses a set of Ruby source files # parse_files %w(file1 file2 file3) # @example Parses a set of Ruby files with a separator and extra files # parse_files %w(file1 file2 - extrafile1 extrafile2) # @param [Array<String>] files the list of files to parse - # @return [nil] + # @return [void] def parse_files(*files) self.files = [] seen_extra_files_marker = false files.each do |file| @@ -124,26 +154,43 @@ self.files << file end end end - # @param [Array<String>] expressions a list of query expressions to - # turn into a proc - def add_verifier(*expressions) - + # Builds .yardoc files for all non-existing gems + # @param [Boolean] rebuild Forces rebuild of all gems + def build_gems(rebuild = false) + require 'rubygems' + Gem.source_index.find_name('').each do |spec| + reload = true + dir = Registry.yardoc_file_for_gem(spec.name) + next unless dir + if File.directory?(dir) && !rebuild + log.debug "#{spec.name} index already exists at '#{dir}'" + else + Dir.chdir(spec.full_gem_path) + log.info "Building yardoc index for gem: #{spec.full_name}" + yfile = Registry.yardoc_file_for_gem(spec.name, ">= 0", true) + Registry.clear + Yardoc.run('-n', '-b', yfile) + reload = false + end + end + exit(0) end # Parses commandline options. # @param [Array<String>] args each tokenized argument def optparse(*args) query_expressions = [] + do_build_gems, do_rebuild_gems = false, false serialopts = SymbolHash.new opts = OptionParser.new opts.banner = "Usage: yardoc [options] [source_files [- extra_files]]" - opts.separator "(if a list of source files is omitted, lib/**/*.rb is used.)" + opts.separator "(if a list of source files is omitted, lib/**/*.rb ext/**/*.c is used.)" opts.separator "" opts.separator "Example: yardoc -o documentation/ - FAQ LICENSE" opts.separator " The above example outputs documentation for files in" opts.separator " lib/**/*.rb to documentation/ including the extra files" opts.separator " FAQ and LICENSE." @@ -153,13 +200,13 @@ opts.separator "by whitespace." opts.separator "" opts.separator "General Options:" opts.on('-c', '--use-cache [FILE]', - 'Use the cached .yardoc db to generate documentation. (defaults to no cache)') do |file| + "Use the cached .yardoc db to generate documentation. (defaults to no cache)") do |file| YARD::Registry.yardoc_file = file if file - self.reload = false + self.use_cache = true end opts.on('-b', '--db FILE', 'Use a specified .yardoc db to load from or save to. (defaults to .yardoc)') do |yfile| YARD::Registry.yardoc_file = yfile end @@ -176,11 +223,20 @@ end opts.on('--legacy', 'Use old style parser and handlers. Unavailable under Ruby 1.8.x') do YARD::Parser::SourceParser.parser_type = :ruby18 end + + opts.on('--build-gems', 'Builds .yardoc files for all gems (implies -n)') do + do_build_gems = true + end + opts.on('--re-build-gems', 'Forces building .yardoc files for all gems (implies -n)') do + do_build_gems = true + do_rebuild_gems = true + end + opts.separator "" opts.separator "Output options:" opts.on('--no-public', "Don't show public methods. (default shows public)") do options[:visibilities].delete(:public) @@ -200,10 +256,18 @@ opts.on('--no-highlight', "Don't highlight code in docs as Ruby.") do options[:no_highlight] = true end + opts.on('--default-return TYPE', "Shown if method has no return type. Defaults to 'Object'") do |type| + options[:default_return] = type + end + + opts.on('--hide-void-return', "Hides return types specified as 'void'. Default is shown.") do + options[:hide_void_return] = true + end + opts.on('--query QUERY', "Only show objects that match a specific query") do |query| query_expressions << query.taint end opts.on('--title TITLE', 'Add a specific title to HTML documents') do |title| @@ -245,30 +309,26 @@ YARD::Templates::Engine.register_template_path(path) end opts.on('-f', '--format FORMAT', 'The output format for the template. (defaults to html)') do |format| - options[:format] = format + options[:format] = format.to_sym end - opts.separator "" - opts.separator "Other options:" - opts.on_tail('-q', '--quiet', 'Show no warnings.') { log.level = Logger::ERROR } - opts.on_tail('--verbose', 'Show debugging information.') { log.level = Logger::DEBUG } - opts.on_tail('-v', '--version', 'Show version.') { puts "yard #{YARD::VERSION}"; exit } - opts.on_tail('-h', '--help', 'Show this help.') { puts opts; exit } + common_options(opts) begin opts.parse!(args) rescue OptionParser::InvalidOption => e STDERR.puts e.message STDERR << "\n" << opts exit end # Last minute modifications + build_gems(do_rebuild_gems) if do_build_gems parse_files(*args) unless args.empty? - self.files = ['lib/**/*.rb'] if self.files.empty? + self.files = ['lib/**/*.rb', 'ext/**/*.c'] if self.files.empty? options[:verifier] = Verifier.new(*query_expressions) unless query_expressions.empty? options[:visibilities].uniq! options[:serializer] ||= Serializers::FileSystemSerializer.new(serialopts) options[:readme] ||= Dir.glob('README*').first end