lib/jazzy/config.rb in jazzy-0.13.7 vs lib/jazzy/config.rb in jazzy-0.14.0
- old
+ new
@@ -1,16 +1,18 @@
+# frozen_string_literal: true
+
require 'optparse'
require 'pathname'
require 'uri'
require 'jazzy/podspec_documenter'
require 'jazzy/source_declaration/access_control_level'
module Jazzy
# rubocop:disable Metrics/ClassLength
class Config
- # rubocop:disable Style/AccessorMethodName
+ # rubocop:disable Naming/AccessorMethodName
class Attribute
attr_reader :name, :description, :command_line, :config_file_key,
:default, :parse
def initialize(name, description: nil, command_line: nil,
@@ -48,10 +50,11 @@
config.method("#{name}_configured").call
end
def attach_to_option_parser(config, opt)
return if command_line.empty?
+
opt.on(*command_line, *description) do |val|
set(config, val)
end
end
@@ -68,15 +71,16 @@
if long_option_name = long_option_names.compact.first
long_option_name.tr('-', '_')
end
end
end
- # rubocop:enable Style/AccessorMethodName
+ # rubocop:enable Naming/AccessorMethodName
def self.config_attr(name, **opts)
attr_accessor name
attr_accessor "#{name}_configured"
+
@all_config_attrs ||= []
@all_config_attrs << Attribute.new(name, **opts)
end
def self.alias_config_attr(name, forward, **opts)
@@ -110,11 +114,11 @@
hide_declarations == 'objc'
end
# ──────── Build ────────
- # rubocop:disable Layout/AlignParameters
+ # rubocop:disable Layout/ArgumentAlignment
config_attr :output,
description: 'Folder to output the HTML docs to',
command_line: ['-o', '--output FOLDER'],
default: 'docs',
@@ -122,11 +126,11 @@
config_attr :clean,
command_line: ['-c', '--[no-]clean'],
description: ['Delete contents of output directory before running. ',
'WARNING: If --output is set to ~/Desktop, this will '\
- 'delete the ~/Desktop directory.'],
+ 'delete the ~/Desktop directory.'],
default: false
config_attr :objc_mode,
command_line: '--[no-]objc',
description: 'Generate docs for Objective-C.',
@@ -148,14 +152,14 @@
default: 'macosx'
config_attr :hide_declarations,
command_line: '--hide-declarations [objc|swift] ',
description: 'Hide declarations in the specified language. Given that ' \
- 'generating Swift docs only generates Swift declarations, ' \
- 'this is useful for hiding a specific interface for ' \
- 'either Objective-C or mixed Objective-C and Swift ' \
- 'projects.',
+ 'generating Swift docs only generates Swift declarations, ' \
+ 'this is useful for hiding a specific interface for ' \
+ 'either Objective-C or mixed Objective-C and Swift ' \
+ 'projects.',
default: ''
config_attr :keep_property_attributes,
command_line: '--[no-]keep-property-attributes',
description: 'Include the default Objective-C property attributes.',
@@ -168,11 +172,11 @@
parse: ->(cf) { expand_path(cf) }
config_attr :build_tool_arguments,
command_line: ['-b', '--build-tool-arguments arg1,arg2,…argN', Array],
description: 'Arguments to forward to xcodebuild, swift build, or ' \
- 'sourcekitten.',
+ 'sourcekitten.',
default: []
alias_config_attr :xcodebuild_arguments, :build_tool_arguments,
command_line: ['-x', '--xcodebuild-arguments arg1,arg2,…argN', Array],
description: 'Back-compatibility alias for build_tool_arguments.'
@@ -190,20 +194,20 @@
parse: ->(sd) { expand_path(sd) }
config_attr :excluded_files,
command_line: ['-e', '--exclude filepath1,filepath2,…filepathN', Array],
description: 'Source file pathnames to be excluded from documentation. '\
- 'Supports wildcards.',
+ 'Supports wildcards.',
default: [],
parse: ->(files) do
Array(files).map { |f| expand_glob_path(f).to_s }
end
config_attr :included_files,
command_line: ['-i', '--include filepath1,filepath2,…filepathN', Array],
description: 'Source file pathnames to be included in documentation. '\
- 'Supports wildcards.',
+ 'Supports wildcards.',
default: [],
parse: ->(files) do
Array(files).map { |f| expand_glob_path(f).to_s }
end
@@ -211,28 +215,30 @@
command_line: '--swift-version VERSION',
default: nil,
parse: ->(v) do
if v.to_s.empty?
nil
+ elsif v.to_f < 2
+ raise 'jazzy only supports Swift 2.0 or later.'
else
- raise 'jazzy only supports Swift 2.0 or later.' if v.to_f < 2
v
end
end
SWIFT_BUILD_TOOLS = %w[spm xcodebuild symbolgraph].freeze
config_attr :swift_build_tool,
command_line: "--swift-build-tool #{SWIFT_BUILD_TOOLS.join(' | ')}",
description: 'Control whether Jazzy uses Swift Package Manager, '\
- 'xcodebuild, or swift-symbolgraph to build the module '\
- 'to be documented. By default it uses xcodebuild if '\
- 'there is a .xcodeproj file in the source directory.',
+ 'xcodebuild, or swift-symbolgraph to build the module '\
+ 'to be documented. By default it uses xcodebuild if '\
+ 'there is a .xcodeproj file in the source directory.',
parse: ->(tool) do
return tool.to_sym if SWIFT_BUILD_TOOLS.include?(tool)
+
raise "Unsupported swift_build_tool #{tool}, "\
- "supported values: #{SWIFT_BUILD_TOOLS.join(', ')}"
+ "supported values: #{SWIFT_BUILD_TOOLS.join(', ')}"
end
# ──────── Metadata ────────
config_attr :author_name,
@@ -252,17 +258,17 @@
default: ''
config_attr :version,
command_line: '--module-version VERSION',
description: 'Version string to use as part of the default docs '\
- 'title and inside the docset.',
+ 'title and inside the docset.',
default: '1.0'
config_attr :title,
command_line: '--title TITLE',
description: 'Title to display at the top of each page, overriding the '\
- 'default generated from module name and version.',
+ 'default generated from module name and version.',
default: ''
config_attr :copyright,
command_line: '--copyright COPYRIGHT_MARKDOWN',
description: 'copyright markdown rendered at the bottom of the docs pages'
@@ -283,20 +289,20 @@
parse: ->(ag) { Pathname.glob(ag) }
config_attr :podspec,
command_line: '--podspec FILEPATH',
description: 'A CocoaPods Podspec that describes the Swift library to '\
- 'document',
+ 'document',
parse: ->(ps) { PodspecDocumenter.create_podspec(Pathname(ps)) if ps },
default: Dir['*.podspec{,.json}'].first
config_attr :pod_sources,
command_line: ['--pod-sources url1,url2,…urlN', Array],
description: 'A list of sources to find pod dependencies. Used only '\
- 'with --podspec when the podspec contains references to '\
- 'privately hosted pods. You must include the default pod '\
- 'source if public pods are also used.',
+ 'with --podspec when the podspec contains references to '\
+ 'privately hosted pods. You must include the default pod '\
+ 'source if public pods are also used.',
default: []
config_attr :docset_icon,
command_line: '--docset-icon FILEPATH',
parse: ->(di) { expand_path(di) }
@@ -314,34 +320,60 @@
parse: ->(r) { URI(r.sub(%r{/?$}, '/')) }
config_attr :dash_url,
command_line: ['-d', '--dash_url URL'],
description: 'Location of the dash XML feed '\
- 'e.g. https://realm.io/docsets/realm.xml)',
+ 'e.g. https://realm.io/docsets/realm.xml)',
parse: ->(d) { URI(d) }
- config_attr :github_url,
- command_line: ['-g', '--github_url URL'],
- description: 'GitHub URL of this project (e.g. '\
- 'https://github.com/realm/realm-cocoa)',
+ SOURCE_HOSTS = %w[github gitlab bitbucket].freeze
+
+ config_attr :source_host,
+ command_line: "--source-host #{SOURCE_HOSTS.join(' | ')}",
+ description: ['The source-code hosting site to be linked from documentation.',
+ 'This setting affects the logo image and link format.',
+ "Default: 'github'"],
+ default: 'github',
+ parse: ->(host) do
+ return host.to_sym if SOURCE_HOSTS.include?(host)
+
+ raise "Unsupported source_host '#{host}', "\
+ "supported values: #{SOURCE_HOSTS.join(', ')}"
+ end
+
+ config_attr :source_host_url,
+ command_line: ['--source-host-url URL'],
+ description: ["URL to link from the source host's logo.",
+ 'For example https://github.com/realm/realm-cocoa'],
parse: ->(g) { URI(g) }
- config_attr :github_file_prefix,
+ alias_config_attr :github_url, :source_host_url,
+ command_line: ['-g', '--github_url URL'],
+ description: 'Back-compatibility alias for source_host_url.'
+
+ config_attr :source_host_files_url,
+ command_line: '--source-host-files-url PREFIX',
+ description: [
+ "The base URL on the source host of the project's files, to link "\
+ 'from individual declarations.',
+ 'For example https://github.com/realm/realm-cocoa/tree/v0.87.1',
+ ]
+
+ alias_config_attr :github_file_prefix, :source_host_files_url,
command_line: '--github-file-prefix PREFIX',
- description: 'GitHub URL file prefix of this project (e.g. '\
- 'https://github.com/realm/realm-cocoa/tree/v0.87.1)'
+ description: 'Back-compatibility alias for source_host_files_url'
config_attr :docset_playground_url,
command_line: '--docset-playground-url URL',
description: 'URL of an interactive playground to demonstrate the '\
- 'framework, linked to from the docset.'
+ 'framework, linked to from the docset.'
# ──────── Doc generation options ────────
config_attr :disable_search,
command_line: '--disable-search',
- description: ['Avoid generating a search index. '\
- 'Search is available in some themes.'],
+ description: 'Avoid generating a search index. '\
+ 'Search is available in some themes.',
default: false
config_attr :skip_documentation,
command_line: '--skip-documentation',
description: 'Will skip the documentation generation phase.',
@@ -357,51 +389,51 @@
end
config_attr :skip_undocumented,
command_line: '--[no-]skip-undocumented',
description: "Don't document declarations that have no documentation "\
- 'comments.',
+ 'comments.',
default: false
config_attr :hide_documentation_coverage,
command_line: '--[no-]hide-documentation-coverage',
description: 'Hide "(X% documented)" from the generated documents',
default: false
config_attr :custom_categories,
- description: ['Custom navigation categories to replace the standard '\
- '“Classes, Protocols, etc.”', 'Types not explicitly named '\
- 'in a custom category appear in generic groups at the end.',
- 'Example: https://git.io/v4Bcp'],
+ description: 'Custom navigation categories to replace the standard '\
+ "'Classes', 'Protocols', etc. Types not explicitly named "\
+ 'in a custom category appear in generic groups at the '\
+ 'end. Example: https://git.io/v4Bcp',
default: []
config_attr :custom_categories_unlisted_prefix,
description: "Prefix for navigation section names that aren't "\
- 'explicitly listed in `custom_categories`.',
+ 'explicitly listed in `custom_categories`.',
default: 'Other '
config_attr :hide_unlisted_documentation,
command_line: '--[no-]hide-unlisted-documentation',
description: "Don't include documentation in the sidebar from the "\
- "`documentation` config value that aren't explicitly "\
- 'listed in `custom_categories`.',
+ "`documentation` config value that aren't explicitly "\
+ 'listed in `custom_categories`.',
default: false
config_attr :custom_head,
command_line: '--head HTML',
description: 'Custom HTML to inject into <head></head>.',
default: ''
- BUILTIN_THEME_DIR = Pathname(__FILE__).parent + 'themes'
+ BUILTIN_THEME_DIR = Pathname(__dir__) + 'themes'
BUILTIN_THEMES = BUILTIN_THEME_DIR.children(false).map(&:to_s)
config_attr :theme_directory,
command_line: "--theme [#{BUILTIN_THEMES.join(' | ')} | DIRPATH]",
description: "Which theme to use. Specify either 'apple' (default), "\
- 'one of the other built-in theme names, or the path to '\
- 'your mustache templates and other assets for a custom '\
- 'theme.',
+ 'one of the other built-in theme names, or the path to '\
+ 'your mustache templates and other assets for a custom '\
+ 'theme.',
default: 'apple',
parse: ->(t) do
if BUILTIN_THEMES.include?(t)
BUILTIN_THEME_DIR + t
else
@@ -410,13 +442,13 @@
end
config_attr :use_safe_filenames,
command_line: '--use-safe-filenames',
description: 'Replace unsafe characters in filenames with an encoded '\
- 'representation. This will reduce human readability of '\
- 'some URLs, but may be necessary for projects that '\
- 'expose filename-unfriendly functions such as /(_:_:)',
+ 'representation. This will reduce human readability of '\
+ 'some URLs, but may be necessary for projects that '\
+ 'expose filename-unfriendly functions such as /(_:_:)',
default: false
config_attr :template_directory,
command_line: ['-t', '--template-directory DIRPATH'],
description: 'DEPRECATED: Use --theme instead.',
@@ -432,21 +464,21 @@
end
config_attr :undocumented_text,
command_line: '--undocumented-text UNDOCUMENTED_TEXT',
description: 'Default text for undocumented symbols. The default '\
- 'is "Undocumented", put "" if no text is required',
+ 'is "Undocumented", put "" if no text is required',
default: 'Undocumented'
config_attr :separate_global_declarations,
command_line: '--[no-]separate-global-declarations',
description: 'Create separate pages for all global declarations '\
- "(classes, structures, enums etc.) even if they don't "\
- 'have children.',
+ "(classes, structures, enums etc.) even if they don't "\
+ 'have children.',
default: false
- # rubocop:enable Style/AlignParameter
+ # rubocop:enable Layout/ArgumentAlignment
def initialize
self.class.all_config_attrs.each do |attr|
attr.set_to_default(self)
end
@@ -455,11 +487,10 @@
def theme_directory=(theme_directory)
@theme_directory = theme_directory
Doc.template_path = theme_directory + 'templates'
end
- # rubocop:disable Metrics/MethodLength
def self.parse!
config = new
config.parse_command_line
config.parse_config_file
PodspecDocumenter.apply_config_defaults(config.podspec, config)
@@ -469,13 +500,20 @@
config.root_url,
"docsets/#{config.module_name}.xml",
)
end
+ config.validate
+
config
end
+ def warning(message)
+ warn "WARNING: #{message}"
+ end
+
+ # rubocop:disable Metrics/MethodLength
def parse_command_line
OptionParser.new do |opt|
opt.banner = 'Usage: jazzy'
opt.separator ''
opt.separator 'Options'
@@ -483,11 +521,11 @@
self.class.all_config_attrs.each do |attr|
attr.attach_to_option_parser(self, opt)
end
opt.on('-v', '--version', 'Print version number') do
- puts 'jazzy version: ' + Jazzy::VERSION
+ puts "jazzy version: #{Jazzy::VERSION}"
exit
end
opt.on('-h', '--help [TOPIC]', 'Available topics:',
' usage Command line options (this help message)',
@@ -502,10 +540,14 @@
print_option_help(topic)
end
exit
end
end.parse!
+
+ unless ARGV.empty?
+ warning "Leftover unused command-line text: #{ARGV}"
+ end
end
def parse_config_file
config_path = locate_config_file
return unless config_path
@@ -519,26 +561,36 @@
self.class.all_config_attrs.group_by(&prop)
end
config_file.each do |key, value|
unless attr = attrs_by_conf_key[key]
- message = "WARNING: Unknown config file attribute #{key.inspect}"
+ message = "Unknown config file attribute #{key.inspect}"
if matching_name = attrs_by_name[key]
- message << ' (Did you mean '
- message << matching_name.first.config_file_key.inspect
- message << '?)'
+ message +=
+ " (Did you mean #{matching_name.first.config_file_key.inspect}?)"
end
- warn message
+ warning message
next
end
attr.first.set_if_unconfigured(self, value)
end
self.base_path = nil
end
+ def validate
+ if source_host_configured &&
+ source_host_url.nil? &&
+ source_host_files_url.nil?
+ warning 'Option `source_host` is set but has no effect without either '\
+ '`source_host_url` or `source_host_files_url`.'
+ end
+ end
+
+ # rubocop:enable Metrics/MethodLength
+
def locate_config_file
return config_file if config_file
source_directory.ascend do |dir|
candidate = dir.join('.jazzy.yaml')
@@ -548,19 +600,14 @@
nil
end
def read_config_file(file)
case File.extname(file)
- when '.json' then JSON.parse(File.read(file))
- when '.yaml', '.yml' then
- if YAML.respond_to?('safe_load') # ruby >= 2.1.0
- YAML.safe_load(File.read(file))
- else
- # rubocop:disable Security/YAMLLoad
- YAML.load(File.read(file))
- # rubocop:enable Security/YAMLLoad
- end
+ when '.json'
+ JSON.parse(File.read(file))
+ when '.yaml', '.yml'
+ YAML.safe_load(File.read(file))
else raise "Config file must be .yaml or .json, but got #{file.inspect}"
end
end
def print_config_file_help
@@ -573,10 +620,10 @@
(The source directory is the current working directory by default.
You can override that with --source-directory.)
The config file can be in YAML or JSON format. Available options are:
- _EOS_
+ _EOS_
.gsub(/^ +/, '')
print_option_help
end