asciidoctor 1.5.5 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
    
        data/test/options_test.rb
    CHANGED
    
    | @@ -6,7 +6,7 @@ end | |
| 6 6 | 
             
            require 'asciidoctor/cli/options'
         | 
| 7 7 |  | 
| 8 8 | 
             
            context 'Options' do
         | 
| 9 | 
            -
              test 'should return error code 0 when help flag is present' do
         | 
| 9 | 
            +
              test 'should print usage and return error code 0 when help flag is present' do
         | 
| 10 10 | 
             
                redirect_streams do |stdout, stderr|
         | 
| 11 11 | 
             
                  exitval = Asciidoctor::Cli::Options.parse!(%w(-h))
         | 
| 12 12 | 
             
                  assert_equal 0, exitval
         | 
| @@ -14,6 +14,23 @@ context 'Options' do | |
| 14 14 | 
             
                end
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
| 17 | 
            +
              test 'should print usage and return error code 0 when help flag is unknown' do
         | 
| 18 | 
            +
                exitval, output = redirect_streams do |out, _|
         | 
| 19 | 
            +
                  [Asciidoctor::Cli::Options.parse!(%w(-h unknown)), out.string]
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                assert_equal 0, exitval
         | 
| 22 | 
            +
                assert_match(/^Usage:/, output)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              test 'should dump man page and return error code 0 when help topic is manpage' do
         | 
| 26 | 
            +
                exitval, output = redirect_streams do |out, _|
         | 
| 27 | 
            +
                  [Asciidoctor::Cli::Options.parse!(%w(-h manpage)), out.string]
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                assert_equal 0, exitval
         | 
| 30 | 
            +
                assert_includes output, 'Manual: Asciidoctor Manual'
         | 
| 31 | 
            +
                assert_includes output, '.TH "ASCIIDOCTOR"'
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 17 34 | 
             
              test 'should return error code 1 when invalid option present' do
         | 
| 18 35 | 
             
                redirect_streams do |stdout, stderr|
         | 
| 19 36 | 
             
                  exitval = Asciidoctor::Cli::Options.parse!(%w(--foobar))
         | 
    
        data/test/paragraphs_test.rb
    CHANGED
    
    | @@ -156,29 +156,29 @@ Note that multi-entry terms generate separate index entries. | |
| 156 156 |  | 
| 157 157 | 
             
                  output = render_embedded_string input, :attributes => {'backend' => 'docbook45'}
         | 
| 158 158 | 
             
                  assert_xpath '/simpara', output, 1
         | 
| 159 | 
            -
                  term1 =  | 
| 159 | 
            +
                  term1 = xmlnodes_at_xpath '(//indexterm)[1]', output, 1
         | 
| 160 160 | 
             
                  assert_equal '<indexterm><primary>tigers</primary></indexterm>', term1.to_s
         | 
| 161 161 | 
             
                  assert term1.next.content.start_with?('tigers')
         | 
| 162 162 |  | 
| 163 | 
            -
                  term2 =  | 
| 163 | 
            +
                  term2 = xmlnodes_at_xpath '(//indexterm)[2]', output, 1
         | 
| 164 164 | 
             
                  term2_elements = term2.elements
         | 
| 165 165 | 
             
                  assert_equal 3, term2_elements.size
         | 
| 166 166 | 
             
                  assert_equal '<primary>Big cats</primary>', term2_elements[0].to_s
         | 
| 167 167 | 
             
                  assert_equal '<secondary>Tigers</secondary>', term2_elements[1].to_s
         | 
| 168 168 | 
             
                  assert_equal '<tertiary>Siberian Tiger</tertiary>', term2_elements[2].to_s
         | 
| 169 169 |  | 
| 170 | 
            -
                  term3 =  | 
| 170 | 
            +
                  term3 = xmlnodes_at_xpath '(//indexterm)[3]', output, 1
         | 
| 171 171 | 
             
                  term3_elements = term3.elements
         | 
| 172 172 | 
             
                  assert_equal 2, term3_elements.size
         | 
| 173 173 | 
             
                  assert_equal '<primary>Tigers</primary>', term3_elements[0].to_s
         | 
| 174 174 | 
             
                  assert_equal '<secondary>Siberian Tiger</secondary>', term3_elements[1].to_s
         | 
| 175 175 |  | 
| 176 | 
            -
                  term4 =  | 
| 176 | 
            +
                  term4 = xmlnodes_at_xpath '(//indexterm)[4]', output, 1
         | 
| 177 177 | 
             
                  term4_elements = term4.elements
         | 
