lib/yard/cli/yardoc.rb in yard-0.6.8 vs lib/yard/cli/yardoc.rb in yard-0.7.0
- old
+ new
@@ -4,168 +4,173 @@
module YARD
module CLI
# Yardoc is the default YARD CLI command (+yard doc+ and historic +yardoc+
# executable) used to generate and output (mainly) HTML documentation given
# a set of source files.
- #
+ #
# == Usage
- #
+ #
# Main usage for this command is:
- #
+ #
# $ yardoc [options] [source_files [- extra_files]]
- #
+ #
# See +yardoc --help+ for details on valid options.
- #
+ #
# == Options File (+.yardopts+)
- #
+ #
# If a +.yardopts+ file is found in the source directory being processed,
- # YARD will use the contents of the file as arguments to the command,
+ # YARD will use the contents of the file as arguments to the command,
# treating newlines as spaces. You can use shell-style quotations to
# group space delimited arguments, just like on the command line.
- #
+ #
# A valid +.yardopts+ file might look like:
- #
+ #
# --no-private
# --title "My Title"
# --exclude foo --exclude bar
- # lib/**/*.erb
+ # lib/**/*.erb
# lib/**/*.rb -
# HACKING.rdoc LEGAL COPYRIGHT
- #
+ #
# Note that Yardoc also supports the legacy RDoc style +.document+ file,
# though this file can only specify source globs to parse, not options.
- #
+ #
# == Queries (+--query+)
- #
+ #
# Yardoc supports queries to select specific code objects for which to
# generate documentation. For example, you might want to generate
# documentation only for your public API. If you've documented your public
# methods with +@api public+, you can use the following query to select
# all of these objects:
- #
+ #
# --query '@api.text == "public"'
- #
+ #
# Note that the syntax for queries is mostly Ruby with a few syntactic
# simplifications for meta-data tags. See the {Verifier} class for an
- # overview of this syntax.
- #
+ # overview of this syntax.
+ #
# == Adding Custom Ad-Hoc Meta-data Tags (+--tag+)
- #
- # YARD allows specification of {file:docs/Tags.md meta-data tags}
- # programmatically via the {YARD::Tags::Library} class, but often this is not
+ #
+ # YARD allows specification of {file:docs/Tags.md meta-data tags}
+ # programmatically via the {YARD::Tags::Library} class, but often this is not
# practical for users writing documentation. To make adding custom tags
- # easier, Yardoc has a few command-line switches for creating basic tags
+ # easier, Yardoc has a few command-line switches for creating basic tags
# and displaying them in generated HTML output.
- #
- # To specify a custom tag to be displayed in output, use any of the
+ #
+ # To specify a custom tag to be displayed in output, use any of the
# following:
- #
+ #
# * +--tag+ TAG:TITLE
# * +--name-tag+ TAG:TITLE
# * +--type-tag+ TAG:TITLE
# * +--type-name-tag+ TAG:TITLE
# * +--title-tag+ TAG:TITLE
- #
+ #
# "TAG:TITLE" is of the form: name:"Display Title", for example:
- #
+ #
# --tag overload:"Overloaded Method"
- #
+ #
# See +yardoc --help+ for a description of the various options.
- #
+ #
# Tags added in this way are automatically displayed in output. To add
# a meta-data tag that does not show up in output, use +--hide-tag TAG+.
# Note that you can also use this option on existing tags to hide
# builtin tags, for instance.
- #
+ #
# == Processed Data Storage (+.yardoc+ directory)
- #
+ #
# When Yardoc parses a source directory, it creates a +.yardoc+ directory
# (by default, override with +-b+) at the root of the project. This directory
# contains marshal dumps for all raw object data in the source, so that
# you can access it later for various commands (+stats+, +graph+, etc.).
# This directory is also used as a cache for any future calls to +yardoc+
# so as to process only the files which have changed since the last call.
- #
+ #
# When Yardoc uses the cache in subsequent calls to +yardoc+, methods
# or classes that have been deleted from source since the last parsing
# will not be erased from the cache (YARD never deletes objects). In such
# a case, you should wipe the cache and do a clean parsing of the source tree.
# You can do this by deleting the +.yardoc+ directory manually, or running
# Yardoc without +--use-cache+ (+-c+).
- #
+ #
# @since 0.2.1
# @see Verifier
class Yardoc < Command
# 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 [Array<String>] list of excluded paths (regexp matches)
# @since 0.5.3
attr_accessor :excluded
-
- # @return [Boolean] whether to use the existing yardoc db if the
+
+ # @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 parse options from .yardopts
attr_accessor :use_yardopts_file
-
+
# @return [Boolean] whether to parse options from .document
attr_accessor :use_document_file
-
+
# @return [Boolean] whether objects should be serialized to .yardoc db
attr_accessor :save_yardoc
-
+
# @return [Boolean] whether to generate output
attr_accessor :generate
# @return [Boolean] whether to print a list of objects
# @since 0.5.5
attr_accessor :list
# The options file name (defaults to {DEFAULT_YARDOPTS_FILE})
# @return [String] the filename to load extra options from
attr_accessor :options_file
-
+
# Keep track of which visibilities are to be shown
# @return [Array<Symbol>] a list of visibilities
# @since 0.5.6
attr_accessor :visibilities
-
+
# @return [Array<Symbol>] a list of tags to hide from templates
# @since 0.6.0
attr_accessor :hidden_tags
-
+
# @return [Boolean] whether to print statistics after parsing
# @since 0.6.0
attr_accessor :statistics
-
+
# @return [Array<String>] a list of assets to copy after generation
# @since 0.6.0
attr_accessor :assets
-
+
+ # @return [Boolean] whether markup option was specified
+ # @since 0.7.0
+ attr_accessor :has_markup
+
# Creates a new instance of the commandline utility
def initialize
super
@options = SymbolHash.new(false)
@options.update(
- :format => :html,
- :template => :default,
+ :format => :html,
+ :template => :default,
:markup => :rdoc, # default is :rdoc but falls back on :none
:serializer => YARD::Serializers::FileSystemSerializer.new,
:default_return => "Object",
:hide_void_return => false,
- :no_highlight => false,
+ :no_highlight => false,
:files => [],
+ :title => "Documentation by YARD #{YARD::VERSION}",
:verifier => Verifier.new
)
@visibilities = [:public]
@assets = {}
@excluded = []
@@ -177,37 +182,41 @@
@generate = true
@options_file = DEFAULT_YARDOPTS_FILE
@statistics = true
@list = false
@save_yardoc = true
-
+ @has_markup = false
+
if defined?(Encoding)
Encoding.default_external, Encoding.default_internal = 'utf-8', 'utf-8'
end
end
-
+
def description
"Generates documentation"
end
-
+
# Runs the commandline utility, parsing arguments and generating
# output if set.
- #
- # @param [Array<String>] args the list of arguments
- # @return [void]
+ #
+ # @param [Array<String>] args the list of arguments. If the list only
+ # contains a single nil value, skip calling of {#parse_arguments}
+ # @return [void]
def run(*args)
- # fail early if arguments are not valid
- return unless parse_arguments(*args)
-
+ if args.size == 0 || !args.first.nil?
+ # fail early if arguments are not valid
+ return unless parse_arguments(*args)
+ end
+
checksums = nil
if use_cache
Registry.load
checksums = Registry.checksums.dup
end
YARD.parse(files, excluded)
Registry.save(use_cache) if save_yardoc
-
+
if generate
run_generate(checksums)
copy_assets
elsif list
print_list
@@ -217,70 +226,66 @@
Registry.load_all
log.enter_level(Logger::ERROR) do
Stats.new(false).run(*args)
end
end
-
+
true
end
-
+
# Parses commandline arguments
# @param [Array<String>] args the list of arguments
# @return [Boolean] whether or not arguments are valid
# @since 0.5.6
def parse_arguments(*args)
- options[:markup] = nil # reset markup
-
- # Hack: parse out --no-yardopts, --no-document before parsing files
- ['document', 'yardopts'].each do |file|
- without, with = args.index("--no-#{file}") || -2, args.index("--#{file}") || -1
- send("use_#{file}_file=", false) if without > with
- end
+ parse_yardopts_options(*args)
# Parse files and then command line arguments
optparse(*support_rdoc_document_file!) if use_document_file
optparse(*yardopts) if use_yardopts_file
optparse(*args)
# Last minute modifications
- self.files = ['lib/**/*.rb', 'ext/**/*.c'] if self.files.empty?
+ self.files = ['{lib,app}/**/*.rb', 'ext/**/*.c'] if self.files.empty?
self.files.delete_if {|x| x =~ /\A\s*\Z/ } # remove empty ones
- options[:readme] ||= Dir.glob('README*').first
+ readme = Dir.glob('README*').first
+ options[:readme] ||= CodeObjects::ExtraFileObject.new(readme) if readme
if options[:onefile]
options[:files] << options[:readme] if options[:readme]
- options[:readme] = Dir.glob(files.first).first
+ readme = Dir.glob(files.first).first
+ options[:readme] = CodeObjects::ExtraFileObject.new(readme) if readme
end
Tags::Library.visible_tags -= hidden_tags
add_visibility_verifier
if generate && !verify_markup_options
false
else
true
end
end
-
+
# The list of all objects to process. Override this method to change
# which objects YARD should generate documentation for.
- #
+ #
# @deprecated To hide methods use the +@private+ tag instead.
# @return [Array<CodeObjects::Base>] a list of code objects to process
def all_objects
Registry.all(:root, :module, :class)
end
-
+
# Parses the .yardopts file for default yard options
- # @return [Array<String>] an array of options parsed from .yardopts
+ # @return [Array<String>] an array of options parsed from .yardopts
def yardopts
return [] unless use_yardopts_file
File.read_binary(options_file).shell_split
rescue Errno::ENOENT
[]
end
-
+
private
-
+
# Generates output for objects
# @param [Hash, nil] checksums if supplied, a list of checkums for files.
# @return [void]
# @since 0.5.1
def run_generate(checksums)
@@ -300,18 +305,17 @@
false
end
end
Templates::Engine.generate(objects, options)
end
-
+
# Verifies that the markup options are valid before parsing any code.
# Failing early is better than failing late.
- #
+ #
# @return (see YARD::Templates::Helpers::MarkupHelper#load_markup_provider)
def verify_markup_options
- has_markup = options[:markup] ? true : false
- options[:markup] ||= :rdoc
+ options[:markup] = :rdoc unless has_markup
result, lvl = false, has_markup ? log.level : Logger::FATAL
obj = Struct.new(:options).new(options)
obj.extend(Templates::Helpers::MarkupHelper)
log.enter_level(lvl) { result = obj.load_markup_provider }
if !result && !has_markup
@@ -321,11 +325,11 @@
true
else
result
end
end
-
+
# Copies any assets to the output directory
# @return [void]
# @since 0.6.0
def copy_assets
return unless options[:serializer]
@@ -341,90 +345,105 @@
# @return [void]
# @since 0.5.5
def print_list
Registry.load_all
run_verifier(Registry.all).
- sort_by {|item| [item.file, item.line]}.each do |item|
- puts "#{item.file}:#{item.line}: #{item}"
+ sort_by {|item| [item.file || '', item.line || 0] }.each do |item|
+ puts "#{item.file}:#{item.line}: #{item.path}"
end
end
+
+ # Parses out the yardopts/document options
+ def parse_yardopts_options(*args)
+ opts = OptionParser.new
+ yardopts_options(opts)
+ begin
+ opts.parse(args)
+ rescue OptionParser::ParseError => err
+ idx = args.index(err.args.first)
+ args = args[(idx+1)..-1]
+ args.shift while args.first && args.first[0,1] != '-'
+ retry
+ end
+ end
# Reads a .document file in the directory to get source file globs
# @return [Array<String>] an array of files parsed from .document
def support_rdoc_document_file!
return [] unless use_document_file
File.read(".document").gsub(/^[ \t]*#.+/m, '').split(/\s+/)
rescue Errno::ENOENT
[]
end
-
+
# Adds a set of extra documentation files to be processed
# @param [Array<String>] files the set of documentation files
def add_extra_files(*files)
files.map! {|f| f.include?("*") ? Dir.glob(f) : f }.flatten!
files.each do |file|
if File.file?(file)
- options[:files] << file
+ options[:files] << CodeObjects::ExtraFileObject.new(file)
else
log.warn "Could not find extra file: #{file}"
end
end
end
-
+
# Parses the file arguments into Ruby files and extra files, which are
# separated by a '-' element.
- #
+ #
# @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 [void]
+ # @return [void]
def parse_files(*files)
seen_extra_files_marker = false
-
+
files.each do |file|
if file == "-"
seen_extra_files_marker = true
next
end
-
+
if seen_extra_files_marker
add_extra_files(file)
else
self.files << file
end
end
end
-
+
# Adds verifier rule for visibilities
# @return [void]
# @since 0.5.6
def add_visibility_verifier
vis_expr = "object.type != :method || #{visibilities.uniq.inspect}.include?(object.visibility)"
options[:verifier].add_expressions(vis_expr)
end
-
+
# (see Templates::Helpers::BaseHelper#run_verifier)
def run_verifier(list)
options[:verifier] ? options[:verifier].run(list) : list
end
-
+
# @since 0.6.0
def add_tag(tag_data, factory_method = nil)
tag, title = *tag_data.split(':')
Tags::Library.define_tag(title, tag.to_sym, factory_method)
Tags::Library.visible_tags |= [tag.to_sym]
end
-
+
# Parses commandline options.
# @param [Array<String>] args each tokenized argument
def optparse(*args)
opts = OptionParser.new
opts.banner = "Usage: yard doc [options] [source_files [- extra_files]]"
- opts.separator "(if a list of source files is omitted, lib/**/*.rb ext/**/*.c is used.)"
+ opts.separator "(if a list of source files is omitted, "
+ opts.separator " {lib,app}/**/*.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."
@@ -444,49 +463,65 @@
# Adds general options
def general_options(opts)
opts.separator ""
opts.separator "General Options:"
- opts.on('-b', '--db FILE', 'Use a specified .yardoc db to load from or save to. (defaults to .yardoc)') do |yfile|
+ 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
-
- opts.on('--[no-]single-db', 'Whether code objects should be stored to single database file (advanced)') do |use_single_db|
+
+ opts.on('--[no-]single-db', 'Whether code objects should be stored to single',
+ ' database file (advanced)') do |use_single_db|
Registry.single_object_db = use_single_db
end
opts.on('-n', '--no-output', 'Only generate .yardoc database, no documentation.') do
self.generate = false
end
- opts.on('-c', '--use-cache [FILE]',
- "Use the cached .yardoc db to generate documentation. (defaults to no cache)") do |file|
+ opts.on('-c', '--use-cache [FILE]',
+ "Use the cached .yardoc db to generate documentation.",
+ " (defaults to no cache)") do |file|
YARD::Registry.yardoc_file = file if file
self.use_cache = true
end
-
+
opts.on('--no-cache', "Clear .yardoc db before parsing source.") do
self.use_cache = false
end
-
- opts.on('--[no-]yardopts', "If arguments should be read from .yardopts file. (defaults to yes)") do |use_yardopts|
- self.use_yardopts_file = use_yardopts
- end
- opts.on('--[no-]document', "If arguments should be read from .document file. (defaults to yes)") do |use_document|
- self.use_document_file = use_document
- end
-
+ yardopts_options(opts)
+
opts.on('--no-save', 'Do not save the parsed data to the yardoc db') do
self.save_yardoc = false
end
opts.on('--exclude REGEXP', 'Ignores a file if it matches path match (regexp)') do |path|
self.excluded << path
end
end
+
+ # Adds --[no-]yardopts / --[no-]document
+ def yardopts_options(opts)
+ opts.on('--[no-]yardopts [FILE]',
+ "If arguments should be read from FILE",
+ " (defaults to yes, FILE defaults to .yardopts)") do |use_yardopts|
+ if use_yardopts.is_a?(String)
+ self.options_file = use_yardopts
+ self.use_yardopts_file = true
+ else
+ self.use_yardopts_file = (use_yardopts != false)
+ end
+ end
+ opts.on('--[no-]document', "If arguments should be read from .document file. ",
+ " (defaults to yes)") do |use_document|
+ self.use_document_file = use_document
+ end
+ end
+
# Adds output options
def output_options(opts)
opts.separator ""
opts.separator "Output options:"
@@ -497,36 +532,38 @@
opts.on('--list', 'List objects to standard out (implies -n)') do |format|
self.generate = false
self.list = true
end
- opts.on('--no-public', "Don't show public methods. (default shows public)") do
+ opts.on('--no-public', "Don't show public methods. (default shows public)") do
visibilities.delete(:public)
end
opts.on('--protected', "Show protected methods. (default hides protected)") do
visibilities.push(:protected)
end
- opts.on('--private', "Show private methods. (default hides private)") do
+ opts.on('--private', "Show private methods. (default hides private)") do
visibilities.push(:private)
end
opts.on('--no-private', "Hide objects with @private tag") do
- options[:verifier].add_expressions '!object.tag(:private) &&
+ options[:verifier].add_expressions '!object.tag(:private) &&
(object.namespace.is_a?(CodeObjects::Proxy) || !object.namespace.tag(:private))'
end
- opts.on('--no-highlight', "Don't highlight code blocks in output.") do
+ opts.on('--no-highlight', "Don't highlight code blocks in output.") do
options[:no_highlight] = true
end
- opts.on('--default-return TYPE', "Shown if method has no return type. Defaults to 'Object'") do |type|
+ 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
+ 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|
next if YARD::Config.options[:safe_mode]
@@ -535,72 +572,81 @@
opts.on('--title TITLE', 'Add a specific title to HTML documents') do |title|
options[:title] = title
end
- opts.on('-r', '--readme FILE', '--main FILE', 'The readme file used as the title page of documentation.') do |readme|
+ opts.on('-r', '--readme FILE', '--main FILE', 'The readme file used as the title page',
+ ' of documentation.') do |readme|
if File.file?(readme)
- options[:readme] = readme
- else
+ options[:readme] = CodeObjects::ExtraFileObject.new(readme)
+ else
log.warn "Could not find readme file: #{readme}"
end
end
- opts.on('--files FILE1,FILE2,...', 'Any extra comma separated static files to be included (eg. FAQ)') do |files|
+ opts.on('--files FILE1,FILE2,...', 'Any extra comma separated static files to be ',
+ ' included (eg. FAQ)') do |files|
add_extra_files(*files.split(","))
end
- opts.on('--asset FROM[:TO]', 'A file or directory to copy over to output directory after generating') do |asset|
+ opts.on('--asset FROM[:TO]', 'A file or directory to copy over to output ',
+ ' directory after generating') do |asset|
re = /^(?:\.\.\/|\/)/
from, to = *asset.split(':').map {|f| File.cleanpath(f) }
to ||= from
if from =~ re || to =~ re
log.warn "Invalid file '#{asset}'"
else
assets[from] = to
end
end
- opts.on('-o', '--output-dir PATH',
+ opts.on('-o', '--output-dir PATH',
'The output directory. (defaults to ./doc)') do |dir|
options[:serializer].basepath = dir
end
-
- opts.on('-m', '--markup MARKUP',
- 'Markup style used in documentation, like textile, markdown or rdoc. (defaults to rdoc)') do |markup|
+
+ opts.on('-m', '--markup MARKUP',
+ 'Markup style used in documentation, like textile, ',
+ ' markdown or rdoc. (defaults to rdoc)') do |markup|
+ self.has_markup = true
options[:markup] = markup.to_sym
end
- opts.on('-M', '--markup-provider MARKUP_PROVIDER',
- 'Overrides the library used to process markup formatting (specify the gem name)') do |markup_provider|
+ opts.on('-M', '--markup-provider MARKUP_PROVIDER',
+ 'Overrides the library used to process markup ',
+ ' formatting (specify the gem name)') do |markup_provider|
options[:markup_provider] = markup_provider.to_sym
end
- opts.on('--charset ENC', 'Character set to use for HTML output (default is system locale)') do |encoding|
+ opts.on('--charset ENC', 'Character set to use when parsing files ',
+ ' (default is system locale)') do |encoding|
begin
Encoding.default_external, Encoding.default_internal = encoding, encoding
rescue ArgumentError => e
raise OptionParser::InvalidOption, e
end
end
- opts.on('-t', '--template TEMPLATE',
+ opts.on('-t', '--template TEMPLATE',
'The template to use. (defaults to "default")') do |template|
options[:template] = template.to_sym
end
- opts.on('-p', '--template-path PATH',
- 'The template path to look for templates in. (used with -t).') do |path|
+ opts.on('-p', '--template-path PATH',
+ 'The template path to look for templates in.',
+ ' (used with -t).') do |path|
next if YARD::Config.options[:safe_mode]
YARD::Templates::Engine.register_template_path(path)
end
- opts.on('-f', '--format FORMAT',
- 'The output format for the template. (defaults to html)') do |format|
+ opts.on('-f', '--format FORMAT',
+ 'The output format for the template.',
+ ' (defaults to html)') do |format|
options[:format] = format.to_sym
end
-
+
opts.on('--no-stats', 'Don\'t print statistics') do
self.statistics = false
end
end
@@ -631,10 +677,10 @@
end
opts.on('--hide-tag TAG', 'Hides a previously defined tag from templates') do |tag|
self.hidden_tags |= [tag.to_sym]
end
-
+
opts.on('--transitive-tag TAG', 'Adds a transitive tag') do |tag|
Tags::Library.transitive_tags += [tag.to_sym]
end
end
end