asciidoctor 0.1.4 → 1.5.0
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 +209 -25
- data/{LICENSE → LICENSE.adoc} +4 -3
- data/README.adoc +392 -395
- data/Rakefile +94 -137
- data/benchmark/benchmark.rb +127 -0
- data/benchmark/sample-data/mdbasics.adoc +334 -0
- data/bin/asciidoctor +5 -8
- data/bin/asciidoctor-safe +4 -8
- data/compat/asciidoc.conf +78 -11
- data/compat/font-awesome-3-compat.css +397 -0
- data/data/stylesheets/asciidoctor-default.css +399 -0
- data/data/stylesheets/coderay-asciidoctor.css +89 -0
- data/features/open_block.feature +92 -0
- data/features/pass_block.feature +66 -0
- data/features/step_definitions.rb +42 -0
- data/features/text_formatting.feature +55 -0
- data/features/xref.feature +116 -0
- data/lib/asciidoctor.rb +1155 -605
- data/lib/asciidoctor/abstract_block.rb +157 -71
- data/lib/asciidoctor/abstract_node.rb +150 -93
- data/lib/asciidoctor/attribute_list.rb +85 -90
- data/lib/asciidoctor/block.rb +51 -24
- data/lib/asciidoctor/callouts.rb +4 -7
- data/lib/asciidoctor/cli.rb +3 -0
- data/lib/asciidoctor/cli/invoker.rb +86 -76
- data/lib/asciidoctor/cli/options.rb +111 -61
- data/lib/asciidoctor/converter.rb +232 -0
- data/lib/asciidoctor/converter/base.rb +58 -0
- data/lib/asciidoctor/converter/composite.rb +66 -0
- data/lib/asciidoctor/converter/docbook45.rb +94 -0
- data/lib/asciidoctor/converter/docbook5.rb +684 -0
- data/lib/asciidoctor/converter/factory.rb +225 -0
- data/lib/asciidoctor/converter/html5.rb +1081 -0
- data/lib/asciidoctor/converter/template.rb +296 -0
- data/lib/asciidoctor/core_ext.rb +7 -0
- data/lib/asciidoctor/core_ext/object/nil_or_empty.rb +23 -0
- data/lib/asciidoctor/core_ext/string/chr.rb +6 -0
- data/lib/asciidoctor/core_ext/symbol/length.rb +6 -0
- data/lib/asciidoctor/document.rb +590 -304
- data/lib/asciidoctor/extensions.rb +1100 -308
- data/lib/asciidoctor/helpers.rb +109 -46
- data/lib/asciidoctor/inline.rb +16 -9
- data/lib/asciidoctor/list.rb +23 -15
- data/lib/asciidoctor/opal_ext.rb +4 -0
- data/lib/asciidoctor/opal_ext/comparable.rb +38 -0
- data/lib/asciidoctor/opal_ext/dir.rb +13 -0
- data/lib/asciidoctor/opal_ext/error.rb +2 -0
- data/lib/asciidoctor/opal_ext/file.rb +125 -0
- data/lib/asciidoctor/{lexer.rb → parser.rb} +646 -455
- data/lib/asciidoctor/path_resolver.rb +141 -77
- data/lib/asciidoctor/reader.rb +257 -187
- data/lib/asciidoctor/section.rb +12 -16
- data/lib/asciidoctor/stylesheets.rb +91 -0
- data/lib/asciidoctor/substitutors.rb +1548 -0
- data/lib/asciidoctor/table.rb +73 -57
- data/lib/asciidoctor/timings.rb +39 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +22 -14
- data/man/asciidoctor.adoc +18 -10
- data/test/attributes_test.rb +314 -14
- data/test/blocks_test.rb +763 -118
- data/test/converter_test.rb +352 -0
- data/test/document_test.rb +518 -199
- data/test/extensions_test.rb +273 -103
- data/test/fixtures/asciidoc_index.txt +27 -13
- data/test/fixtures/basic-docinfo.xml +1 -1
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/docinfo.xml +1 -1
- data/test/fixtures/include-file.asciidoc +2 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/invoker_test.rb +173 -61
- data/test/links_test.rb +97 -21
- data/test/lists_test.rb +181 -22
- data/test/options_test.rb +86 -2
- data/test/paragraphs_test.rb +47 -5
- data/test/{lexer_test.rb → parser_test.rb} +128 -57
- data/test/paths_test.rb +36 -1
- data/test/preamble_test.rb +25 -17
- data/test/reader_test.rb +404 -249
- data/test/sections_test.rb +623 -58
- data/test/substitutions_test.rb +609 -132
- data/test/tables_test.rb +198 -24
- data/test/test_helper.rb +101 -31
- data/test/text_test.rb +88 -31
- metadata +160 -64
- data/Gemfile +0 -12
- data/Guardfile +0 -18
- data/asciidoctor.gemspec +0 -143
- data/lib/asciidoctor/backends/_stylesheets.rb +0 -466
- data/lib/asciidoctor/backends/base_template.rb +0 -114
- data/lib/asciidoctor/backends/docbook45.rb +0 -774
- data/lib/asciidoctor/backends/docbook5.rb +0 -103
- data/lib/asciidoctor/backends/html5.rb +0 -1214
- data/lib/asciidoctor/renderer.rb +0 -259
- data/lib/asciidoctor/substituters.rb +0 -1083
- data/test/fixtures/asciidoc.txt +0 -105
- data/test/fixtures/ascshort.txt +0 -32
- data/test/fixtures/list_elements.asciidoc +0 -10
- data/test/renderer_test.rb +0 -162
    
        data/test/substitutions_test.rb
    CHANGED
    
    | @@ -1,4 +1,8 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
            unless defined? ASCIIDOCTOR_PROJECT_DIR
         | 
| 3 | 
            +
              $: << File.dirname(__FILE__); $:.uniq!
         | 
| 4 | 
            +
              require 'test_helper'
         | 
| 5 | 
            +
            end
         | 
| 2 6 |  | 
| 3 7 | 
             
            # TODO
         | 
| 4 8 | 
             
            # - test negatives
         | 
| @@ -6,7 +10,7 @@ require 'test_helper' | |
| 6 10 | 
             
            context 'Substitutions' do
         | 
| 7 11 | 
             
              context 'Dispatcher' do
         | 
| 8 12 | 
             
                test 'apply normal substitutions' do
         | 