| 178 178 | 
             
                  assert_equal 1, term4_elements.size
         | 
| 179 179 | 
             
                  assert_equal '<primary>Siberian Tiger</primary>', term4_elements[0].to_s
         | 
| 180 180 |  | 
| 181 | 
            -
                  term5 =  | 
| 181 | 
            +
                  term5 = xmlnodes_at_xpath '(//indexterm)[5]', output, 1
         | 
| 182 182 | 
             
                  assert_equal '<indexterm><primary>Linux</primary></indexterm>', term5.to_s
         | 
| 183 183 | 
             
                  assert term5.next.content.start_with?('Linux')
         | 
| 184 184 |  | 
| @@ -418,6 +418,26 @@ Content goes here | |
| 418 418 | 
             
                  assert_xpath "//*[@class='sidebarblock']//p", result, 1
         | 
| 419 419 | 
             
                end
         | 
| 420 420 |  | 
| 421 | 
            +
                test 'should process preprocessor conditional in paragrpah content' do
         | 
| 422 | 
            +
                  input = <<-EOS
         | 
| 423 | 
            +
            ifdef::asciidoctor-version[]
         | 
| 424 | 
            +
            [sidebar]
         | 
| 425 | 
            +
            First line of sidebar.
         | 
| 426 | 
            +
            ifdef::backend[The backend is {backend}.]
         | 
| 427 | 
            +
            Last line of sidebar.
         | 
| 428 | 
            +
            endif::[]
         | 
| 429 | 
            +
                  EOS
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                  result = render_embedded_string input
         | 
| 432 | 
            +
                  assert_equal %(<div class="sidebarblock">
         | 
| 433 | 
            +
            <div class="content">
         | 
| 434 | 
            +
            First line of sidebar.
         | 
| 435 | 
            +
            The backend is html5.
         | 
| 436 | 
            +
            Last line of sidebar.
         | 
| 437 | 
            +
            </div>
         | 
| 438 | 
            +
            </div>), result
         | 
| 439 | 
            +
                end
         | 
| 440 | 
            +
             | 
| 421 441 | 
             
                context 'Styled Paragraphs' do
         | 
| 422 442 | 
             
                  test 'should wrap text in simpara for styled paragraphs when rendered to DocBook' do
         | 
| 423 443 | 
             
                    input = <<-EOS
         | 
| @@ -514,10 +534,15 @@ Wise words from a wise person. | |
| 514 534 | 
             
                    assert_equal '<a href="http://asciidoc.org">AsciiDoc</a> is a <em>lightweight</em> markup language…​', output
         | 
| 515 535 | 
             
                  end
         | 
| 516 536 |  | 
| 517 | 
            -
                  test 'should output nil if first block is not a paragraph' do
         | 
| 537 | 
            +
                  test 'should output nil and warn if first block is not a paragraph' do
         | 
| 518 538 | 
             
                    input = '* bullet'
         | 
| 519 | 
            -
                    output =  | 
| 539 | 
            +
                    output = nil
         | 
| 540 | 
            +
                    warnings = redirect_streams do |_, err|
         | 
| 541 | 
            +
                      output =  render_string input, :doctype => 'inline'
         | 
| 542 | 
            +
                      err.string
         | 
| 543 | 
            +
                    end
         | 
| 520 544 | 
             
                    assert output.nil?
         | 
| 545 | 
            +
                    assert_includes warnings, 'no inline candidate'
         | 
| 521 546 | 
             
                  end
         | 
| 522 547 | 
             
                end
         | 
| 523 548 | 
             
              end
         | 
    
        data/test/parser_test.rb
    CHANGED
    
    | @@ -17,6 +17,85 @@ context "Parser" do | |
| 17 17 | 
             
                assert_equal 'foo3-bar', Asciidoctor::Parser.sanitize_attribute_name("Foo 3^ # - Bar[")
         | 
| 18 18 | 
             
              end
         | 
| 19 19 |  | 
| 20 | 
            +
              test 'store attribute with value' do
         | 
| 21 | 
            +
                attr_name, attr_value = Asciidoctor::Parser.store_attribute 'foo', 'bar'
         | 
| 22 | 
            +
                assert_equal 'foo', attr_name
         | 
| 23 | 
            +
                assert_equal 'bar', attr_value
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              test 'store attribute with negated value' do
         | 
| 27 | 
            +
                { 'foo!' => nil, '!foo' => nil, 'foo' => nil }.each do |name, value|
         | 
| 28 | 
            +
                  attr_name, attr_value = Asciidoctor::Parser.store_attribute name, value
         | 
