asciidoctor 2.0.12 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +142 -22
- data/LICENSE +1 -1
- data/README-de.adoc +15 -6
- data/README-fr.adoc +14 -8
- data/README-jp.adoc +15 -6
- data/README-zh_CN.adoc +14 -5
- data/README.adoc +135 -125
- data/asciidoctor.gemspec +4 -11
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-it.adoc +4 -4
- data/data/locale/attributes-nl.adoc +6 -6
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +51 -52
- data/lib/asciidoctor.rb +12 -12
- data/lib/asciidoctor/abstract_block.rb +4 -4
- data/lib/asciidoctor/abstract_node.rb +10 -9
- data/lib/asciidoctor/attribute_list.rb +6 -6
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +0 -1
- data/lib/asciidoctor/cli/options.rb +27 -26
- data/lib/asciidoctor/convert.rb +1 -0
- data/lib/asciidoctor/converter.rb +5 -3
- data/lib/asciidoctor/converter/docbook5.rb +45 -26
- data/lib/asciidoctor/converter/html5.rb +89 -69
- data/lib/asciidoctor/converter/manpage.rb +113 -86
- data/lib/asciidoctor/converter/template.rb +11 -12
- data/lib/asciidoctor/document.rb +44 -51
- data/lib/asciidoctor/extensions.rb +10 -12
- data/lib/asciidoctor/helpers.rb +3 -6
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +13 -11
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +135 -150
- data/lib/asciidoctor/path_resolver.rb +3 -3
- data/lib/asciidoctor/reader.rb +72 -71
- data/lib/asciidoctor/rx.rb +4 -3
- data/lib/asciidoctor/substitutors.rb +117 -117
- data/lib/asciidoctor/syntax_highlighter.rb +8 -11
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +6 -5
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +33 -26
- data/lib/asciidoctor/table.rb +17 -19
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +10 -11
- data/man/asciidoctor.adoc +8 -7
- metadata +14 -67
data/lib/asciidoctor.rb
CHANGED
@@ -53,12 +53,12 @@ module Asciidoctor
|
|
53
53
|
module SafeMode
|
54
54
|
# A safe mode level that disables any of the security features enforced
|
55
55
|
# by Asciidoctor (Ruby is still subject to its own restrictions).
|
56
|
-
UNSAFE = 0
|
56
|
+
UNSAFE = 0
|
57
57
|
|
58
58
|
# A safe mode level that closely parallels safe mode in AsciiDoc. This value
|
59
59
|
# prevents access to files which reside outside of the parent directory of
|
60
60
|
# the source file and disables any macro other than the include::[] directive.
|
61
|
-
SAFE = 1
|
61
|
+
SAFE = 1
|
62
62
|
|
63
63
|
# A safe mode level that disallows the document from setting attributes
|
64
64
|
# that would affect the conversion of the document, in addition to all the
|
@@ -66,19 +66,19 @@ module Asciidoctor
|
|
66
66
|
# changing the backend or source-highlighter using an attribute defined
|
67
67
|
# in the source document header. This is the most fundamental level of
|
68
68
|
# security for server deployments (hence the name).
|
69
|
-
SERVER = 10
|
69
|
+
SERVER = 10
|
70
70
|
|
71
71
|
# A safe mode level that disallows the document from attempting to read
|
72
72
|
# files from the file system and including the contents of them into the
|
73
73
|
# document, in additional to all the security features of SafeMode::SERVER.
|
74
74
|
# For instance, this level disallows use of the include::[] directive and the
|
75
75
|
# embedding of binary content (data uri), stylesheets and JavaScripts
|
76
|
-
# referenced by the document.(Asciidoctor and trusted extensions may still
|
76
|
+
# referenced by the document. (Asciidoctor and trusted extensions may still
|
77
77
|
# be allowed to embed trusted content into the document).
|
78
78
|
#
|
79
79
|
# Since Asciidoctor is aiming for wide adoption, this level is the default
|
80
80
|
# and is recommended for server deployments.
|
81
|
-
SECURE = 20
|
81
|
+
SECURE = 20
|
82
82
|
|
83
83
|
# A planned safe mode level that disallows the use of passthrough macros and
|
84
84
|
# prevents the document from setting any known attributes, in addition to all
|
@@ -86,9 +86,9 @@ module Asciidoctor
|
|
86
86
|
#
|
87
87
|
# Please note that this level is not currently implemented (and therefore not
|
88
88
|
# enforced)!
|
89
|
-
#PARANOID = 100
|
89
|
+
#PARANOID = 100
|
90
90
|
|
91
|
-
@names_by_value =
|
91
|
+
@names_by_value = (constants false).map {|sym| [(const_get sym), sym.to_s.downcase] }.sort {|(a), (b)| a <=> b }.to_h
|
92
92
|
|
93
93
|
def self.value_for_name name
|
94
94
|
const_get name.upcase, false
|
@@ -136,8 +136,8 @@ module Asciidoctor
|
|
136
136
|
# Compliance value: true
|
137
137
|
define :underline_style_section_titles, true
|
138
138
|
|
139
|
-
# Asciidoctor will unwrap the content in a preamble
|
140
|
-
#
|
139
|
+
# Asciidoctor will unwrap the content in a preamble if the document has a
|
140
|
+
# title and no sections, then discard the empty preamble.
|
141
141
|
# Compliance value: false
|
142
142
|
define :unwrap_standalone_preamble, true
|
143
143
|
|
@@ -332,7 +332,7 @@ module Asciidoctor
|
|
332
332
|
|
333
333
|
LIST_CONTINUATION = '+'
|
334
334
|
|
335
|
-
# NOTE AsciiDoc
|
335
|
+
# NOTE AsciiDoc.py allows + to be preceded by TAB; Asciidoctor does not
|
336
336
|
HARD_LINE_BREAK = ' +'
|
337
337
|
|
338
338
|
LINE_CONTINUATION = ' \\'
|
@@ -459,9 +459,9 @@ module Asciidoctor
|
|
459
459
|
[:emphasis, :unconstrained, /\\?(?:\[([^\]]+)\])?__(#{CC_ALL}+?)__/m],
|
460
460
|
# _emphasis_
|
461
461
|
[:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?_(\S|\S#{CC_ALL}*?\S)_(?!#{CG_WORD})/m],
|
462
|
-
# ##mark## (referred to in AsciiDoc
|
462
|
+
# ##mark## (referred to in AsciiDoc.py as unquoted)
|
463
463
|
[:mark, :unconstrained, /\\?(?:\[([^\]]+)\])?##(#{CC_ALL}+?)##/m],
|
464
|
-
# #mark# (referred to in AsciiDoc
|
464
|
+
# #mark# (referred to in AsciiDoc.py as unquoted)
|
465
465
|
[:mark, :constrained, /(^|[^#{CC_WORD}&;:}])(?:\[([^\]]+)\])?#(\S|\S#{CC_ALL}*?\S)#(?!#{CG_WORD})/m],
|
466
466
|
# ^superscript^
|
467
467
|
[:superscript, :unconstrained, /\\?(?:\[([^\]]+)\])?\^(\S+?)\^/],
|
@@ -90,7 +90,7 @@ class AbstractBlock < AbstractNode
|
|
90
90
|
#
|
91
91
|
# context - the context Symbol context to assign to this block
|
92
92
|
#
|
93
|
-
# Returns the
|
93
|
+
# Returns the specified Symbol context
|
94
94
|
def context= context
|
95
95
|
@node_name = (@context = context).to_s
|
96
96
|
end
|
@@ -296,7 +296,7 @@ class AbstractBlock < AbstractNode
|
|
296
296
|
|
297
297
|
# Public: Set the String block title.
|
298
298
|
#
|
299
|
-
# Returns the
|
299
|
+
# Returns the specified String title
|
300
300
|
def title= val
|
301
301
|
@converted_title = nil
|
302
302
|
@title = val
|
@@ -480,7 +480,7 @@ class AbstractBlock < AbstractNode
|
|
480
480
|
@header.find_by_internal selector, result, &block
|
481
481
|
end
|
482
482
|
@blocks.each do |b|
|
483
|
-
next if
|
483
|
+
next if context_selector == :section && b.context != :section # optimization
|
484
484
|
b.find_by_internal selector, result, &block
|
485
485
|
end
|
486
486
|
end
|
@@ -505,7 +505,7 @@ class AbstractBlock < AbstractNode
|
|
505
505
|
end
|
506
506
|
else
|
507
507
|
@blocks.each do |b|
|
508
|
-
next if
|
508
|
+
next if context_selector == :section && b.context != :section # optimization
|
509
509
|
b.find_by_internal selector, result, &block
|
510
510
|
end
|
511
511
|
end
|
@@ -4,7 +4,8 @@ module Asciidoctor
|
|
4
4
|
# node of AsciiDoc content. The state and methods on this class are common to
|
5
5
|
# all content segments in an AsciiDoc document.
|
6
6
|
class AbstractNode
|
7
|
-
include
|
7
|
+
include Logging
|
8
|
+
include Substitutors
|
8
9
|
|
9
10
|
# Public: Get the Hash of attributes for this node
|
10
11
|
attr_reader :attributes
|
@@ -65,7 +66,7 @@ class AbstractNode
|
|
65
66
|
#
|
66
67
|
# parent - The Block to set as the parent of this Block
|
67
68
|
#
|
68
|
-
# Returns the
|
69
|
+
# Returns the the specified Block parent
|
69
70
|
def parent= parent
|
70
71
|
@parent, @document = parent, parent.document
|
71
72
|
end
|
@@ -155,7 +156,7 @@ class AbstractNode
|
|
155
156
|
#
|
156
157
|
# name - the String name of the option
|
157
158
|
#
|
158
|
-
# Returns
|
159
|
+
# Returns nothing
|
159
160
|
def set_option name
|
160
161
|
@attributes[%(#{name}-option)] = ''
|
161
162
|
nil
|
@@ -216,11 +217,11 @@ class AbstractNode
|
|
216
217
|
(val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
|
217
218
|
end
|
218
219
|
|
219
|
-
# Public: Sets the value of the role attribute on this
|
220
|
+
# Public: Sets the value of the role attribute on this node.
|
220
221
|
#
|
221
222
|
# names - A single role name, a space-separated String of role names, or an Array of role names
|
222
223
|
#
|
223
|
-
# Returns the
|
224
|
+
# Returns the specified String role name or Array of role names
|
224
225
|
def role= names
|
225
226
|
@attributes['role'] = (::Array === names) ? (names.join ' ') : names
|
226
227
|
end
|
@@ -462,8 +463,8 @@ class AbstractNode
|
|
462
463
|
start = doc.base_dir
|
463
464
|
end
|
464
465
|
else
|
465
|
-
start
|
466
|
-
jail
|
466
|
+
start ||= doc.base_dir
|
467
|
+
jail ||= doc.base_dir
|
467
468
|
end
|
468
469
|
doc.path_resolver.system_path target, start, jail, opts
|
469
470
|
end
|
@@ -542,8 +543,8 @@ class AbstractNode
|
|
542
543
|
rescue
|
543
544
|
logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
|
544
545
|
end
|
545
|
-
|
546
|
-
logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled))
|
546
|
+
elsif opts.fetch :warn_on_failure, true
|
547
|
+
logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled))
|
547
548
|
end
|
548
549
|
else
|
549
550
|
target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
|
@@ -27,7 +27,7 @@ class AttributeList
|
|
27
27
|
QUOT = '"'
|
28
28
|
|
29
29
|
# Public: Regular expressions for detecting the boundary of a value
|
30
|
-
|
30
|
+
BoundaryRx = {
|
31
31
|
QUOT => /.*?[^\\](?=")/,
|
32
32
|
APOS => /.*?[^\\](?=')/,
|
33
33
|
',' => /.*?(?=[ \t]*(,|$))/
|
@@ -46,7 +46,7 @@ class AttributeList
|
|
46
46
|
BlankRx = /[ \t]+/
|
47
47
|
|
48
48
|
# Public: Regular expressions for skipping delimiters
|
49
|
-
|
49
|
+
SkipRx = {
|
50
50
|
',' => /[ \t]*(,|$)/
|
51
51
|
}
|
52
52
|
|
@@ -54,8 +54,8 @@ class AttributeList
|
|
54
54
|
@scanner = ::StringScanner.new source
|
55
55
|
@block = block
|
56
56
|
@delimiter = delimiter
|
57
|
-
@delimiter_skip_pattern =
|
58
|
-
@delimiter_boundary_pattern =
|
57
|
+
@delimiter_skip_pattern = SkipRx[delimiter]
|
58
|
+
@delimiter_boundary_pattern = BoundaryRx[delimiter]
|
59
59
|
@attributes = nil
|
60
60
|
end
|
61
61
|
|
@@ -173,7 +173,7 @@ class AttributeList
|
|
173
173
|
end
|
174
174
|
else
|
175
175
|
name = @block.apply_subs name if single_quoted && @block
|
176
|
-
if (positional_attr_name = positional_attrs[index])
|
176
|
+
if (positional_attr_name = positional_attrs[index]) && name
|
177
177
|
@attributes[positional_attr_name] = name
|
178
178
|
end
|
179
179
|
# QUESTION should we assign the positional key even when it's claimed by a positional attribute?
|
@@ -214,7 +214,7 @@ class AttributeList
|
|
214
214
|
end
|
215
215
|
|
216
216
|
def scan_to_quote quote
|
217
|
-
@scanner.scan
|
217
|
+
@scanner.scan BoundaryRx[quote]
|
218
218
|
end
|
219
219
|
end
|
220
220
|
end
|
data/lib/asciidoctor/block.rb
CHANGED
@@ -54,21 +54,21 @@ class Block < AbstractBlock
|
|
54
54
|
# FIXME feels funky; we have to be defensive to get commit_subs to honor override
|
55
55
|
# FIXME does not resolve substitution groups inside Array (e.g., [:normal])
|
56
56
|
if (subs = opts[:subs])
|
57
|
-
|
57
|
+
case subs
|
58
|
+
# e.g., subs: :default
|
58
59
|
# subs attribute is honored; falls back to opts[:default_subs], then built-in defaults based on context
|
59
|
-
|
60
|
+
when :default
|
60
61
|
@default_subs = opts[:default_subs]
|
61
62
|
# e.g., subs: [:quotes]
|
62
63
|
# subs attribute is not honored
|
63
|
-
|
64
|
+
when ::Array
|
64
65
|
@default_subs = subs.drop 0
|
65
66
|
@attributes.delete 'subs'
|
66
67
|
# e.g., subs: :normal or subs: 'normal'
|
67
68
|
# subs attribute is not honored
|
68
69
|
else
|
69
70
|
@default_subs = nil
|
70
|
-
|
71
|
-
@attributes['subs'] = %(#{subs})
|
71
|
+
@attributes['subs'] = subs.to_s
|
72
72
|
end
|
73
73
|
# resolve the subs eagerly only if subs option is specified
|
74
74
|
# QUESTION should we skip subsequent calls to commit_subs?
|
@@ -123,7 +123,7 @@ class Block < AbstractBlock
|
|
123
123
|
result.join LF
|
124
124
|
end
|
125
125
|
else
|
126
|
-
logger.warn %(Unknown content model '#{@content_model}' for block: #{
|
126
|
+
logger.warn %(Unknown content model '#{@content_model}' for block: #{self}) unless @content_model == :empty
|
127
127
|
nil
|
128
128
|
end
|
129
129
|
end
|
@@ -39,19 +39,20 @@ module Asciidoctor
|
|
39
39
|
# NOTE don't use squiggly heredoc to maintain compatibility with Ruby < 2.3
|
40
40
|
opts.banner = <<-'EOS'.gsub ' ', ''
|
41
41
|
Usage: asciidoctor [OPTION]... FILE...
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
Convert the AsciiDoc input FILE(s) to the backend output format (e.g., HTML 5, DocBook 5, etc.)
|
43
|
+
Unless specified otherwise, the output is written to a file whose name is derived from the input file.
|
44
|
+
Application log messages are printed to STDERR.
|
45
|
+
Example: asciidoctor input.adoc
|
45
46
|
|
46
47
|
EOS
|
47
48
|
|
48
|
-
opts.on('-b', '--backend BACKEND', 'set output format
|
49
|
-
|
49
|
+
opts.on('-b', '--backend BACKEND', 'set backend output format: [html5, xhtml5, docbook5, manpage] (default: html5)',
|
50
|
+
'additional backends are supported via extended converters (e.g., pdf, epub3)') do |backend|
|
50
51
|
self[:attributes]['backend'] = backend
|
51
52
|
end
|
52
53
|
opts.on('-d', '--doctype DOCTYPE', ['article', 'book', 'manpage', 'inline'],
|
53
|
-
|
54
|
-
self[:attributes]['doctype'] =
|
54
|
+
'document type to use when converting document: [article, book, manpage, inline] (default: article)') do |doctype|
|
55
|
+
self[:attributes]['doctype'] = doctype
|
55
56
|
end
|
56
57
|
opts.on('-e', '--embedded', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
57
58
|
self[:standalone] = false
|
@@ -60,14 +61,14 @@ module Asciidoctor
|
|
60
61
|
self[:output_file] = output_file
|
61
62
|
end
|
62
63
|
opts.on('--safe',
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
'set safe mode level to safe (default: unsafe)',
|
65
|
+
'enables include directives, but prevents access to ancestor paths of source file',
|
66
|
+
'provided for compatibility with the asciidoc command') do
|
66
67
|
self[:safe] = SafeMode::SAFE
|
67
68
|
end
|
68
69
|
opts.on('-S', '--safe-mode SAFE_MODE', (safe_mode_names = SafeMode.names),
|
69
|
-
|
70
|
-
|
70
|
+
%(set safe mode level explicitly: [#{safe_mode_names.join ', '}] (default: unsafe)),
|
71
|
+
'disables potentially dangerous macros in source files, such as include::[]') do |name|
|
71
72
|
self[:safe] = SafeMode.value_for_name name
|
72
73
|
end
|
73
74
|
opts.on('-s', '--no-header-footer', 'suppress enclosing document structure and output an embedded document (default: false)') do
|
@@ -77,19 +78,19 @@ module Asciidoctor
|
|
77
78
|
self[:attributes]['sectnums'] = ''
|
78
79
|
end
|
79
80
|
opts.on('--eruby ERUBY', ['erb', 'erubi', 'erubis'],
|
80
|
-
|
81
|
+
'specify eRuby implementation to use when rendering custom ERB templates: [erb, erubi, erubis] (default: erb)') do |eruby|
|
81
82
|
self[:eruby] = eruby
|
82
83
|
end
|
83
84
|
opts.on('-a', '--attribute name[=value]', 'a document attribute to set in the form of name, name!, or name=value pair',
|
84
|
-
|
85
|
-
|
85
|
+
'this attribute takes precedence over the same attribute defined in the source document',
|
86
|
+
'unless either the name or value ends in @ (i.e., name@=value or name=value@)') do |attr|
|
86
87
|
next if (attr = attr.rstrip).empty? || attr == '='
|
87
88
|
attr = attr.encode UTF_8 unless attr.encoding == UTF_8
|
88
89
|
name, _, val = attr.partition '='
|
89
90
|
self[:attributes][name] = val
|
90
91
|
end
|
91
92
|
opts.on('-T', '--template-dir DIR', 'a directory containing custom converter templates that override the built-in converter (requires tilt gem)',
|
92
|
-
|
93
|
+
'may be specified multiple times') do |template_dir|
|
93
94
|
if self[:template_dirs].nil?
|
94
95
|
self[:template_dirs] = [template_dir]
|
95
96
|
elsif ::Array === self[:template_dirs]
|
@@ -120,21 +121,21 @@ module Asciidoctor
|
|
120
121
|
end
|
121
122
|
opts.on('--failure-level LEVEL', %w(warning WARNING error ERROR info INFO), 'set minimum logging level that triggers non-zero exit code: [WARN, ERROR, INFO] (default: FATAL)') do |level|
|
122
123
|
level = 'WARN' if (level = level.upcase) == 'WARNING'
|
123
|
-
self[:failure_level] = ::Logger::Severity.const_get level
|
124
|
+
self[:failure_level] = ::Logger::Severity.const_get level
|
124
125
|
end
|
125
|
-
opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
|
126
|
+
opts.on('-q', '--quiet', 'silence application log messages and script warnings (default: false)') do
|
126
127
|
self[:verbose] = 0
|
127
128
|
end
|
128
|
-
opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
|
129
|
+
opts.on('--trace', 'include backtrace information when reporting errors (default: false)') do
|
129
130
|
self[:trace] = true
|
130
131
|
end
|
131
|
-
opts.on('-v', '--verbose', '
|
132
|
+
opts.on('-v', '--verbose', 'directs application messages logged at DEBUG or INFO level to STDERR (default: false)') do
|
132
133
|
self[:verbose] = 2
|
133
134
|
end
|
134
|
-
opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
|
135
|
+
opts.on('-w', '--warnings', 'turn on script warnings (default: false)') do
|
135
136
|
self[:warnings] = true
|
136
137
|
end
|
137
|
-
opts.on('-t', '--timings', 'print timings report (default: false)') do
|
138
|
+
opts.on('-t', '--timings', 'print timings report (default: false)') do
|
138
139
|
self[:timings] = true
|
139
140
|
end
|
140
141
|
opts.on_tail('-h', '--help [TOPIC]', 'print a help message',
|
@@ -160,7 +161,7 @@ module Asciidoctor
|
|
160
161
|
elsif ::File.exist? (manpage_path = (::File.join ROOT_DIR, 'man', 'asciidoctor.1'))
|
161
162
|
$stdout.puts ::File.read manpage_path
|
162
163
|
else
|
163
|
-
manpage_path =
|
164
|
+
manpage_path = %x(man -w asciidoctor).chop rescue ''
|
164
165
|
if manpage_path.empty?
|
165
166
|
$stderr.puts 'asciidoctor: FAILED: manual page not found; try `man asciidoctor`'
|
166
167
|
return 1
|
@@ -248,7 +249,7 @@ module Asciidoctor
|
|
248
249
|
|
249
250
|
self[:input_files] = infiles
|
250
251
|
|
251
|
-
|
252
|
+
delete :attributes if self[:attributes].empty?
|
252
253
|
|
253
254
|
if self[:template_dirs]
|
254
255
|
begin
|
@@ -289,11 +290,11 @@ module Asciidoctor
|
|
289
290
|
rescue ::OptionParser::MissingArgument
|
290
291
|
$stderr.puts %(asciidoctor: option #{$!.message})
|
291
292
|
$stdout.puts opts_parser
|
292
|
-
|
293
|
+
1
|
293
294
|
rescue ::OptionParser::InvalidOption, ::OptionParser::InvalidArgument
|
294
295
|
$stderr.puts %(asciidoctor: #{$!.message})
|
295
296
|
$stdout.puts opts_parser
|
296
|
-
|
297
|
+
1
|
297
298
|
ensure
|
298
299
|
$VERBOSE = old_verbose
|
299
300
|
end
|
data/lib/asciidoctor/convert.rb
CHANGED
@@ -366,15 +366,17 @@ module Converter
|
|
366
366
|
# into - The Class into which the {Converter} module is being included.
|
367
367
|
#
|
368
368
|
# Returns nothing.
|
369
|
-
|
369
|
+
def self.included into
|
370
370
|
into.send :include, BackendTraits
|
371
371
|
into.extend Config
|
372
|
-
end
|
372
|
+
end
|
373
|
+
private_class_method :included # use separate declaration for Ruby 2.0.x
|
373
374
|
|
374
375
|
# An abstract base class for defining converters that can be used to convert {AbstractNode} objects in a parsed
|
375
376
|
# AsciiDoc document to a backend format such as HTML or DocBook.
|
376
377
|
class Base
|
377
|
-
include
|
378
|
+
include Logging
|
379
|
+
include Converter
|
378
380
|
|
379
381
|
# Public: Converts an {AbstractNode} by delegating to a method that matches the transform value.
|
380
382
|
#
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# A built-in {Converter} implementation that generates DocBook 5 output. The output is inspired by the output produced
|
4
|
-
# by the docbook45 backend from AsciiDoc
|
4
|
+
# by the docbook45 backend from AsciiDoc.py, except it has been migrated to the DocBook 5 specification.
|
5
5
|
class Converter::DocBook5Converter < Converter::Base
|
6
6
|
register_for 'docbook5'
|
7
7
|
|
8
8
|
# default represents variablelist
|
9
9
|
(DLIST_TAGS = {
|
10
|
-
'qanda' => { list:
|
11
|
-
'glossary' => { list:
|
12
|
-
}).default = { list:
|
10
|
+
'qanda' => { list: 'qandaset', entry: 'qandaentry', label: 'question', term: 'simpara', item: 'answer' },
|
11
|
+
'glossary' => { list: nil, entry: 'glossentry', term: 'glossterm', item: 'glossdef' },
|
12
|
+
}).default = { list: 'variablelist', entry: 'varlistentry', term: 'term', item: 'listitem' }
|
13
13
|
|
14
14
|
(QUOTE_TAGS = {
|
15
15
|
monospaced: ['<literal>', '</literal>'],
|
@@ -25,7 +25,7 @@ class Converter::DocBook5Converter < Converter::Base
|
|
25
25
|
MANPAGE_SECTION_TAGS = { 'section' => 'refsection', 'synopsis' => 'refsynopsisdiv' }
|
26
26
|
TABLE_PI_NAMES = ['dbhtml', 'dbfo', 'dblatex']
|
27
27
|
|
28
|
-
CopyrightRx = /^(#{CC_ANY}+?)(?: ((?:\d{4}
|
28
|
+
CopyrightRx = /^(#{CC_ANY}+?)(?: ((?:\d{4}-)?\d{4}))?$/
|
29
29
|
ImageMacroRx = /^image::?(\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
|
30
30
|
|
31
31
|
def initialize backend, opts = {}
|
@@ -41,7 +41,8 @@ class Converter::DocBook5Converter < Converter::Base
|
|
41
41
|
if (root_tag_name = node.doctype) == 'manpage'
|
42
42
|
root_tag_name = 'refentry'
|
43
43
|
end
|
44
|
-
|
44
|
+
root_tag_idx = result.size
|
45
|
+
id = node.id
|
45
46
|
result << (document_info_tag node) unless node.noheader
|
46
47
|
unless (docinfo_content = node.docinfo :header).empty?
|
47
48
|
result << docinfo_content
|
@@ -50,6 +51,9 @@ class Converter::DocBook5Converter < Converter::Base
|
|
50
51
|
unless (docinfo_content = node.docinfo :footer).empty?
|
51
52
|
result << docinfo_content
|
52
53
|
end
|
54
|
+
id, node.id = node.id, nil unless id
|
55
|
+
# defer adding root tag in case document ID is auto-generated on demand
|
56
|
+
result.insert root_tag_idx, %(<#{root_tag_name} xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"#{lang_attribute}#{common_attributes id}>)
|
53
57
|
result << %(</#{root_tag_name}>)
|
54
58
|
result.join LF
|
55
59
|
end
|
@@ -298,13 +302,13 @@ class Converter::DocBook5Converter < Converter::Base
|
|
298
302
|
</abstract>)
|
299
303
|
end
|
300
304
|
when 'partintro'
|
301
|
-
|
302
|
-
logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
|
303
|
-
''
|
304
|
-
else
|
305
|
+
if node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
|
305
306
|
%(<partintro#{common_attributes node.id, node.role, node.reftext}>
|
306
307
|
#{title_tag node}#{enclose_content node}
|
307
308
|
</partintro>)
|
309
|
+
else
|
310
|
+
logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
|
311
|
+
''
|
308
312
|
end
|
309
313
|
else
|
310
314
|
reftext = node.reftext if (id = node.id)
|
@@ -374,19 +378,19 @@ class Converter::DocBook5Converter < Converter::Base
|
|
374
378
|
frame = 'topbot' if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
|
375
379
|
grid = node.attr 'grid', nil, 'table-grid'
|
376
380
|
result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{frame}" rowsep="#{['none', 'cols'].include?(grid) ? 0 : 1}" colsep="#{['none', 'rows'].include?(grid) ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', 'table-orientation') ? ' orient="land"' : ''}>)
|
377
|
-
if
|
381
|
+
if node.option? 'unbreakable'
|
378
382
|
result << '<?dbfo keep-together="always"?>'
|
379
|
-
elsif
|
383
|
+
elsif node.option? 'breakable'
|
380
384
|
result << '<?dbfo keep-together="auto"?>'
|
381
385
|
end
|
382
386
|
result << %(<title>#{node.title}</title>) if tag_name == 'table'
|
383
|
-
|
387
|
+
if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
|
384
388
|
TABLE_PI_NAMES.each do |pi_name|
|
385
389
|
result << %(<?#{pi_name} table-width="#{width}"?>)
|
386
390
|
end
|
387
|
-
'colabswidth'
|
391
|
+
col_width_key = 'colabswidth'
|
388
392
|
else
|
389
|
-
'colpcwidth'
|
393
|
+
col_width_key = 'colpcwidth'
|
390
394
|
end
|
391
395
|
result << %(<tgroup cols="#{node.attr 'colcount'}">)
|
392
396
|
node.columns.each do |col|
|
@@ -474,10 +478,16 @@ class Converter::DocBook5Converter < Converter::Base
|
|
474
478
|
%(<anchor#{common_attributes((id = node.id), nil, node.reftext || %([#{id}]))}/>)
|
475
479
|
when :xref
|
476
480
|
if (path = node.attributes['path'])
|
477
|
-
# QUESTION should we use refid as fallback text instead? (like the html5 backend?)
|
478
481
|
%(<link xl:href="#{node.target}">#{node.text || path}</link>)
|
479
482
|
else
|
480
|
-
linkend = node.attributes['
|
483
|
+
if (linkend = node.attributes['refid']).nil_or_empty?
|
484
|
+
root_doc = get_root_document node
|
485
|
+
# Q: should we warn instead of generating a document ID on demand?
|
486
|
+
linkend = (root_doc.id ||= generate_document_id root_doc)
|
487
|
+
end
|
488
|
+
# NOTE the xref tag in DocBook does not support explicit link text, so the link tag must be used instead
|
489
|
+
# The section at http://www.sagehill.net/docbookxsl/CrossRefs.html#IdrefLinks gives an explanation for this choice
|
490
|
+
# "link - a cross reference where you supply the text of the reference as the content of the link element."
|
481
491
|
(text = node.text) ? %(<link linkend="#{linkend}">#{text}</link>) : %(<xref linkend="#{linkend}"/>)
|
482
492
|
end
|
483
493
|
when :link
|
@@ -533,9 +543,8 @@ class Converter::DocBook5Converter < Converter::Base
|
|
533
543
|
%(<indexterm>
|
534
544
|
<primary>#{node.text}</primary>#{rel}
|
535
545
|
</indexterm>#{node.text})
|
536
|
-
|
537
|
-
|
538
|
-
%(<indexterm>
|
546
|
+
elsif (numterms = (terms = node.attr 'terms').size) > 2
|
547
|
+
%(<indexterm>
|
539
548
|
<primary>#{terms[0]}</primary><secondary>#{terms[1]}</secondary><tertiary>#{terms[2]}</tertiary>#{rel}
|
540
549
|
</indexterm>#{(node.document.option? 'indexterm-promotion') ? %[
|
541
550
|
<indexterm>
|
@@ -544,18 +553,17 @@ class Converter::DocBook5Converter < Converter::Base
|
|
544
553
|
<indexterm>
|
545
554
|
<primary>#{terms[2]}</primary>
|
546
555
|
</indexterm>] : ''})
|
547
|
-
|
548
|
-
|
556
|
+
elsif numterms > 1
|
557
|
+
%(<indexterm>
|
549
558
|
<primary>#{terms[0]}</primary><secondary>#{terms[1]}</secondary>#{rel}
|
550
|
-
</indexterm>#{(node.document.option?
|
559
|
+
</indexterm>#{(node.document.option? 'indexterm-promotion') ? %[
|
551
560
|
<indexterm>
|
552
561
|
<primary>#{terms[1]}</primary>
|
553
562
|
</indexterm>] : ''})
|
554
|
-
|
555
|
-
|
563
|
+
else
|
564
|
+
%(<indexterm>
|
556
565
|
<primary>#{terms[0]}</primary>#{rel}
|
557
566
|
</indexterm>)
|
558
|
-
end
|
559
567
|
end
|
560
568
|
end
|
561
569
|
|
@@ -710,6 +718,17 @@ class Converter::DocBook5Converter < Converter::Base
|
|
710
718
|
result.join LF
|
711
719
|
end
|
712
720
|
|
721
|
+
def get_root_document node
|
722
|
+
while (node = node.document).nested?
|
723
|
+
node = node.parent_document
|
724
|
+
end
|
725
|
+
node
|
726
|
+
end
|
727
|
+
|
728
|
+
def generate_document_id doc
|
729
|
+
%(__#{doc.doctype}-root__)
|
730
|
+
end
|
731
|
+
|
713
732
|
# FIXME this should be handled through a template mechanism
|
714
733
|
def enclose_content node
|
715
734
|
node.content_model == :compound ? node.content : %(<simpara>#{node.content}</simpara>)
|