| 9 | 
            -
                  para = block_from_string("[blue] | 
| 13 | 
            +
                  para = block_from_string("[blue]_http://asciidoc.org[AsciiDoc]_ & [red]*Ruby*\n§ Making +++<u>documentation</u>+++ together +\nsince (C) {inception_year}.")
         | 
| 10 14 | 
             
                  para.document.attributes['inception_year'] = '2012'
         | 
| 11 15 | 
             
                  result = para.apply_normal_subs(para.lines) 
         | 
| 12 16 | 
             
                  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
         | 
| @@ -14,84 +18,147 @@ context 'Substitutions' do | |
| 14 18 | 
             
              end
         | 
| 15 19 |  | 
| 16 20 | 
             
              context 'Quotes' do
         | 
| 21 | 
            +
                BACKSLASH = '\\'
         | 
| 22 | 
            +
             | 
| 17 23 | 
             
                test 'single-line double-quoted string' do
         | 
| 18 | 
            -
                  para = block_from_string(%q{``a few quoted words''})
         | 
| 24 | 
            +
                  para = block_from_string(%q{``a few quoted words''}, :attributes => {'compat-mode' => ''})
         | 
| 25 | 
            +
                  assert_equal '“a few quoted words”', para.sub_quotes(para.source)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  para = block_from_string(%q{"`a few quoted words`"})
         | 
| 19 28 | 
             
                  assert_equal '“a few quoted words”', para.sub_quotes(para.source)
         | 
| 20 29 | 
             
                end
         | 
| 21 30 |  | 
| 22 31 | 
             
                test 'escaped single-line double-quoted string' do
         | 
| 23 | 
            -
                  para = block_from_string( | 
| 32 | 
            +
                  para = block_from_string %(#{BACKSLASH}``a few quoted words''), :attributes => {'compat-mode' => ''}
         | 
| 24 33 | 
             
                  assert_equal %q(‘`a few quoted words’'), para.sub_quotes(para.source)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  para = block_from_string %(#{BACKSLASH * 2}``a few quoted words''), :attributes => {'compat-mode' => ''}
         | 
| 36 | 
            +
                  assert_equal %q(``a few quoted words''), para.sub_quotes(para.source)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  para = block_from_string(%(#{BACKSLASH}"`a few quoted words`"))
         | 
| 39 | 
            +
                  assert_equal %q("`a few quoted words`"), para.sub_quotes(para.source)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  para = block_from_string(%(#{BACKSLASH * 2}"`a few quoted words`"))
         | 
| 42 | 
            +
                  assert_equal %(#{BACKSLASH}"`a few quoted words`"), para.sub_quotes(para.source)
         | 
| 25 43 | 
             
                end
         | 
| 26 44 |  | 
| 27 45 | 
             
                test 'multi-line double-quoted string' do
         | 
| 28 | 
            -
                  para = block_from_string(%Q{``a few\nquoted words''})
         | 
| 46 | 
            +
                  para = block_from_string(%Q{``a few\nquoted words''}, :attributes => {'compat-mode' => ''})
         | 
| 47 | 
            +
                  assert_equal "“a few\nquoted words”", para.sub_quotes(para.source)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  para = block_from_string(%Q{"`a few\nquoted words`"})
         | 
| 29 50 | 
             
                  assert_equal "“a few\nquoted words”", para.sub_quotes(para.source)
         | 
| 30 51 | 
             
                end
         | 
| 31 52 |  | 
| 32 53 | 
             
                test 'double-quoted string with inline single quote' do
         | 
| 33 | 
            -
                  para = block_from_string(%q{``Here's Johnny!''})
         | 
| 54 | 
            +
                  para = block_from_string(%q{``Here's Johnny!''}, :attributes => {'compat-mode' => ''})
         | 
| 55 | 
            +
                  assert_equal %q{“Here's Johnny!”}, para.sub_quotes(para.source)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  para = block_from_string(%q{"`Here's Johnny!`"})
         | 
| 34 58 | 
             
                  assert_equal %q{“Here's Johnny!”}, para.sub_quotes(para.source)
         | 
| 35 59 | 
             
                end
         | 
| 36 60 |  | 
| 37 61 | 
             
                test 'double-quoted string with inline backquote' do
         | 
| 38 | 
            -
                  para = block_from_string(%q{``Here`s Johnny!''})
         | 
| 62 | 
            +
                  para = block_from_string(%q{``Here`s Johnny!''}, :attributes => {'compat-mode' => ''})
         | 
| 39 63 | 
             
                  assert_equal %q{“Here`s Johnny!”}, para.sub_quotes(para.source)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  para = block_from_string(%q{"`Here`s Johnny!`"})
         | 
| 66 | 
            +
                  assert_equal %q{“Here`s Johnny!”}, para.sub_quotes(para.source)
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                test 'double-quoted string around monospaced text' do
         | 
| 70 | 
            +
                  para = block_from_string(%q("``E=mc^2^` is the solution!`"))
         | 
| 71 | 
            +
                  assert_equal %q(“`E=mc<sup>2</sup>` is the solution!”), para.apply_subs(para.source);
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  para = block_from_string(%q("```E=mc^2^`` is the solution!`"))
         | 
| 74 | 
            +
                  assert_equal %q(“<code>E=mc<sup>2</sup></code> is the solution!”), para.apply_subs(para.source);
         | 
| 40 75 | 
             
                end
         | 
| 41 76 |  | 
| 42 77 | 
             
                test 'single-line single-quoted string' do
         | 
| 43 | 
            -
                  para = block_from_string(%q{`a few quoted words'})
         | 
| 78 | 
            +
                  para = block_from_string(%q{`a few quoted words'}, :attributes => {'compat-mode' => ''})
         | 
| 79 | 
            +
                  assert_equal '‘a few quoted words’', para.sub_quotes(para.source)
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  para = block_from_string(%q{'`a few quoted words`'})
         | 
| 44 82 | 
             
                  assert_equal '‘a few quoted words’', para.sub_quotes(para.source)
         | 
| 45 83 | 
             
                end
         | 
| 46 84 |  | 
| 47 85 | 
             
                test 'escaped single-line single-quoted string' do
         | 
| 48 | 
            -
                  para = block_from_string(% | 
| 86 | 
            +
                  para = block_from_string(%(#{BACKSLASH}`a few quoted words'), :attributes => {'compat-mode' => ''})
         | 
| 49 87 | 
             
                  assert_equal %(`a few quoted words'), para.sub_quotes(para.source)
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  para = block_from_string(%(#{BACKSLASH}'`a few quoted words`'))
         | 
| 90 | 
            +
                  assert_equal %('`a few quoted words`'), para.sub_quotes(para.source)
         | 
| 50 91 | 
             
                end
         | 
| 51 92 |  | 
| 52 93 | 
             
                test 'multi-line single-quoted string' do
         | 
| 53 | 
            -
                  para = block_from_string(%Q{`a few\nquoted words'})
         | 
| 94 | 
            +
                  para = block_from_string(%Q{`a few\nquoted words'}, :attributes => {'compat-mode' => ''})
         | 
| 95 | 
            +
                  assert_equal "‘a few\nquoted words’", para.sub_quotes(para.source)
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                  para = block_from_string(%Q{'`a few\nquoted words`'})
         | 
| 54 98 | 
             
                  assert_equal "‘a few\nquoted words’", para.sub_quotes(para.source)
         | 
| 55 99 | 
             
                end
         | 
| 56 100 |  | 
| 57 101 | 
             
                test 'single-quoted string with inline single quote' do
         | 
| 58 | 
            -
                  para = block_from_string(%q{`That isn't what I did.'})
         | 
| 102 | 
            +
                  para = block_from_string(%q{`That isn't what I did.'}, :attributes => {'compat-mode' => ''})
         | 
| 103 | 
            +
                  assert_equal %q{‘That isn't what I did.’}, para.sub_quotes(para.source)
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  para = block_from_string(%q{'`That isn't what I did.`'})
         | 
| 59 106 | 
             
                  assert_equal %q{‘That isn't what I did.’}, para.sub_quotes(para.source)
         | 
| 60 107 | 
             
                end
         | 
| 61 108 |  | 
| 62 109 | 
             
                test 'single-quoted string with inline backquote' do
         | 
| 63 | 
            -
                  para = block_from_string(%q{`Here`s Johnny!'})
         | 
| 110 | 
            +
                  para = block_from_string(%q{`Here`s Johnny!'}, :attributes => {'compat-mode' => ''})
         | 
| 111 | 
            +
                  assert_equal %q{‘Here`s Johnny!’}, para.sub_quotes(para.source)
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  para = block_from_string(%q{'`Here`s Johnny!`'})
         | 
| 64 114 | 
             
                  assert_equal %q{‘Here`s Johnny!’}, para.sub_quotes(para.source)
         | 
| 65 115 | 
             
                end
         | 
| 66 116 |  | 
| 67 | 
            -
                test 'single-line constrained  | 
| 117 | 
            +
                test 'single-line constrained marked string' do
         | 
| 118 | 
            +
                  #para = block_from_string(%q{#a few words#}, :attributes => {'compat-mode' => ''})
         | 
| 119 | 
            +
                  #assert_equal 'a few words', para.sub_quotes(para.source)
         | 
| 120 | 
            +
             | 
| 68 121 | 
             
                  para = block_from_string(%q{#a few words#})
         | 
| 69 | 
            -
                  assert_equal 'a few words', para.sub_quotes(para.source)
         | 
| 122 | 
            +
                  assert_equal '<mark>a few words</mark>', para.sub_quotes(para.source)
         | 
| 70 123 | 
             
                end
         | 
| 71 124 |  | 
| 72 | 
            -
                test 'escaped single-line constrained  | 
| 73 | 
            -
                  para = block_from_string(% | 
| 125 | 
            +
                test 'escaped single-line constrained marked string' do
         | 
| 126 | 
            +
                  para = block_from_string(%(#{BACKSLASH}#a few words#))
         | 
| 74 127 | 
             
                  assert_equal '#a few words#', para.sub_quotes(para.source)
         | 
| 75 128 | 
             
                end
         | 
| 76 129 |  | 
| 77 | 
            -
                test 'multi-line constrained  | 
| 130 | 
            +
                test 'multi-line constrained marked string' do
         | 
| 131 | 
            +
                  #para = block_from_string(%Q{#a few\nwords#}, :attributes => {'compat-mode' => ''})
         | 
| 132 | 
            +
                  #assert_equal "a few\nwords", para.sub_quotes(para.source)
         | 
| 133 | 
            +
             | 
| 78 134 | 
             
                  para = block_from_string(%Q{#a few\nwords#})
         | 
| 79 | 
            -
                  assert_equal "a few\nwords", para.sub_quotes(para.source)
         | 
| 135 | 
            +
                  assert_equal "<mark>a few\nwords</mark>", para.sub_quotes(para.source)
         | 
| 80 136 | 
             
                end
         | 
| 81 137 |  | 
| 82 | 
            -
                test 'single-line unconstrained  | 
| 138 | 
            +
                test 'single-line unconstrained marked string' do
         | 
| 139 | 
            +
                  #para = block_from_string(%q{##--anything goes ##}, :attributes => {'compat-mode' => ''})
         | 
| 140 | 
            +
                  #assert_equal '--anything goes ', para.sub_quotes(para.source)
         | 
| 141 | 
            +
             | 
| 83 142 | 
             
                  para = block_from_string(%q{##--anything goes ##})
         | 
| 84 | 
            -
                  assert_equal ' | 
| 143 | 
            +
                  assert_equal '<mark>--anything goes </mark>', para.sub_quotes(para.source)
         | 
| 85 144 | 
             
                end
         | 
| 86 145 |  | 
| 87 | 
            -
                test 'escaped single-line unconstrained  | 
| 88 | 
            -
                  para = block_from_string(% | 
| 89 | 
            -
                  assert_equal ' | 
| 146 | 
            +
                test 'escaped single-line unconstrained marked string' do
         | 
| 147 | 
            +
                  para = block_from_string(%(#{BACKSLASH}#{BACKSLASH}##--anything goes ##))
         | 
| 148 | 
            +
                  assert_equal '##--anything goes ##', para.sub_quotes(para.source)
         | 
| 90 149 | 
             
                end
         | 
| 91 150 |  | 
| 92 | 
            -
                test 'multi-line unconstrained  | 
| 151 | 
            +
                test 'multi-line unconstrained marked string' do
         | 
| 152 | 
            +
                  #para = block_from_string(%Q{##--anything\ngoes ##}, :attributes => {'compat-mode' => ''})
         | 
| 153 | 
            +
                  #assert_equal "--anything\ngoes ", para.sub_quotes(para.source)
         | 
| 154 | 
            +
             | 
| 93 155 | 
             
                  para = block_from_string(%Q{##--anything\ngoes ##})
         | 
| 94 | 
            -
                  assert_equal " | 
| 156 | 
            +
                  assert_equal "<mark>--anything\ngoes </mark>", para.sub_quotes(para.source)
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                test 'single-line constrained marked string with role' do
         | 
| 160 | 
            +
                  para = block_from_string(%q{[statement]#a few words#})
         | 
| 161 | 
            +
                  assert_equal '<span class="statement">a few words</span>', para.sub_quotes(para.source)
         | 
| 95 162 | 
             
                end
         | 
| 96 163 |  | 
| 97 164 | 
             
                test 'single-line constrained strong string' do
         | 
| @@ -100,7 +167,7 @@ context 'Substitutions' do | |
| 100 167 | 
             
                end
         | 
| 101 168 |  | 
| 102 169 | 
             
                test 'escaped single-line constrained strong string' do
         | 
| 103 | 
            -
                  para = block_from_string(% | 
| 170 | 
            +
                  para = block_from_string(%(#{BACKSLASH}*a few strong words*))
         | 
| 104 171 | 
             
                  assert_equal '*a few strong words*', para.sub_quotes(para.source)
         | 
| 105 172 | 
             
                end
         | 
| 106 173 |  | 
| @@ -114,30 +181,46 @@ context 'Substitutions' do | |
| 114 181 | 
             
                  assert_equal '<strong>bl*ck</strong>-eye', para.sub_quotes(para.source)
         | 
| 115 182 | 
             
                end
         | 
| 116 183 |  | 
| 184 | 
            +
                test 'constrained strong string containing an asterisk and multibyte word chars' do
         | 
| 185 | 
            +
                  para = block_from_string(%q{*黑*眼圈*})
         | 
| 186 | 
            +
                  assert_equal '<strong>黑*眼圈</strong>', para.sub_quotes(para.source)
         | 
| 187 | 
            +
                end if ::RUBY_MIN_VERSION_1_9
         | 
| 188 | 
            +
             | 
| 117 189 | 
             
                test 'single-line constrained quote variation emphasized string' do
         | 
| 118 | 
            -
                  para = block_from_string(%q{ | 
| 190 | 
            +
                  para = block_from_string(%q{_a few emphasized words_})
         | 
| 119 191 | 
             
                  assert_equal '<em>a few emphasized words</em>', para.sub_quotes(para.source)
         | 
| 120 192 | 
             
                end
         | 
| 121 193 |  | 
| 122 194 | 
             
                test 'escaped single-line constrained quote variation emphasized string' do
         | 
| 123 | 
            -
                  para = block_from_string(% | 
| 124 | 
            -
                  assert_equal %q( | 
| 195 | 
            +
                  para = block_from_string(%(#{BACKSLASH}_a few emphasized words_))
         | 
| 196 | 
            +
                  assert_equal %q(_a few emphasized words_), para.sub_quotes(para.source)
         | 
| 197 | 
            +
                end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                test 'escaped single quoted string' do
         | 
| 200 | 
            +
                  para = block_from_string(%(#{BACKSLASH}'a few emphasized words'))
         | 
| 201 | 
            +
                  # NOTE the \' is replaced with ' by the :replacements substitution, later in the substitution pipeline
         | 
| 202 | 
            +
                  assert_equal %(#{BACKSLASH}'a few emphasized words'), para.sub_quotes(para.source)
         | 
| 125 203 | 
             
                end
         | 
| 126 204 |  | 
| 127 205 | 
             
                test 'multi-line constrained emphasized quote variation string' do
         | 
| 128 | 
            -
                  para = block_from_string(%Q{ | 
| 206 | 
            +
                  para = block_from_string(%Q{_a few\nemphasized words_})
         | 
| 129 207 | 
             
                  assert_equal "<em>a few\nemphasized words</em>", para.sub_quotes(para.source)
         | 
| 130 208 | 
             
                end
         | 
| 131 209 |  | 
| 132 210 | 
             
                test 'single-quoted string containing an emphasized phrase' do
         | 
| 133 | 
            -
                  para = block_from_string(%q{`I told him, 'Just go for it!''})
         | 
| 211 | 
            +
                  para = block_from_string(%q{`I told him, 'Just go for it!''}, :attributes => {'compat-mode' => ''})
         | 
| 134 212 | 
             
                  assert_equal '‘I told him, <em>Just go for it!</em>’', para.sub_quotes(para.source)
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                  para = block_from_string(%q{'`I told him, 'Just go for it!'`'})
         | 
| 215 | 
            +
                  assert_equal %q(‘I told him, 'Just go for it!'’), para.sub_quotes(para.source)
         | 
| 135 216 | 
             
                end
         | 
| 136 217 |  | 
| 137 218 | 
             
                test 'escaped single-quotes inside emphasized words are restored' do
         | 
| 138 | 
            -
                  para = block_from_string(% | 
| 139 | 
            -
                   | 
| 140 | 
            -
             | 
| 219 | 
            +
                  para = block_from_string(%('Here#{BACKSLASH}'s Johnny!'), :attributes => {'compat-mode' => ''})
         | 
| 220 | 
            +
                  assert_equal %q(<em>Here's Johnny!</em>), para.apply_normal_subs(para.lines)
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                  para = block_from_string(%('Here#{BACKSLASH}'s Johnny!'))
         | 
| 223 | 
            +
                  assert_equal %q('Here's Johnny!'), para.apply_normal_subs(para.lines)
         | 
| 141 224 | 
             
                end
         | 
| 142 225 |  | 
| 143 226 | 
             
                test 'single-line constrained emphasized underline variation string' do
         | 
| @@ -146,7 +229,7 @@ context 'Substitutions' do | |
| 146 229 | 
             
                end
         | 
| 147 230 |  | 
| 148 231 | 
             
                test 'escaped single-line constrained emphasized underline variation string' do
         | 
| 149 | 
            -
                  para = block_from_string(% | 
| 232 | 
            +
                  para = block_from_string(%(#{BACKSLASH}_a few emphasized words_))
         | 
| 150 233 | 
             
                  assert_equal '_a few emphasized words_', para.sub_quotes(para.source)
         | 
| 151 234 | 
             
                end
         | 
| 152 235 |  | 
| @@ -155,46 +238,67 @@ context 'Substitutions' do | |
| 155 238 | 
             
                  assert_equal "<em>a few\nemphasized words</em>", para.sub_quotes(para.source)
         | 
| 156 239 | 
             
                end
         | 
| 157 240 |  | 
| 241 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 158 242 | 
             
                test 'single-line constrained monospaced string' do
         | 
| 159 | 
            -
                  para = block_from_string(% | 
| 160 | 
            -
                  # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 243 | 
            +
                  para = block_from_string(%(`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
         | 
| 161 244 | 
             
                  assert_equal '<code>a few <{monospaced}> words</code>', para.apply_normal_subs(para.lines)
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                  para = block_from_string(%(`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
         | 
| 247 | 
            +
                  assert_equal '<code>a few <monospaced> words</code>', para.apply_normal_subs(para.lines)
         | 
| 162 248 | 
             
                end
         | 
| 163 249 |  | 
| 250 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 164 251 | 
             
                test 'single-line constrained monospaced string with role' do
         | 
| 165 | 
            -
                  para = block_from_string(% | 
| 166 | 
            -
                  # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 252 | 
            +
                  para = block_from_string(%([input]`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
         | 
| 167 253 | 
             
                  assert_equal '<code class="input">a few <{monospaced}> words</code>', para.apply_normal_subs(para.lines)
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                  para = block_from_string(%([input]`a few <{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
         | 
| 256 | 
            +
                  assert_equal '<code class="input">a few <monospaced> words</code>', para.apply_normal_subs(para.lines)
         | 
| 168 257 | 
             
                end
         | 
| 169 258 |  | 
| 259 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 170 260 | 
             
                test 'escaped single-line constrained monospaced string' do
         | 
| 171 | 
            -
                  para = block_from_string(% | 
| 172 | 
            -
                   | 
| 261 | 
            +
                  para = block_from_string(%(#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
         | 
| 262 | 
            +
                  assert_equal '`a few <monospaced> words`', para.apply_normal_subs(para.lines)
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                  para = block_from_string(%(#{BACKSLASH}`a few <monospaced> words`))
         | 
| 173 265 | 
             
                  assert_equal '`a few <monospaced> words`', para.apply_normal_subs(para.lines)
         | 
| 174 266 | 
             
                end
         | 
| 175 267 |  | 
| 268 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 176 269 | 
             
                test 'escaped single-line constrained monospaced string with role' do
         | 
| 177 | 
            -
                  para = block_from_string(% | 
| 178 | 
            -
                   | 
| 270 | 
            +
                  para = block_from_string(%([input]#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
         | 
| 271 | 
            +
                  assert_equal '[input]`a few <monospaced> words`', para.apply_normal_subs(para.lines)
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                  para = block_from_string(%([input]#{BACKSLASH}`a few <monospaced> words`))
         | 
| 179 274 | 
             
                  assert_equal '[input]`a few <monospaced> words`', para.apply_normal_subs(para.lines)
         | 
| 180 275 | 
             
                end
         | 
| 181 276 |  | 
| 277 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 182 278 | 
             
                test 'escaped role on single-line constrained monospaced string' do
         | 
| 183 | 
            -
                  para = block_from_string(% | 
| 184 | 
            -
                   | 
| 279 | 
            +
                  para = block_from_string(%(#{BACKSLASH}[input]`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
         | 
| 280 | 
            +
                  assert_equal '[input]<code>a few <monospaced> words</code>', para.apply_normal_subs(para.lines)
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                  para = block_from_string(%(#{BACKSLASH}[input]`a few <monospaced> words`))
         | 
| 185 283 | 
             
                  assert_equal '[input]<code>a few <monospaced> words</code>', para.apply_normal_subs(para.lines)
         | 
| 186 284 | 
             
                end
         | 
| 187 285 |  | 
| 286 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 188 287 | 
             
                test 'escaped role on escaped single-line constrained monospaced string' do
         | 
| 189 | 
            -
                  para = block_from_string(% | 
| 190 | 
            -
                  #  | 
| 191 | 
            -
             | 
| 288 | 
            +
                  para = block_from_string(%(#{BACKSLASH}[input]#{BACKSLASH}`a few <monospaced> words`), :attributes => {'compat-mode' => ''})
         | 
| 289 | 
            +
                  assert_equal %(#{BACKSLASH}[input]`a few <monospaced> words`), para.apply_normal_subs(para.lines)
         | 
| 290 | 
            +
             | 
| 291 | 
            +
                  para = block_from_string(%(#{BACKSLASH}[input]#{BACKSLASH}`a few <monospaced> words`))
         | 
| 292 | 
            +
                  assert_equal %(#{BACKSLASH}[input]`a few <monospaced> words`), para.apply_normal_subs(para.lines)
         | 
| 192 293 | 
             
                end
         | 
| 193 294 |  | 
| 295 | 
            +
                # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 194 296 | 
             
                test 'multi-line constrained monospaced string' do
         | 
| 195 | 
            -
                  para = block_from_string(% | 
| 196 | 
            -
                  # NOTE must use apply_normal_subs because constrained monospaced is handled as a passthrough
         | 
| 297 | 
            +
                  para = block_from_string(%(`a few\n<{monospaced}> words`), :attributes => {'monospaced' => 'monospaced', 'compat-mode' => ''})
         | 
| 197 298 | 
             
                  assert_equal "<code>a few\n<{monospaced}> words</code>", para.apply_normal_subs(para.lines)
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                  para = block_from_string(%(`a few\n<{monospaced}> words`), :attributes => {'monospaced' => 'monospaced'})
         | 
| 301 | 
            +
                  assert_equal "<code>a few\n<monospaced> words</code>", para.apply_normal_subs(para.lines)
         | 
| 198 302 | 
             
                end
         | 
| 199 303 |  | 
| 200 304 | 
             
                test 'single-line unconstrained strong chars' do
         | 
| @@ -203,7 +307,7 @@ context 'Substitutions' do | |
| 203 307 | 
             
                end
         | 
| 204 308 |  | 
| 205 309 | 
             
                test 'escaped single-line unconstrained strong chars' do
         | 
| 206 | 
            -
                  para = block_from_string(% | 
| 310 | 
            +
                  para = block_from_string(%(#{BACKSLASH}**Git**Hub))
         | 
| 207 311 | 
             
                  assert_equal '<strong>*Git</strong>*Hub', para.sub_quotes(para.source)
         | 
| 208 312 | 
             
                end
         | 
| 209 313 |  | 
| @@ -224,7 +328,7 @@ context 'Substitutions' do | |
| 224 328 |  | 
| 225 329 | 
             
                # TODO this is not the same result as AsciiDoc, though I don't understand why AsciiDoc gets what it gets
         | 
| 226 330 | 
             
                test 'escaped unconstrained strong chars with role' do
         | 
| 227 | 
            -
                  para = block_from_string(% | 
| 331 | 
            +
                  para = block_from_string(%(Git#{BACKSLASH}[blue]**Hub**))
         | 
| 228 332 | 
             
                  assert_equal %q{Git[blue]<strong>*Hub</strong>*}, para.sub_quotes(para.source)
         | 
| 229 333 | 
             
                end
         | 
| 230 334 |  | 
| @@ -234,10 +338,15 @@ context 'Substitutions' do | |
| 234 338 | 
             
                end
         | 
| 235 339 |  | 
| 236 340 | 
             
                test 'escaped single-line unconstrained emphasized chars' do
         | 
| 237 | 
            -
                  para = block_from_string(% | 
| 341 | 
            +
                  para = block_from_string(%(#{BACKSLASH}__Git__Hub))
         | 
| 238 342 | 
             
                  assert_equal '__Git__Hub', para.sub_quotes(para.source)
         | 
| 239 343 | 
             
                end
         | 
| 240 344 |  | 
| 345 | 
            +
                test 'escaped single-line unconstrained emphasized chars around word' do
         | 
| 346 | 
            +
                  para = block_from_string(%(#{BACKSLASH}#{BACKSLASH}__GitHub__))
         | 
| 347 | 
            +
                  assert_equal '__GitHub__', para.sub_quotes(para.source)
         | 
| 348 | 
            +
                end
         | 
| 349 | 
            +
             | 
| 241 350 | 
             
                test 'multi-line unconstrained emphasized chars' do
         | 
| 242 351 | 
             
                  para = block_from_string(%Q{__G\ni\nt\n__Hub})
         | 
| 243 352 | 
             
                  assert_equal "<em>G\ni\nt\n</em>Hub", para.sub_quotes(para.source)
         | 
| @@ -249,68 +358,120 @@ context 'Substitutions' do | |
| 249 358 | 
             
                end
         | 
| 250 359 |  | 
| 251 360 | 
             
                test 'escaped unconstrained emphasis chars with role' do
         | 
| 252 | 
            -
                  para = block_from_string(% | 
| 361 | 
            +
                  para = block_from_string(%(#{BACKSLASH}[gray]__Git__Hub))
         | 
| 253 362 | 
             
                  assert_equal %q{[gray]__Git__Hub}, para.sub_quotes(para.source)
         | 
| 254 363 | 
             
                end
         | 
| 255 364 |  | 
| 256 365 | 
             
                test 'single-line constrained monospaced chars' do
         | 
| 257 | 
            -
                  para = block_from_string(%q{call +save()+ to persist the changes})
         | 
| 366 | 
            +
                  para = block_from_string(%q{call +save()+ to persist the changes}, :attributes => {'compat-mode' => ''})
         | 
| 367 | 
            +
                  assert_equal 'call <code>save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                  para = block_from_string(%q{call [x-]+save()+ to persist the changes})
         | 
| 370 | 
            +
                  assert_equal 'call <code>save()</code> to persist the changes', para.apply_subs(para.source)
         | 
| 371 | 
            +
             | 
| 372 | 
            +
                  para = block_from_string(%q{call `save()` to persist the changes})
         | 
| 258 373 | 
             
                  assert_equal 'call <code>save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 259 374 | 
             
                end
         | 
| 260 375 |  | 
| 261 376 | 
             
                test 'single-line constrained monospaced chars with role' do
         | 
| 262 | 
            -
                  para = block_from_string(%q{call [method]+save()+ to persist the changes})
         | 
| 377 | 
            +
                  para = block_from_string(%q{call [method]+save()+ to persist the changes}, :attributes => {'compat-mode' => ''})
         | 
| 378 | 
            +
                  assert_equal 'call <code class="method">save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                  para = block_from_string(%q{call [method x-]+save()+ to persist the changes})
         | 
| 381 | 
            +
                  assert_equal 'call <code class="method">save()</code> to persist the changes', para.apply_subs(para.source)
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                  para = block_from_string(%q{call [method]`save()` to persist the changes})
         | 
| 263 384 | 
             
                  assert_equal 'call <code class="method">save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 264 385 | 
             
                end
         | 
| 265 386 |  | 
| 266 387 | 
             
                test 'escaped single-line constrained monospaced chars' do
         | 
| 267 | 
            -
                  para = block_from_string(% | 
| 388 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}+save()+ to persist the changes), :attributes => {'compat-mode' => ''})
         | 
| 268 389 | 
             
                  assert_equal 'call +save()+ to persist the changes', para.sub_quotes(para.source)
         | 
| 390 | 
            +
             | 
| 391 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}`save()` to persist the changes))
         | 
| 392 | 
            +
                  assert_equal 'call `save()` to persist the changes', para.sub_quotes(para.source)
         | 
| 269 393 | 
             
                end
         | 
| 270 394 |  | 
| 271 395 | 
             
                test 'escaped single-line constrained monospaced chars with role' do
         | 
| 272 | 
            -
                  para = block_from_string(% | 
| 396 | 
            +
                  para = block_from_string(%(call [method]#{BACKSLASH}+save()+ to persist the changes), :attributes => {'compat-mode' => ''})
         | 
| 273 397 | 
             
                  assert_equal 'call [method]+save()+ to persist the changes', para.sub_quotes(para.source)
         | 
| 398 | 
            +
             | 
| 399 | 
            +
                  para = block_from_string(%(call [method]#{BACKSLASH}`save()` to persist the changes))
         | 
| 400 | 
            +
                  assert_equal 'call [method]`save()` to persist the changes', para.sub_quotes(para.source)
         | 
| 274 401 | 
             
                end
         | 
| 275 402 |  | 
| 276 403 | 
             
                test 'escaped role on single-line constrained monospaced chars' do
         | 
| 277 | 
            -
                  para = block_from_string(% | 
| 404 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}[method]+save()+ to persist the changes), :attributes => {'compat-mode' => ''})
         | 
| 405 | 
            +
                  assert_equal 'call [method]<code>save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 406 | 
            +
             | 
| 407 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}[method]`save()` to persist the changes))
         | 
| 278 408 | 
             
                  assert_equal 'call [method]<code>save()</code> to persist the changes', para.sub_quotes(para.source)
         | 
| 279 409 | 
             
                end
         | 
| 280 410 |  | 
| 281 411 | 
             
                test 'escaped role on escaped single-line constrained monospaced chars' do
         | 
| 282 | 
            -
                  para = block_from_string(% | 
| 283 | 
            -
                  assert_equal  | 
| 412 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}[method]#{BACKSLASH}+save()+ to persist the changes), :attributes => {'compat-mode' => ''})
         | 
| 413 | 
            +
                  assert_equal %(call #{BACKSLASH}[method]+save()+ to persist the changes), para.sub_quotes(para.source)
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                  para = block_from_string(%(call #{BACKSLASH}[method]#{BACKSLASH}`save()` to persist the changes))
         | 
| 416 | 
            +
                  assert_equal %(call #{BACKSLASH}[method]`save()` to persist the changes), para.sub_quotes(para.source)
         | 
| 284 417 | 
             
                end
         | 
| 285 418 |  | 
| 286 419 | 
             
                test 'single-line unconstrained monospaced chars' do
         | 
| 287 | 
            -
                  para = block_from_string(%q{Git++Hub++})
         | 
| 420 | 
            +
                  para = block_from_string(%q{Git++Hub++}, :attributes => {'compat-mode' => ''})
         | 
| 421 | 
            +
                  assert_equal 'Git<code>Hub</code>', para.sub_quotes(para.source)
         | 
| 422 | 
            +
             | 
| 423 | 
            +
                  para = block_from_string(%q{Git[x-]++Hub++})
         | 
| 424 | 
            +
                  assert_equal 'Git<code>Hub</code>', para.apply_subs(para.source)
         | 
| 425 | 
            +
             | 
| 426 | 
            +
                  para = block_from_string(%q{Git``Hub``})
         | 
| 288 427 | 
             
                  assert_equal 'Git<code>Hub</code>', para.sub_quotes(para.source)
         | 
| 289 428 | 
             
                end
         | 
| 290 429 |  | 
| 291 430 | 
             
                test 'escaped single-line unconstrained monospaced chars' do
         | 
| 292 | 
            -
                  para = block_from_string(% | 
| 431 | 
            +
                  para = block_from_string(%(Git#{BACKSLASH}++Hub++), :attributes => {'compat-mode' => ''})
         | 
| 293 432 | 
             
                  assert_equal 'Git+<code>Hub</code>+', para.sub_quotes(para.source)
         | 
| 433 | 
            +
             | 
| 434 | 
            +
                  para = block_from_string(%(Git#{BACKSLASH * 2}++Hub++), :attributes => {'compat-mode' => ''})
         | 
| 435 | 
            +
                  assert_equal 'Git++Hub++', para.sub_quotes(para.source)
         | 
| 436 | 
            +
             | 
| 437 | 
            +
                  para = block_from_string(%(Git#{BACKSLASH}``Hub``))
         | 
| 438 | 
            +
                  assert_equal 'Git``Hub``', para.sub_quotes(para.source)
         | 
| 294 439 | 
             
                end
         | 
| 295 440 |  | 
| 296 441 | 
             
                test 'multi-line unconstrained monospaced chars' do
         | 
| 297 | 
            -
                  para = block_from_string(%Q{Git++\nH\nu\nb++})
         | 
| 442 | 
            +
                  para = block_from_string(%Q{Git++\nH\nu\nb++}, :attributes => {'compat-mode' => ''})
         | 
| 443 | 
            +
                  assert_equal "Git<code>\nH\nu\nb</code>", para.sub_quotes(para.source)
         | 
| 444 | 
            +
             | 
| 445 | 
            +
                  para = block_from_string(%Q{Git[x-]++\nH\nu\nb++})
         | 
| 446 | 
            +
                  assert_equal %(Git<code>\nH\nu\nb</code>), para.apply_subs(para.source)
         | 
| 447 | 
            +
             | 
| 448 | 
            +
                  para = block_from_string(%Q{Git``\nH\nu\nb``})
         | 
| 298 449 | 
             
                  assert_equal "Git<code>\nH\nu\nb</code>", para.sub_quotes(para.source)
         | 
| 299 450 | 
             
                end
         | 
| 300 451 |  | 
| 301 452 | 
             
                test 'single-line superscript chars' do
         | 
| 302 | 
            -
                  para = block_from_string(% | 
| 303 | 
            -
                  assert_equal  | 
| 453 | 
            +
                  para = block_from_string(%(x^2^ = x * x, e = mc^2^, there's a 1^st^ time for everything))
         | 
| 454 | 
            +
                  assert_equal %(x<sup>2</sup> = x * x, e = mc<sup>2</sup>, there\'s a 1<sup>st</sup> time for everything), para.sub_quotes(para.source)
         | 
| 304 455 | 
             
                end
         | 
| 305 456 |  | 
| 306 457 | 
             
                test 'escaped single-line superscript chars' do
         | 
| 307 | 
            -
                  para = block_from_string(% | 
| 458 | 
            +
                  para = block_from_string(%(x#{BACKSLASH}^2^ = x * x))
         | 
| 308 459 | 
             
                  assert_equal 'x^2^ = x * x', para.sub_quotes(para.source)
         | 
| 309 460 | 
             
                end
         | 
| 310 461 |  | 
| 311 | 
            -
                test ' | 
| 462 | 
            +
                test 'does not match superscript across whitespace' do
         | 
| 312 463 | 
             
                  para = block_from_string(%Q{x^(n\n-\n1)^})
         | 
| 313 | 
            -
                  assert_equal  | 
| 464 | 
            +
                  assert_equal para.source, para.sub_quotes(para.source)
         | 
| 465 | 
            +
                end
         | 
| 466 | 
            +
             | 
| 467 | 
            +
                test 'does not match adjacent superscript chars' do
         | 
| 468 | 
            +
                  para = block_from_string 'a ^^ b'
         | 
| 469 | 
            +
                  assert_equal 'a ^^ b', para.sub_quotes(para.source)
         | 
| 470 | 
            +
                end
         | 
| 471 | 
            +
             | 
| 472 | 
            +
                test 'does not confuse superscript and links with blank window shorthand' do
         | 
| 473 | 
            +
                  para = block_from_string(%Q{http://localhost[Text^] on the 21^st^ and 22^nd^})
         | 
| 474 | 
            +
                  assert_equal '<a href="http://localhost" target="_blank">Text</a> on the 21<sup>st</sup> and 22<sup>nd</sup>', para.content
         | 
| 314 475 | 
             
                end
         | 
| 315 476 |  | 
| 316 477 | 
             
                test 'single-line subscript chars' do
         | 
| @@ -319,13 +480,23 @@ context 'Substitutions' do | |
| 319 480 | 
             
                end
         | 
| 320 481 |  | 
| 321 482 | 
             
                test 'escaped single-line subscript chars' do
         | 
| 322 | 
            -
                  para = block_from_string(% | 
| 483 | 
            +
                  para = block_from_string(%(H#{BACKSLASH}~2~O))
         | 
| 323 484 | 
             
                  assert_equal 'H~2~O', para.sub_quotes(para.source)
         | 
| 324 485 | 
             
                end
         | 
| 325 486 |  | 
| 326 | 
            -
                test ' | 
| 487 | 
            +
                test 'does not match subscript across whitespace' do
         | 
| 327 488 | 
             
                  para = block_from_string(%Q{project~ view\non\nGitHub~})
         | 
| 328 | 
            -
                  assert_equal  | 
| 489 | 
            +
                  assert_equal para.source, para.sub_quotes(para.source)
         | 
| 490 | 
            +
                end
         | 
| 491 | 
            +
             | 
| 492 | 
            +
                test 'does not match adjacent subscript chars' do
         | 
| 493 | 
            +
                  para = block_from_string 'a ~~ b'
         | 
| 494 | 
            +
                  assert_equal 'a ~~ b', para.sub_quotes(para.source)
         | 
| 495 | 
            +
                end
         | 
| 496 | 
            +
             | 
| 497 | 
            +
                test 'does not match subscript across distinct URLs' do
         | 
| 498 | 
            +
                  para = block_from_string(%Q{http://www.abc.com/~def[DEF] and http://www.abc.com/~ghi[GHI]})
         | 
| 499 | 
            +
                  assert_equal para.source, para.sub_quotes(para.source)
         | 
| 329 500 | 
             
                end
         | 
| 330 501 |  | 
| 331 502 | 
             
                test 'quoted text with role shorthand' do
         | 
| @@ -344,7 +515,7 @@ context 'Substitutions' do | |
| 344 515 | 
             
                end
         | 
| 345 516 |  | 
| 346 517 | 
             
                test 'quoted text with id and role shorthand using docbook backend' do
         | 
| 347 | 
            -
                  para = block_from_string(%q{[#bond.white.red-background]#007#}, :backend => ' | 
| 518 | 
            +
                  para = block_from_string(%q{[#bond.white.red-background]#007#}, :backend => 'docbook45')
         | 
| 348 519 | 
             
                  assert_equal '<anchor id="bond" xreflabel="007"/><phrase role="white red-background">007</phrase>', para.sub_quotes(para.source)
         | 
| 349 520 | 
             
                end
         | 
| 350 521 |  | 
| @@ -352,12 +523,26 @@ context 'Substitutions' do | |
| 352 523 | 
             
                  para = block_from_string(%q{[red, foobar]#alert#})
         | 
| 353 524 | 
             
                  assert_equal '<span class="red">alert</span>', para.sub_quotes(para.source)
         | 
| 354 525 | 
             
                end
         | 
| 526 | 
            +
             | 
| 527 | 
            +
                test 'should assign role attribute when shorthand style contains a role' do
         | 
| 528 | 
            +
                  para = block_from_string 'blah'
         | 
| 529 | 
            +
                  result = para.parse_quoted_text_attributes '.red#idref'
         | 
| 530 | 
            +
                  expect = {'id' => 'idref', 'role' => 'red'}
         | 
| 531 | 
            +
                  assert_equal expect, result
         | 
| 532 | 
            +
                end
         | 
| 533 | 
            +
             | 
| 534 | 
            +
                test 'should not assign role attribute if shorthand style has no roles' do
         | 
| 535 | 
            +
                  para = block_from_string 'blah'
         | 
| 536 | 
            +
                  result = para.parse_quoted_text_attributes '#idref'
         | 
| 537 | 
            +
                  expect = {'id' => 'idref'}
         | 
| 538 | 
            +
                  assert_equal expect, result
         | 
| 539 | 
            +
                end
         | 
| 355 540 | 
             
              end
         | 
| 356 541 |  | 
| 357 542 | 
             
              context 'Macros' do
         | 
| 358 543 | 
             
                test 'a single-line link macro should be interpreted as a link' do
         | 
| 359 544 | 
             
                  para = block_from_string('link:/home.html[]')
         | 
| 360 | 
            -
                  assert_equal %q{<a href="/home.html">/home.html</a>}, para.sub_macros(para.source)
         | 
| 545 | 
            +
                  assert_equal %q{<a href="/home.html" class="bare">/home.html</a>}, para.sub_macros(para.source)
         | 
| 361 546 | 
             
                end
         | 
| 362 547 |  | 
| 363 548 | 
             
                test 'a single-line link macro with text should be interpreted as a link' do
         | 
| @@ -397,13 +582,13 @@ context 'Substitutions' do | |
| 397 582 | 
             
                end
         | 
| 398 583 |  | 
| 399 584 | 
             
                test 'should ignore escaped inline email address' do
         | 
| 400 | 
            -
                  para = block_from_string( | 
| 585 | 
            +
                  para = block_from_string(%(#{BACKSLASH}doc.writer@asciidoc.org))
         | 
| 401 586 | 
             
                  assert_equal %q{doc.writer@asciidoc.org}, para.sub_macros(para.source)
         | 
| 402 587 | 
             
                end
         | 
| 403 588 |  | 
| 404 589 | 
             
                test 'a single-line raw url should be interpreted as a link' do
         | 
| 405 590 | 
             
                  para = block_from_string('http://google.com')
         | 
| 406 | 
            -
                  assert_equal %q{<a href="http://google.com">http://google.com</a>}, para.sub_macros(para.source)
         | 
| 591 | 
            +
                  assert_equal %q{<a href="http://google.com" class="bare">http://google.com</a>}, para.sub_macros(para.source)
         | 
| 407 592 | 
             
                end
         | 
| 408 593 |  | 
| 409 594 | 
             
                test 'a single-line raw url with text should be interpreted as a link' do
         | 
| @@ -423,13 +608,13 @@ context 'Substitutions' do | |
| 423 608 | 
             
                end
         | 
| 424 609 |  | 
| 425 610 | 
             
                test 'a single-line escaped raw url should not be interpreted as a link' do
         | 
| 426 | 
            -
                  para = block_from_string( | 
| 611 | 
            +
                  para = block_from_string(%(#{BACKSLASH}http://google.com))
         | 
| 427 612 | 
             
                  assert_equal %q{http://google.com}, para.sub_macros(para.source)
         | 
| 428 613 | 
             
                end
         | 
| 429 614 |  | 
| 430 615 | 
             
                test 'a comma separated list of links should not include commas in links' do
         | 
| 431 616 | 
             
                  para = block_from_string('http://foo.com, http://bar.com, http://example.org')
         | 
| 432 | 
            -
                  assert_equal %q{<a href="http://foo.com">http://foo.com</a>, <a href="http://bar.com">http://bar.com</a>, <a href="http://example.org">http://example.org</a>}, para.sub_macros(para.source)
         | 
| 617 | 
            +
                  assert_equal %q{<a href="http://foo.com" class="bare">http://foo.com</a>, <a href="http://bar.com" class="bare">http://bar.com</a>, <a href="http://example.org" class="bare">http://example.org</a>}, para.sub_macros(para.source)
         | 
| 433 618 | 
             
                end
         | 
| 434 619 |  | 
| 435 620 | 
             
                test 'a single-line image macro should be interpreted as an image' do
         | 
| @@ -443,7 +628,7 @@ context 'Substitutions' do | |
| 443 628 | 
             
                end
         | 
| 444 629 |  | 
| 445 630 | 
             
                test 'a single-line image macro with text containing escaped square bracket should be interpreted as an image with alt text' do
         | 
| 446 | 
            -
                  para = block_from_string( | 
| 631 | 
            +
                  para = block_from_string(%(image:tiger.png[[Another#{BACKSLASH}] Tiger]))
         | 
| 447 632 | 
             
                  assert_equal %{<span class="image"><img src="tiger.png" alt="[Another] Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 448 633 | 
             
                end
         | 
| 449 634 |  | 
| @@ -453,6 +638,12 @@ context 'Substitutions' do | |
| 453 638 | 
             
                      para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 454 639 | 
             
                end
         | 
| 455 640 |  | 
| 641 | 
            +
                test 'a single-line image macro with text and dimensions should be interpreted as an image with alt text and dimensions in docbook' do
         | 
| 642 | 
            +
                  para = block_from_string 'image:tiger.png[Tiger, 200, 100]', :backend => 'docbook'
         | 
| 643 | 
            +
                  assert_equal %{<inlinemediaobject><imageobject><imagedata fileref="tiger.png" contentwidth="200" contentdepth="100"/></imageobject><textobject><phrase>Tiger</phrase></textobject></inlinemediaobject>},
         | 
| 644 | 
            +
                      para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 645 | 
            +
                end
         | 
| 646 | 
            +
             | 
| 456 647 | 
             
                test 'a single-line image macro with text and link should be interpreted as a linked image with alt text' do
         | 
| 457 648 | 
             
                  para = block_from_string('image:tiger.png[Tiger, link="http://en.wikipedia.org/wiki/Tiger"]')
         | 
| 458 649 | 
             
                  assert_equal %{<span class="image"><a class="image" href="http://en.wikipedia.org/wiki/Tiger"><img src="tiger.png" alt="Tiger"></a></span>},
         | 
| @@ -471,7 +662,7 @@ context 'Substitutions' do | |
| 471 662 | 
             
                      para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 472 663 | 
             
                end
         | 
| 473 664 |  | 
| 474 | 
            -
                test ' | 
| 665 | 
            +
                test 'an inline image macro with a float attribute should be interpreted as a floating image' do
         | 
| 475 666 | 
             
                  para = block_from_string %(image:http://example.com/images/tiger.png[tiger, float="right"] Beware of the tigers!)
         | 
| 476 667 | 
             
                  assert_equal %{<span class="image" style="float: right"><img src="http://example.com/images/tiger.png" alt="tiger"></span> Beware of the tigers!},
         | 
| 477 668 | 
             
                      para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| @@ -519,17 +710,17 @@ context 'Substitutions' do | |
| 519 710 |  | 
| 520 711 | 
             
                test 'an icon macro should be interpreted as a font-based icon when icons=font' do
         | 
| 521 712 | 
             
                  para = block_from_string 'icon:github[]', :attributes => {'icons' => 'font'}
         | 
| 522 | 
            -
                  assert_equal %{<span class="icon"><i class=" | 
| 713 | 
            +
                  assert_equal %{<span class="icon"><i class="fa fa-github"></i></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 523 714 | 
             
                end
         | 
| 524 715 |  | 
| 525 716 | 
             
                test 'an icon macro with a size should be interpreted as a font-based icon with a size when icons=font' do
         | 
| 526 717 | 
             
                  para = block_from_string 'icon:github[4x]', :attributes => {'icons' => 'font'}
         | 
| 527 | 
            -
                  assert_equal %{<span class="icon"><i class=" | 
| 718 | 
            +
                  assert_equal %{<span class="icon"><i class="fa fa-github fa-4x"></i></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 528 719 | 
             
                end
         | 
| 529 720 |  | 
| 530 721 | 
             
                test 'an icon macro with a role and title should be interpreted as a font-based icon with a class and title when icons=font' do
         | 
| 531 722 | 
             
                  para = block_from_string 'icon:heart[role="red", title="Heart me"]', :attributes => {'icons' => 'font'}
         | 
| 532 | 
            -
                  assert_equal %{<span class="icon red"><i class=" | 
| 723 | 
            +
                  assert_equal %{<span class="icon red"><i class="fa fa-heart" title="Heart me"></i></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
         | 
| 533 724 | 
             
                end
         | 
| 534 725 |  | 
| 535 726 | 
             
                test 'a single-line footnote macro should be registered and rendered as a footnote' do
         | 
| @@ -542,14 +733,22 @@ context 'Substitutions' do | |
| 542 733 | 
             
                  assert_equal 'An example footnote.', footnote.text
         | 
| 543 734 | 
             
                end
         | 
| 544 735 |  | 
| 545 | 
            -
                test 'a multi-line footnote macro should be registered and rendered as a footnote' do
         | 
| 736 | 
            +
                test 'a multi-line footnote macro should be registered and rendered as a footnote without endline' do
         | 
| 546 737 | 
             
                  para = block_from_string("Sentence text footnote:[An example footnote\nwith wrapped text.].")
         | 
| 547 738 | 
             
                  assert_equal %(Sentence text <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>.), para.sub_macros(para.source)
         | 
| 548 739 | 
             
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 549 740 | 
             
                  footnote = para.document.references[:footnotes].first
         | 
| 550 741 | 
             
                  assert_equal 1, footnote.index
         | 
| 551 742 | 
             
                  assert footnote.id.nil?
         | 
| 552 | 
            -
                  assert_equal "An example footnote | 
| 743 | 
            +
                  assert_equal "An example footnote with wrapped text.", footnote.text
         | 
| 744 | 
            +
                end
         | 
| 745 | 
            +
             | 
| 746 | 
            +
                test 'an escaped closing square bracket in a footnote should be unescaped when rendered' do
         | 
| 747 | 
            +
                  para = block_from_string(%(footnote:[a #{BACKSLASH}] b].))
         | 
| 748 | 
            +
                  assert_equal %(<span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>.), para.sub_macros(para.source)
         | 
| 749 | 
            +
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 750 | 
            +
                  footnote = para.document.references[:footnotes].first
         | 
| 751 | 
            +
                  assert_equal "a ] b", footnote.text
         | 
| 553 752 | 
             
                end
         | 
| 554 753 |  | 
| 555 754 | 
             
                test 'a footnote macro can be directly adjacent to preceding word' do
         | 
| @@ -557,7 +756,19 @@ context 'Substitutions' do | |
| 557 756 | 
             
                  assert_equal %(Sentence text<span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>.), para.sub_macros(para.source)
         | 
| 558 757 | 
             
                end
         | 
| 559 758 |  | 
| 560 | 
            -
                test 'a footnote macro may contain  | 
| 759 | 
            +
                test 'a footnote macro may contain an escaped backslash' do
         | 
| 760 | 
            +
                  para = block_from_string("footnote:[\\]]\nfootnote:[a \\] b]\nfootnote:[a \\]\\] b]")
         | 
| 761 | 
            +
                  para.sub_macros(para.source)
         | 
| 762 | 
            +
                  assert_equal 3, para.document.references[:footnotes].size
         | 
| 763 | 
            +
                  footnote1 = para.document.references[:footnotes][0]
         | 
| 764 | 
            +
                  assert_equal ']', footnote1.text
         | 
| 765 | 
            +
                  footnote2 = para.document.references[:footnotes][1]
         | 
| 766 | 
            +
                  assert_equal 'a ] b', footnote2.text
         | 
| 767 | 
            +
                  footnote3 = para.document.references[:footnotes][2]
         | 
| 768 | 
            +
                  assert_equal 'a ]] b', footnote3.text
         | 
| 769 | 
            +
                end
         | 
| 770 | 
            +
             | 
| 771 | 
            +
                test 'a footnote macro may contain a link macro' do
         | 
| 561 772 | 
             
                  para = block_from_string('Share your code. footnote:[http://github.com[GitHub]]')
         | 
| 562 773 | 
             
                  assert_equal %(Share your code. <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>), para.sub_macros(para.source)
         | 
| 563 774 | 
             
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| @@ -571,7 +782,7 @@ context 'Substitutions' do | |
| 571 782 | 
             
                  assert_equal %(the JLine <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>\nlibrary.), result
         | 
| 572 783 | 
             
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 573 784 | 
             
                  fn1 = para.document.references[:footnotes].first
         | 
| 574 | 
            -
                  assert_equal '<a href="https://github.com/jline/jline2">https://github.com/jline/jline2</a>', fn1.text
         | 
| 785 | 
            +
                  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
         | 
| 575 786 | 
             
                end
         | 
| 576 787 |  | 
| 577 788 | 
             
                test 'a footnote macro followed by a semi-colon may contain a plain URL' do
         | 
| @@ -580,7 +791,32 @@ context 'Substitutions' do | |
| 580 791 | 
             
                  assert_equal %(the JLine <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>;\nlibrary.), result
         | 
| 581 792 | 
             
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 582 793 | 
             
                  fn1 = para.document.references[:footnotes].first
         | 
| 583 | 
            -
                  assert_equal '<a href="https://github.com/jline/jline2">https://github.com/jline/jline2</a>', fn1.text
         | 
| 794 | 
            +
                  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
         | 
| 795 | 
            +
                end
         | 
| 796 | 
            +
             | 
| 797 | 
            +
                test 'a footnote macro may contain an xref macro' do
         | 
| 798 | 
            +
                  # specialcharacters escaping is simulated
         | 
| 799 | 
            +
                  para = block_from_string('text footnote:[<<_install,Install>>]')
         | 
| 800 | 
            +
                  assert_equal %(text <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>), para.sub_macros(para.source)
         | 
| 801 | 
            +
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 802 | 
            +
                  footnote1 = para.document.references[:footnotes][0]
         | 
| 803 | 
            +
                  assert_equal '<a href="#_install">Install</a>', footnote1.text
         | 
| 804 | 
            +
                end
         | 
| 805 | 
            +
             | 
| 806 | 
            +
                test 'a footnote macro may contain an anchor macro' do
         | 
| 807 | 
            +
                  para = block_from_string('text footnote:[a [[b\]\] \[[c\]\] d]')
         | 
| 808 | 
            +
                  assert_equal %(text <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>), para.sub_macros(para.source)
         | 
| 809 | 
            +
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 810 | 
            +
                  footnote1 = para.document.references[:footnotes][0]
         | 
| 811 | 
            +
                  assert_equal 'a <a id="b"></a> [[c]] d', footnote1.text
         | 
| 812 | 
            +
                end
         | 
| 813 | 
            +
             | 
| 814 | 
            +
                test 'a footnote macro may contain a bibliographic anchor macro' do
         | 
| 815 | 
            +
                  para = block_from_string('text footnote:[a [[[b\]\]\] c]')
         | 
| 816 | 
            +
                  assert_equal %(text <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>), para.sub_macros(para.source)
         | 
| 817 | 
            +
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 818 | 
            +
                  footnote1 = para.document.references[:footnotes][0]
         | 
| 819 | 
            +
                  assert_equal 'a <a id="b"></a>[b] c', footnote1.text
         | 
| 584 820 | 
             
                end
         | 
| 585 821 |  | 
| 586 822 | 
             
                test 'should increment index of subsequent footnote macros' do
         | 
| @@ -607,14 +843,14 @@ context 'Substitutions' do | |
| 607 843 | 
             
                  assert_equal 'An example footnote.', footnote.text
         | 
| 608 844 | 
             
                end
         | 
| 609 845 |  | 
| 610 | 
            -
                test 'a footnoteref macro with id and multi-line text should be registered and rendered as a footnote' do
         | 
| 846 | 
            +
                test 'a footnoteref macro with id and multi-line text should be registered and rendered as a footnote without endlines' do
         | 
| 611 847 | 
             
                  para = block_from_string("Sentence text footnoteref:[ex1, An example footnote\nwith wrapped text.].")
         | 
| 612 848 | 
             
                  assert_equal %(Sentence text <span class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>.), para.sub_macros(para.source)
         | 
| 613 849 | 
             
                  assert_equal 1, para.document.references[:footnotes].size
         | 
| 614 850 | 
             
                  footnote = para.document.references[:footnotes].first
         | 
| 615 851 | 
             
                  assert_equal 1, footnote.index
         | 
| 616 852 | 
             
                  assert_equal 'ex1', footnote.id
         | 
| 617 | 
            -
                  assert_equal "An example footnote | 
| 853 | 
            +
                  assert_equal "An example footnote with wrapped text.", footnote.text
         | 
| 618 854 | 
             
                end
         | 
| 619 855 |  | 
| 620 856 | 
             
                test 'a footnoteref macro with id should refer to footnoteref with same id' do
         | 
| @@ -627,6 +863,11 @@ context 'Substitutions' do | |
| 627 863 | 
             
                  assert_equal 'An example footnote.', footnote.text
         | 
| 628 864 | 
             
                end
         | 
| 629 865 |  | 
| 866 | 
            +
                test 'an unresolved footnoteref should not crash the processor' do
         | 
| 867 | 
            +
                  para = block_from_string('Sentence text footnoteref:[ex1].')
         | 
| 868 | 
            +
                  para.sub_macros para.source
         | 
| 869 | 
            +
                end
         | 
| 870 | 
            +
             | 
| 630 871 | 
             
                test 'a single-line index term macro with a primary term should be registered as an index reference' do
         | 
| 631 872 | 
             
                  sentence = "The tiger (Panthera tigris) is the largest cat species.\n"
         | 
| 632 873 | 
             
                  macros = ['indexterm:[Tigers]', '(((Tigers)))']
         | 
| @@ -675,6 +916,31 @@ context 'Substitutions' do | |
| 675 916 | 
             
                  end
         | 
| 676 917 | 
             
                end
         | 
| 677 918 |  | 
| 919 | 
            +
                test 'should not split index terms on commas inside of quoted terms' do
         | 
| 920 | 
            +
                  inputs = []
         | 
| 921 | 
            +
                  inputs.push <<-EOS
         | 
| 922 | 
            +
            Tigers are big, scary cats.
         | 
| 923 | 
            +
            indexterm:[Tigers, "[Big\\],
         | 
| 924 | 
            +
            scary cats"]
         | 
| 925 | 
            +
            EOS
         | 
| 926 | 
            +
                  inputs.push <<-EOS
         | 
| 927 | 
            +
            Tigers are big, scary cats.
         | 
| 928 | 
            +
            (((Tigers, "[Big],
         | 
| 929 | 
            +
            scary cats")))
         | 
| 930 | 
            +
            EOS
         | 
| 931 | 
            +
             | 
| 932 | 
            +
                  inputs.each do |input|
         | 
| 933 | 
            +
                    para = block_from_string input
         | 
| 934 | 
            +
                    output = para.sub_macros(para.source)
         | 
| 935 | 
            +
                    assert_equal input.lines.first, output
         | 
| 936 | 
            +
                    assert_equal 1, para.document.references[:indexterms].size
         | 
| 937 | 
            +
                    terms = para.document.references[:indexterms].first
         | 
| 938 | 
            +
                    assert_equal 2, terms.size
         | 
| 939 | 
            +
                    assert_equal 'Tigers', terms.first
         | 
| 940 | 
            +
                    assert_equal '[Big], scary cats', terms.last
         | 
| 941 | 
            +
                  end
         | 
| 942 | 
            +
                end
         | 
| 943 | 
            +
             | 
| 678 944 | 
             
                test 'normal substitutions are performed on an index term macro' do
         | 
| 679 945 | 
             
                  sentence = "The tiger (Panthera tigris) is the largest cat species.\n"
         | 
| 680 946 | 
             
                  macros = ['indexterm:[*Tigers*]', '(((*Tigers*)))']
         | 
| @@ -768,8 +1034,8 @@ context 'Substitutions' do | |
| 768 1034 | 
             
                  assert_equal "The panthera tigris is the largest cat species.\n", output
         | 
| 769 1035 | 
             
                  terms = para.document.references[:indexterms]
         | 
| 770 1036 | 
             
                  assert_equal 2, terms.size
         | 
| 771 | 
            -
                  assert_equal [' | 
| 772 | 
            -
                  assert_equal [' | 
| 1037 | 
            +
                  assert_equal ['panthera tigris'], terms[0]
         | 
| 1038 | 
            +
                  assert_equal ['Big cats', 'Tigers'], terms[1]
         | 
| 773 1039 | 
             
                end
         | 
| 774 1040 |  | 
| 775 1041 | 
             
                context 'Button macro' do
         | 
| @@ -797,37 +1063,37 @@ context 'Substitutions' do | |
| 797 1063 |  | 
| 798 1064 | 
             
                  test 'kbd macro with key combination' do
         | 
| 799 1065 | 
             
                    para = block_from_string('kbd:[Ctrl+Shift+T]', :attributes => {'experimental' => ''})
         | 
| 800 | 
            -
                    assert_equal %q{< | 
| 1066 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
         | 
| 801 1067 | 
             
                  end
         | 
| 802 1068 |  | 
| 803 1069 | 
             
                  test 'kbd macro with key combination with spaces' do
         | 
| 804 1070 | 
             
                    para = block_from_string('kbd:[Ctrl + Shift + T]', :attributes => {'experimental' => ''})
         | 
| 805 | 
            -
                    assert_equal %q{< | 
| 1071 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
         | 
| 806 1072 | 
             
                  end
         | 
| 807 1073 |  | 
| 808 1074 | 
             
                  test 'kbd macro with key combination delimited by commas' do
         | 
| 809 1075 | 
             
                    para = block_from_string('kbd:[Ctrl,Shift,T]', :attributes => {'experimental' => ''})
         | 
| 810 | 
            -
                    assert_equal %q{< | 
| 1076 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>T</kbd></span>}, para.sub_macros(para.source)
         | 
| 811 1077 | 
             
                  end
         | 
| 812 1078 |  | 
| 813 1079 | 
             
                  test 'kbd macro with key combination containing a plus key no spaces' do
         | 
| 814 1080 | 
             
                    para = block_from_string('kbd:[Ctrl++]', :attributes => {'experimental' => ''})
         | 
| 815 | 
            -
                    assert_equal %q{< | 
| 1081 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>+</kbd></span>}, para.sub_macros(para.source)
         | 
| 816 1082 | 
             
                  end
         | 
| 817 1083 |  | 
| 818 1084 | 
             
                  test 'kbd macro with key combination delimited by commands containing a comma key' do
         | 
| 819 1085 | 
             
                    para = block_from_string('kbd:[Ctrl,,]', :attributes => {'experimental' => ''})
         | 
| 820 | 
            -
                    assert_equal %q{< | 
| 1086 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>,</kbd></span>}, para.sub_macros(para.source)
         | 
| 821 1087 | 
             
                  end
         | 
| 822 1088 |  | 
| 823 1089 | 
             
                  test 'kbd macro with key combination containing a plus key with spaces' do
         | 
| 824 1090 | 
             
                    para = block_from_string('kbd:[Ctrl + +]', :attributes => {'experimental' => ''})
         | 
| 825 | 
            -
                    assert_equal %q{< | 
| 1091 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>+</kbd></span>}, para.sub_macros(para.source)
         | 
| 826 1092 | 
             
                  end
         | 
| 827 1093 |  | 
| 828 1094 | 
             
                  test 'kbd macro with key combination containing escaped bracket' do
         | 
| 829 1095 | 
             
                    para = block_from_string('kbd:[Ctrl + \]]', :attributes => {'experimental' => ''})
         | 
| 830 | 
            -
                    assert_equal %q{< | 
| 1096 | 
            +
                    assert_equal %q{<span class="keyseq"><kbd>Ctrl</kbd>+<kbd>]</kbd></span>}, para.sub_macros(para.source)
         | 
| 831 1097 | 
             
                  end
         | 
| 832 1098 |  | 
| 833 1099 | 
             
                  test 'kbd macro with key combination, docbook backend' do
         | 
| @@ -886,6 +1152,16 @@ context 'Substitutions' do | |
| 886 1152 | 
             
                    para = block_from_string('<span class="xmltag"><node></span><span class="classname">r</span>', :attributes => {'experimental' => ''})
         | 
| 887 1153 | 
             
                    assert_equal %q{<span class="xmltag"><node></span><span class="classname">r</span>}, para.sub_macros(para.source)
         | 
| 888 1154 | 
             
                  end
         | 
| 1155 | 
            +
             | 
| 1156 | 
            +
                  test 'should process menu macro with items containing multibyte characters' do
         | 
| 1157 | 
            +
                    para = block_from_string('menu:视图[放大, 重置]', :attributes => {'experimental' => ''})
         | 
| 1158 | 
            +
                    assert_equal %q{<span class="menuseq"><span class="menu">视图</span> ▸ <span class="submenu">放大</span> ▸ <span class="menuitem">重置</span></span>}, para.sub_macros(para.source)
         | 
| 1159 | 
            +
                  end if ::RUBY_MIN_VERSION_1_9
         | 
| 1160 | 
            +
             | 
| 1161 | 
            +
                  test 'should process inline menu with items containing multibyte characters' do
         | 
| 1162 | 
            +
                    para = block_from_string('"视图 > 放大 > 重置"', :attributes => {'experimental' => ''})
         | 
| 1163 | 
            +
                    assert_equal %q{<span class="menuseq"><span class="menu">视图</span> ▸ <span class="submenu">放大</span> ▸ <span class="menuitem">重置</span></span>}, para.sub_macros(para.source)
         | 
| 1164 | 
            +
                  end if ::RUBY_MIN_VERSION_1_9
         | 
| 889 1165 | 
             
                end
         | 
| 890 1166 | 
             
              end
         | 
| 891 1167 |  | 
| @@ -893,74 +1169,111 @@ context 'Substitutions' do | |
| 893 1169 | 
             
                test 'collect inline triple plus passthroughs' do
         | 
| 894 1170 | 
             
                  para = block_from_string('+++<code>inline code</code>+++')
         | 
| 895 1171 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 896 | 
            -
                  assert_equal  | 
| 1172 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 897 1173 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 898 | 
            -
                  assert_equal '<code>inline code</code>', para.passthroughs | 
| 899 | 
            -
                  assert para.passthroughs | 
| 1174 | 
            +
                  assert_equal '<code>inline code</code>', para.passthroughs[0][:text]
         | 
| 1175 | 
            +
                  assert para.passthroughs[0][:subs].empty?
         | 
| 900 1176 | 
             
                end
         | 
| 901 1177 |  | 
| 902 1178 | 
             
                test 'collect multi-line inline triple plus passthroughs' do
         | 
| 903 1179 | 
             
                  para = block_from_string("+++<code>inline\ncode</code>+++")
         | 
| 904 1180 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 905 | 
            -
                  assert_equal  | 
| 1181 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 906 1182 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 907 | 
            -
                  assert_equal "<code>inline\ncode</code>", para.passthroughs | 
| 908 | 
            -
                  assert para.passthroughs | 
| 1183 | 
            +
                  assert_equal "<code>inline\ncode</code>", para.passthroughs[0][:text]
         | 
| 1184 | 
            +
                  assert para.passthroughs[0][:subs].empty?
         | 
| 909 1185 | 
             
                end
         | 
| 910 1186 |  | 
| 911 1187 | 
             
                test 'collect inline double dollar passthroughs' do
         | 
| 912 1188 | 
             
                  para = block_from_string('$$<code>{code}</code>$$')
         | 
| 913 1189 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 914 | 
            -
                  assert_equal  | 
| 1190 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 1191 | 
            +
                  assert_equal 1, para.passthroughs.size
         | 
| 1192 | 
            +
                  assert_equal '<code>{code}</code>', para.passthroughs[0][:text]
         | 
| 1193 | 
            +
                  assert_equal [:specialcharacters], para.passthroughs[0][:subs]
         | 
| 1194 | 
            +
                end
         | 
| 1195 | 
            +
             | 
| 1196 | 
            +
                test 'collect inline double plus passthroughs' do
         | 
| 1197 | 
            +
                  para = block_from_string('++<code>{code}</code>++')
         | 
| 1198 | 
            +
                  result = para.extract_passthroughs(para.source)
         | 
| 1199 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 915 1200 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 916 | 
            -
                  assert_equal '<code>{code}</code>', para.passthroughs | 
| 917 | 
            -
                  assert_equal [:specialcharacters], para.passthroughs | 
| 1201 | 
            +
                  assert_equal '<code>{code}</code>', para.passthroughs[0][:text]
         | 
| 1202 | 
            +
                  assert_equal [:specialcharacters], para.passthroughs[0][:subs]
         | 
| 918 1203 | 
             
                end
         | 
| 919 1204 |  | 
| 920 1205 | 
             
                test 'collect multi-line inline double dollar passthroughs' do
         | 
| 921 1206 | 
             
                  para = block_from_string("$$<code>\n{code}\n</code>$$")
         | 
| 922 1207 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 923 | 
            -
                  assert_equal  | 
| 1208 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 924 1209 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 925 | 
            -
                  assert_equal "<code>\n{code}\n</code>", para.passthroughs | 
| 926 | 
            -
                  assert_equal [:specialcharacters], para.passthroughs | 
| 1210 | 
            +
                  assert_equal "<code>\n{code}\n</code>", para.passthroughs[0][:text]
         | 
| 1211 | 
            +
                  assert_equal [:specialcharacters], para.passthroughs[0][:subs]
         | 
| 1212 | 
            +
                end
         | 
| 1213 | 
            +
             | 
| 1214 | 
            +
                test 'collect multi-line inline double plus passthroughs' do
         | 
| 1215 | 
            +
                  para = block_from_string("++<code>\n{code}\n</code>++")
         | 
| 1216 | 
            +
                  result = para.extract_passthroughs(para.source)
         | 
| 1217 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 1218 | 
            +
                  assert_equal 1, para.passthroughs.size
         | 
| 1219 | 
            +
                  assert_equal "<code>\n{code}\n</code>", para.passthroughs[0][:text]
         | 
| 1220 | 
            +
                  assert_equal [:specialcharacters], para.passthroughs[0][:subs]
         | 
| 927 1221 | 
             
                end
         | 
| 928 1222 |  | 
| 929 1223 | 
             
                test 'collect passthroughs from inline pass macro' do
         | 
| 930 1224 | 
             
                  para = block_from_string(%Q{pass:specialcharacters,quotes[<code>['code'\\]</code>]})
         | 
| 931 1225 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 932 | 
            -
                  assert_equal  | 
| 1226 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 933 1227 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 934 | 
            -
                  assert_equal %q{<code>['code']</code>}, para.passthroughs | 
| 935 | 
            -
                  assert_equal [:specialcharacters, :quotes], para.passthroughs | 
| 1228 | 
            +
                  assert_equal %q{<code>['code']</code>}, para.passthroughs[0][:text]
         | 
| 1229 | 
            +
                  assert_equal [:specialcharacters, :quotes], para.passthroughs[0][:subs]
         | 
| 936 1230 | 
             
                end
         | 
| 937 1231 |  | 
| 938 1232 | 
             
                test 'collect multi-line passthroughs from inline pass macro' do
         | 
| 939 1233 | 
             
                  para = block_from_string(%Q{pass:specialcharacters,quotes[<code>['more\ncode'\\]</code>]})
         | 
| 940 1234 | 
             
                  result = para.extract_passthroughs(para.source)
         | 
| 941 | 
            -
                  assert_equal  | 
| 1235 | 
            +
                  assert_equal Asciidoctor::Substitutors::PASS_START + '0' + Asciidoctor::Substitutors::PASS_END, result
         | 
| 1236 | 
            +
                  assert_equal 1, para.passthroughs.size
         | 
| 1237 | 
            +
                  assert_equal %Q{<code>['more\ncode']</code>}, para.passthroughs[0][:text]
         | 
| 1238 | 
            +
                  assert_equal [:specialcharacters, :quotes], para.passthroughs[0][:subs]
         | 
| 1239 | 
            +
                end
         | 
| 1240 | 
            +
             | 
| 1241 | 
            +
                test 'resolves sub shorthands on inline pass macro' do
         | 
| 1242 | 
            +
                  para = block_from_string 'pass:q,a[*<{backend}>*]'
         | 
| 1243 | 
            +
                  result = para.extract_passthroughs para.source
         | 
| 942 1244 | 
             
                  assert_equal 1, para.passthroughs.size
         | 
| 943 | 
            -
                  assert_equal  | 
| 944 | 
            -
                   | 
| 1245 | 
            +
                  assert_equal [:quotes, :attributes], para.passthroughs[0][:subs]
         | 
| 1246 | 
            +
                  result = para.restore_passthroughs result
         | 
| 1247 | 
            +
                  assert_equal '<strong><html5></strong>', result
         | 
| 945 1248 | 
             
                end
         | 
| 946 1249 |  | 
| 947 1250 | 
             
                # NOTE placeholder is surrounded by text to prevent reader from stripping trailing boundary char (unique to test scenario)
         | 
| 948 1251 | 
             
                test 'restore inline passthroughs without subs' do
         | 
| 949 | 
            -
                  para = block_from_string("some  | 
| 950 | 
            -
                  para.passthroughs  | 
| 1252 | 
            +
                  para = block_from_string("some #{Asciidoctor::Substitutors::PASS_START}" + '0' + "#{Asciidoctor::Substitutors::PASS_END} to study")
         | 
| 1253 | 
            +
                  para.passthroughs[0] = {:text => '<code>inline code</code>', :subs => []}
         | 
| 951 1254 | 
             
                  result = para.restore_passthroughs(para.source)
         | 
| 952 1255 | 
             
                  assert_equal "some <code>inline code</code> to study", result
         | 
| 953 1256 | 
             
                end
         | 
| 954 1257 |  | 
| 955 1258 | 
             
                # NOTE placeholder is surrounded by text to prevent reader from stripping trailing boundary char (unique to test scenario)
         | 
| 956 1259 | 
             
                test 'restore inline passthroughs with subs' do
         | 
| 957 | 
            -
                  para = block_from_string("some  | 
| 958 | 
            -
                  para.passthroughs  | 
| 959 | 
            -
                  para.passthroughs  | 
| 1260 | 
            +
                  para = block_from_string("some #{Asciidoctor::Substitutors::PASS_START}" + '0' + "#{Asciidoctor::Substitutors::PASS_END} to study in the #{Asciidoctor::Substitutors::PASS_START}" + '1' + "#{Asciidoctor::Substitutors::PASS_END} programming language")
         | 
| 1261 | 
            +
                  para.passthroughs[0] = {:text => '<code>{code}</code>', :subs => [:specialcharacters]}
         | 
| 1262 | 
            +
                  para.passthroughs[1] = {:text => '{language}', :subs => [:specialcharacters]}
         | 
| 960 1263 | 
             
                  result = para.restore_passthroughs(para.source)
         | 
| 961 1264 | 
             
                  assert_equal 'some <code>{code}</code> to study in the {language} programming language', result
         | 
| 962 1265 | 
             
                end
         | 
| 963 1266 |  | 
| 1267 | 
            +
                test 'should restore nested passthroughs' do
         | 
| 1268 | 
            +
                  result = render_embedded_string %q(+Sometimes you feel pass:q[`mono`].+ Sometimes you +$$don't$$+.), :doctype => :inline
         | 
| 1269 | 
            +
                  assert_equal %q(Sometimes you feel <code>mono</code>. Sometimes you don't.), result
         | 
| 1270 | 
            +
                end
         | 
| 1271 | 
            +
             | 
| 1272 | 
            +
                test 'should honor role on double plus passthrough' do
         | 
| 1273 | 
            +
                  result = render_embedded_string 'Print the version using [var]++{asciidoctor-version}++.', :doctype => :inline
         | 
| 1274 | 
            +
                  assert_equal 'Print the version using <span class="var">{asciidoctor-version}</span>.', result
         | 
| 1275 | 
            +
                end
         | 
| 1276 | 
            +
             | 
| 964 1277 | 
             
                test 'complex inline passthrough macro' do
         | 
| 965 1278 | 
             
                  text_to_escape = %q{[(] <'basic form'> <'logical operator'> <'basic form'> [)]}
         | 
| 966 1279 | 
             
                  para = block_from_string %($$#{text_to_escape}$$) 
         | 
| @@ -979,6 +1292,112 @@ context 'Substitutions' do | |
| 979 1292 | 
             
                  para = block_from_string %(pass:verbatim[<{backend}>])
         | 
| 980 1293 | 
             
                  assert_equal '<{backend}>', para.content
         | 
| 981 1294 | 
             
                end
         | 
| 1295 | 
            +
             | 
| 1296 | 
            +
                context 'Math macros' do
         | 
| 1297 | 
            +
                  test 'should passthrough text in asciimath macro and surround with AsciiMath delimiters' do
         | 
| 1298 | 
            +
                    input = 'asciimath:[x/x={(1,if x!=0),(text{undefined},if x=0):}]'
         | 
| 1299 | 
            +
                    para = block_from_string input
         | 
| 1300 | 
            +
                    assert_equal '\$x/x={(1,if x!=0),(text{undefined},if x=0):}\$', para.content
         | 
| 1301 | 
            +
                  end
         | 
| 1302 | 
            +
             | 
| 1303 | 
            +
                  test 'should not recognize asciimath macro with no content' do
         | 
| 1304 | 
            +
                    input = 'asciimath:[]'
         | 
| 1305 | 
            +
                    para = block_from_string input
         | 
| 1306 | 
            +
                    assert_equal 'asciimath:[]', para.content
         | 
| 1307 | 
            +
                  end
         | 
| 1308 | 
            +
             | 
| 1309 | 
            +
                  test 'should perform specialcharacters subs on asciimath macro content in html backend by default' do
         | 
| 1310 | 
            +
                    input = 'asciimath:[a < b]'
         | 
| 1311 | 
            +
                    para = block_from_string input
         | 
| 1312 | 
            +
                    assert_equal '\$a < b\$', para.content
         | 
| 1313 | 
            +
                  end
         | 
| 1314 | 
            +
             | 
| 1315 | 
            +
                  test 'should not perform specialcharacters subs on asciimath macro content in docbook backend by default' do
         | 
| 1316 | 
            +
                    input = 'asciimath:[a < b]'
         | 
| 1317 | 
            +
                    para = block_from_string input, :backend => :docbook
         | 
| 1318 | 
            +
                    assert_equal 'a < b', para.content
         | 
| 1319 | 
            +
                  end
         | 
| 1320 | 
            +
             | 
| 1321 | 
            +
                  test 'should honor explicit subslist on asciimath macro' do
         | 
| 1322 | 
            +
                    input = 'asciimath:attributes[{expr}]'
         | 
| 1323 | 
            +
                    para = block_from_string input, :attributes => {'expr' => 'x != 0'}
         | 
| 1324 | 
            +
                    assert_equal '\$x != 0\$', para.content
         | 
| 1325 | 
            +
                  end
         | 
| 1326 | 
            +
             | 
| 1327 | 
            +
                  test 'should passthrough text in latexmath macro and surround with LaTeX math delimiters' do
         | 
| 1328 | 
            +
                    input = 'latexmath:[C = \alpha + \beta Y^{\gamma} + \epsilon]'
         | 
| 1329 | 
            +
                    para = block_from_string input
         | 
| 1330 | 
            +
                    assert_equal '\(C = \alpha + \beta Y^{\gamma} + \epsilon\)', para.content
         | 
| 1331 | 
            +
                  end
         | 
| 1332 | 
            +
             | 
| 1333 | 
            +
                  test 'should not recognize latexmath macro with no content' do
         | 
| 1334 | 
            +
                    input = 'latexmath:[]'
         | 
| 1335 | 
            +
                    para = block_from_string input
         | 
| 1336 | 
            +
                    assert_equal 'latexmath:[]', para.content
         | 
| 1337 | 
            +
                  end
         | 
| 1338 | 
            +
             | 
| 1339 | 
            +
                  test 'should perform specialcharacters subs on latexmath macro in html backend by default' do
         | 
| 1340 | 
            +
                    input = 'latexmath:[a < b]'
         | 
| 1341 | 
            +
                    para = block_from_string input
         | 
| 1342 | 
            +
                    assert_equal '\(a < b\)', para.content
         | 
| 1343 | 
            +
                  end
         | 
| 1344 | 
            +
             | 
| 1345 | 
            +
                  test 'should not perform specialcharacters subs on latexmath macro content in docbook backend by default' do
         | 
| 1346 | 
            +
                    input = 'latexmath:[a < b]'
         | 
| 1347 | 
            +
                    para = block_from_string input, :backend => :docbook
         | 
| 1348 | 
            +
                    assert para.content.include?('<alt><![CDATA[a < b]]></alt>')
         | 
| 1349 | 
            +
                  end
         | 
| 1350 | 
            +
             | 
| 1351 | 
            +
                  test 'should honor explicit subslist on latexmath macro' do
         | 
| 1352 | 
            +
                    input = 'latexmath:attributes[{expr}]'
         | 
| 1353 | 
            +
                    para = block_from_string input, :attributes => {'expr' => '\sqrt{4} = 2'}
         | 
| 1354 | 
            +
                    assert_equal '\(\sqrt{4} = 2\)', para.content
         | 
| 1355 | 
            +
                  end
         | 
| 1356 | 
            +
             | 
| 1357 | 
            +
                  test 'should passthrough math macro inside another passthrough' do
         | 
| 1358 | 
            +
                    input = 'the text `asciimath:[x = y]` should be passed through as +literal+ text'
         | 
| 1359 | 
            +
                    para = block_from_string input, :attributes => {'compat-mode' => ''}
         | 
| 1360 | 
            +
                    assert_equal 'the text <code>asciimath:[x = y]</code> should be passed through as <code>literal</code> text', para.content
         | 
| 1361 | 
            +
             | 
| 1362 | 
            +
                    input = 'the text [x-]`asciimath:[x = y]` should be passed through as `literal` text'
         | 
| 1363 | 
            +
                    para = block_from_string input
         | 
| 1364 | 
            +
                    assert_equal 'the text <code>asciimath:[x = y]</code> should be passed through as <code>literal</code> text', para.content
         | 
| 1365 | 
            +
             | 
| 1366 | 
            +
                    input = 'the text `+asciimath:[x = y]+` should be passed through as `literal` text'
         | 
| 1367 | 
            +
                    para = block_from_string input
         | 
| 1368 | 
            +
                    assert_equal 'the text <code>asciimath:[x = y]</code> should be passed through as <code>literal</code> text', para.content
         | 
| 1369 | 
            +
                  end
         | 
| 1370 | 
            +
             | 
| 1371 | 
            +
                  test 'should not recognize stem macro with no content' do
         | 
| 1372 | 
            +
                    input = 'stem:[]'
         | 
| 1373 | 
            +
                    para = block_from_string input
         | 
| 1374 | 
            +
                    assert_equal input, para.content
         | 
| 1375 | 
            +
                  end
         | 
| 1376 | 
            +
             | 
| 1377 | 
            +
                  test 'should passthrough text in stem macro and surround with AsciiMath delimiters if stem attribute != latexmath' do
         | 
| 1378 | 
            +
                    [
         | 
| 1379 | 
            +
                      {},
         | 
| 1380 | 
            +
                      {'stem' => ''},
         | 
| 1381 | 
            +
                      {'stem' => 'asciimath'}
         | 
| 1382 | 
            +
                    ].each do |attributes|
         | 
| 1383 | 
            +
                      input = 'stem:[x/x={(1,if x!=0),(text{undefined},if x=0):}]'
         | 
| 1384 | 
            +
                      para = block_from_string input, :attributes => attributes
         | 
| 1385 | 
            +
                      assert_equal '\$x/x={(1,if x!=0),(text{undefined},if x=0):}\$', para.content
         | 
| 1386 | 
            +
                    end
         | 
| 1387 | 
            +
                  end
         | 
| 1388 | 
            +
             | 
| 1389 | 
            +
                  test 'should passthrough text in stem macro and surround with LaTeX math delimiters if stem attribute = latexmath' do
         | 
| 1390 | 
            +
                    input = 'stem:[C = \alpha + \beta Y^{\gamma} + \epsilon]'
         | 
| 1391 | 
            +
                    para = block_from_string input, :attributes => {'stem' => 'latexmath'}
         | 
| 1392 | 
            +
                    assert_equal '\(C = \alpha + \beta Y^{\gamma} + \epsilon\)', para.content
         | 
| 1393 | 
            +
                  end
         | 
| 1394 | 
            +
             | 
| 1395 | 
            +
                  test 'should find and replace placeholder duplicated by substitution' do
         | 
| 1396 | 
            +
                    input = %q(+first passthrough+ followed by link:$$http://example.com/__u_no_format_me__$$[] with passthrough)
         | 
| 1397 | 
            +
                    result = render_embedded_string input, :doctype => :inline
         | 
| 1398 | 
            +
                    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
         | 
| 1399 | 
            +
                  end
         | 
| 1400 | 
            +
                end
         | 
| 982 1401 | 
             
              end
         | 
| 983 1402 |  | 
| 984 1403 | 
             
              context 'Replacements' do
         | 
| @@ -993,29 +1412,72 @@ context 'Substitutions' do | |
| 993 1412 | 
             
                end
         | 
| 994 1413 |  | 
| 995 1414 | 
             
                test 'replaces dashes' do
         | 
| 996 | 
            -
                  para = block_from_string %(-- foo foo--bar foo\\--bar foo -- bar foo \\-- bar
         | 
| 1415 | 
            +
                  para = block_from_string %(-- foo foo--bar foo\\--bar foo -- bar foo \\-- bar 
         | 
| 997 1416 | 
             
            stuff in between
         | 
| 998 1417 | 
             
            -- foo
         | 
| 999 1418 | 
             
            stuff in between
         | 
| 1000 1419 | 
             
            foo --
         | 
| 1001 1420 | 
             
            stuff in between
         | 
| 1002 1421 | 
             
            foo --)
         | 
| 1003 | 
            -
                  expected =  | 
| 1422 | 
            +
                  expected = ' — foo foo—​bar foo--bar foo — bar foo -- bar
         | 
| 1004 1423 | 
             
            stuff in between — foo
         | 
| 1005 1424 | 
             
            stuff in between
         | 
| 1006 1425 | 
             
            foo — stuff in between
         | 
| 1007 | 
            -
            foo —  | 
| 1426 | 
            +
            foo — '
         | 
| 1008 1427 | 
             
                  assert_equal expected, para.sub_replacements(para.source)
         | 
| 1009 1428 | 
             
                end
         | 
| 1010 1429 |  | 
| 1430 | 
            +
                test 'replaces dashes between multibyte word characters' do
         | 
| 1431 | 
            +
                  para = block_from_string %(富--巴)
         | 
| 1432 | 
            +
                  expected = '富—​巴'
         | 
| 1433 | 
            +
                  assert_equal expected, para.sub_replacements(para.source)
         | 
| 1434 | 
            +
                end if ::RUBY_MIN_VERSION_1_9
         | 
| 1435 | 
            +
             | 
| 1011 1436 | 
             
                test 'replaces marks' do
         | 
| 1012 1437 | 
             
                  para = block_from_string '(C) (R) (TM) \(C) \(R) \(TM)' 
         | 
| 1013 1438 | 
             
                  assert_equal '© ® ™ (C) (R) (TM)', para.sub_replacements(para.source)
         | 
| 1014 1439 | 
             
                end
         | 
| 1015 1440 |  | 
| 1441 | 
            +
                test 'preserves entity references' do
         | 
| 1442 | 
            +
                  input = '& © ✔ •'
         | 
| 1443 | 
            +
                  result = render_embedded_string input, :doctype => :inline
         | 
| 1444 | 
            +
                  assert_equal input, result
         | 
| 1445 | 
            +
                end
         | 
| 1446 | 
            +
             | 
| 1016 1447 | 
             
                test 'replaces punctuation' do
         | 
| 1017 | 
            -
                  para = block_from_string %(John's Hideout... foo\\'bar)
         | 
| 1018 | 
            -
                  assert_equal "John’s Hideout… foo'bar", para.sub_replacements(para.source)
         | 
| 1448 | 
            +
                  para = block_from_string %(John's Hideout is the Whites`' place... foo\\'bar)
         | 
| 1449 | 
            +
                  assert_equal "John’s Hideout is the Whites’ place…​ foo'bar", para.sub_replacements(para.source)
         | 
| 1450 | 
            +
                end
         | 
| 1451 | 
            +
             | 
| 1452 | 
            +
                test 'should replace right single quote marks' do
         | 
| 1453 | 
            +
                  given = [
         | 
| 1454 | 
            +
                    %(`'Twas the night),
         | 
| 1455 | 
            +
                    %(a `'57 Chevy!),
         | 
| 1456 | 
            +
                    %(the whites`' place),
         | 
| 1457 | 
            +
                    %(the whites`'.),
         | 
| 1458 | 
            +
                    %(the whites`'--where the wild things are),
         | 
| 1459 | 
            +
                    %(the whites`'\nhave),
         | 
| 1460 | 
            +
                    %(It's Mary`'s little lamb.),
         | 
| 1461 | 
            +
                    %(consecutive single quotes '' are not modified),
         | 
| 1462 | 
            +
                    %(he is 6' tall),
         | 
| 1463 | 
            +
                    %(\\`')
         | 
| 1464 | 
            +
                  ]
         | 
| 1465 | 
            +
                  expected = [
         | 
| 1466 | 
            +
                    %(’Twas the night),
         | 
| 1467 | 
            +
                    %(a ’57 Chevy!),
         | 
| 1468 | 
            +
                    %(the whites’ place),
         | 
| 1469 | 
            +
                    %(the whites’.),
         | 
| 1470 | 
            +
                    %(the whites’--where the wild things are),
         | 
| 1471 | 
            +
                    %(the whites’\nhave),
         | 
| 1472 | 
            +
                    %(It’s Mary’s little lamb.),
         | 
| 1473 | 
            +
                    %(consecutive single quotes '' are not modified),
         | 
| 1474 | 
            +
                    %(he is 6' tall),
         | 
| 1475 | 
            +
                    %(`')
         | 
| 1476 | 
            +
                  ]
         | 
| 1477 | 
            +
                  given.size.times {|i|
         | 
| 1478 | 
            +
                    para = block_from_string given[i]
         | 
| 1479 | 
            +
                    assert_equal expected[i], para.sub_replacements(para.source)
         | 
| 1480 | 
            +
                  }
         | 
| 1019 1481 | 
             
                end
         | 
| 1020 1482 | 
             
              end
         | 
| 1021 1483 |  | 
| @@ -1023,25 +1485,25 @@ foo — ) | |
| 1023 1485 | 
             
                test 'line break inserted after line with line break character' do
         | 
| 1024 1486 | 
             
                  para = block_from_string("First line +\nSecond line")
         | 
| 1025 1487 | 
             
                  result = para.apply_subs(para.lines, :post_replacements, true)
         | 
| 1026 | 
            -
                  assert_equal  | 
| 1488 | 
            +
                  assert_equal 'First line<br>', result.first
         | 
| 1027 1489 | 
             
                end
         | 
| 1028 1490 |  | 
| 1029 1491 | 
             
                test 'line break inserted after line wrap with hardbreaks enabled' do
         | 
| 1030 1492 | 
             
                  para = block_from_string("First line\nSecond line", :attributes => {'hardbreaks' => ''})
         | 
| 1031 1493 | 
             
                  result = para.apply_subs(para.lines, :post_replacements, true)
         | 
| 1032 | 
            -
                  assert_equal  | 
| 1494 | 
            +
                  assert_equal 'First line<br>', result.first
         | 
| 1033 1495 | 
             
                end
         | 
| 1034 1496 |  | 
| 1035 1497 | 
             
                test 'line break character stripped from end of line with hardbreaks enabled' do
         | 
| 1036 1498 | 
             
                  para = block_from_string("First line +\nSecond line", :attributes => {'hardbreaks' => ''})
         | 
| 1037 1499 | 
             
                  result = para.apply_subs(para.lines, :post_replacements, true)
         | 
| 1038 | 
            -
                  assert_equal  | 
| 1500 | 
            +
                  assert_equal 'First line<br>', result.first
         | 
| 1039 1501 | 
             
                end
         | 
| 1040 1502 |  | 
| 1041 1503 | 
             
                test 'line break not inserted for single line with hardbreaks enabled' do
         | 
| 1042 | 
            -
                  para = block_from_string( | 
| 1504 | 
            +
                  para = block_from_string('First line', :attributes => {'hardbreaks' => ''})
         | 
| 1043 1505 | 
             
                  result = para.apply_subs(para.lines, :post_replacements, true)
         | 
| 1044 | 
            -
                  assert_equal  | 
| 1506 | 
            +
                  assert_equal 'First line', result.first
         | 
| 1045 1507 | 
             
                end
         | 
| 1046 1508 | 
             
              end
         | 
| 1047 1509 |  | 
| @@ -1083,4 +1545,19 @@ foo — ) | |
| 1083 1545 | 
             
                  assert_equal [:specialcharacters], block.subs
         | 
| 1084 1546 | 
             
                end
         | 
| 1085 1547 | 
             
              end
         | 
| 1548 | 
            +
             | 
| 1549 | 
            +
              # TODO move to helpers_test.rb
         | 
| 1550 | 
            +
              context 'Helpers' do
         | 
| 1551 | 
            +
                test 'should URI encode non-word characters generally' do
         | 
| 1552 | 
            +
                  given = ' /%&?\\'
         | 
| 1553 | 
            +
                  expect = '%20%2F%25%26%3F%5C'
         | 
| 1554 | 
            +
                  assert_equal expect, (Asciidoctor::Helpers.encode_uri given)
         | 
| 1555 | 
            +
                end
         | 
| 1556 | 
            +
             | 
| 1557 | 
            +
                test 'should not URI select non-word characters' do
         | 
| 1558 | 
            +
                  given = '-.!~*\';:@=+$,()[]'
         | 
| 1559 | 
            +
                  expect = given
         | 
| 1560 | 
            +
                  assert_equal expect, (Asciidoctor::Helpers.encode_uri given)
         | 
| 1561 | 
            +
                end
         | 
| 1562 | 
            +
              end
         | 
| 1086 1563 | 
             
            end
         |