| 29 | 
            +
                  assert_equal name.sub('!', ''), attr_name
         | 
| 30 | 
            +
                  assert_nil attr_value
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              test 'store accessible attribute on document with value' do
         | 
| 35 | 
            +
                doc = empty_document
         | 
| 36 | 
            +
                doc.set_attribute 'foo', 'baz'
         | 
| 37 | 
            +
                attrs = {}
         | 
| 38 | 
            +
                attr_name, attr_value = Asciidoctor::Parser.store_attribute 'foo', 'bar', doc, attrs
         | 
| 39 | 
            +
                assert_equal 'foo', attr_name
         | 
| 40 | 
            +
                assert_equal 'bar', attr_value
         | 
| 41 | 
            +
                assert_equal 'bar', (doc.attr 'foo')
         | 
| 42 | 
            +
                assert attrs.key?(:attribute_entries)
         | 
| 43 | 
            +
                assert_equal 1, attrs[:attribute_entries].size
         | 
| 44 | 
            +
                assert_equal 'foo', attrs[:attribute_entries][0].name
         | 
| 45 | 
            +
                assert_equal 'bar', attrs[:attribute_entries][0].value
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              test 'store accessible attribute on document with value that contains attribute reference' do
         | 
| 49 | 
            +
                doc = empty_document
         | 
| 50 | 
            +
                doc.set_attribute 'foo', 'baz'
         | 
| 51 | 
            +
                doc.set_attribute 'release', 'ultramega'
         | 
| 52 | 
            +
                attrs = {}
         | 
| 53 | 
            +
                attr_name, attr_value = Asciidoctor::Parser.store_attribute 'foo', '{release}', doc, attrs
         | 
| 54 | 
            +
                assert_equal 'foo', attr_name
         | 
| 55 | 
            +
                assert_equal 'ultramega', attr_value
         | 
| 56 | 
            +
                assert_equal 'ultramega', (doc.attr 'foo')
         | 
| 57 | 
            +
                assert attrs.key?(:attribute_entries)
         | 
| 58 | 
            +
                assert_equal 1, attrs[:attribute_entries].size
         | 
| 59 | 
            +
                assert_equal 'foo', attrs[:attribute_entries][0].name
         | 
| 60 | 
            +
                assert_equal 'ultramega', attrs[:attribute_entries][0].value
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              test 'store inaccessible attribute on document with value' do
         | 
| 64 | 
            +
                doc = empty_document :attributes => { 'foo' => 'baz' }
         | 
| 65 | 
            +
                attrs = {}
         | 
| 66 | 
            +
                attr_name, attr_value = Asciidoctor::Parser.store_attribute 'foo', 'bar', doc, attrs
         | 
| 67 | 
            +
                assert_equal 'foo', attr_name
         | 
| 68 | 
            +
                assert_equal 'bar', attr_value
         | 
| 69 | 
            +
                assert_equal 'baz', (doc.attr 'foo')
         | 
| 70 | 
            +
                refute attrs.key?(:attribute_entries)
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              test 'store accessible attribute on document with negated value' do
         | 
| 74 | 
            +
                { 'foo!' => nil, '!foo' => nil, 'foo' => nil }.each do |name, value|
         | 
| 75 | 
            +
                  doc = empty_document
         | 
| 76 | 
            +
                  doc.set_attribute 'foo', 'baz'
         | 
| 77 | 
            +
                  attrs = {}
         | 
| 78 | 
            +
                  attr_name, attr_value = Asciidoctor::Parser.store_attribute name, value, doc, attrs
         | 
| 79 | 
            +
                  assert_equal name.sub('!', ''), attr_name
         | 
| 80 | 
            +
                  assert_nil attr_value
         | 
| 81 | 
            +
                  assert attrs.key?(:attribute_entries)
         | 
| 82 | 
            +
                  assert_equal 1, attrs[:attribute_entries].size
         | 
| 83 | 
            +
                  assert_equal 'foo', attrs[:attribute_entries][0].name
         | 
| 84 | 
            +
                  assert_nil attrs[:attribute_entries][0].value
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              test 'store inaccessible attribute on document with negated value' do
         | 
| 89 | 
            +
                { 'foo!' => nil, '!foo' => nil, 'foo' => nil }.each do |name, value|
         | 
| 90 | 
            +
                  doc = empty_document :attributes => { 'foo' => 'baz' }
         | 
| 91 | 
            +
                  attrs = {}
         | 
| 92 | 
            +
                  attr_name, attr_value = Asciidoctor::Parser.store_attribute name, value, doc, attrs
         | 
| 93 | 
            +
                  assert_equal name.sub('!', ''), attr_name
         | 
