asciidoctor 2.0.9 → 2.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +193 -16
- data/LICENSE +1 -1
- data/README-de.adoc +12 -13
- data/README-fr.adoc +11 -15
- data/README-jp.adoc +242 -185
- data/README-zh_CN.adoc +17 -18
- data/README.adoc +133 -131
- data/asciidoctor.gemspec +6 -6
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +4 -4
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +6 -5
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +6 -5
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +6 -5
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +30 -30
- data/lib/asciidoctor.rb +40 -14
- data/lib/asciidoctor/abstract_block.rb +9 -4
- data/lib/asciidoctor/abstract_node.rb +16 -6
- data/lib/asciidoctor/attribute_list.rb +63 -71
- data/lib/asciidoctor/cli/invoker.rb +2 -0
- data/lib/asciidoctor/cli/options.rb +10 -9
- data/lib/asciidoctor/convert.rb +167 -162
- data/lib/asciidoctor/converter.rb +13 -12
- data/lib/asciidoctor/converter/docbook5.rb +5 -9
- data/lib/asciidoctor/converter/html5.rb +58 -45
- data/lib/asciidoctor/converter/manpage.rb +61 -38
- data/lib/asciidoctor/converter/template.rb +3 -0
- data/lib/asciidoctor/document.rb +44 -51
- data/lib/asciidoctor/extensions.rb +2 -4
- data/lib/asciidoctor/helpers.rb +20 -15
- data/lib/asciidoctor/load.rb +102 -101
- data/lib/asciidoctor/parser.rb +40 -32
- data/lib/asciidoctor/path_resolver.rb +14 -12
- data/lib/asciidoctor/reader.rb +20 -13
- data/lib/asciidoctor/rx.rb +7 -6
- data/lib/asciidoctor/substitutors.rb +69 -50
- data/lib/asciidoctor/syntax_highlighter.rb +15 -7
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +12 -4
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +6 -7
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +33 -19
- data/lib/asciidoctor/table.rb +52 -23
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +8 -8
- data/man/asciidoctor.adoc +4 -4
- metadata +16 -15
data/lib/asciidoctor.rb
CHANGED
@@ -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
|
|
@@ -148,7 +148,7 @@ module Asciidoctor
|
|
148
148
|
# Compliance value: 'drop-line'
|
149
149
|
define :attribute_missing, 'skip'
|
150
150
|
|
151
|
-
# AsciiDoc drops lines that contain an attribute
|
151
|
+
# AsciiDoc drops lines that contain an attribute unassignment.
|
152
152
|
# This behavior may need to be tuned depending on the circumstances.
|
153
153
|
# Compliance value: 'drop-line'
|
154
154
|
define :attribute_undefined, 'drop-line'
|
@@ -296,7 +296,7 @@ module Asciidoctor
|
|
296
296
|
DELIMITED_BLOCK_TAILS = {}.tap {|accum| DELIMITED_BLOCKS.each_key {|k| accum[k] = k[k.length - 1] if k.length == 4 } }
|
297
297
|
|
298
298
|
# NOTE the 'figure' key as a string is historical and used by image blocks
|
299
|
-
|
299
|
+
CAPTION_ATTRIBUTE_NAMES = { example: 'example-caption', 'figure' => 'figure-caption', listing: 'listing-caption', table: 'table-caption' }
|
300
300
|
|
301
301
|
LAYOUT_BREAK_CHARS = {
|
302
302
|
'\'' => :thematic_break,
|
@@ -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 = ' \\'
|
@@ -357,9 +357,35 @@ module Asciidoctor
|
|
357
357
|
|
358
358
|
FONT_AWESOME_VERSION = '4.7.0'
|
359
359
|
|
360
|
-
HIGHLIGHT_JS_VERSION = '9.
|
361
|
-
|
362
|
-
MATHJAX_VERSION = '2.7.
|
360
|
+
HIGHLIGHT_JS_VERSION = '9.18.3'
|
361
|
+
|
362
|
+
MATHJAX_VERSION = '2.7.9'
|
363
|
+
|
364
|
+
DEFAULT_ATTRIBUTES = {
|
365
|
+
'appendix-caption' => 'Appendix',
|
366
|
+
'appendix-refsig' => 'Appendix',
|
367
|
+
'caution-caption' => 'Caution',
|
368
|
+
'chapter-refsig' => 'Chapter',
|
369
|
+
#'encoding' => 'UTF-8',
|
370
|
+
'example-caption' => 'Example',
|
371
|
+
'figure-caption' => 'Figure',
|
372
|
+
'important-caption' => 'Important',
|
373
|
+
'last-update-label' => 'Last updated',
|
374
|
+
#'listing-caption' => 'Listing',
|
375
|
+
'note-caption' => 'Note',
|
376
|
+
'part-refsig' => 'Part',
|
377
|
+
#'preface-title' => 'Preface',
|
378
|
+
'prewrap' => '',
|
379
|
+
'sectids' => '',
|
380
|
+
'section-refsig' => 'Section',
|
381
|
+
'table-caption' => 'Table',
|
382
|
+
'tip-caption' => 'Tip',
|
383
|
+
'toc-placement' => 'auto',
|
384
|
+
'toc-title' => 'Table of Contents',
|
385
|
+
'untitled-label' => 'Untitled',
|
386
|
+
'version-label' => 'Version',
|
387
|
+
'warning-caption' => 'Warning',
|
388
|
+
}
|
363
389
|
|
364
390
|
# attributes which be changed throughout the flow of the document (e.g., sectnums)
|
365
391
|
FLEXIBLE_ATTRIBUTES = ['sectnums']
|
@@ -433,9 +459,9 @@ module Asciidoctor
|
|
433
459
|
[:emphasis, :unconstrained, /\\?(?:\[([^\]]+)\])?__(#{CC_ALL}+?)__/m],
|
434
460
|
# _emphasis_
|
435
461
|
[:emphasis, :constrained, /(^|[^#{CC_WORD};:}])(?:\[([^\]]+)\])?_(\S|\S#{CC_ALL}*?\S)_(?!#{CG_WORD})/m],
|
436
|
-
# ##mark## (referred to in AsciiDoc
|
462
|
+
# ##mark## (referred to in AsciiDoc.py as unquoted)
|
437
463
|
[:mark, :unconstrained, /\\?(?:\[([^\]]+)\])?##(#{CC_ALL}+?)##/m],
|
438
|
-
# #mark# (referred to in AsciiDoc
|
464
|
+
# #mark# (referred to in AsciiDoc.py as unquoted)
|
439
465
|
[:mark, :constrained, /(^|[^#{CC_WORD}&;:}])(?:\[([^\]]+)\])?#(\S|\S#{CC_ALL}*?\S)#(?!#{CG_WORD})/m],
|
440
466
|
# ^superscript^
|
441
467
|
[:superscript, :unconstrained, /\\?(?:\[([^\]]+)\])?\^(\S+?)\^/],
|
@@ -469,8 +495,8 @@ module Asciidoctor
|
|
469
495
|
# (TM)
|
470
496
|
[/\\?\(TM\)/, '™', :none],
|
471
497
|
# foo -- bar (where either space character can be a newline)
|
472
|
-
# NOTE this necessarily drops the newline if
|
473
|
-
[/(
|
498
|
+
# NOTE this necessarily drops the newline if replacement appears at end of line
|
499
|
+
[/(?: |\n|^|\\)--(?: |\n|$)/, ' — ', :none],
|
474
500
|
# foo--bar
|
475
501
|
[/(#{CG_WORD})\\?--(?=#{CG_WORD})/, '—​', :leading],
|
476
502
|
# ellipsis
|
@@ -511,8 +537,8 @@ module Asciidoctor
|
|
511
537
|
end unless RUBY_ENGINE == 'opal'
|
512
538
|
|
513
539
|
unless RUBY_ENGINE == 'opal'
|
514
|
-
autoload :SyntaxHighlighter, %(#{
|
515
|
-
autoload :Timings, %(#{
|
540
|
+
autoload :SyntaxHighlighter, %(#{__dir__}/asciidoctor/syntax_highlighter)
|
541
|
+
autoload :Timings, %(#{__dir__}/asciidoctor/timings)
|
516
542
|
end
|
517
543
|
end
|
518
544
|
|
@@ -141,6 +141,11 @@ class AbstractBlock < AbstractNode
|
|
141
141
|
(Integer @numeral) rescue @numeral
|
142
142
|
end
|
143
143
|
|
144
|
+
# Deprecated: Legacy property to set the numeral of this section by coercing the value to a String.
|
145
|
+
def number= val
|
146
|
+
@numeral = val.to_s
|
147
|
+
end
|
148
|
+
|
144
149
|
# Public: Walk the document tree and find all block-level nodes that match the specified selector (context, style, id,
|
145
150
|
# role, and/or custom filter).
|
146
151
|
#
|
@@ -338,17 +343,17 @@ class AbstractBlock < AbstractNode
|
|
338
343
|
if (val = reftext) && !val.empty?
|
339
344
|
val
|
340
345
|
# NOTE xrefstyle only applies to blocks with a title and a caption or number
|
341
|
-
elsif xrefstyle && @title &&
|
346
|
+
elsif xrefstyle && @title && !@caption.nil_or_empty?
|
342
347
|
case xrefstyle
|
343
348
|
when 'full'
|
344
349
|
quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title
|
345
|
-
if @numeral && (caption_attr_name =
|
350
|
+
if @numeral && (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[@context]) && (prefix = @document.attributes[caption_attr_name])
|
346
351
|
%(#{prefix} #{@numeral}, #{quoted_title})
|
347
352
|
else
|
348
353
|
%(#{@caption.chomp '. '}, #{quoted_title})
|
349
354
|
end
|
350
355
|
when 'short'
|
351
|
-
if @numeral && (caption_attr_name =
|
356
|
+
if @numeral && (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[@context]) && (prefix = @document.attributes[caption_attr_name])
|
352
357
|
%(#{prefix} #{@numeral})
|
353
358
|
else
|
354
359
|
@caption.chomp '. '
|
@@ -380,7 +385,7 @@ class AbstractBlock < AbstractNode
|
|
380
385
|
# Returns nothing.
|
381
386
|
def assign_caption value, caption_context = @context
|
382
387
|
unless @caption || !@title || (@caption = value || @document.attributes['caption'])
|
383
|
-
if (attr_name =
|
388
|
+
if (attr_name = CAPTION_ATTRIBUTE_NAMES[caption_context]) && (prefix = @document.attributes[attr_name])
|
384
389
|
@caption = %(#{prefix} #{@numeral = @document.increment_and_store_counter %(#{caption_context}-number), self}. )
|
385
390
|
nil
|
386
391
|
end
|
@@ -65,7 +65,7 @@ class AbstractNode
|
|
65
65
|
#
|
66
66
|
# parent - The Block to set as the parent of this Block
|
67
67
|
#
|
68
|
-
# Returns the
|
68
|
+
# Returns the value of the parent argument
|
69
69
|
def parent= parent
|
70
70
|
@parent, @document = parent, parent.document
|
71
71
|
end
|
@@ -216,6 +216,15 @@ class AbstractNode
|
|
216
216
|
(val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
|
217
217
|
end
|
218
218
|
|
219
|
+
# Public: Sets the value of the role attribute on this node.
|
220
|
+
#
|
221
|
+
# names - A single role name, a space-separated String of role names, or an Array of role names
|
222
|
+
#
|
223
|
+
# Returns the value of the names argument
|
224
|
+
def role= names
|
225
|
+
@attributes['role'] = (::Array === names) ? (names.join ' ') : names
|
226
|
+
end
|
227
|
+
|
219
228
|
# Public: Adds the given role directly to this node.
|
220
229
|
#
|
221
230
|
# Returns a [Boolean] indicating whether the role was added.
|
@@ -514,6 +523,7 @@ class AbstractNode
|
|
514
523
|
# * :normalize a Boolean that indicates whether the data should be normalized (default: false)
|
515
524
|
# * :start the String relative base path to use when resolving the target (default: nil)
|
516
525
|
# * :warn_on_failure a Boolean that indicates whether warnings are issued if the target cannot be read (default: true)
|
526
|
+
# * :warn_if_empty a Boolean that indicates whether a warning is issued if contents of target is empty (default: false)
|
517
527
|
# Returns the contents of the resolved target or nil if the resolved target cannot be read
|
518
528
|
# --
|
519
529
|
# TODO refactor other methods in this class to use this method were possible (repurposing if necessary)
|
@@ -525,22 +535,22 @@ class AbstractNode
|
|
525
535
|
Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri'
|
526
536
|
begin
|
527
537
|
if opts[:normalize]
|
528
|
-
(Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
|
538
|
+
contents = (Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
|
529
539
|
else
|
530
|
-
::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
|
540
|
+
contents = ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
|
531
541
|
end
|
532
542
|
rescue
|
533
543
|
logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
|
534
|
-
return
|
535
544
|
end
|
536
545
|
else
|
537
546
|
logger.warn %(cannot retrieve contents of #{opts[:label] || 'asset'} at URI: #{target} (allow-uri-read attribute not enabled)) if opts.fetch :warn_on_failure, true
|
538
|
-
return
|
539
547
|
end
|
540
548
|
else
|
541
549
|
target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
|
542
|
-
read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
|
550
|
+
contents = read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
|
543
551
|
end
|
552
|
+
logger.warn %(contents of #{opts[:label] || 'asset'} is empty: #{target}) if contents && opts[:warn_if_empty] && contents.empty?
|
553
|
+
contents
|
544
554
|
end
|
545
555
|
|
546
556
|
# Deprecated: Check whether the specified String is a URI by
|
@@ -22,19 +22,20 @@ module Asciidoctor
|
|
22
22
|
# => { 'style' => 'quote', 'attribution' => 'Famous Person', 'citetitle' => 'Famous Book (2001)' }
|
23
23
|
#
|
24
24
|
class AttributeList
|
25
|
-
BACKSLASH = '\\'
|
26
25
|
APOS = '\''
|
26
|
+
BACKSLASH = '\\'
|
27
|
+
QUOT = '"'
|
27
28
|
|
28
29
|
# Public: Regular expressions for detecting the boundary of a value
|
29
|
-
|
30
|
-
|
30
|
+
BoundaryRx = {
|
31
|
+
QUOT => /.*?[^\\](?=")/,
|
31
32
|
APOS => /.*?[^\\](?=')/,
|
32
33
|
',' => /.*?(?=[ \t]*(,|$))/
|
33
34
|
}
|
34
35
|
|
35
36
|
# Public: Regular expressions for unescaping quoted characters
|
36
37
|
EscapedQuotes = {
|
37
|
-
|
38
|
+
QUOT => '\\"',
|
38
39
|
APOS => '\\\''
|
39
40
|
}
|
40
41
|
|
@@ -45,14 +46,16 @@ class AttributeList
|
|
45
46
|
BlankRx = /[ \t]+/
|
46
47
|
|
47
48
|
# Public: Regular expressions for skipping delimiters
|
48
|
-
|
49
|
+
SkipRx = {
|
50
|
+
',' => /[ \t]*(,|$)/
|
51
|
+
}
|
49
52
|
|
50
53
|
def initialize source, block = nil, delimiter = ','
|
51
54
|
@scanner = ::StringScanner.new source
|
52
55
|
@block = block
|
53
56
|
@delimiter = delimiter
|
54
|
-
@delimiter_skip_pattern =
|
55
|
-
@delimiter_boundary_pattern =
|
57
|
+
@delimiter_skip_pattern = SkipRx[delimiter]
|
58
|
+
@delimiter_boundary_pattern = BoundaryRx[delimiter]
|
56
59
|
@attributes = nil
|
57
60
|
end
|
58
61
|
|
@@ -65,8 +68,6 @@ class AttributeList
|
|
65
68
|
return @attributes if @attributes
|
66
69
|
|
67
70
|
@attributes = {}
|
68
|
-
# QUESTION do we want to store the attribute list as the zero-index attribute?
|
69
|
-
#attributes[0] = @scanner.string
|
70
71
|
index = 0
|
71
72
|
|
72
73
|
while parse_attribute index, positional_attrs
|
@@ -83,75 +84,73 @@ class AttributeList
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def self.rekey attributes, positional_attrs
|
86
|
-
|
87
|
-
|
88
|
-
index += 1
|
89
|
-
if (val = attributes[index])
|
87
|
+
positional_attrs.each_with_index do |key, index|
|
88
|
+
if key && (val = attributes[index + 1])
|
90
89
|
# QUESTION should we delete the positional key?
|
91
90
|
attributes[key] = val
|
92
|
-
end
|
91
|
+
end
|
93
92
|
end
|
94
93
|
attributes
|
95
94
|
end
|
96
95
|
|
97
96
|
private
|
98
97
|
|
99
|
-
def parse_attribute index
|
100
|
-
|
98
|
+
def parse_attribute index, positional_attrs
|
99
|
+
continue = true
|
101
100
|
skip_blank
|
102
|
-
|
103
|
-
|
101
|
+
case @scanner.peek 1
|
102
|
+
# example: "quote" || "foo
|
103
|
+
when QUOT
|
104
104
|
name = parse_attribute_value @scanner.get_byte
|
105
|
-
|
106
|
-
|
107
|
-
elsif first == APOS
|
105
|
+
# example: 'quote' || 'foo
|
106
|
+
when APOS
|
108
107
|
name = parse_attribute_value @scanner.get_byte
|
109
|
-
|
110
|
-
single_quoted_value = true unless name.start_with? APOS
|
108
|
+
single_quoted = true unless name.start_with? APOS
|
111
109
|
else
|
112
|
-
name = scan_name
|
113
|
-
|
114
|
-
skipped = 0
|
115
|
-
c = nil
|
110
|
+
skipped = ((name = scan_name) && skip_blank) || 0
|
116
111
|
if @scanner.eos?
|
117
|
-
return
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else
|
131
|
-
skip_blank
|
132
|
-
if @scanner.peek(1)
|
133
|
-
# example: foo="bar" || foo="ba\"zaar"
|
134
|
-
if (c = @scanner.get_byte) == '"'
|
112
|
+
return unless name || (@scanner.string.rstrip.end_with? @delimiter)
|
113
|
+
# example: quote (at eos)
|
114
|
+
continue = nil
|
115
|
+
# example: quote,
|
116
|
+
elsif (c = @scanner.get_byte) == @delimiter
|
117
|
+
@scanner.unscan
|
118
|
+
elsif name
|
119
|
+
# example: foo=...
|
120
|
+
if c == '='
|
121
|
+
skip_blank
|
122
|
+
case (c = @scanner.get_byte)
|
123
|
+
# example: foo="bar" || foo="ba\"zaar" || foo="bar
|
124
|
+
when QUOT
|
135
125
|
value = parse_attribute_value c
|
136
|
-
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar'
|
137
|
-
|
126
|
+
# example: foo='bar' || foo='ba\'zaar' || foo='ba"zaar' || foo='bar
|
127
|
+
when APOS
|
138
128
|
value = parse_attribute_value c
|
139
|
-
|
129
|
+
single_quoted = true unless value.start_with? APOS
|
140
130
|
# example: foo=,
|
141
|
-
|
131
|
+
when @delimiter
|
132
|
+
value = ''
|
133
|
+
@scanner.unscan
|
134
|
+
# example: foo= (at eos)
|
135
|
+
when nil
|
142
136
|
value = ''
|
143
|
-
# example: foo=bar
|
137
|
+
# example: foo=bar || foo=None
|
144
138
|
else
|
145
139
|
value = %(#{c}#{scan_to_delimiter})
|
146
140
|
return true if value == 'None'
|
147
141
|
end
|
142
|
+
# example: foo bar
|
143
|
+
else
|
144
|
+
name = %(#{name}#{' ' * skipped}#{c}#{scan_to_delimiter})
|
148
145
|
end
|
146
|
+
# example: =foo= || !foo
|
147
|
+
else
|
148
|
+
name = %(#{c}#{scan_to_delimiter})
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
152
|
if value
|
153
|
-
# example: options="opt1,opt2,opt3"
|
154
|
-
# opts is an alias for options
|
153
|
+
# example: options="opt1,opt2,opt3" || opts="opts1,opt2,opt3"
|
155
154
|
case name
|
156
155
|
when 'options', 'opts'
|
157
156
|
if value.include? ','
|
@@ -161,7 +160,7 @@ class AttributeList
|
|
161
160
|
@attributes[%(#{value}-option)] = '' unless value.empty?
|
162
161
|
end
|
163
162
|
else
|
164
|
-
if
|
163
|
+
if single_quoted && @block
|
165
164
|
case name
|
166
165
|
when 'title', 'reftext'
|
167
166
|
@attributes[name] = value
|
@@ -173,33 +172,26 @@ class AttributeList
|
|
173
172
|
end
|
174
173
|
end
|
175
174
|
else
|
176
|
-
|
175
|
+
name = @block.apply_subs name if single_quoted && @block
|
177
176
|
if (positional_attr_name = positional_attrs[index])
|
178
|
-
@attributes[positional_attr_name] =
|
177
|
+
@attributes[positional_attr_name] = name
|
179
178
|
end
|
180
|
-
# QUESTION should we
|
181
|
-
@attributes[index + 1] =
|
182
|
-
# QUESTION should we assign the resolved name as an attribute?
|
183
|
-
#@attributes[resolved_name] = nil
|
179
|
+
# QUESTION should we assign the positional key even when it's claimed by a positional attribute?
|
180
|
+
@attributes[index + 1] = name
|
184
181
|
end
|
185
182
|
|
186
|
-
|
183
|
+
continue
|
187
184
|
end
|
188
185
|
|
189
186
|
def parse_attribute_value quote
|
190
187
|
# empty quoted value
|
191
|
-
if @scanner.peek
|
188
|
+
if (@scanner.peek 1) == quote
|
192
189
|
@scanner.get_byte
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
if (value = scan_to_quote quote)
|
190
|
+
''
|
191
|
+
elsif (value = scan_to_quote quote)
|
197
192
|
@scanner.get_byte
|
198
|
-
|
199
|
-
|
200
|
-
else
|
201
|
-
value
|
202
|
-
end
|
193
|
+
(value.include? BACKSLASH) ? (value.gsub EscapedQuotes[quote], quote) : value
|
194
|
+
# leading quote only
|
203
195
|
else
|
204
196
|
%(#{quote}#{scan_to_delimiter})
|
205
197
|
end
|
@@ -222,7 +214,7 @@ class AttributeList
|
|
222
214
|
end
|
223
215
|
|
224
216
|
def scan_to_quote quote
|
225
|
-
@scanner.scan
|
217
|
+
@scanner.scan BoundaryRx[quote]
|
226
218
|
end
|
227
219
|
end
|
228
220
|
end
|
@@ -42,6 +42,8 @@ module Asciidoctor
|
|
42
42
|
non_posix_env = ::File::ALT_SEPARATOR == RS
|
43
43
|
err = @err || $stderr
|
44
44
|
show_timings = false
|
45
|
+
# NOTE in Ruby 2.7, RubyGems sets SOURCE_DATE_EPOCH if it's not set
|
46
|
+
::ENV.delete 'SOURCE_DATE_EPOCH' if (::ENV.key? 'IGNORE_SOURCE_DATE_EPOCH') && (::Gem.respond_to? :source_date_epoch)
|
45
47
|
|
46
48
|
@options.map do |key, val|
|
47
49
|
case key
|