asciidoctor 1.5.5 → 1.5.6
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.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
    
        data/test/substitutions_test.rb
    CHANGED
    
    | @@ -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§ Making +++<u>documentation</u>+++ together +\nsince (C) {inception_year}.")
         | 
| 14 15 | 
             
                  para.document.attributes['inception_year'] = '2012'
         | 
| 15 | 
            -
                  result = para. | 
| 16 | 
            +
                  result = para.apply_subs(para.source)
         | 
| 16 17 | 
             
                  assert_equal %{<em class="blue"><a href="http://asciidoc.org">AsciiDoc</a></em> & <strong class="red">Ruby</strong>\n§ Making <u>documentation</u> together<br>\nsince © 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>', '→ Asciidoctor<br>', '<br>', ''], result
         | 
| 27 | 
            +
                  result = para.apply_subs(para.lines * "\n")
         | 
| 28 | 
            +
                  assert_equal %(this<br>\nis<br>\n→ 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 > 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 > 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 '“a few quoted words”', 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. | 
| 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. | 
| 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  | 
| 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 <{monospaced}> words</code>', para. | 
| 270 | 
            +
                  assert_equal '<code>a few <{monospaced}> 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 <monospaced> words</code>', para. | 
| 273 | 
            +
                  assert_equal '<code>a few <monospaced> words</code>', para.apply_subs(para.source)
         | 
| 253 274 | 
             
                end
         | 
| 254 275 |  | 
| 255 | 
            -
                # NOTE must use  | 
| 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 <{monospaced}> words</code>', para. | 
| 279 | 
            +
                  assert_equal '<code class="input">a few <{monospaced}> 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 <monospaced> words</code>', para. | 
| 282 | 
            +
                  assert_equal '<code class="input">a few <monospaced> words</code>', para.apply_subs(para.source)
         | 
| 262 283 | 
             
                end
         | 
| 263 284 |  | 
| 264 | 
            -
                # NOTE must use  | 
| 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 <monospaced> words`', para. | 
| 288 | 
            +
                  assert_equal '`a few <monospaced> words`', para.apply_subs(para.source)
         | 
| 268 289 |  | 
| 269 290 | 
             
                  para = block_from_string(%(#{BACKSLASH}`a few <monospaced> words`))
         | 
| 270 | 
            -
                  assert_equal '`a few <monospaced> words`', para. | 
| 291 | 
            +
                  assert_equal '`a few <monospaced> words`', para.apply_subs(para.source)
         | 
| 271 292 | 
             
                end
         | 
| 272 293 |  | 
| 273 | 
            -
                # NOTE must use  | 
| 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 <monospaced> words`', para. | 
| 297 | 
            +
                  assert_equal '[input]`a few <monospaced> 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 <monospaced> words`', para. | 
| 300 | 
            +
                  assert_equal '[input]`a few <monospaced> words`', para.apply_subs(para.source)
         | 
| 280 301 | 
             
                end
         | 
| 281 302 |  | 
| 282 | 
            -
                # NOTE must use  | 
| 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 <monospaced> words</code>', para. | 
| 306 | 
            +
                  assert_equal '[input]<code>a few <monospaced> 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 <monospaced> words</code>', para. | 
| 309 | 
            +
                  assert_equal '[input]<code>a few <monospaced> words</code>', para.apply_subs(para.source)
         | 
| 289 310 | 
             
                end
         | 
| 290 311 |  | 
| 291 | 
            -
                # NOTE must use  | 
| 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 <monospaced> words`), para. | 
| 315 | 
            +
                  assert_equal %(#{BACKSLASH}[input]`a few <monospaced> 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 <monospaced> words`), para. | 
| 318 | 
            +
                  assert_equal %(#{BACKSLASH}[input]`a few <monospaced> words`), para.apply_subs(para.source)
         | 
| 298 319 | 
             
                end
         | 
| 299 320 |  | 
| 300 | 
            -
                # NOTE must use  | 
| 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<{monospaced}> words</code>", para. | 
| 324 | 
            +
                  assert_equal "<code>a few\n<{monospaced}> 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<monospaced> words</code>", para. | 
| 327 | 
            +
                  assert_equal "<code>a few\n<monospaced> 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{<<a href="mailto:doc.writer@asciidoc.org">doc.writer@asciidoc.org</a>>}, para. | 
| 603 | 
            +
                  assert_equal %q{<<a href="mailto:doc.writer@asciidoc.org">doc.writer@asciidoc.org</a>>}, 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  | 
| 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’s "roar" is < a bear’s "growl"'
         | 
| 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 ' | 
| 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. | 
| 774 | 
            -
                  footnote = para.document. | 
| 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. | 
| 784 | 
            -
                  footnote = para.document. | 
| 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. | 
| 794 | 
            -
                  footnote = para.document. | 
| 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. | 
| 807 | 
            -
                  footnote1 = para.document. | 
| 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. | 
| 882 | 
            +
                  footnote2 = para.document.catalog[:footnotes][1]
         | 
| 810 883 | 
             
                  assert_equal 'a ] b', footnote2.text
         | 
| 811 | 
            -
                  footnote3 = para.document. | 
| 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:[ | 
| 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. | 
| 819 | 
            -
                  footnote1 = para.document. | 
| 820 | 
            -
                  assert_equal '<a href=" | 
| 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. | 
| 828 | 
            -
                  fn1 = para.document. | 
| 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. | 
| 837 | 
            -
                  fn1 = para.document. | 
| 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:[<<_install, | 
| 916 | 
            +
                  para = block_from_string('text footnote:[<<_install,install>>]')
         | 
| 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,  | 
| 846 | 
            -
                  footnote1 =  | 
| 847 | 
            -
                  assert_equal '<a href="#_install"> | 
| 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. | 
| 854 | 
            -
                  footnote1 = para.document. | 
| 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. | 
| 879 | 
            -
                  footnote1 = para.document. | 
| 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. | 
| 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. | 
| 893 | 
            -
                  footnote = para.document. | 
| 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. | 
| 903 | 
            -
                  footnote = para.document. | 
| 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. | 
| 913 | 
            -
                  footnote = para.document. | 
| 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. | 
| 932 | 
            -
                    assert_equal ['Tigers'], para.document. | 
| 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. | 
| 944 | 
            -
                    assert_equal ['Big cats', 'Tigers'], para.document. | 
| 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. | 
| 956 | 
            -
                    assert_equal ['Big cats', 'Tigers', 'Panthera tigris'], para.document. | 
| 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. | 
| 968 | 
            -
                    assert_equal ['Panthera tigris'], para.document. | 
| 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. | 
| 990 | 
            -
                    terms = para.document. | 
| 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. | 
| 1070 | 
            +
                    output = para.apply_subs(para.source)
         | 
| 1003 1071 | 
             
                    assert_equal sentence, output
         | 
| 1004 | 
            -
                    assert_equal 1, para.document. | 
| 1005 | 
            -
                    assert_equal ['<strong>Tigers</strong>'], para.document. | 
| 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. | 
| 1016 | 
            -
                  assert_equal ['Tigers'], para.document. | 
| 1017 | 
            -
                  assert_equal ['Animals', 'Cats'], para.document. | 
| 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. | 
| 1027 | 
            -
                  assert_equal ['Tiger (Panthera tigris)'], para.document. | 
| 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. | 
| 1037 | 
            -
                  assert_equal ['Tiger [Panthera tigris]'], para.document. | 
| 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. | 
| 1048 | 
            -
                    assert_equal ['tiger'], para.document. | 
| 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. | 
| 1060 | 
            -
                    assert_equal ['panthera tigris'], para.document. | 
| 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. | 
| 1070 | 
            -
                  assert_equal ['tiger'], para.document. | 
| 1071 | 
            -
                  assert_equal ['cat'], para.document. | 
| 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. | 
| 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. | 
| 1080 | 
            -
                  assert_equal ['<strong>tiger</strong>'], para.document. | 
| 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. | 
| 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  | 
| 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  | 
| 1133 | 
            -
                    para = block_from_string('kbd:[Ctrl | 
| 1134 | 
            -
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd | 
| 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  | 
| 1138 | 
            -
                    para = block_from_string('kbd:[Ctrl | 
| 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 | 
| 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 | 
| 1153 | 
            -
                    para = block_from_string( | 
| 1154 | 
            -
                    assert_equal %q | 
| 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{< | 
| 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…]', :attributes => {'experimental' => ''})
         | 
| 1171 | 
            -
                    assert_equal %q{<span class="menuseq">< | 
| 1303 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">File</b> <b class="caret">›</b> <b class="menuitem">Save As…</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> <b class="caret">›</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> <b class="caret">›</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 > Extensions]', :attributes => {'experimental' => '', 'icons' => 'font'})
         | 
| 1320 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">Tools</b> <i class="fa fa-angle-right caret"></i> <b class="submenu">More Tools</b> <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 > Build]', :attributes => {'experimental' => ''})
         | 
| 1181 | 
            -
                    assert_equal %q{<span class="menuseq">< | 
| 1330 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">Tools</b> <b class="caret">›</b> <b class="submenu">Project</b> <b class="caret">›</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">< | 
| 1340 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">Tools</b> <b class="caret">›</b> <b class="submenu">Project</b> <b class="caret">›</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 > Save As…"', :attributes => {'experimental' => ''})
         | 
| 1196 | 
            -
                    assert_equal %q{<span class="menuseq">< | 
| 1345 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">File</b> <b class="caret">›</b> <b class="menuitem">Save As…</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 > Project > Build"', :attributes => {'experimental' => ''})
         | 
| 1201 | 
            -
                    assert_equal %q{<span class="menuseq">< | 
| 1350 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">Tools</b> <b class="caret">›</b> <b class="submenu">Project</b> <b class="caret">›</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"><node></span><span class="classname">r</span>', :attributes => {'experimental' => ''})
         | 
| 1206 1355 | 
             
                    assert_equal %q{<span class="xmltag"><node></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">< | 
| 1360 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">视图</b> <b class="caret">›</b> <b class="submenu">放大</b> <b class="caret">›</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('"视图 > 放大 > 重置"', :attributes => {'experimental' => ''})
         | 
| 1216 | 
            -
                    assert_equal %q{<span class="menuseq">< | 
| 1365 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">视图</b> <b class="caret">›</b> <b class="submenu">放大</b> <b class="caret">›</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:⋮[More Tools, Extensions]', :attributes => {'experimental' => ''})
         | 
| 1370 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">⋮</b> <b class="caret">›</b> <b class="submenu">More Tools</b> <b class="caret">›</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('"⋮ > More Tools > Extensions"', :attributes => {'experimental' => ''})
         | 
| 1383 | 
            +
                    assert_equal %q{<span class="menuseq"><b class="menu">⋮</b> <b class="caret">›</b> <b class="submenu">More Tools</b> <b class="caret">›</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  | 
| 1457 | 
            -
                    input =  | 
| 1458 | 
            -
                     | 
| 1459 | 
            -
                    assert_equal ' | 
| 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) <=> 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 '< " " " >'
         | 
| 1467 | 
            -
                  assert_equal '< " " " >', para. | 
| 1674 | 
            +
                  para = block_from_string '< " ∴ " " >'
         | 
| 1675 | 
            +
                  assert_equal '< " ∴ " " >', 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 '← → ⇐ ⇒ <- -> <= =>', para. | 
| 1680 | 
            +
                  assert_equal '← → ⇐ ⇒ <- -> <= =>', para.apply_subs(para.source)
         | 
| 1473 1681 | 
             
                end
         | 
| 1474 1682 |  | 
| 1475 1683 | 
             
                test 'replaces dashes' do
         | 
| @@ -1667,13 +1875,13 @@ foo — ' | |
| 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. | 
| 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. | 
| 1884 | 
            +
                  assert_equal expect, (Asciidoctor::Helpers.uri_encode given)
         | 
| 1677 1885 | 
             
                end
         | 
| 1678 1886 | 
             
              end
         | 
| 1679 1887 | 
             
            end
         |