| 94 | 
            +
                  assert_nil attr_value
         | 
| 95 | 
            +
                  refute attrs.key?(:attribute_entries)
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 20 99 | 
             
              test "collect unnamed attribute" do
         | 
| 21 100 | 
             
                attributes = {}
         | 
| 22 101 | 
             
                line = 'quote'
         | 
| @@ -172,7 +251,7 @@ context "Parser" do | |
| 172 251 | 
             
              test "collect options attribute" do
         | 
| 173 252 | 
             
                attributes = {}
         | 
| 174 253 | 
             
                line = "quote, options='opt1,opt2 , opt3'"
         | 
| 175 | 
            -
                expected = {1 => 'quote', 'options' => 'opt1,opt2 | 
| 254 | 
            +
                expected = {1 => 'quote', 'options' => 'opt1,opt2,opt3', 'opt1-option' => '', 'opt2-option' => '', 'opt3-option' => ''}
         | 
| 176 255 | 
             
                Asciidoctor::AttributeList.new(line).parse_into(attributes)
         | 
| 177 256 | 
             
                assert_equal expected, attributes
         | 
| 178 257 | 
             
              end
         | 
| @@ -180,7 +259,7 @@ context "Parser" do | |
| 180 259 | 
             
              test "collect opts attribute as options" do
         | 
| 181 260 | 
             
                attributes = {}
         | 
| 182 261 | 
             
                line = "quote, opts='opt1,opt2 , opt3'"
         | 
| 183 | 
            -
                expected = {1 => 'quote', 'options' => 'opt1,opt2 | 
| 262 | 
            +
                expected = {1 => 'quote', 'options' => 'opt1,opt2,opt3', 'opt1-option' => '', 'opt2-option' => '', 'opt3-option' => ''}
         | 
| 184 263 | 
             
                Asciidoctor::AttributeList.new(line).parse_into(attributes)
         | 
| 185 264 | 
             
                assert_equal expected, attributes
         | 
| 186 265 | 
             
              end
         | 
| @@ -202,9 +281,8 @@ context "Parser" do | |
| 202 281 |  | 
| 203 282 | 
             
              test 'parse style attribute with id and role' do
         | 
| 204 283 | 
             
                attributes = {1 => 'style#id.role'}
         | 
| 205 | 
            -
                style | 
| 284 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 206 285 | 
             
                assert_equal 'style', style
         | 
| 207 | 
            -
                assert_nil original_style
         | 
| 208 286 | 
             
                assert_equal 'style', attributes['style']
         | 
| 209 287 | 
             
                assert_equal 'id', attributes['id']
         | 
| 210 288 | 
             
                assert_equal 'role', attributes['role']
         | 
| @@ -213,9 +291,8 @@ context "Parser" do | |
| 213 291 |  | 
| 214 292 | 
             
              test 'parse style attribute with style, role, id and option' do
         | 
| 215 293 | 
             
                attributes = {1 => 'style.role#id%fragment'}
         | 
| 216 | 
            -
                style | 
| 294 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 217 295 | 
             
                assert_equal 'style', style
         | 
| 218 | 
            -
                assert_nil original_style
         | 
| 219 296 | 
             
                assert_equal 'style', attributes['style']
         | 
| 220 297 | 
             
                assert_equal 'id', attributes['id']
         | 
| 221 298 | 
             
                assert_equal 'role', attributes['role']
         | 
| @@ -226,9 +303,8 @@ context "Parser" do | |
| 226 303 |  | 
| 227 304 | 
             
              test 'parse style attribute with style, id and multiple roles' do
         | 
| 228 305 | 
             
                attributes = {1 => 'style#id.role1.role2'}
         | 
| 229 | 
            -
                style | 
| 306 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 230 307 | 
             
                assert_equal 'style', style
         | 
| 231 | 
            -
                assert_nil original_style
         | 
| 232 308 | 
             
                assert_equal 'style', attributes['style']
         | 
| 233 309 | 
             
                assert_equal 'id', attributes['id']
         | 
| 234 310 | 
             
                assert_equal 'role1 role2', attributes['role']
         | 
| @@ -237,9 +313,8 @@ context "Parser" do | |
| 237 313 |  | 
| 238 314 | 
             
              test 'parse style attribute with style, multiple roles and id' do
         | 
| 239 315 | 
             
                attributes = {1 => 'style.role1.role2#id'}
         | 
| 240 | 
            -
                style | 
| 316 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 241 317 | 
             
                assert_equal 'style', style
         | 
| 242 | 
            -
                assert_nil original_style
         | 
| 243 318 | 
             
                assert_equal 'style', attributes['style']
         | 
| 244 319 | 
             
                assert_equal 'id', attributes['id']
         | 
| 245 320 | 
             
                assert_equal 'role1 role2', attributes['role']
         | 
| @@ -248,18 +323,16 @@ context "Parser" do | |
| 248 323 |  | 
| 249 324 | 
             
              test 'parse style attribute with positional and original style' do
         | 
| 250 325 | 
             
                attributes = {1 => 'new_style', 'style' => 'original_style'}
         | 
| 251 | 
            -
                style | 
| 326 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 252 327 | 
             
                assert_equal 'new_style', style
         | 
| 253 | 
            -
                assert_equal 'original_style', original_style
         | 
| 254 328 | 
             
                assert_equal 'new_style', attributes['style']
         | 
| 255 329 | 
             
                assert_equal 'new_style', attributes[1]
         | 
| 256 330 | 
             
              end
         | 
| 257 331 |  | 
| 258 332 | 
             
              test 'parse style attribute with id and role only' do
         | 
| 259 333 | 
             
                attributes = {1 => '#id.role'}
         | 
| 260 | 
            -
                style | 
| 334 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 261 335 | 
             
                assert_nil style
         | 
| 262 | 
            -
                assert_nil original_style
         | 
| 263 336 | 
             
                assert_equal 'id', attributes['id']
         | 
| 264 337 | 
             
                assert_equal 'role', attributes['role']
         | 
| 265 338 | 
             
                assert_equal '#id.role', attributes[1]
         | 
| @@ -267,9 +340,8 @@ context "Parser" do | |
| 267 340 |  | 
| 268 341 | 
             
              test 'parse empty style attribute' do
         | 
| 269 342 | 
             
                attributes = {1 => nil}
         | 
| 270 | 
            -
                style | 
| 343 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 271 344 | 
             
                assert_nil style
         | 
| 272 | 
            -
                assert_nil original_style
         | 
| 273 345 | 
             
                assert_nil attributes['id']
         | 
| 274 346 | 
             
                assert_nil attributes['role']
         | 
| 275 347 | 
             
                assert_nil attributes[1]
         | 
| @@ -277,9 +349,8 @@ context "Parser" do | |
| 277 349 |  | 
| 278 350 | 
             
              test 'parse style attribute with option should preserve existing options' do
         | 
| 279 351 | 
             
                attributes = {1 => '%header', 'options' => 'footer', 'footer-option' => ''}
         | 
| 280 | 
            -
                style | 
| 352 | 
            +
                style = Asciidoctor::Parser.parse_style_attribute(attributes)
         | 
| 281 353 | 
             
                assert_nil style
         | 
| 282 | 
            -
                assert_nil original_style
         | 
| 283 354 | 
             
                assert_equal 'header,footer', attributes['options']
         | 
| 284 355 | 
             
                assert_equal '', attributes['header-option']
         | 
| 285 356 | 
             
                assert_equal '', attributes['footer-option']
         | 
| @@ -455,6 +526,56 @@ context "Parser" do | |
| 455 526 | 
             
                assert_equal 'John Smith', metadata['author_2']
         | 
| 456 527 | 
             
              end
         | 
| 457 528 |  | 
| 529 | 
            +
              test 'parse name with more than 3 parts in author attribute' do
         | 
| 530 | 
            +
                doc = empty_document
         | 
| 531 | 
            +
                parse_header_metadata ':author: Leroy  Harold  Scherer,  Jr.', doc
         | 
| 532 | 
            +
                assert_equal 'Leroy Harold Scherer, Jr.', doc.attributes['author']
         | 
| 533 | 
            +
                assert_equal 'Leroy', doc.attributes['firstname']
         | 
| 534 | 
            +
                assert_equal 'Harold', doc.attributes['middlename']
         | 
| 535 | 
            +
                assert_equal 'Scherer, Jr.', doc.attributes['lastname']
         | 
| 536 | 
            +
              end
         | 
| 537 | 
            +
             | 
| 538 | 
            +
              test 'does not drop name joiner when using multiple authors' do
         | 
| 539 | 
            +
                input = <<-EOS
         | 
| 540 | 
            +
            Kismet Chameleon; Lazarus het_Draeke
         | 
| 541 | 
            +
                EOS
         | 
| 542 | 
            +
                doc = empty_document
         | 
| 543 | 
            +
                parse_header_metadata input, doc
         | 
| 544 | 
            +
                assert_equal 2, doc.attributes['authorcount']
         | 
| 545 | 
            +
                assert_equal 'Kismet Chameleon, Lazarus het Draeke', doc.attributes['authors']
         | 
| 546 | 
            +
                assert_equal 'Kismet Chameleon', doc.attributes['author_1']
         | 
| 547 | 
            +
                assert_equal 'Lazarus het Draeke', doc.attributes['author_2']
         | 
| 548 | 
            +
                assert_equal 'het Draeke', doc.attributes['lastname_2']
         | 
| 549 | 
            +
              end
         | 
| 550 | 
            +
             | 
| 551 | 
            +
              test 'allows authors to be overridden using explicit author attributes' do
         | 
| 552 | 
            +
                input = <<-EOS
         | 
| 553 | 
            +
            Kismet Chameleon; Johnny Bravo; Lazarus het_Draeke
         | 
| 554 | 
            +
            :author_2: Danger Mouse
         | 
| 555 | 
            +
                EOS
         | 
| 556 | 
            +
                doc = empty_document
         | 
| 557 | 
            +
                parse_header_metadata input, doc
         | 
| 558 | 
            +
                assert_equal 3, doc.attributes['authorcount']
         | 
| 559 | 
            +
                assert_equal 'Kismet Chameleon, Danger Mouse, Lazarus het Draeke', doc.attributes['authors']
         | 
| 560 | 
            +
                assert_equal 'Kismet Chameleon', doc.attributes['author_1']
         | 
| 561 | 
            +
                assert_equal 'Danger Mouse', doc.attributes['author_2']
         | 
| 562 | 
            +
                assert_equal 'Lazarus het Draeke', doc.attributes['author_3']
         | 
| 563 | 
            +
                assert_equal 'het Draeke', doc.attributes['lastname_3']
         | 
| 564 | 
            +
              end
         | 
| 565 | 
            +
             | 
| 566 | 
            +
              test 'removes formatting before partitioning author defined using author attribute' do
         | 
| 567 | 
            +
                input = <<-EOS
         | 
| 568 | 
            +
            :author: pass:n[http://example.org/community/team.html[Ze_**Project** team]]
         | 
| 569 | 
            +
                EOS
         | 
| 570 | 
            +
             | 
| 571 | 
            +
                doc = empty_document
         | 
| 572 | 
            +
                parse_header_metadata input, doc
         | 
| 573 | 
            +
                assert_equal 1, doc.attributes['authorcount']
         | 
| 574 | 
            +
                assert_equal '<a href="http://example.org/community/team.html">Ze <strong>Project</strong> team</a>', doc.attributes['authors']
         | 
| 575 | 
            +
                assert_equal 'Ze Project', doc.attributes['firstname']
         | 
| 576 | 
            +
                assert_equal 'team', doc.attributes['lastname']
         | 
| 577 | 
            +
              end
         | 
| 578 | 
            +
             | 
| 458 579 | 
             
              test "parse rev number date remark" do
         | 
| 459 580 | 
             
                input = <<-EOS
         | 
| 460 581 | 
             
            Ryan Waldron
         | 
| @@ -591,19 +712,18 @@ v0.0.7, 2013-12-18 | |
| 591 712 | 
             
                assert_equal '2013-12-18', metadata['revdate']
         | 
| 592 713 | 
             
              end
         | 
| 593 714 |  | 
| 594 | 
            -
              test  | 
| 595 | 
            -
                 | 
| 596 | 
            -
                 | 
| 597 | 
            -
                metadata = Asciidoctor::Parser.parse_header_metadata(reader, blankdoc)
         | 
| 715 | 
            +
              test 'attribute entry overrides generated author initials' do
         | 
| 716 | 
            +
                doc = empty_document
         | 
| 717 | 
            +
                metadata, _ = parse_header_metadata %(Stuart Rackham <founder@asciidoc.org>\n:Author Initials: SJR), doc
         | 
| 598 718 | 
             
                assert_equal 'SR', metadata['authorinitials']
         | 
| 599 | 
            -
                assert_equal 'SJR',  | 
| 719 | 
            +
                assert_equal 'SJR', doc.attributes['authorinitials']
         | 
| 600 720 | 
             
              end
         | 
| 601 721 |  | 
| 602 722 | 
             
              test 'adjust indentation to 0' do
         | 
| 603 723 | 
             
                input = <<-EOS.chomp
         | 
| 604 724 | 
             
                def names
         | 
| 605 725 |  | 
| 606 | 
            -
                  @name.split | 
| 726 | 
            +
                  @name.split
         | 
| 607 727 |  | 
| 608 728 | 
             
                end
         | 
| 609 729 | 
             
                EOS
         | 
| @@ -611,7 +731,7 @@ v0.0.7, 2013-12-18 | |
| 611 731 | 
             
                expected = <<-EOS.chomp
         | 
| 612 732 | 
             
            def names
         | 
| 613 733 |  | 
| 614 | 
            -
              @name.split | 
| 734 | 
            +
              @name.split
         | 
| 615 735 |  | 
| 616 736 | 
             
            end
         | 
| 617 737 | 
             
                EOS
         | 
| @@ -625,7 +745,7 @@ end | |
| 625 745 | 
             
                input = <<-EOS.chomp
         | 
| 626 746 | 
             
                def names
         | 
| 627 747 |  | 
| 628 | 
            -
            \t  @name.split | 
| 748 | 
            +
            \t  @name.split
         | 
| 629 749 |  | 
| 630 750 | 
             
                end
         | 
| 631 751 | 
             
                EOS
         | 
| @@ -633,7 +753,7 @@ end | |
| 633 753 | 
             
                expected = <<-EOS.chomp
         | 
| 634 754 | 
             
            def names
         | 
| 635 755 |  | 
| 636 | 
            -
              @name.split | 
| 756 | 
            +
              @name.split
         | 
| 637 757 |  | 
| 638 758 | 
             
            end
         | 
| 639 759 | 
             
                EOS
         | 
| @@ -667,7 +787,7 @@ devtmpfs                3.9G       0     3.9G     0%    /dev | |
| 667 787 | 
             
                input = <<-EOS.chomp
         | 
| 668 788 | 
             
                def names
         | 
| 669 789 |  | 
| 670 | 
            -
                  @name.split | 
| 790 | 
            +
                  @name.split
         | 
| 671 791 |  | 
| 672 792 | 
             
                end
         | 
| 673 793 | 
             
                EOS
         | 
| @@ -675,7 +795,7 @@ devtmpfs                3.9G       0     3.9G     0%    /dev | |
| 675 795 | 
             
                expected = <<-EOS.chomp
         | 
| 676 796 | 
             
              def names
         | 
| 677 797 |  | 
| 678 | 
            -
                @name.split | 
| 798 | 
            +
                @name.split
         | 
| 679 799 |  | 
| 680 800 | 
             
              end
         | 
| 681 801 | 
             
                EOS
         | 
| @@ -689,7 +809,7 @@ devtmpfs                3.9G       0     3.9G     0%    /dev | |
| 689 809 | 
             
                input = <<-EOS
         | 
| 690 810 | 
             
                def names
         | 
| 691 811 |  | 
| 692 | 
            -
                  @name.split | 
| 812 | 
            +
                  @name.split
         | 
| 693 813 |  | 
| 694 814 | 
             
                end
         | 
| 695 815 | 
             
                EOS
         | 
    
        data/test/paths_test.rb
    CHANGED
    
    | @@ -88,13 +88,17 @@ context 'Path Resolver' do | |
| 88 88 | 
             
                  assert_equal 'assets/images', @resolver.web_path(nil, 'assets/images')
         | 
| 89 89 | 
             
                end
         | 
| 90 90 |  | 
| 91 | 
            -
                test ' | 
| 91 | 
            +
                test 'posixifies windows paths' do
         | 
| 92 92 | 
             
                  assert_equal '/images', @resolver.web_path('\\images')
         | 
| 93 93 | 
             
                  assert_equal '../images', @resolver.web_path('..\\images')
         | 
| 94 94 | 
             
                  assert_equal '/images', @resolver.web_path('\\..\\images')
         | 
| 95 95 | 
             
                  assert_equal 'assets/images', @resolver.web_path('assets\\images')
         | 
| 96 96 | 
             
                  assert_equal '../assets/images', @resolver.web_path('assets\\images', '..\\images\\..')
         | 
| 97 97 | 
             
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                test 'URL encode spaces in path' do
         | 
| 100 | 
            +
                  assert_equal 'assets%20and%20stuff/lots%20of%20images', @resolver.web_path('lots of images', 'assets and stuff')
         | 
| 101 | 
            +
                end
         | 
| 98 102 | 
             
              end
         | 
| 99 103 |  | 
| 100 104 | 
             
              context 'System Paths' do
         | 
| @@ -105,9 +109,23 @@ context 'Path Resolver' do | |
| 105 109 | 
             
                end
         | 
| 106 110 |  | 
| 107 111 | 
             
                test 'prevents access to paths outside of jail' do
         | 
| 108 | 
            -
                   | 
| 109 | 
            -
             | 
| 110 | 
            -
                   | 
| 112 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 113 | 
            +
                    [(@resolver.system_path '../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL), err.string]
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                  assert_equal %(#{JAIL}/css), result
         | 
| 116 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 119 | 
            +
                    [(@resolver.system_path '/../../../../../css', %(#{JAIL}/assets/stylesheets), JAIL), err.string]
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                  assert_equal %(#{JAIL}/css), result
         | 
| 122 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 125 | 
            +
                    [(@resolver.system_path '../../../css', '../../..', JAIL), err.string]
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
                  assert_equal %(#{JAIL}/css), result
         | 
| 128 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 111 129 | 
             
                end
         | 
| 112 130 |  | 
| 113 131 | 
             
                test 'throws exception for illegal path access if recover is false' do
         | 
| @@ -181,6 +199,7 @@ context 'Path Resolver' do | |
| 181 199 | 
             
                  pwd = File.expand_path(Dir.pwd)
         | 
| 182 200 | 
             
                  assert_equal "#{pwd}/images/tiger.png", @resolver.system_path('images/tiger.png', '')
         | 
| 183 201 | 
             
                  assert_equal "#{pwd}/images/tiger.png", @resolver.system_path('images/tiger.png', nil)
         | 
| 202 | 
            +
                  assert_equal "#{pwd}/images/tiger.png", @resolver.system_path('images/tiger.png')
         | 
| 184 203 | 
             
                end
         | 
| 185 204 |  | 
| 186 205 | 
             
                test 'resolves relative hidden target relative to current directory if start is empty' do
         | 
| @@ -190,22 +209,37 @@ context 'Path Resolver' do | |
| 190 209 | 
             
                end
         | 
| 191 210 |  | 
| 192 211 | 
             
                test 'resolves and normalizes start with target is empty' do
         | 
| 193 | 
            -
                  pwd = File.expand_path | 
| 194 | 
            -
                  assert_equal '/home/doctor/docs', @resolver.system_path | 
| 195 | 
            -
                  assert_equal '/home/doctor/docs', @resolver.system_path | 
| 196 | 
            -
                  assert_equal  | 
| 197 | 
            -
                   | 
| 212 | 
            +
                  pwd = File.expand_path Dir.pwd
         | 
| 213 | 
            +
                  assert_equal '/home/doctor/docs', (@resolver.system_path '', '/home/doctor/docs')
         | 
| 214 | 
            +
                  assert_equal '/home/doctor/docs', (@resolver.system_path nil, '/home/doctor/docs')
         | 
| 215 | 
            +
                  assert_equal %(#{pwd}/assets/images), (@resolver.system_path nil, 'assets/images')
         | 
| 216 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 217 | 
            +
                    [(@resolver.system_path '', '../assets/images', JAIL), err.string]
         | 
| 218 | 
            +
                  end
         | 
| 219 | 
            +
                  assert_equal %(#{JAIL}/assets/images), result
         | 
| 220 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 198 221 | 
             
                end
         | 
| 199 222 |  | 
| 200 | 
            -
                test ' | 
| 223 | 
            +
                test 'posixifies windows paths' do
         | 
| 201 224 | 
             
                  assert_equal "#{JAIL}/assets/css", @resolver.system_path('..\\css', 'assets\\stylesheets', JAIL)
         | 
| 202 225 | 
             
                end
         | 
| 203 226 |  | 
| 204 227 | 
             
                test 'resolves windows paths when file separator is backlash' do
         | 
| 205 228 | 
             
                  @resolver.file_separator = '\\'
         | 
| 206 | 
            -
             | 
| 207 | 
            -
                  assert_equal 'C:/data/docs', @resolver.system_path | 
| 208 | 
            -
             | 
| 229 | 
            +
             | 
| 230 | 
            +
                  assert_equal 'C:/data/docs', (@resolver.system_path '..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 233 | 
            +
                    [(@resolver.system_path '..\\..', 'C:\\data\\docs\\assets', 'C:\\data\\docs'), err.string]
         | 
| 234 | 
            +
                  end
         | 
| 235 | 
            +
                  assert_equal 'C:/data/docs', result
         | 
| 236 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                  result, warnings = redirect_streams do |_, err|
         | 
| 239 | 
            +
                    [(@resolver.system_path '..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs'), err.string]
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
                  assert_equal 'C:/data/docs/css', result
         | 
| 242 | 
            +
                  assert_includes warnings, 'path has illegal reference to ancestor of jail'
         | 
| 209 243 | 
             
                end
         | 
| 210 244 |  | 
| 211 245 | 
             
                test 'should calculate relative path' do
         |