asciidoctor 1.5.8 → 2.0.0.rc.1
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 +162 -17
- data/LICENSE +1 -1
- data/README-de.adoc +12 -13
- data/README-fr.adoc +11 -12
- data/README-jp.adoc +11 -12
- data/README-zh_CN.adoc +12 -13
- data/README.adoc +6 -7
- data/asciidoctor.gemspec +19 -24
- data/bin/asciidoctor +5 -4
- data/data/reference/syntax.adoc +283 -0
- data/data/stylesheets/asciidoctor-default.css +56 -52
- data/data/stylesheets/coderay-asciidoctor.css +7 -9
- data/lib/asciidoctor.rb +171 -232
- data/lib/asciidoctor/abstract_block.rb +96 -105
- data/lib/asciidoctor/abstract_node.rb +118 -139
- data/lib/asciidoctor/attribute_list.rb +10 -14
- data/lib/asciidoctor/block.rb +20 -19
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/cli/invoker.rb +14 -21
- data/lib/asciidoctor/cli/options.rb +64 -54
- data/lib/asciidoctor/converter.rb +357 -185
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +604 -640
- data/lib/asciidoctor/converter/html5.rb +949 -963
- data/lib/asciidoctor/converter/manpage.rb +569 -548
- data/lib/asciidoctor/converter/template.rb +231 -272
- data/lib/asciidoctor/core_ext.rb +5 -18
- data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
- data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
- data/lib/asciidoctor/document.rb +399 -377
- data/lib/asciidoctor/extensions.rb +72 -140
- data/lib/asciidoctor/helpers.rb +122 -83
- data/lib/asciidoctor/inline.rb +5 -1
- data/lib/asciidoctor/list.rb +13 -11
- data/lib/asciidoctor/logging.rb +17 -16
- data/lib/asciidoctor/parser.rb +390 -423
- data/lib/asciidoctor/path_resolver.rb +10 -5
- data/lib/asciidoctor/reader.rb +286 -263
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/section.rb +9 -8
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +364 -509
- data/lib/asciidoctor/syntax_highlighter.rb +238 -0
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
- data/lib/asciidoctor/table.rb +73 -66
- data/lib/asciidoctor/timings.rb +4 -2
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/man/asciidoctor.1 +19 -15
- data/man/asciidoctor.adoc +14 -12
- metadata +69 -216
- data/CONTRIBUTING.adoc +0 -185
- data/Gemfile +0 -60
- data/Rakefile +0 -129
- data/bin/asciidoctor-safe +0 -15
- data/features/open_block.feature +0 -92
- data/features/pass_block.feature +0 -66
- data/features/step_definitions.rb +0 -49
- data/features/text_formatting.feature +0 -57
- data/features/xref.feature +0 -1039
- data/lib/asciidoctor/converter/base.rb +0 -59
- data/lib/asciidoctor/converter/docbook45.rb +0 -93
- data/lib/asciidoctor/converter/factory.rb +0 -226
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
- data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
- data/test/api_test.rb +0 -1240
- data/test/attribute_list_test.rb +0 -242
- data/test/attributes_test.rb +0 -1623
- data/test/blocks_test.rb +0 -3870
- data/test/converter_test.rb +0 -470
- data/test/document_test.rb +0 -1853
- data/test/extensions_test.rb +0 -1560
- data/test/fixtures/asciidoc_index.txt +0 -521
- data/test/fixtures/basic-docinfo-footer.html +0 -6
- data/test/fixtures/basic-docinfo-footer.xml +0 -8
- data/test/fixtures/basic-docinfo.html +0 -1
- data/test/fixtures/basic-docinfo.xml +0 -4
- data/test/fixtures/basic.asciidoc +0 -5
- data/test/fixtures/chapter-a.adoc +0 -3
- data/test/fixtures/child-include.adoc +0 -5
- data/test/fixtures/circle.svg +0 -9
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
- data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
- data/test/fixtures/docinfo-footer.html +0 -1
- data/test/fixtures/docinfo-footer.xml +0 -9
- data/test/fixtures/docinfo.html +0 -1
- data/test/fixtures/docinfo.xml +0 -3
- data/test/fixtures/doctime-localtime.adoc +0 -2
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +0 -13
- data/test/fixtures/file-with-missing-include.adoc +0 -1
- data/test/fixtures/grandchild-include.adoc +0 -3
- data/test/fixtures/hello-asciidoctor.pdf +0 -69
- data/test/fixtures/include-file.asciidoc +0 -24
- data/test/fixtures/include-file.jsx +0 -8
- data/test/fixtures/include-file.ml +0 -3
- data/test/fixtures/include-file.xml +0 -5
- data/test/fixtures/lists.adoc +0 -96
- data/test/fixtures/master.adoc +0 -5
- data/test/fixtures/mismatched-end-tag.adoc +0 -7
- data/test/fixtures/other-chapters.adoc +0 -11
- data/test/fixtures/outer-include.adoc +0 -5
- data/test/fixtures/parent-include-restricted.adoc +0 -5
- data/test/fixtures/parent-include.adoc +0 -5
- data/test/fixtures/sample.asciidoc +0 -30
- data/test/fixtures/section-a.adoc +0 -4
- data/test/fixtures/stylesheets/custom.css +0 -3
- data/test/fixtures/subdir/index.adoc +0 -3
- data/test/fixtures/subdir/inner-include.adoc +0 -3
- data/test/fixtures/subdir/middle-include.adoc +0 -5
- data/test/fixtures/subs-docinfo.html +0 -2
- data/test/fixtures/subs.adoc +0 -6
- data/test/fixtures/tagged-class-enclosed.rb +0 -25
- data/test/fixtures/tagged-class.rb +0 -23
- data/test/fixtures/tip.gif +0 -0
- data/test/fixtures/unclosed-tag.adoc +0 -3
- data/test/fixtures/unexpected-end-tag.adoc +0 -4
- data/test/invoker_test.rb +0 -745
- data/test/links_test.rb +0 -855
- data/test/lists_test.rb +0 -5151
- data/test/logger_test.rb +0 -211
- data/test/manpage_test.rb +0 -660
- data/test/options_test.rb +0 -262
- data/test/paragraphs_test.rb +0 -562
- data/test/parser_test.rb +0 -742
- data/test/paths_test.rb +0 -395
- data/test/preamble_test.rb +0 -173
- data/test/reader_test.rb +0 -2161
- data/test/sections_test.rb +0 -3575
- data/test/substitutions_test.rb +0 -2066
- data/test/tables_test.rb +0 -2036
- data/test/test_helper.rb +0 -447
- data/test/text_test.rb +0 -309
@@ -1,51 +1,57 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
class AbstractBlock < AbstractNode
|
4
|
-
# Public: Get the Array of
|
4
|
+
# Public: Get the Array of {AbstractBlock} child blocks for this block. Only applies if content model is :compound.
|
5
5
|
attr_reader :blocks
|
6
6
|
|
7
|
-
# Public: Set the caption for this block
|
7
|
+
# Public: Set the caption for this block.
|
8
8
|
attr_writer :caption
|
9
9
|
|
10
|
-
# Public:
|
10
|
+
# Public: Describes the type of content this block accepts and how it should be converted. Acceptable values are:
|
11
|
+
# * :compound - this block contains other blocks
|
12
|
+
# * :simple - this block holds a paragraph of prose that receives normal substitutions
|
13
|
+
# * :verbatim - this block holds verbatim text (displayed "as is") that receives verbatim substitutions
|
14
|
+
# * :raw - this block holds unprocessed content passed directly to the output with no sustitutions applied
|
15
|
+
# * :empty - this block has no content
|
11
16
|
attr_accessor :content_model
|
12
17
|
|
13
|
-
# Public: Set the Integer level of this Section or the Section
|
18
|
+
# Public: Set the Integer level of this {Section} or the level of the Section to which this {AbstractBlock} belongs.
|
14
19
|
attr_accessor :level
|
15
20
|
|
16
|
-
# Public: Get/Set the numeral of this block (if section, relative to parent, otherwise absolute)
|
17
|
-
# Only assigned to section if automatic section numbering is enabled
|
18
|
-
# Only assigned to formal block (block with title) if corresponding caption attribute is present
|
21
|
+
# Public: Get/Set the numeral of this block (if section, relative to parent, otherwise absolute).
|
22
|
+
# Only assigned to section if automatic section numbering is enabled.
|
23
|
+
# Only assigned to formal block (block with title) if corresponding caption attribute is present.
|
19
24
|
attr_accessor :numeral
|
20
25
|
|
21
|
-
# Deprecated: Legacy property to get/set the numeral of this block
|
26
|
+
# Deprecated: Legacy property to get/set the numeral of this block.
|
22
27
|
alias number numeral
|
23
28
|
alias number= numeral=
|
24
29
|
|
25
|
-
# Public: Gets/Sets the location in the AsciiDoc source where this block begins
|
30
|
+
# Public: Gets/Sets the location in the AsciiDoc source where this block begins.
|
26
31
|
attr_accessor :source_location
|
27
32
|
|
28
33
|
# Public: Get/Set the String style (block type qualifier) for this block.
|
29
34
|
attr_accessor :style
|
30
35
|
|
31
|
-
# Public: Substitutions to be applied to content in this block
|
36
|
+
# Public: Substitutions to be applied to content in this block.
|
32
37
|
attr_reader :subs
|
33
38
|
|
39
|
+
# Internal: Set the default subs applied to this block; used during block creation
|
40
|
+
attr_writer :default_subs
|
41
|
+
|
34
42
|
def initialize parent, context, opts = {}
|
35
43
|
super
|
36
44
|
@content_model = :compound
|
37
45
|
@blocks = []
|
38
46
|
@subs = []
|
39
|
-
@id = @title = @
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@
|
47
|
+
@id = @title = @caption = @numeral = @style = @default_subs = @source_location = nil
|
48
|
+
case context
|
49
|
+
when :document, :section
|
50
|
+
@level = @next_section_index = 0
|
51
|
+
@next_section_ordinal = 1
|
44
52
|
else
|
45
|
-
@level = nil
|
53
|
+
@level = AbstractBlock === parent ? parent.level : nil
|
46
54
|
end
|
47
|
-
@next_section_index = 0
|
48
|
-
@next_section_ordinal = 1
|
49
55
|
end
|
50
56
|
|
51
57
|
def block?
|
@@ -101,10 +107,10 @@ class AbstractBlock < AbstractNode
|
|
101
107
|
#
|
102
108
|
# Examples
|
103
109
|
#
|
104
|
-
# block = Block.new(parent, :preamble, :
|
110
|
+
# block = Block.new(parent, :preamble, content_model: :compound)
|
105
111
|
#
|
106
|
-
# block << Block.new(block, :paragraph, :
|
107
|
-
# block << Block.new(block, :paragraph, :
|
112
|
+
# block << Block.new(block, :paragraph, source: 'p1')
|
113
|
+
# block << Block.new(block, :paragraph, source: 'p2')
|
108
114
|
# block.blocks?
|
109
115
|
# # => true
|
110
116
|
# block.blocks.size
|
@@ -170,56 +176,6 @@ class AbstractBlock < AbstractNode
|
|
170
176
|
|
171
177
|
alias query find_by
|
172
178
|
|
173
|
-
# Internal: Performs the work for find_by, but does not handle the StopIteration exception.
|
174
|
-
def find_by_internal selector = {}, result = [], &block
|
175
|
-
if ((any_context = !(context_selector = selector[:context])) || context_selector == @context) &&
|
176
|
-
(!(style_selector = selector[:style]) || style_selector == @style) &&
|
177
|
-
(!(role_selector = selector[:role]) || (has_role? role_selector)) &&
|
178
|
-
(!(id_selector = selector[:id]) || id_selector == @id)
|
179
|
-
if id_selector
|
180
|
-
result.replace block_given? ? ((yield self) ? [self] : []) : [self]
|
181
|
-
raise ::StopIteration
|
182
|
-
elsif block_given?
|
183
|
-
if (verdict = yield self)
|
184
|
-
case verdict
|
185
|
-
when :skip_children
|
186
|
-
result << self
|
187
|
-
return result
|
188
|
-
when :skip
|
189
|
-
return result
|
190
|
-
else
|
191
|
-
result << self
|
192
|
-
end
|
193
|
-
end
|
194
|
-
else
|
195
|
-
result << self
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
# process document header as a section if present
|
200
|
-
if @context == :document && (any_context || context_selector == :section) && header?
|
201
|
-
@header.find_by_internal selector, result, &block
|
202
|
-
end
|
203
|
-
|
204
|
-
unless context_selector == :document # optimization
|
205
|
-
# yuck, dlist is a special case
|
206
|
-
if @context == :dlist
|
207
|
-
if any_context || context_selector != :section # optimization
|
208
|
-
@blocks.flatten.each do |li|
|
209
|
-
# NOTE the list item of a dlist can be nil, so we have to check
|
210
|
-
li.find_by_internal selector, result, &block if li
|
211
|
-
end
|
212
|
-
end
|
213
|
-
elsif
|
214
|
-
@blocks.each do |b|
|
215
|
-
next if (context_selector == :section && b.context != :section) # optimization
|
216
|
-
b.find_by_internal selector, result, &block
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
result
|
221
|
-
end
|
222
|
-
|
223
179
|
# Move to the next adjacent block in document order. If the current block is the last
|
224
180
|
# item in a list, this method will return the following sibling of the list block.
|
225
181
|
def next_adjacent_block
|
@@ -234,12 +190,12 @@ class AbstractBlock < AbstractNode
|
|
234
190
|
#
|
235
191
|
# doc << (sect1 = Section.new doc, 1)
|
236
192
|
# sect1.title = 'Section 1'
|
237
|
-
# para1 = Block.new sect1, :paragraph, :
|
238
|
-
# para2 = Block.new sect1, :paragraph, :
|
193
|
+
# para1 = Block.new sect1, :paragraph, source: 'Paragraph 1'
|
194
|
+
# para2 = Block.new sect1, :paragraph, source: 'Paragraph 2'
|
239
195
|
# sect1 << para1 << para2
|
240
196
|
# sect1 << (sect1_1 = Section.new sect1, 2)
|
241
197
|
# sect1_1.title = 'Section 1.1'
|
242
|
-
# sect1_1 << (Block.new sect1_1, :paragraph, :
|
198
|
+
# sect1_1 << (Block.new sect1_1, :paragraph, source: 'Paragraph 3')
|
243
199
|
# sect1.blocks?
|
244
200
|
# # => true
|
245
201
|
# sect1.blocks.size
|
@@ -318,7 +274,7 @@ class AbstractBlock < AbstractNode
|
|
318
274
|
# Returns the converted String title for this Block, or nil if the source title is falsy
|
319
275
|
def title
|
320
276
|
# prevent substitutions from being applied to title multiple times
|
321
|
-
@
|
277
|
+
@converted_title ||= @title && (apply_title_subs @title)
|
322
278
|
end
|
323
279
|
|
324
280
|
# Public: A convenience method that checks whether the title of this block is defined.
|
@@ -332,7 +288,8 @@ class AbstractBlock < AbstractNode
|
|
332
288
|
#
|
333
289
|
# Returns the new String title assigned to this Block
|
334
290
|
def title= val
|
335
|
-
@
|
291
|
+
@converted_title = nil
|
292
|
+
@title = val
|
336
293
|
end
|
337
294
|
|
338
295
|
# Public: A convenience method that checks whether the specified
|
@@ -379,7 +336,7 @@ class AbstractBlock < AbstractNode
|
|
379
336
|
elsif xrefstyle && @title && @caption
|
380
337
|
case xrefstyle
|
381
338
|
when 'full'
|
382
|
-
quoted_title =
|
339
|
+
quoted_title = sub_placeholder (sub_quotes @document.compat_mode ? %q(``%s'') : '"`%s`"'), title
|
383
340
|
if @numeral && (prefix = @document.attributes[@context == :image ? 'figure-caption' : %(#{@context}-caption)])
|
384
341
|
%(#{prefix} #{@numeral}, #{quoted_title})
|
385
342
|
else
|
@@ -477,35 +434,69 @@ class AbstractBlock < AbstractNode
|
|
477
434
|
end
|
478
435
|
end
|
479
436
|
|
480
|
-
#
|
481
|
-
=
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
437
|
+
# Internal: Performs the work for find_by, but does not handle the StopIteration exception.
|
438
|
+
protected def find_by_internal selector = {}, result = [], &block
|
439
|
+
if ((any_context = (context_selector = selector[:context]) ? nil : true) || context_selector == @context) &&
|
440
|
+
(!(style_selector = selector[:style]) || style_selector == @style) &&
|
441
|
+
(!(role_selector = selector[:role]) || (has_role? role_selector)) &&
|
442
|
+
(!(id_selector = selector[:id]) || id_selector == @id)
|
443
|
+
if id_selector
|
444
|
+
block_given? && !(yield self) ? result.clear : (result.replace [self])
|
445
|
+
raise ::StopIteration
|
446
|
+
elsif block_given?
|
447
|
+
if (verdict = yield self)
|
448
|
+
case verdict
|
449
|
+
when :skip_children
|
450
|
+
result << self
|
451
|
+
return result
|
452
|
+
when :skip
|
453
|
+
return result
|
454
|
+
else
|
455
|
+
result << self
|
456
|
+
end
|
457
|
+
end
|
458
|
+
else
|
459
|
+
result << self
|
460
|
+
end
|
495
461
|
end
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
462
|
+
case @context
|
463
|
+
when :document
|
464
|
+
unless context_selector == :document
|
465
|
+
# process document header as a section, if present
|
466
|
+
if header? && (any_context || context_selector == :section)
|
467
|
+
@header.find_by_internal selector, result, &block
|
468
|
+
end
|
469
|
+
@blocks.each do |b|
|
470
|
+
next if (context_selector == :section && b.context != :section) # optimization
|
471
|
+
b.find_by_internal selector, result, &block
|
472
|
+
end
|
473
|
+
end
|
474
|
+
when :dlist
|
475
|
+
# dlist has different structure than other blocks
|
476
|
+
if any_context || context_selector != :section # optimization
|
477
|
+
# NOTE the list item of a dlist can be nil, so we have to check
|
478
|
+
@blocks.flatten.each {|b| b.find_by_internal selector, result, &block if b }
|
479
|
+
end
|
480
|
+
when :table
|
481
|
+
if selector[:traverse_documents]
|
482
|
+
rows.head.each {|r| r.each {|c| c.find_by_internal selector, result, &block } }
|
483
|
+
selector = selector.merge context: :document if context_selector == :inner_document
|
484
|
+
(rows.body + rows.foot).each do |r|
|
485
|
+
r.each do |c|
|
486
|
+
c.find_by_internal selector, result, &block
|
487
|
+
c.inner_document.find_by_internal selector, result, &block if c.style == :asciidoc
|
488
|
+
end
|
489
|
+
end
|
490
|
+
else
|
491
|
+
(rows.head + rows.body + rows.foot).each {|r| r.each {|c| c.find_by_internal selector, result, &block } }
|
492
|
+
end
|
493
|
+
else
|
494
|
+
@blocks.each do |b|
|
495
|
+
next if (context_selector == :section && b.context != :section) # optimization
|
496
|
+
b.find_by_internal selector, result, &block
|
497
|
+
end
|
506
498
|
end
|
507
|
-
|
499
|
+
result
|
508
500
|
end
|
509
|
-
=end
|
510
501
|
end
|
511
502
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# Public: An abstract base class that provides state and methods for managing a
|
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 Logging
|
8
|
-
include Substitutors
|
7
|
+
include Substitutors, Logging
|
9
8
|
|
10
9
|
# Public: Get the Hash of attributes for this node
|
11
10
|
attr_reader :attributes
|
@@ -16,13 +15,13 @@ class AbstractNode
|
|
16
15
|
# Public: Get the Asciidoctor::Document to which this node belongs
|
17
16
|
attr_reader :document
|
18
17
|
|
19
|
-
# Public: Get/Set the id of this node
|
18
|
+
# Public: Get/Set the String id of this node
|
20
19
|
attr_accessor :id
|
21
20
|
|
22
21
|
# Public: Get the String name of this node
|
23
22
|
attr_reader :node_name
|
24
23
|
|
25
|
-
# Public: Get the
|
24
|
+
# Public: Get the AbstractBlock parent element of this node
|
26
25
|
attr_reader :parent
|
27
26
|
|
28
27
|
def initialize parent, context, opts = {}
|
@@ -39,7 +38,7 @@ class AbstractNode
|
|
39
38
|
@node_name = (@context = context).to_s
|
40
39
|
# QUESTION are we correct in duplicating the attributes (seems to be just as fast)
|
41
40
|
@attributes = (opts.key? :attributes) ? opts[:attributes].dup : {}
|
42
|
-
@passthroughs =
|
41
|
+
@passthroughs = []
|
43
42
|
end
|
44
43
|
|
45
44
|
# Public: Returns whether this {AbstractNode} is an instance of {Block}
|
@@ -75,51 +74,43 @@ class AbstractNode
|
|
75
74
|
@parent, @document = parent, parent.document
|
76
75
|
end
|
77
76
|
|
78
|
-
# Public: Get the value of the specified attribute
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# this node and return the value of the attribute if found.
|
82
|
-
# this node is
|
83
|
-
# Document node and return
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
# return a Boolean indicating whether the attribute exists and, if a
|
114
|
-
# comparison value is specified, whether the value of the attribute matches
|
115
|
-
# the comparison value
|
116
|
-
def attr? name, expect_val = nil, inherit = true
|
117
|
-
name = name.to_s
|
118
|
-
# NOTE if @parent is set, it means @document is also set
|
119
|
-
if expect_val.nil?
|
120
|
-
(@attributes.key? name) || (inherit && @parent && (@document.attributes.key? name))
|
77
|
+
# Public: Get the value of the specified attribute. If the attribute is not found on this node, fallback_name is set,
|
78
|
+
# and this node is not the Document node, get the value of the specified attribute from the Document node.
|
79
|
+
#
|
80
|
+
# Look for the specified attribute in the attributes on this node and return the value of the attribute, if found.
|
81
|
+
# Otherwise, if fallback_name is set (default: same as name) and this node is not the Document node, look for that
|
82
|
+
# attribute on the Document node and return its value, if found. Otherwise, return the default value (default: nil).
|
83
|
+
#
|
84
|
+
# name - The String or Symbol name of the attribute to resolve.
|
85
|
+
# default_value - The Object value to return if the attribute is not found (default: nil).
|
86
|
+
# fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
|
87
|
+
# this node (default: same as name).
|
88
|
+
#
|
89
|
+
# Returns the [Object] value (typically a String) of the attribute or default_value if the attribute is not found.
|
90
|
+
def attr name, default_value = nil, fallback_name = nil
|
91
|
+
@attributes[name.to_s] || (fallback_name && @parent && @document.attributes[(fallback_name == true ? name : fallback_name).to_s] || default_value)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Public: Check if the specified attribute is defined using the same logic as {#attr}, optionally performing a
|
95
|
+
# comparison with the expected value if specified.
|
96
|
+
#
|
97
|
+
# Look for the specified attribute in the attributes on this node. If not found, fallback_name is specified (default:
|
98
|
+
# same as name), and this node is not the Document node, look for that attribute on the Document node. In either case,
|
99
|
+
# if the attribute is found, and the comparison value is truthy, return whether the two values match. Otherwise,
|
100
|
+
# return whether the attribute was found.
|
101
|
+
#
|
102
|
+
# name - The String or Symbol name of the attribute to resolve.
|
103
|
+
# expected_value - The expected Object value of the attribute (default: nil).
|
104
|
+
# fallback_name - The String or Symbol of the attribute to resolve on the Document if the attribute is not found on
|
105
|
+
# this node (default: same as name).
|
106
|
+
#
|
107
|
+
# Returns a [Boolean] indicating whether the attribute exists and, if a truthy comparison value is specified, whether
|
108
|
+
# the value of the attribute matches the comparison value.
|
109
|
+
def attr? name, expected_value = nil, fallback_name = nil
|
110
|
+
if expected_value
|
111
|
+
expected_value == (@attributes[name.to_s] || (fallback_name && @parent ? @document.attributes[(fallback_name == true ? name : fallback_name).to_s] : nil))
|
121
112
|
else
|
122
|
-
|
113
|
+
(@attributes.key? name.to_s) || (fallback_name && @parent ? (@document.attributes.key? (fallback_name == true ? name : fallback_name).to_s) : false)
|
123
114
|
end
|
124
115
|
end
|
125
116
|
|
@@ -153,34 +144,32 @@ class AbstractNode
|
|
153
144
|
# enabled on the current node.
|
154
145
|
#
|
155
146
|
# Check if the option is enabled. This method simply checks to see if the
|
156
|
-
#
|
147
|
+
# <name>-option attribute is defined on the current node.
|
157
148
|
#
|
158
149
|
# name - the String or Symbol name of the option
|
159
150
|
#
|
160
151
|
# return a Boolean indicating whether the option has been specified
|
161
|
-
def option?
|
162
|
-
@attributes
|
152
|
+
def option? name
|
153
|
+
@attributes[%(#{name}-option)] ? true : false
|
163
154
|
end
|
164
155
|
|
165
156
|
# Public: Set the specified option on this node.
|
166
157
|
#
|
167
|
-
# This method sets the specified option on this node
|
168
|
-
# It will add the name to the options attribute and set the <name>-option
|
169
|
-
# attribute.
|
158
|
+
# This method sets the specified option on this node by setting the <name>-option attribute.
|
170
159
|
#
|
171
160
|
# name - the String name of the option
|
172
161
|
#
|
173
|
-
#
|
174
|
-
def set_option
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
162
|
+
# Returns Nothing
|
163
|
+
def set_option name
|
164
|
+
@attributes[%(#{name}-option)] = ''
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# Public: Retrieve the Set of option names that are set on this node
|
169
|
+
#
|
170
|
+
# Returns a [Set] of option names
|
171
|
+
def options
|
172
|
+
::Set.new.tap {|accum| @attributes.each_key {|k| accum << (k.slice 0, k.length - 7) if k.to_s.end_with? '-option' } }
|
184
173
|
end
|
185
174
|
|
186
175
|
# Public: Update the attributes of this node with the new values in
|
@@ -197,59 +186,66 @@ class AbstractNode
|
|
197
186
|
nil
|
198
187
|
end
|
199
188
|
|
200
|
-
# Public:
|
189
|
+
# Public: Retrieves the space-separated String role for this node.
|
190
|
+
#
|
191
|
+
# Returns the role as a space-separated [String].
|
201
192
|
def role
|
202
|
-
@attributes['role']
|
193
|
+
@attributes['role']
|
203
194
|
end
|
204
195
|
|
205
|
-
# Public:
|
196
|
+
# Public: Retrieves the String role names for this node as an Array.
|
206
197
|
#
|
207
|
-
# Returns the role names as
|
198
|
+
# Returns the role names as a String [Array], which is empty if the role attribute is absent on this node.
|
208
199
|
def roles
|
209
|
-
(val = @attributes['role']
|
200
|
+
(val = @attributes['role']) ? val.split : []
|
210
201
|
end
|
211
202
|
|
212
|
-
# Public:
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
203
|
+
# Public: Checks if the role attribute is set on this node and, if an expected value is given, whether the
|
204
|
+
# space-separated role matches that value.
|
205
|
+
#
|
206
|
+
# expected_value - The expected String value of the role (optional, default: nil)
|
207
|
+
#
|
208
|
+
# Returns a [Boolean] indicating whether the role attribute is set on this node and, if an expected value is given,
|
209
|
+
# whether the space-separated role matches that value.
|
210
|
+
def role? expected_value = nil
|
211
|
+
expected_value ? expected_value == @attributes['role'] : (@attributes.key? 'role')
|
219
212
|
end
|
220
213
|
|
221
|
-
# Public:
|
222
|
-
#
|
223
|
-
|
214
|
+
# Public: Checks if the specified role is present in the list of roles for this node.
|
215
|
+
#
|
216
|
+
# name - The String name of the role to find.
|
217
|
+
#
|
218
|
+
# Returns a [Boolean] indicating whether this node has the specified role.
|
219
|
+
def has_role? name
|
224
220
|
# NOTE center + include? is faster than split + include?
|
225
|
-
(val = @attributes['role']
|
221
|
+
(val = @attributes['role']) ? (%( #{val} ).include? %( #{name} )) : false
|
226
222
|
end
|
227
223
|
|
228
|
-
# Public:
|
224
|
+
# Public: Adds the given role directly to this node.
|
229
225
|
#
|
230
|
-
# Returns a Boolean indicating whether the role was added.
|
231
|
-
def add_role
|
232
|
-
if (val = @attributes['role'])
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
226
|
+
# Returns a [Boolean] indicating whether the role was added.
|
227
|
+
def add_role name
|
228
|
+
if (val = @attributes['role'])
|
229
|
+
# NOTE center + include? is faster than split + include?
|
230
|
+
if %( #{val} ).include? %( #{name} )
|
231
|
+
false
|
232
|
+
else
|
233
|
+
@attributes['role'] = %(#{val} #{name})
|
234
|
+
true
|
235
|
+
end
|
238
236
|
else
|
239
|
-
@attributes['role'] =
|
237
|
+
@attributes['role'] = name
|
240
238
|
true
|
241
239
|
end
|
242
240
|
end
|
243
241
|
|
244
|
-
# Public:
|
242
|
+
# Public: Removes the given role directly from this node.
|
245
243
|
#
|
246
|
-
# Returns a Boolean indicating whether the role was removed.
|
247
|
-
def remove_role
|
248
|
-
if (val = @attributes['role']).
|
249
|
-
false
|
250
|
-
elsif (val = val.split).delete name
|
244
|
+
# Returns a [Boolean] indicating whether the role was removed.
|
245
|
+
def remove_role name
|
246
|
+
if (val = @attributes['role']) && ((val = val.split).delete name)
|
251
247
|
if val.empty?
|
252
|
-
@attributes.delete
|
248
|
+
@attributes.delete 'role'
|
253
249
|
else
|
254
250
|
@attributes['role'] = val.join ' '
|
255
251
|
end
|
@@ -273,12 +269,12 @@ class AbstractNode
|
|
273
269
|
# specified icon name.
|
274
270
|
#
|
275
271
|
# If the 'icon' attribute is set on this block, the name is ignored and the
|
276
|
-
# value of this attribute is used as the
|
272
|
+
# value of this attribute is used as the target image path. Otherwise,
|
277
273
|
# construct a target image path by concatenating the value of the 'iconsdir'
|
278
|
-
# attribute, the icon name and the value of the 'icontype' attribute
|
274
|
+
# attribute, the icon name, and the value of the 'icontype' attribute
|
279
275
|
# (defaulting to 'png').
|
280
276
|
#
|
281
|
-
# The target image path is then passed through the #image_uri() method.
|
277
|
+
# The target image path is then passed through the #image_uri() method. If
|
282
278
|
# the 'data-uri' attribute is set on the document, the image will be
|
283
279
|
# safely converted to a data URI.
|
284
280
|
#
|
@@ -289,7 +285,8 @@ class AbstractNode
|
|
289
285
|
# Returns A String reference or data URI for an icon image
|
290
286
|
def icon_uri name
|
291
287
|
if attr? 'icon'
|
292
|
-
|
288
|
+
# Ruby 2.3 requires the extra brackets around the attr method call
|
289
|
+
if (::File.extname (icon = (attr 'icon'))).empty?
|
293
290
|
# QUESTION should we be adding the extension if the icon is an absolute URI?
|
294
291
|
icon = %(#{icon}.#{@document.attr 'icontype', 'png'})
|
295
292
|
end
|
@@ -320,7 +317,7 @@ class AbstractNode
|
|
320
317
|
# Returns A String reference or data URI for the target image
|
321
318
|
def image_uri(target_image, asset_dir_key = 'imagesdir')
|
322
319
|
if (doc = @document).safe < SafeMode::SECURE && (doc.attr? 'data-uri')
|
323
|
-
if ((Helpers.uriish? target_image) && (target_image =
|
320
|
+
if ((Helpers.uriish? target_image) && (target_image = Helpers.encode_uri target_image)) ||
|
324
321
|
(asset_dir_key && (images_base = doc.attr asset_dir_key) && (Helpers.uriish? images_base) &&
|
325
322
|
(target_image = normalize_web_path target_image, images_base, false))
|
326
323
|
if doc.attr? 'allow-uri-read'
|
@@ -371,14 +368,14 @@ class AbstractNode
|
|
371
368
|
# QUESTION what if ext is empty?
|
372
369
|
mimetype = (ext == '.svg' ? 'image/svg+xml' : %(image/#{ext.slice 1, ext.length}))
|
373
370
|
if asset_dir_key
|
374
|
-
image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, :
|
371
|
+
image_path = normalize_system_path(target_image, @document.attr(asset_dir_key), nil, target_name: 'image')
|
375
372
|
else
|
376
373
|
image_path = normalize_system_path(target_image)
|
377
374
|
end
|
378
375
|
|
379
376
|
if ::File.readable? image_path
|
380
377
|
# NOTE base64 is autoloaded by reference to ::Base64
|
381
|
-
%(data:#{mimetype};base64,#{::Base64.strict_encode64 ::
|
378
|
+
%(data:#{mimetype};base64,#{::Base64.strict_encode64 ::File.binread image_path})
|
382
379
|
else
|
383
380
|
logger.warn %(image to embed not found or not readable: #{image_path})
|
384
381
|
%(data:#{mimetype};base64,)
|
@@ -404,17 +401,13 @@ class AbstractNode
|
|
404
401
|
# caching requires the open-uri-cached gem to be installed
|
405
402
|
# processing will be automatically aborted if these libraries can't be opened
|
406
403
|
Helpers.require_library 'open-uri/cached', 'open-uri-cached'
|
407
|
-
elsif
|
404
|
+
elsif !RUBY_ENGINE_OPAL
|
408
405
|
# autoload open-uri
|
409
406
|
::OpenURI
|
410
407
|
end
|
411
408
|
|
412
409
|
begin
|
413
|
-
mimetype =
|
414
|
-
bindata = open image_uri, 'rb' do |f|
|
415
|
-
mimetype = f.content_type
|
416
|
-
f.read
|
417
|
-
end
|
410
|
+
mimetype, bindata = ::OpenURI.open_uri(image_uri, URI_READ_MODE) {|f| [f.content_type, f.read] }
|
418
411
|
# NOTE base64 is autoloaded by reference to ::Base64
|
419
412
|
%(data:#{mimetype};base64,#{::Base64.strict_encode64 bindata})
|
420
413
|
rescue
|
@@ -432,8 +425,7 @@ class AbstractNode
|
|
432
425
|
# Delegates to normalize_system_path, with the start path set to the value of
|
433
426
|
# the base_dir instance variable on the Document object.
|
434
427
|
def normalize_asset_path(asset_ref, asset_name = 'path', autocorrect = true)
|
435
|
-
normalize_system_path(asset_ref, @document.base_dir, nil,
|
436
|
-
:target_name => asset_name, :recover => autocorrect)
|
428
|
+
normalize_system_path(asset_ref, @document.base_dir, nil, target_name: asset_name, recover: autocorrect)
|
437
429
|
end
|
438
430
|
|
439
431
|
# Public: Resolve and normalize a secure path from the target and start paths
|
@@ -486,7 +478,7 @@ class AbstractNode
|
|
486
478
|
# Returns the resolved [String] path
|
487
479
|
def normalize_web_path(target, start = nil, preserve_uri_target = true)
|
488
480
|
if preserve_uri_target && (Helpers.uriish? target)
|
489
|
-
|
481
|
+
Helpers.encode_uri target
|
490
482
|
else
|
491
483
|
@document.path_resolver.web_path target, start
|
492
484
|
end
|
@@ -507,15 +499,10 @@ class AbstractNode
|
|
507
499
|
# if the file does not exist.
|
508
500
|
def read_asset path, opts = {}
|
509
501
|
# remap opts for backwards compatibility
|
510
|
-
opts = { :
|
502
|
+
opts = { warn_on_failure: (opts != false) } unless ::Hash === opts
|
511
503
|
if ::File.readable? path
|
512
|
-
if
|
513
|
-
|
514
|
-
(Helpers.normalize_lines_array ::File.open(path, 'rb') {|f| f.each_line.to_a }).join LF
|
515
|
-
else
|
516
|
-
# QUESTION should we chomp or rstrip content?
|
517
|
-
::IO.read path
|
518
|
-
end
|
504
|
+
# QUESTION should we chomp content if normalize is false?
|
505
|
+
opts[:normalize] ? ((Helpers.prepare_source_string ::File.read path, mode: FILE_READ_MODE).join LF) : (::File.read path, mode: FILE_READ_MODE)
|
519
506
|
elsif opts[:warn_on_failure]
|
520
507
|
logger.warn %(#{(attr 'docfile') || '<stdin>'}: #{opts[:label] || 'file'} does not exist or cannot be read: #{path})
|
521
508
|
nil
|
@@ -546,10 +533,9 @@ class AbstractNode
|
|
546
533
|
Helpers.require_library 'open-uri/cached', 'open-uri-cached' if doc.attr? 'cache-uri'
|
547
534
|
begin
|
548
535
|
if opts[:normalize]
|
549
|
-
|
550
|
-
(Helpers.normalize_lines_array ::OpenURI.open_uri(target) {|f| f.each_line.to_a }).join LF
|
536
|
+
(Helpers.prepare_source_string ::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }).join LF
|
551
537
|
else
|
552
|
-
::OpenURI.open_uri(target) {|f| f.read }
|
538
|
+
::OpenURI.open_uri(target, URI_READ_MODE) {|f| f.read }
|
553
539
|
end
|
554
540
|
rescue
|
555
541
|
logger.warn %(could not retrieve contents of #{opts[:label] || 'asset'} at URI: #{target}) if opts.fetch :warn_on_failure, true
|
@@ -560,23 +546,16 @@ class AbstractNode
|
|
560
546
|
return
|
561
547
|
end
|
562
548
|
else
|
563
|
-
target = normalize_system_path target, opts[:start], nil, :
|
564
|
-
read_asset target, :
|
549
|
+
target = normalize_system_path target, opts[:start], nil, target_name: (opts[:label] || 'asset')
|
550
|
+
read_asset target, normalize: opts[:normalize], warn_on_failure: (opts.fetch :warn_on_failure, true), label: opts[:label]
|
565
551
|
end
|
566
552
|
end
|
567
553
|
|
568
|
-
#
|
569
|
-
#
|
570
|
-
# str - the String to encode
|
571
|
-
#
|
572
|
-
# Returns the String with all spaces replaced with %20.
|
573
|
-
def uri_encode_spaces str
|
574
|
-
(str.include? ' ') ? (str.gsub ' ', '%20') : str
|
575
|
-
end
|
576
|
-
|
577
|
-
# Public: Check whether the specified String is a URI by
|
554
|
+
# Deprecated: Check whether the specified String is a URI by
|
578
555
|
# matching it against the Asciidoctor::UriSniffRx regex.
|
579
556
|
#
|
557
|
+
# In use by Asciidoctor PDF
|
558
|
+
#
|
580
559
|
# @deprecated Use Helpers.uriish? instead
|
581
560
|
def is_uri? str
|
582
561
|
Helpers.uriish? str
|