asciidoctor 1.5.5 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +216 -1
  3. data/CONTRIBUTING.adoc +2 -2
  4. data/Gemfile +20 -1
  5. data/LICENSE.adoc +1 -1
  6. data/README-fr.adoc +4 -3
  7. data/README-jp.adoc +11 -10
  8. data/README-zh_CN.adoc +4 -3
  9. data/README.adoc +17 -202
  10. data/Rakefile +41 -25
  11. data/asciidoctor.gemspec +9 -10
  12. data/data/locale/attributes.adoc +216 -34
  13. data/data/stylesheets/asciidoctor-default.css +23 -16
  14. data/features/step_definitions.rb +15 -19
  15. data/features/xref.feature +584 -20
  16. data/lib/asciidoctor.rb +292 -278
  17. data/lib/asciidoctor/abstract_block.rb +155 -94
  18. data/lib/asciidoctor/abstract_node.rb +108 -94
  19. data/lib/asciidoctor/attribute_list.rb +30 -22
  20. data/lib/asciidoctor/block.rb +7 -7
  21. data/lib/asciidoctor/cli/invoker.rb +47 -34
  22. data/lib/asciidoctor/cli/options.rb +22 -11
  23. data/lib/asciidoctor/converter.rb +3 -3
  24. data/lib/asciidoctor/converter/base.rb +2 -2
  25. data/lib/asciidoctor/converter/composite.rb +1 -1
  26. data/lib/asciidoctor/converter/docbook45.rb +2 -2
  27. data/lib/asciidoctor/converter/docbook5.rb +132 -87
  28. data/lib/asciidoctor/converter/factory.rb +0 -1
  29. data/lib/asciidoctor/converter/html5.rb +116 -98
  30. data/lib/asciidoctor/converter/manpage.rb +51 -52
  31. data/lib/asciidoctor/converter/template.rb +47 -36
  32. data/lib/asciidoctor/core_ext.rb +8 -2
  33. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
  34. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
  35. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
  36. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
  37. data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
  38. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
  39. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
  40. data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
  41. data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
  42. data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
  43. data/lib/asciidoctor/document.rb +216 -213
  44. data/lib/asciidoctor/extensions.rb +318 -185
  45. data/lib/asciidoctor/helpers.rb +35 -35
  46. data/lib/asciidoctor/inline.rb +32 -1
  47. data/lib/asciidoctor/list.rb +22 -6
  48. data/lib/asciidoctor/parser.rb +1008 -1038
  49. data/lib/asciidoctor/path_resolver.rb +46 -50
  50. data/lib/asciidoctor/reader.rb +275 -251
  51. data/lib/asciidoctor/section.rb +86 -58
  52. data/lib/asciidoctor/stylesheets.rb +6 -6
  53. data/lib/asciidoctor/substitutors.rb +567 -649
  54. data/lib/asciidoctor/table.rb +163 -108
  55. data/lib/asciidoctor/version.rb +1 -1
  56. data/man/asciidoctor.1 +18 -16
  57. data/man/asciidoctor.adoc +15 -13
  58. data/test/attributes_test.rb +138 -22
  59. data/test/blocks_test.rb +377 -97
  60. data/test/converter_test.rb +13 -0
  61. data/test/document_test.rb +244 -34
  62. data/test/extensions_test.rb +409 -42
  63. data/test/fixtures/asciidoc_index.txt +521 -0
  64. data/test/fixtures/basic-docinfo-footer.html +6 -0
  65. data/test/fixtures/basic-docinfo-footer.xml +8 -0
  66. data/test/fixtures/basic-docinfo.html +1 -0
  67. data/test/fixtures/basic-docinfo.xml +4 -0
  68. data/test/fixtures/basic.asciidoc +5 -0
  69. data/test/fixtures/chapter-a.adoc +3 -0
  70. data/test/fixtures/child-include.adoc +5 -0
  71. data/test/fixtures/circle.svg +9 -0
  72. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
  73. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
  74. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
  75. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
  76. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
  77. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
  78. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
  79. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
  80. data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
  81. data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
  82. data/test/fixtures/docinfo-footer.html +1 -0
  83. data/test/fixtures/docinfo-footer.xml +9 -0
  84. data/test/fixtures/docinfo.html +1 -0
  85. data/test/fixtures/docinfo.xml +3 -0
  86. data/test/fixtures/dot.gif +0 -0
  87. data/test/fixtures/encoding.asciidoc +13 -0
  88. data/test/fixtures/grandchild-include.adoc +3 -0
  89. data/test/fixtures/hello-asciidoctor.pdf +69 -0
  90. data/test/fixtures/include-file.asciidoc +24 -0
  91. data/test/fixtures/include-file.ml +3 -0
  92. data/test/fixtures/include-file.xml +5 -0
  93. data/test/fixtures/master.adoc +5 -0
  94. data/test/fixtures/mismatched-end-tag.adoc +7 -0
  95. data/test/fixtures/parent-include-restricted.adoc +5 -0
  96. data/test/fixtures/parent-include.adoc +5 -0
  97. data/test/fixtures/sample.asciidoc +26 -0
  98. data/test/fixtures/stylesheets/custom.css +3 -0
  99. data/test/fixtures/subs-docinfo.html +2 -0
  100. data/test/fixtures/subs.adoc +7 -0
  101. data/test/fixtures/tagged-class-enclosed.rb +26 -0
  102. data/test/fixtures/tagged-class.rb +23 -0
  103. data/test/fixtures/tip.gif +0 -0
  104. data/test/invoker_test.rb +82 -4
  105. data/test/links_test.rb +312 -37
  106. data/test/lists_test.rb +204 -25
  107. data/test/manpage_test.rb +191 -4
  108. data/test/options_test.rb +18 -1
  109. data/test/paragraphs_test.rb +32 -7
  110. data/test/parser_test.rb +150 -30
  111. data/test/paths_test.rb +47 -13
  112. data/test/preamble_test.rb +1 -1
  113. data/test/reader_test.rb +366 -126
  114. data/test/sections_test.rb +203 -56
  115. data/test/substitutions_test.rb +339 -131
  116. data/test/tables_test.rb +315 -15
  117. data/test/test_helper.rb +400 -0
  118. data/test/text_test.rb +5 -5
  119. metadata +110 -22
@@ -8,18 +8,39 @@ end
8
8
  # - test negatives
9
9
  # - test role on every quote type
10
10
  context 'Substitutions' do
11
+ BACKSLASH = %(\x5c)
11
12
  context 'Dispatcher' do
12
13
  test 'apply normal substitutions' do
13
14
  para = block_from_string("[blue]_http://asciidoc.org[AsciiDoc]_ & [red]*Ruby*\n&#167; Making +++<u>documentation</u>+++ together +\nsince (C) {inception_year}.")
14
15
  para.document.attributes['inception_year'] = '2012'
15
- result = para.apply_normal_subs(para.lines)
16
+ result = para.apply_subs(para.source)
16
17
  assert_equal %{<em class="blue"><a href="http://asciidoc.org">AsciiDoc</a></em> &amp; <strong class="red">Ruby</strong>\n&#167; Making <u>documentation</u> together<br>\nsince &#169; 2012.}, result
17
18
  end
19
+
20
+ test 'should not drop trailing blank lines when performing substitutions' do
21
+ para = block_from_string %([%hardbreaks]\nthis\nis\n-> {program})
22
+ para.lines << ''
23
+ para.lines << ''
24
+ para.document.attributes['program'] = 'Asciidoctor'
25
+ result = para.apply_subs(para.lines)
26
+ assert_equal ['this<br>', 'is<br>', '&#8594; Asciidoctor<br>', '<br>', ''], result
27
+ result = para.apply_subs(para.lines * "\n")
28
+ assert_equal %(this<br>\nis<br>\n&#8594; Asciidoctor<br>\n<br>\n), result
29
+ end
30
+
31
+ test 'should expand subs passed to apply_subs when expand argument is set' do
32
+ para = block_from_string %({program}\n*bold*\n2 > 1)
33
+ para.document.attributes['program'] = 'Asciidoctor'
34
+ result = para.apply_subs para.lines, [:specialchars], true
35
+ assert_equal ['{program}', '*bold*', '2 &gt; 1'], result
36
+ result = para.apply_subs para.lines, [:none], true
37
+ assert_equal ['{program}', '*bold*', '2 > 1'], result
38
+ result = para.apply_subs para.lines, [:normal], true
39
+ assert_equal ['Asciidoctor', '<strong>bold</strong>', '2 &gt; 1'], result
40
+ end
18
41
  end
19
42
 
20
43
  context 'Quotes' do
21
- BACKSLASH = '\\'
22
-
23
44
  test 'single-line double-quoted string' do
24
45
  para = block_from_string(%q{``a few quoted words''}, :attributes => {'compat-mode' => ''})
25
46
  assert_equal '&#8220;a few quoted words&#8221;', para.sub_quotes(para.source)
@@ -222,10 +243,10 @@ context 'Substitutions' do
222
243
 
223
244
  test 'escaped single-quotes inside emphasized words are restored' do
224
245
  para = block_from_string(%('Here#{BACKSLASH}'s Johnny!'), :attributes => {'compat-mode' => ''})
225
- assert_equal %q(<em>Here's Johnny!</em>), para.apply_normal_subs(para.lines)
246
+ assert_equal %q(<em>Here's Johnny!</em>), para.apply_subs(para.source)
226
247
 
227
248
  para = block_from_string(%('Here#{BACKSLASH}'s Johnny!'))
228
- assert_equal %q('Here's Johnny!'), para.apply_normal_subs(para.lines)
249
+ assert_equal %q('Here's Johnny!'), para.apply_subs(para.source)
229
250
  end
230
251
 
231
252
  test 'single-line constrained emphasized underline variation string' do
@@ -243,67 +264,67 @@ context 'Substitutions' do
243
264
  assert_equal "<em>a few\nemphasized words</em>", para.sub_quotes(para.source)
244
265
  end
245
266
 
246
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
267
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
247
268
  test 'single-line constrained monospaced string' do
248
269
  para = block_from_string(%(`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
249
- assert_equal '<code>a few &lt;{monospaced}&gt; words</code>', para.apply_normal_subs(para.lines)
270
+ assert_equal '<code>a few &lt;{monospaced}&gt; words</code>', para.apply_subs(para.source)
250
271
 
251
272
  para = block_from_string(%(`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
252
- assert_equal '<code>a few &lt;monospaced&gt; words</code>', para.apply_normal_subs(para.lines)
273
+ assert_equal '<code>a few &lt;monospaced&gt; words</code>', para.apply_subs(para.source)
253
274
  end
254
275
 
255
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
276
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
256
277
  test 'single-line constrained monospaced string with role' do
257
278
  para = block_from_string(%([input]`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
258
- assert_equal '<code class="input">a few &lt;{monospaced}&gt; words</code>', para.apply_normal_subs(para.lines)
279
+ assert_equal '<code class="input">a few &lt;{monospaced}&gt; words</code>', para.apply_subs(para.source)
259
280
 
260
281
  para = block_from_string(%([input]`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
261
- assert_equal '<code class="input">a few &lt;monospaced&gt; words</code>', para.apply_normal_subs(para.lines)
282
+ assert_equal '<code class="input">a few &lt;monospaced&gt; words</code>', para.apply_subs(para.source)
262
283
  end
263
284
 
264
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
285
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
265
286
  test 'escaped single-line constrained monospaced string' do
266
287
  para = block_from_string(%(#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
267
- assert_equal '`a few &lt;monospaced&gt; words`', para.apply_normal_subs(para.lines)
288
+ assert_equal '`a few &lt;monospaced&gt; words`', para.apply_subs(para.source)
268
289
 
269
290
  para = block_from_string(%(#{BACKSLASH}`a few <monospaced> words`))
270
- assert_equal '`a few &lt;monospaced&gt; words`', para.apply_normal_subs(para.lines)
291
+ assert_equal '`a few &lt;monospaced&gt; words`', para.apply_subs(para.source)
271
292
  end
272
293
 
273
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
294
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
274
295
  test 'escaped single-line constrained monospaced string with role' do
275
296
  para = block_from_string(%([input]#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
276
- assert_equal '[input]`a few &lt;monospaced&gt; words`', para.apply_normal_subs(para.lines)
297
+ assert_equal '[input]`a few &lt;monospaced&gt; words`', para.apply_subs(para.source)
277
298
 
278
299
  para = block_from_string(%([input]#{BACKSLASH}`a few <monospaced> words`))
279
- assert_equal '[input]`a few &lt;monospaced&gt; words`', para.apply_normal_subs(para.lines)
300
+ assert_equal '[input]`a few &lt;monospaced&gt; words`', para.apply_subs(para.source)
280
301
  end
281
302
 
282
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
303
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
283
304
  test 'escaped role on single-line constrained monospaced string' do
284
305
  para = block_from_string(%(#{BACKSLASH}[input]`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
285
- assert_equal '[input]<code>a few &lt;monospaced&gt; words</code>', para.apply_normal_subs(para.lines)
306
+ assert_equal '[input]<code>a few &lt;monospaced&gt; words</code>', para.apply_subs(para.source)
286
307
 
287
308
  para = block_from_string(%(#{BACKSLASH}[input]`a few <monospaced> words`))
288
- assert_equal '[input]<code>a few &lt;monospaced&gt; words</code>', para.apply_normal_subs(para.lines)
309
+ assert_equal '[input]<code>a few &lt;monospaced&gt; words</code>', para.apply_subs(para.source)
289
310
  end
290
311
 
291
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
312
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
292
313
  test 'escaped role on escaped single-line constrained monospaced string' do
293
314
  para = block_from_string(%(#{BACKSLASH}[input]#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
294
- assert_equal %(#{BACKSLASH}[input]`a few &lt;monospaced&gt; words`), para.apply_normal_subs(para.lines)
315
+ assert_equal %(#{BACKSLASH}[input]`a few &lt;monospaced&gt; words`), para.apply_subs(para.source)
295
316
 
296
317
  para = block_from_string(%(#{BACKSLASH}[input]#{BACKSLASH}`a few <monospaced> words`))
297
- assert_equal %(#{BACKSLASH}[input]`a few &lt;monospaced&gt; words`), para.apply_normal_subs(para.lines)
318
+ assert_equal %(#{BACKSLASH}[input]`a few &lt;monospaced&gt; words`), para.apply_subs(para.source)
298
319
  end
299
320
 
300
- # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
321
+ # NOTE must use apply_subs because constrained monospaced is handled as a passthrough
301
322
  test 'multi-line constrained monospaced string' do
302
323
  para = block_from_string(%(`a few\n<{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
303
- assert_equal "<code>a few\n&lt;{monospaced}&gt; words</code>", para.apply_normal_subs(para.lines)
324
+ assert_equal "<code>a few\n&lt;{monospaced}&gt; words</code>", para.apply_subs(para.source)
304
325
 
305
326
  para = block_from_string(%(`a few\n<{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
306
- assert_equal "<code>a few\n&lt;monospaced&gt; words</code>", para.apply_normal_subs(para.lines)
327
+ assert_equal "<code>a few\n&lt;monospaced&gt; words</code>", para.apply_subs(para.source)
307
328
  end
308
329
 
309
330
  test 'single-line unconstrained strong chars' do
@@ -476,7 +497,7 @@ context 'Substitutions' do
476
497
 
477
498
  test 'does not confuse superscript and links with blank window shorthand' do
478
499
  para = block_from_string(%Q{http://localhost[Text^] on the 21^st^ and 22^nd^})
479
- assert_equal '<a href="http://localhost" target="_blank">Text</a> on the 21<sup>st</sup> and 22<sup>nd</sup>', para.content
500
+ assert_equal '<a href="http://localhost" target="_blank" rel="noopener">Text</a> on the 21<sup>st</sup> and 22<sup>nd</sup>', para.content
480
501
  end
481
502
 
482
503
  test 'single-line subscript chars' do
@@ -579,7 +600,7 @@ context 'Substitutions' do
579
600
  para = block_from_string('doc.writer@asciidoc.org')
580
601
  assert_equal %q{<a href="mailto:doc.writer@asciidoc.org">doc.writer@asciidoc.org</a>}, para.sub_macros(para.source)
581
602
  para = block_from_string('<doc.writer@asciidoc.org>')
582
- assert_equal %q{&lt;<a href="mailto:doc.writer@asciidoc.org">doc.writer@asciidoc.org</a>&gt;}, para.apply_normal_subs(para.lines)
603
+ assert_equal %q{&lt;<a href="mailto:doc.writer@asciidoc.org">doc.writer@asciidoc.org</a>&gt;}, para.apply_subs(para.source)
583
604
  para = block_from_string('author+website@4fs.no')
584
605
  assert_equal %q{<a href="mailto:author+website@4fs.no">author+website@4fs.no</a>}, para.sub_macros(para.source)
585
606
  para = block_from_string('john@domain.uk.co')
@@ -606,10 +627,21 @@ context 'Substitutions' do
606
627
  assert_equal %{<a href="http://google.com">Google\nHomepage</a>}, para.sub_macros(para.source)
607
628
  end
608
629
 
609
- test 'a multi-line raw url with attribute as text should be interpreted as a link with resolved attribute' do
630
+ test 'a single-line raw url with attribute as text should be interpreted as a link with resolved attribute' do
610
631
  para = block_from_string("http://google.com[{google_homepage}]")
611
632
  para.document.attributes['google_homepage'] = 'Google Homepage'
612
- assert_equal %q{<a href="http://google.com">Google Homepage</a>}, para.sub_macros(para.source)
633
+ assert_equal %q{<a href="http://google.com">Google Homepage</a>}, para.sub_macros(para.sub_attributes(para.source))
634
+ end
635
+
636
+ test 'should not resolve an escaped attribute in link text' do
637
+ {
638
+ 'http://google.com' => "http://google.com[#{BACKSLASH}{google_homepage}]",
639
+ 'http://google.com?q=,' => "link:http://google.com?q=,[#{BACKSLASH}{google_homepage}]"
640
+ }.each do |uri, macro|
641
+ para = block_from_string macro
642
+ para.document.attributes['google_homepage'] = 'Google Homepage'
643
+ assert_equal %(<a href="#{uri}">{google_homepage}</a>), para.sub_macros(para.sub_attributes(para.source))
644
+ end
613
645
  end
614
646
 
615
647
  test 'a single-line escaped raw url should not be interpreted as a link' do
@@ -637,6 +669,13 @@ context 'Substitutions' do
637
669
  assert_equal %{<span class="image"><img src="tiger.png" alt="Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
638
670
  end
639
671
 
672
+ test 'should encode special characters in alt text of inline image' do
673
+ input = 'A tiger\'s "roar" is < a bear\'s "growl"'
674
+ expected = 'A tiger&#8217;s &quot;roar&quot; is &lt; a bear&#8217;s &quot;growl&quot;'
675
+ output = (render_embedded_string %(image:tiger-roar.png[#{input}]), :doctype => :inline).gsub(/>\s+</, '><')
676
+ assert_equal %(<span class="image"><img src="tiger-roar.png" alt="#{expected}"></span>), output
677
+ end
678
+
640
679
  test 'an image macro with SVG image and text should be interpreted as an image with alt text' do
641
680
  para = block_from_string('image:tiger.svg[Tiger]')
642
681
  assert_equal %{<span class="image"><img src="tiger.svg" alt="Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
@@ -694,6 +733,18 @@ context 'Substitutions' do
694
733
  para.sub_macros(para.source).gsub(/>\s+</, '><')
695
734
  end
696
735
 
736
+ test 'rel=noopener should be added to an image with a link that targets the _blank window' do
737
+ para = block_from_string 'image:tiger.png[Tiger,link=http://en.wikipedia.org/wiki/Tiger,window=_blank]'
738
+ assert_equal %{<span class="image"><a class="image" href="http://en.wikipedia.org/wiki/Tiger" target="_blank" rel="noopener"><img src="tiger.png" alt="Tiger"></a></span>},
739
+ para.sub_macros(para.source).gsub(/>\s+</, '><')
740
+ end
741
+
742
+ test 'rel=noopener should be added to an image with a link that targets a named window when the noopener option is set' do
743
+ para = block_from_string 'image:tiger.png[Tiger,link=http://en.wikipedia.org/wiki/Tiger,window=name,opts=noopener]'
744
+ assert_equal %{<span class="image"><a class="image" href="http://en.wikipedia.org/wiki/Tiger" target="name" rel="noopener"><img src="tiger.png" alt="Tiger"></a></span>},
745
+ para.sub_macros(para.source).gsub(/>\s+</, '><')
746
+ end
747
+
697
748
  test 'a multi-line image macro with text and dimensions should be interpreted as an image with alt text and dimensions' do
698
749
  para = block_from_string(%(image:tiger.png[Another\nAwesome\nTiger, 200,\n100]))
699
750
  assert_equal %{<span class="image"><img src="tiger.png" alt="Another Awesome Tiger" width="200" height="100"></span>},
@@ -730,7 +781,29 @@ context 'Substitutions' do
730
781
  para.sub_macros(para.source).gsub(/>\s+</, '><')
731
782
  end
732
783
 
733
- test 'a block image macro should not be detected within paragraph text' do
784
+ test 'should match an inline image macro if target contains a space character' do
785
+ para = block_from_string(%(Beware of the image:big cats.png[] around here.))
786
+ assert_equal %(Beware of the <span class="image"><img src="big%20cats.png" alt="big cats"></span> around here.),
787
+ para.sub_macros(para.source).gsub(/>\s+</, '><')
788
+ end
789
+
790
+ test 'should not match an inline image macro if target contains an endline character' do
791
+ para = block_from_string(%(Fear not. There are no image:big\ncats.png[] around here.))
792
+ result = para.sub_macros(para.source)
793
+ assert !result.include?('<img ')
794
+ assert_includes result, %(image:big\ncats.png[])
795
+ end
796
+
797
+ test 'should not match an inline image macro if target begins or ends with space character' do
798
+ ['image: big cats.png[]', 'image:big cats.png []'].each do |input|
799
+ para = block_from_string %(Fear not. There are no #{input} around here.)
800
+ result = para.sub_macros(para.source)
801
+ assert !result.include?('<img ')
802
+ assert_includes result, input
803
+ end
804
+ end
805
+
806
+ test 'should not detect a block image macro found inline' do
734
807
  para = block_from_string(%(Not an inline image macro image::tiger.png[].))
735
808
  result = para.sub_macros(para.source)
736
809
  assert !result.include?('<img ')
@@ -770,8 +843,8 @@ context 'Substitutions' do
770
843
  test 'a single-line footnote macro should be registered and rendered as a footnote' do
771
844
  para = block_from_string('Sentence text footnote:[An example footnote.].')
772
845
  assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
773
- assert_equal 1, para.document.references[:footnotes].size
774
- footnote = para.document.references[:footnotes].first
846
+ assert_equal 1, para.document.catalog[:footnotes].size
847
+ footnote = para.document.catalog[:footnotes].first
775
848
  assert_equal 1, footnote.index
776
849
  assert footnote.id.nil?
777
850
  assert_equal 'An example footnote.', footnote.text
@@ -780,8 +853,8 @@ context 'Substitutions' do
780
853
  test 'a multi-line footnote macro should be registered and rendered as a footnote without endline' do
781
854
  para = block_from_string("Sentence text footnote:[An example footnote\nwith wrapped text.].")
782
855
  assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
783
- assert_equal 1, para.document.references[:footnotes].size
784
- footnote = para.document.references[:footnotes].first
856
+ assert_equal 1, para.document.catalog[:footnotes].size
857
+ footnote = para.document.catalog[:footnotes].first
785
858
  assert_equal 1, footnote.index
786
859
  assert footnote.id.nil?
787
860
  assert_equal "An example footnote with wrapped text.", footnote.text
@@ -790,8 +863,8 @@ context 'Substitutions' do
790
863
  test 'an escaped closing square bracket in a footnote should be unescaped when rendered' do
791
864
  para = block_from_string(%(footnote:[a #{BACKSLASH}] b].))
792
865
  assert_equal %(<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
793
- assert_equal 1, para.document.references[:footnotes].size
794
- footnote = para.document.references[:footnotes].first
866
+ assert_equal 1, para.document.catalog[:footnotes].size
867
+ footnote = para.document.catalog[:footnotes].first
795
868
  assert_equal "a ] b", footnote.text
796
869
  end
797
870
 
@@ -803,29 +876,29 @@ context 'Substitutions' do
803
876
  test 'a footnote macro may contain an escaped backslash' do
804
877
  para = block_from_string("footnote:[\\]]\nfootnote:[a \\] b]\nfootnote:[a \\]\\] b]")
805
878
  para.sub_macros(para.source)
806
- assert_equal 3, para.document.references[:footnotes].size
807
- footnote1 = para.document.references[:footnotes][0]
879
+ assert_equal 3, para.document.catalog[:footnotes].size
880
+ footnote1 = para.document.catalog[:footnotes][0]
808
881
  assert_equal ']', footnote1.text
809
- footnote2 = para.document.references[:footnotes][1]
882
+ footnote2 = para.document.catalog[:footnotes][1]
810
883
  assert_equal 'a ] b', footnote2.text
811
- footnote3 = para.document.references[:footnotes][2]
884
+ footnote3 = para.document.catalog[:footnotes][2]
812
885
  assert_equal 'a ]] b', footnote3.text
813
886
  end
814
887
 
815
888
  test 'a footnote macro may contain a link macro' do
816
- para = block_from_string('Share your code. footnote:[http://github.com[GitHub]]')
889
+ para = block_from_string('Share your code. footnote:[https://github.com[GitHub]]')
817
890
  assert_equal %(Share your code. <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
818
- assert_equal 1, para.document.references[:footnotes].size
819
- footnote1 = para.document.references[:footnotes][0]
820
- assert_equal '<a href="http://github.com">GitHub</a>', footnote1.text
891
+ assert_equal 1, para.document.catalog[:footnotes].size
892
+ footnote1 = para.document.catalog[:footnotes][0]
893
+ assert_equal '<a href="https://github.com">GitHub</a>', footnote1.text
821
894
  end
822
895
 
823
896
  test 'a footnote macro may contain a plain URL' do
824
897
  para = block_from_string %(the JLine footnote:[https://github.com/jline/jline2]\nlibrary.)
825
898
  result = para.sub_macros para.source
826
899
  assert_equal %(the JLine <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>\nlibrary.), result
827
- assert_equal 1, para.document.references[:footnotes].size
828
- fn1 = para.document.references[:footnotes].first
900
+ assert_equal 1, para.document.catalog[:footnotes].size
901
+ fn1 = para.document.catalog[:footnotes].first
829
902
  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
830
903
  end
831
904
 
@@ -833,25 +906,28 @@ context 'Substitutions' do
833
906
  para = block_from_string %(the JLine footnote:[https://github.com/jline/jline2];\nlibrary.)
834
907
  result = para.sub_macros para.source
835
908
  assert_equal %(the JLine <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>;\nlibrary.), result
836
- assert_equal 1, para.document.references[:footnotes].size
837
- fn1 = para.document.references[:footnotes].first
909
+ assert_equal 1, para.document.catalog[:footnotes].size
910
+ fn1 = para.document.catalog[:footnotes].first
838
911
  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
839
912
  end
840
913
 
841
914
  test 'a footnote macro may contain an xref macro' do
842
915
  # specialcharacters escaping is simulated
843
- para = block_from_string('text footnote:[&lt;&lt;_install,Install&gt;&gt;]')
916
+ para = block_from_string('text footnote:[&lt;&lt;_install,install&gt;&gt;]')
917
+ doc = para.document
918
+ doc.register :refs, ['_install', (Asciidoctor::Inline.new doc, :anchor, 'Install', :type => :ref, :target => '_install'), 'Install']
919
+ catalog = doc.catalog
844
920
  assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
845
- assert_equal 1, para.document.references[:footnotes].size
846
- footnote1 = para.document.references[:footnotes][0]
847
- assert_equal '<a href="#_install">Install</a>', footnote1.text
921
+ assert_equal 1, catalog[:footnotes].size
922
+ footnote1 = catalog[:footnotes][0]
923
+ assert_equal '<a href="#_install">install</a>', footnote1.text
848
924
  end
849
925
 
850
926
  test 'a footnote macro may contain an anchor macro' do
851
927
  para = block_from_string('text footnote:[a [[b\]\] \[[c\]\] d]')
852
928
  assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
853
- assert_equal 1, para.document.references[:footnotes].size
854
- footnote1 = para.document.references[:footnotes][0]
929
+ assert_equal 1, para.document.catalog[:footnotes].size
930
+ footnote1 = para.document.catalog[:footnotes][0]
855
931
  assert_equal 'a <a id="b"></a> [[c]] d', footnote1.text
856
932
  end
857
933
 
@@ -864,23 +940,15 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
864
940
  assert_equal 'foo<footnote><simpara>http://example.com</simpara></footnote>bar<footnote><simpara>http://acme.com</simpara></footnote>baz', result
865
941
  end
866
942
 
867
- test 'a footnote macro may contain a bibliographic anchor macro' do
868
- para = block_from_string('text footnote:[a [[[b\]\]\] c]')
869
- assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
870
- assert_equal 1, para.document.references[:footnotes].size
871
- footnote1 = para.document.references[:footnotes][0]
872
- assert_equal 'a <a id="b"></a>[b] c', footnote1.text
873
- end
874
-
875
943
  test 'should increment index of subsequent footnote macros' do
876
944
  para = block_from_string("Sentence text footnote:[An example footnote.]. Sentence text footnote:[Another footnote.].")
877
945
  assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>. Sentence text <sup class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnote_2" title="View footnote.">2</a>]</sup>.), para.sub_macros(para.source)
878
- assert_equal 2, para.document.references[:footnotes].size
879
- footnote1 = para.document.references[:footnotes][0]
946
+ assert_equal 2, para.document.catalog[:footnotes].size
947
+ footnote1 = para.document.catalog[:footnotes][0]
880
948
  assert_equal 1, footnote1.index
881
949
  assert footnote1.id.nil?
882
950
  assert_equal "An example footnote.", footnote1.text
883
- footnote2 = para.document.references[:footnotes][1]
951
+ footnote2 = para.document.catalog[:footnotes][1]
884
952
  assert_equal 2, footnote2.index
885
953
  assert footnote2.id.nil?
886
954
  assert_equal "Another footnote.", footnote2.text
@@ -889,8 +957,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
889
957
  test 'a footnoteref macro with id and single-line text should be registered and rendered as a footnote' do
890
958
  para = block_from_string('Sentence text footnoteref:[ex1, An example footnote.].')
891
959
  assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
892
- assert_equal 1, para.document.references[:footnotes].size
893
- footnote = para.document.references[:footnotes].first
960
+ assert_equal 1, para.document.catalog[:footnotes].size
961
+ footnote = para.document.catalog[:footnotes].first
894
962
  assert_equal 1, footnote.index
895
963
  assert_equal 'ex1', footnote.id
896
964
  assert_equal 'An example footnote.', footnote.text
@@ -899,8 +967,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
899
967
  test 'a footnoteref macro with id and multi-line text should be registered and rendered as a footnote without endlines' do
900
968
  para = block_from_string("Sentence text footnoteref:[ex1, An example footnote\nwith wrapped text.].")
901
969
  assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
902
- assert_equal 1, para.document.references[:footnotes].size
903
- footnote = para.document.references[:footnotes].first
970
+ assert_equal 1, para.document.catalog[:footnotes].size
971
+ footnote = para.document.catalog[:footnotes].first
904
972
  assert_equal 1, footnote.index
905
973
  assert_equal 'ex1', footnote.id
906
974
  assert_equal "An example footnote with wrapped text.", footnote.text
@@ -909,8 +977,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
909
977
  test 'a footnoteref macro with id should refer to footnoteref with same id' do
910
978
  para = block_from_string('Sentence text footnoteref:[ex1, An example footnote.]. Sentence text footnoteref:[ex1].')
911
979
  assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>. Sentence text <sup class="footnoteref">[<a class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
912
- assert_equal 1, para.document.references[:footnotes].size
913
- footnote = para.document.references[:footnotes].first
980
+ assert_equal 1, para.document.catalog[:footnotes].size
981
+ footnote = para.document.catalog[:footnotes].first
914
982
  assert_equal 1, footnote.index
915
983
  assert_equal 'ex1', footnote.id
916
984
  assert_equal 'An example footnote.', footnote.text
@@ -928,8 +996,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
928
996
  para = block_from_string("#{sentence}#{macro}")
929
997
  output = para.sub_macros(para.source)
930
998
  assert_equal sentence, output
931
- assert_equal 1, para.document.references[:indexterms].size
932
- assert_equal ['Tigers'], para.document.references[:indexterms].first
999
+ assert_equal 1, para.document.catalog[:indexterms].size
1000
+ assert_equal ['Tigers'], para.document.catalog[:indexterms].first
933
1001
  end
934
1002
  end
935
1003
 
@@ -940,8 +1008,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
940
1008
  para = block_from_string("#{sentence}#{macro}")
941
1009
  output = para.sub_macros(para.source)
942
1010
  assert_equal sentence, output
943
- assert_equal 1, para.document.references[:indexterms].size
944
- assert_equal ['Big cats', 'Tigers'], para.document.references[:indexterms].first
1011
+ assert_equal 1, para.document.catalog[:indexterms].size
1012
+ assert_equal ['Big cats', 'Tigers'], para.document.catalog[:indexterms].first
945
1013
  end
946
1014
  end
947
1015
 
@@ -952,8 +1020,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
952
1020
  para = block_from_string("#{sentence}#{macro}")
953
1021
  output = para.sub_macros(para.source)
954
1022
  assert_equal sentence, output
955
- assert_equal 1, para.document.references[:indexterms].size
956
- assert_equal ['Big cats', 'Tigers', 'Panthera tigris'], para.document.references[:indexterms].first
1023
+ assert_equal 1, para.document.catalog[:indexterms].size
1024
+ assert_equal ['Big cats', 'Tigers', 'Panthera tigris'], para.document.catalog[:indexterms].first
957
1025
  end
958
1026
  end
959
1027
 
@@ -964,8 +1032,8 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
964
1032
  para = block_from_string("#{sentence}#{macro}")
965
1033
  output = para.sub_macros(para.source)
966
1034
  assert_equal sentence, output
967
- assert_equal 1, para.document.references[:indexterms].size
968
- assert_equal ['Panthera tigris'], para.document.references[:indexterms].first
1035
+ assert_equal 1, para.document.catalog[:indexterms].size
1036
+ assert_equal ['Panthera tigris'], para.document.catalog[:indexterms].first
969
1037
  end
970
1038
  end
971
1039
 
@@ -986,8 +1054,8 @@ EOS
986
1054
  para = block_from_string input
987
1055
  output = para.sub_macros(para.source)
988
1056
  assert_equal input.lines.first, output
989
- assert_equal 1, para.document.references[:indexterms].size
990
- terms = para.document.references[:indexterms].first
1057
+ assert_equal 1, para.document.catalog[:indexterms].size
1058
+ terms = para.document.catalog[:indexterms].first
991
1059
  assert_equal 2, terms.size
992
1060
  assert_equal 'Tigers', terms.first
993
1061
  assert_equal '[Big], scary cats', terms.last
@@ -999,10 +1067,10 @@ EOS
999
1067
  macros = ['indexterm:[*Tigers*]', '(((*Tigers*)))']
1000
1068
  macros.each do |macro|
1001
1069
  para = block_from_string("#{sentence}#{macro}")
1002
- output = para.apply_normal_subs(para.lines)
1070
+ output = para.apply_subs(para.source)
1003
1071
  assert_equal sentence, output
1004
- assert_equal 1, para.document.references[:indexterms].size
1005
- assert_equal ['<strong>Tigers</strong>'], para.document.references[:indexterms].first
1072
+ assert_equal 1, para.document.catalog[:indexterms].size
1073
+ assert_equal ['<strong>Tigers</strong>'], para.document.catalog[:indexterms].first
1006
1074
  end
1007
1075
  end
1008
1076
 
@@ -1012,9 +1080,9 @@ EOS
1012
1080
  para = block_from_string("#{sentence}\n#{macros}")
1013
1081
  output = para.sub_macros(para.source)
1014
1082
  assert_equal sentence, output.rstrip
1015
- assert_equal 2, para.document.references[:indexterms].size
1016
- assert_equal ['Tigers'], para.document.references[:indexterms][0]
1017
- assert_equal ['Animals', 'Cats'], para.document.references[:indexterms][1]
1083
+ assert_equal 2, para.document.catalog[:indexterms].size
1084
+ assert_equal ['Tigers'], para.document.catalog[:indexterms][0]
1085
+ assert_equal ['Animals', 'Cats'], para.document.catalog[:indexterms][1]
1018
1086
  end
1019
1087
 
1020
1088
  test 'an index term macro with round bracket syntax may contain round brackets in term' do
@@ -1023,8 +1091,32 @@ EOS
1023
1091
  para = block_from_string("#{sentence}#{macro}")
1024
1092
  output = para.sub_macros(para.source)
1025
1093
  assert_equal sentence, output
1026
- assert_equal 1, para.document.references[:indexterms].size
1027
- assert_equal ['Tiger (Panthera tigris)'], para.document.references[:indexterms].first
1094
+ assert_equal 1, para.document.catalog[:indexterms].size
1095
+ assert_equal ['Tiger (Panthera tigris)'], para.document.catalog[:indexterms].first
1096
+ end
1097
+
1098
+ test 'visible shorthand index term macro should not consume trailing round bracket' do
1099
+ input = '(text with ((index term)))'
1100
+ expected = '(text with <indexterm><primary>index term</primary></indexterm>index term)'
1101
+ expected_term = ['index term']
1102
+ para = block_from_string input, :backend => :docbook
1103
+ output = para.sub_macros para.source
1104
+ indexterms_table = para.document.catalog[:indexterms]
1105
+ assert_equal 1, indexterms_table.size
1106
+ assert_equal expected_term, indexterms_table[0]
1107
+ assert_equal expected, output
1108
+ end
1109
+
1110
+ test 'visible shorthand index term macro should not consume leading round bracket' do
1111
+ input = '(((index term)) for text)'
1112
+ expected = '(<indexterm><primary>index term</primary></indexterm>index term for text)'
1113
+ expected_term = ['index term']
1114
+ para = block_from_string input, :backend => :docbook
1115
+ output = para.sub_macros para.source
1116
+ indexterms_table = para.document.catalog[:indexterms]
1117
+ assert_equal 1, indexterms_table.size
1118
+ assert_equal expected_term, indexterms_table[0]
1119
+ assert_equal expected, output
1028
1120
  end
1029
1121
 
1030
1122
  test 'an index term macro with square bracket syntax may contain square brackets in term' do
@@ -1033,8 +1125,8 @@ EOS
1033
1125
  para = block_from_string("#{sentence}#{macro}")
1034
1126
  output = para.sub_macros(para.source)
1035
1127
  assert_equal sentence, output
1036
- assert_equal 1, para.document.references[:indexterms].size
1037
- assert_equal ['Tiger [Panthera tigris]'], para.document.references[:indexterms].first
1128
+ assert_equal 1, para.document.catalog[:indexterms].size
1129
+ assert_equal ['Tiger [Panthera tigris]'], para.document.catalog[:indexterms].first
1038
1130
  end
1039
1131
 
1040
1132
  test 'a single-line index term 2 macro should be registered as an index reference and retain term inline' do
@@ -1044,8 +1136,8 @@ EOS
1044
1136
  para = block_from_string(macro)
1045
1137
  output = para.sub_macros(para.source)
1046
1138
  assert_equal sentence, output
1047
- assert_equal 1, para.document.references[:indexterms].size
1048
- assert_equal ['tiger'], para.document.references[:indexterms].first
1139
+ assert_equal 1, para.document.catalog[:indexterms].size
1140
+ assert_equal ['tiger'], para.document.catalog[:indexterms].first
1049
1141
  end
1050
1142
  end
1051
1143
 
@@ -1056,8 +1148,8 @@ EOS
1056
1148
  para = block_from_string(macro)
1057
1149
  output = para.sub_macros(para.source)
1058
1150
  assert_equal sentence, output
1059
- assert_equal 1, para.document.references[:indexterms].size
1060
- assert_equal ['panthera tigris'], para.document.references[:indexterms].first
1151
+ assert_equal 1, para.document.catalog[:indexterms].size
1152
+ assert_equal ['panthera tigris'], para.document.catalog[:indexterms].first
1061
1153
  end
1062
1154
  end
1063
1155
 
@@ -1066,18 +1158,18 @@ EOS
1066
1158
  para = block_from_string(sentence)
1067
1159
  output = para.sub_macros(para.source)
1068
1160
  assert_equal 'The tiger (Panthera tigris) is the largest cat species.', output
1069
- assert_equal 2, para.document.references[:indexterms].size
1070
- assert_equal ['tiger'], para.document.references[:indexterms][0]
1071
- assert_equal ['cat'], para.document.references[:indexterms][1]
1161
+ assert_equal 2, para.document.catalog[:indexterms].size
1162
+ assert_equal ['tiger'], para.document.catalog[:indexterms][0]
1163
+ assert_equal ['cat'], para.document.catalog[:indexterms][1]
1072
1164
  end
1073
1165
 
1074
1166
  test 'normal substitutions are performed on an index term 2 macro' do
1075
1167
  sentence = 'The ((*tiger*)) (Panthera tigris) is the largest cat species.'
1076
1168
  para = block_from_string sentence
1077
- output = para.apply_normal_subs(para.lines)
1169
+ output = para.apply_subs(para.source)
1078
1170
  assert_equal 'The <strong>tiger</strong> (Panthera tigris) is the largest cat species.', output
1079
- assert_equal 1, para.document.references[:indexterms].size
1080
- assert_equal ['<strong>tiger</strong>'], para.document.references[:indexterms].first
1171
+ assert_equal 1, para.document.catalog[:indexterms].size
1172
+ assert_equal ['<strong>tiger</strong>'], para.document.catalog[:indexterms].first
1081
1173
  end
1082
1174
 
1083
1175
  test 'index term 2 macro with round bracket syntex should not interfer with index term macro with round bracket syntax' do
@@ -1085,7 +1177,7 @@ EOS
1085
1177
  para = block_from_string sentence
1086
1178
  output = para.sub_macros(para.source)
1087
1179
  assert_equal "The panthera tigris is the largest cat species.\n", output
1088
- terms = para.document.references[:indexterms]
1180
+ terms = para.document.catalog[:indexterms]
1089
1181
  assert_equal 2, terms.size
1090
1182
  assert_equal ['panthera tigris'], terms[0]
1091
1183
  assert_equal ['Big cats', 'Tigers'], terms[1]
@@ -1097,6 +1189,11 @@ EOS
1097
1189
  assert_equal %q{<b class="button">Save</b>}, para.sub_macros(para.source)
1098
1190
  end
1099
1191
 
1192
+ test 'btn macro that spans multiple lines' do
1193
+ para = block_from_string(%(btn:[Rebase and\nmerge]), :attributes => {'experimental' => ''})
1194
+ assert_equal %q{<b class="button">Rebase and merge</b>}, para.sub_macros(para.source)
1195
+ end
1196
+
1100
1197
  test 'btn macro for docbook backend' do
1101
1198
  para = block_from_string('btn:[Save]', :backend => 'docbook', :attributes => {'experimental' => ''})
1102
1199
  assert_equal %q{<guibutton>Save</guibutton>}, para.sub_macros(para.source)
@@ -1109,6 +1206,11 @@ EOS
1109
1206
  assert_equal %q{<kbd>F3</kbd>}, para.sub_macros(para.source)
1110
1207
  end
1111
1208
 
1209
+ test 'kbd macro with single backslash key' do
1210
+ para = block_from_string("kbd:[#{BACKSLASH} ]", :attributes => {'experimental' => ''})
1211
+ assert_equal %q(<kbd>\</kbd>), para.sub_macros(para.source)
1212
+ end
1213
+
1112
1214
  test 'kbd macro with single key, docbook backend' do
1113
1215
  para = block_from_string('kbd:[F3]', :backend => 'docbook', :attributes => {'experimental' => ''})
1114
1216
  assert_equal %q{<keycap>F3</keycap>}, para.sub_macros(para.source)
@@ -1119,7 +1221,17 @@ EOS
1119
1221
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
1120
1222
  end
1121
1223
 
1122
- test 'kbd macro with key combination with spaces' do
1224
+ test 'kbd macro with key combination that spans multiple lines' do
1225
+ para = block_from_string(%(kbd:[Ctrl +\nT]), :attributes => {'experimental' => ''})
1226
+ assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
1227
+ end
1228
+
1229
+ test 'kbd macro with key combination, docbook backend' do
1230
+ para = block_from_string('kbd:[Ctrl+Shift+T]', :backend => 'docbook', :attributes => {'experimental' => ''})
1231
+ assert_equal %q{<keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap><keycap>T</keycap></keycombo>}, para.sub_macros(para.source)
1232
+ end
1233
+
1234
+ test 'kbd macro with key combination delimited by pluses with spaces' do
1123
1235
  para = block_from_string('kbd:[Ctrl + Shift + T]', :attributes => {'experimental' => ''})
1124
1236
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
1125
1237
  end
@@ -1129,36 +1241,56 @@ EOS
1129
1241
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
1130
1242
  end
1131
1243
 
1132
- test 'kbd macro with key combination containing a plus key no spaces' do
1133
- para = block_from_string('kbd:[Ctrl++]', :attributes => {'experimental' => ''})
1134
- assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>+</kbd></span>}, para.sub_macros(para.source)
1244
+ test 'kbd macro with key combination delimited by commas with spaces' do
1245
+ para = block_from_string('kbd:[Ctrl, Shift, T]', :attributes => {'experimental' => ''})
1246
+ assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
1135
1247
  end
1136
1248
 
1137
- test 'kbd macro with key combination delimited by commands containing a comma key' do
1138
- para = block_from_string('kbd:[Ctrl,,]', :attributes => {'experimental' => ''})
1249
+ test 'kbd macro with key combination delimited by plus containing a comma key' do
1250
+ para = block_from_string('kbd:[Ctrl+,]', :attributes => {'experimental' => ''})
1139
1251
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>,</kbd></span>}, para.sub_macros(para.source)
1140
1252
  end
1141
1253
 
1142
- test 'kbd macro with key combination containing a plus key with spaces' do
1254
+ test 'kbd macro with key combination delimited by commas containing a plus key' do
1255
+ para = block_from_string('kbd:[Ctrl, +, Shift]', :attributes => {'experimental' => ''})
1256
+ assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>+</kbd>+<kbd>Shift</kbd></span>}, para.sub_macros(para.source)
1257
+ end
1258
+
1259
+ test 'kbd macro with key combination where last key matches plus delimiter' do
1143
1260
  para = block_from_string('kbd:[Ctrl + +]', :attributes => {'experimental' => ''})
1144
1261
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>+</kbd></span>}, para.sub_macros(para.source)
1145
1262
  end
1146
1263
 
1264
+ test 'kbd macro with key combination where last key matches comma delimiter' do
1265
+ para = block_from_string('kbd:[Ctrl, ,]', :attributes => {'experimental' => ''})
1266
+ assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>,</kbd></span>}, para.sub_macros(para.source)
1267
+ end
1268
+
1147
1269
  test 'kbd macro with key combination containing escaped bracket' do
1148
1270
  para = block_from_string('kbd:[Ctrl + \]]', :attributes => {'experimental' => ''})
1149
1271
  assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>]</kbd></span>}, para.sub_macros(para.source)
1150
1272
  end
1151
1273
 
1152
- test 'kbd macro with key combination, docbook backend' do
1153
- para = block_from_string('kbd:[Ctrl+Shift+T]', :backend => 'docbook', :attributes => {'experimental' => ''})
1154
- assert_equal %q{<keycombo><keycap>Ctrl</keycap><keycap>Shift</keycap><keycap>T</keycap></keycombo>}, para.sub_macros(para.source)
1274
+ test 'kbd macro with key combination ending in backslash' do
1275
+ para = block_from_string("kbd:[Ctrl + #{BACKSLASH} ]", :attributes => {'experimental' => ''})
1276
+ assert_equal %q(<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>\\</kbd></span>), para.sub_macros(para.source)
1277
+ end
1278
+
1279
+ test 'kbd macro looks for delimiter beyond first character' do
1280
+ para = block_from_string('kbd:[,te]', :attributes => {'experimental' => ''})
1281
+ assert_equal %q(<kbd>,te</kbd>), para.sub_macros(para.source)
1282
+ end
1283
+
1284
+ test 'kbd macro restores trailing delimiter as key value' do
1285
+ para = block_from_string('kbd:[te,]', :attributes => {'experimental' => ''})
1286
+ assert_equal %q(<kbd>te,</kbd>), para.sub_macros(para.source)
1155
1287
  end
1156
1288
  end
1157
1289
 
1158
1290
  context 'Menu macro' do
1159
1291
  test 'should process menu using macro sytnax' do
1160
1292
  para = block_from_string('menu:File[]', :attributes => {'experimental' => ''})
1161
- assert_equal %q{<span class="menu">File</span>}, para.sub_macros(para.source)
1293
+ assert_equal %q{<b class="menuref">File</b>}, para.sub_macros(para.source)
1162
1294
  end
1163
1295
 
1164
1296
  test 'should process menu for docbook backend' do
@@ -1168,7 +1300,24 @@ EOS
1168
1300
 
1169
1301
  test 'should process menu with menu item using macro syntax' do
1170
1302
  para = block_from_string('menu:File[Save As&#8230;]', :attributes => {'experimental' => ''})
1171
- assert_equal %q{<span class="menuseq"><span class="menu">File</span>&#160;&#9656; <span class="menuitem">Save As&#8230;</span></span>}, para.sub_macros(para.source)
1303
+ assert_equal %q{<span class="menuseq"><b class="menu">File</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Save As&#8230;</b></span>}, para.sub_macros(para.source)
1304
+ end
1305
+
1306
+ test 'should process menu macro that spans multiple lines' do
1307
+ input = %(menu:Preferences[Compile\non\nSave])
1308
+ para = block_from_string input, :attributes => {'experimental' => ''}
1309
+ assert_equal %(<span class="menuseq"><b class="menu">Preferences</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Compile\non\nSave</b></span>), para.sub_macros(para.source)
1310
+ end
1311
+
1312
+ test 'should unescape escaped closing bracket in menu macro' do
1313
+ input = 'menu:Preferences[Compile [on\\] Save]'
1314
+ para = block_from_string input, :attributes => {'experimental' => ''}
1315
+ assert_equal %q(<span class="menuseq"><b class="menu">Preferences</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Compile [on] Save</b></span>), para.sub_macros(para.source)
1316
+ end
1317
+
1318
+ test 'should process menu with menu item using macro syntax when fonts icons are enabled' do
1319
+ para = block_from_string('menu:Tools[More Tools &gt; Extensions]', :attributes => {'experimental' => '', 'icons' => 'font'})
1320
+ assert_equal %q{<span class="menuseq"><b class="menu">Tools</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="submenu">More Tools</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Extensions</b></span>}, para.sub_macros(para.source)
1172
1321
  end
1173
1322
 
1174
1323
  test 'should process menu with menu item for docbook backend' do
@@ -1178,7 +1327,7 @@ EOS
1178
1327
 
1179
1328
  test 'should process menu with menu item in submenu using macro syntax' do
1180
1329
  para = block_from_string('menu:Tools[Project &gt; Build]', :attributes => {'experimental' => ''})
1181
- assert_equal %q{<span class="menuseq"><span class="menu">Tools</span>&#160;&#9656; <span class="submenu">Project</span>&#160;&#9656; <span class="menuitem">Build</span></span>}, para.sub_macros(para.source)
1330
+ assert_equal %q{<span class="menuseq"><b class="menu">Tools</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">Project</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Build</b></span>}, para.sub_macros(para.source)
1182
1331
  end
1183
1332
 
1184
1333
  test 'should process menu with menu item in submenu for docbook backend' do
@@ -1188,33 +1337,51 @@ EOS
1188
1337
 
1189
1338
  test 'should process menu with menu item in submenu using macro syntax and comma delimiter' do
1190
1339
  para = block_from_string('menu:Tools[Project, Build]', :attributes => {'experimental' => ''})
1191
- assert_equal %q{<span class="menuseq"><span class="menu">Tools</span>&#160;&#9656; <span class="submenu">Project</span>&#160;&#9656; <span class="menuitem">Build</span></span>}, para.sub_macros(para.source)
1340
+ assert_equal %q{<span class="menuseq"><b class="menu">Tools</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">Project</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Build</b></span>}, para.sub_macros(para.source)
1192
1341
  end
1193
1342
 
1194
1343
  test 'should process menu with menu item using inline syntax' do
1195
1344
  para = block_from_string('"File &gt; Save As&#8230;"', :attributes => {'experimental' => ''})
1196
- assert_equal %q{<span class="menuseq"><span class="menu">File</span>&#160;&#9656; <span class="menuitem">Save As&#8230;</span></span>}, para.sub_macros(para.source)
1345
+ assert_equal %q{<span class="menuseq"><b class="menu">File</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Save As&#8230;</b></span>}, para.sub_macros(para.source)
1197
1346
  end
1198
1347
 
1199
1348
  test 'should process menu with menu item in submenu using inline syntax' do
1200
1349
  para = block_from_string('"Tools &gt; Project &gt; Build"', :attributes => {'experimental' => ''})
1201
- assert_equal %q{<span class="menuseq"><span class="menu">Tools</span>&#160;&#9656; <span class="submenu">Project</span>&#160;&#9656; <span class="menuitem">Build</span></span>}, para.sub_macros(para.source)
1350
+ assert_equal %q{<span class="menuseq"><b class="menu">Tools</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">Project</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Build</b></span>}, para.sub_macros(para.source)
1202
1351
  end
1203
1352
 
1204
- test 'inline syntax should not closing quote of XML attribute' do
1353
+ test 'inline menu syntax should not match closing quote of XML attribute' do
1205
1354
  para = block_from_string('<span class="xmltag">&lt;node&gt;</span><span class="classname">r</span>', :attributes => {'experimental' => ''})
1206
1355
  assert_equal %q{<span class="xmltag">&lt;node&gt;</span><span class="classname">r</span>}, para.sub_macros(para.source)
1207
1356
  end
1208
1357
 
1209
1358
  test 'should process menu macro with items containing multibyte characters' do
1210
1359
  para = block_from_string('menu:视图[放大, 重置]', :attributes => {'experimental' => ''})
1211
- assert_equal %q{<span class="menuseq"><span class="menu">视图</span>&#160;&#9656; <span class="submenu">放大</span>&#160;&#9656; <span class="menuitem">重置</span></span>}, para.sub_macros(para.source)
1360
+ assert_equal %q{<span class="menuseq"><b class="menu">视图</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">放大</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">重置</b></span>}, para.sub_macros(para.source)
1212
1361
  end if ::RUBY_MIN_VERSION_1_9
1213
1362
 
1214
1363
  test 'should process inline menu with items containing multibyte characters' do
1215
1364
  para = block_from_string('"视图 &gt; 放大 &gt; 重置"', :attributes => {'experimental' => ''})
1216
- assert_equal %q{<span class="menuseq"><span class="menu">视图</span>&#160;&#9656; <span class="submenu">放大</span>&#160;&#9656; <span class="menuitem">重置</span></span>}, para.sub_macros(para.source)
1365
+ assert_equal %q{<span class="menuseq"><b class="menu">视图</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">放大</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">重置</b></span>}, para.sub_macros(para.source)
1217
1366
  end if ::RUBY_MIN_VERSION_1_9
1367
+
1368
+ test 'should process a menu macro with a target that begins with a character reference' do
1369
+ para = block_from_string('menu:&#8942;[More Tools, Extensions]', :attributes => {'experimental' => ''})
1370
+ assert_equal %q{<span class="menuseq"><b class="menu">&#8942;</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">More Tools</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Extensions</b></span>}, para.sub_macros(para.source)
1371
+ end
1372
+
1373
+ test 'should not process a menu macro with a target that ends with a space' do
1374
+ input = 'menu:foo [bar] menu:File[Save]'
1375
+ para = block_from_string input, :attributes => {'experimental' => ''}
1376
+ result = para.sub_macros para.source
1377
+ assert_xpath '/span[@class="menuseq"]', result, 1
1378
+ assert_xpath '//b[@class="menu"][text()="File"]', result, 1
1379
+ end
1380
+
1381
+ test 'should process an inline menu that begins with a character reference' do
1382
+ para = block_from_string('"&#8942; &gt; More Tools &gt; Extensions"', :attributes => {'experimental' => ''})
1383
+ assert_equal %q{<span class="menuseq"><b class="menu">&#8942;</b>&#160;<b class="caret">&#8250;</b> <b class="submenu">More Tools</b>&#160;<b class="caret">&#8250;</b> <b class="menuitem">Extensions</b></span>}, para.sub_macros(para.source)
1384
+ end
1218
1385
  end
1219
1386
  end
1220
1387
 
@@ -1255,6 +1422,18 @@ EOS
1255
1422
  assert_equal [:specialcharacters], para.passthroughs[0][:subs]
1256
1423
  end
1257
1424
 
1425
+ test 'should allow inline double plus passthrough to be escaped using backslash' do
1426
+ para = block_from_string("you need to replace `int a = n#{BACKSLASH}++;` with `int a = ++n;`!")
1427
+ result = para.apply_subs para.source
1428
+ assert_equal 'you need to replace <code>int a = n++;</code> with <code>int a = ++n;</code>!', result
1429
+ end
1430
+
1431
+ test 'should allow inline double plus passthrough with attributes to be escaped using backslash' do
1432
+ para = block_from_string("=[attrs]#{BACKSLASH}#{BACKSLASH}++text++")
1433
+ result = para.apply_subs para.source
1434
+ assert_equal '=[attrs]++text++', result
1435
+ end
1436
+
1258
1437
  test 'collect multi-line inline double dollar passthroughs' do
1259
1438
  para = block_from_string("$$<code>\n{code}\n</code>$$")
1260
1439
  result = para.extract_passthroughs(para.source)
@@ -1291,6 +1470,12 @@ EOS
1291
1470
  assert_equal [:specialcharacters, :quotes], para.passthroughs[0][:subs]
1292
1471
  end
1293
1472
 
1473
+ test 'should find and replace placeholder duplicated by substitution' do
1474
+ input = %q(+first passthrough+ followed by link:$$http://example.com/__u_no_format_me__$$[] with passthrough)
1475
+ result = render_embedded_string input, :doctype => :inline
1476
+ assert_equal 'first passthrough followed by <a href="http://example.com/__u_no_format_me__" class="bare">http://example.com/__u_no_format_me__</a> with passthrough', result
1477
+ end
1478
+
1294
1479
  test 'resolves sub shorthands on inline pass macro' do
1295
1480
  para = block_from_string 'pass:q,a[*<{backend}>*]'
1296
1481
  result = para.extract_passthroughs para.source
@@ -1300,6 +1485,21 @@ EOS
1300
1485
  assert_equal '<strong><html5></strong>', result
1301
1486
  end
1302
1487
 
1488
+ test 'should not recognize pass macro with invalid subsitution list' do
1489
+ [',', '42', 'a,'].each do |subs|
1490
+ para = block_from_string %(pass:#{subs}[foobar])
1491
+ result = para.extract_passthroughs para.source
1492
+ assert_equal %(pass:#{subs}[foobar]), result
1493
+ end
1494
+ end
1495
+
1496
+ test 'should allow content of inline pass macro to be empty' do
1497
+ para = block_from_string 'pass:[]'
1498
+ result = para.extract_passthroughs para.source
1499
+ assert_equal 1, para.passthroughs.size
1500
+ assert_equal '', para.restore_passthroughs(result)
1501
+ end
1502
+
1303
1503
  # NOTE placeholder is surrounded by text to prevent reader from stripping trailing boundary char (unique to test scenario)
1304
1504
  test 'restore inline passthroughs without subs' do
1305
1505
  para = block_from_string("some #{Asciidoctor::Substitutors::PASS_START}" + '0' + "#{Asciidoctor::Substitutors::PASS_END} to study")
@@ -1453,23 +1653,31 @@ EOS
1453
1653
  assert_equal '\(C = \alpha + \beta Y^{\gamma} + \epsilon\)', para.content
1454
1654
  end
1455
1655
 
1456
- test 'should find and replace placeholder duplicated by substitution' do
1457
- input = %q(+first passthrough+ followed by link:$$http://example.com/__u_no_format_me__$$[] with passthrough)
1458
- result = render_embedded_string input, :doctype => :inline
1459
- assert_equal 'first passthrough followed by <a href="http://example.com/__u_no_format_me__" class="bare">http://example.com/__u_no_format_me__</a> with passthrough', result
1656
+ test 'should apply substitutions specified on stem macro' do
1657
+ input = 'stem:c,a[sqrt(x) <=> {solve-for-x}]'
1658
+ para = block_from_string input, :attributes => {'stem' => 'asciimath', 'solve-for-x' => '13'}
1659
+ assert_equal '\$sqrt(x) &lt;=&gt; 13\$', para.content
1660
+ end
1661
+
1662
+ test 'should not recognize stem macro with invalid substitution list' do
1663
+ [',', '42', 'a,'].each do |subs|
1664
+ input = %(stem:#{subs}[x^2])
1665
+ para = block_from_string input, :attributes => {'stem' => 'asciimath'}
1666
+ assert_equal %(stem:#{subs}[x^2]), para.content
1667
+ end
1460
1668
  end
1461
1669
  end
1462
1670
  end
1463
1671
 
1464
1672
  context 'Replacements' do
1465
1673
  test 'unescapes XML entities' do
1466
- para = block_from_string '< &quot; &#34; &#x22; >'
1467
- assert_equal '&lt; &quot; &#34; &#x22; &gt;', para.apply_normal_subs(para.lines)
1674
+ para = block_from_string '< &quot; &there4; &#34; &#x22; >'
1675
+ assert_equal '&lt; &quot; &there4; &#34; &#x22; &gt;', para.apply_subs(para.source)
1468
1676
  end
1469
1677
 
1470
1678
  test 'replaces arrows' do
1471
1679
  para = block_from_string '<- -> <= => \<- \-> \<= \=>'
1472
- assert_equal '&#8592; &#8594; &#8656; &#8658; &lt;- -&gt; &lt;= =&gt;', para.apply_normal_subs(para.source)
1680
+ assert_equal '&#8592; &#8594; &#8656; &#8658; &lt;- -&gt; &lt;= =&gt;', para.apply_subs(para.source)
1473
1681
  end
1474
1682
 
1475
1683
  test 'replaces dashes' do
@@ -1667,13 +1875,13 @@ foo&#8201;&#8212;&#8201;'
1667
1875
  test 'should URI encode non-word characters generally' do
1668
1876
  given = ' /%&?\\'
1669
1877
  expect = '%20%2F%25%26%3F%5C'
1670
- assert_equal expect, (Asciidoctor::Helpers.encode_uri given)
1878
+ assert_equal expect, (Asciidoctor::Helpers.uri_encode given)
1671
1879
  end
1672
1880
 
1673
1881
  test 'should not URI select non-word characters' do
1674
1882
  given = '-.!~*\';:@=+$,()[]'
1675
1883
  expect = given
1676
- assert_equal expect, (Asciidoctor::Helpers.encode_uri given)
1884
+ assert_equal expect, (Asciidoctor::Helpers.uri_encode given)
1677
1885
  end
1678
1886
  end
1679
1887
  end