asciidoctor 1.5.2 → 1.5.3

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

Potentially problematic release.


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

Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +107 -1
  3. data/LICENSE.adoc +1 -1
  4. data/README.adoc +155 -230
  5. data/Rakefile +2 -1
  6. data/bin/asciidoctor +5 -1
  7. data/data/stylesheets/asciidoctor-default.css +37 -29
  8. data/data/stylesheets/coderay-asciidoctor.css +3 -3
  9. data/features/text_formatting.feature +2 -0
  10. data/lib/asciidoctor.rb +46 -21
  11. data/lib/asciidoctor/abstract_block.rb +14 -8
  12. data/lib/asciidoctor/abstract_node.rb +77 -24
  13. data/lib/asciidoctor/attribute_list.rb +1 -1
  14. data/lib/asciidoctor/block.rb +2 -3
  15. data/lib/asciidoctor/cli/options.rb +14 -15
  16. data/lib/asciidoctor/converter/docbook45.rb +8 -8
  17. data/lib/asciidoctor/converter/docbook5.rb +25 -17
  18. data/lib/asciidoctor/converter/factory.rb +6 -1
  19. data/lib/asciidoctor/converter/html5.rb +159 -117
  20. data/lib/asciidoctor/converter/manpage.rb +671 -0
  21. data/lib/asciidoctor/converter/template.rb +24 -17
  22. data/lib/asciidoctor/document.rb +89 -47
  23. data/lib/asciidoctor/extensions.rb +22 -21
  24. data/lib/asciidoctor/helpers.rb +73 -16
  25. data/lib/asciidoctor/list.rb +26 -5
  26. data/lib/asciidoctor/parser.rb +179 -122
  27. data/lib/asciidoctor/path_resolver.rb +6 -10
  28. data/lib/asciidoctor/reader.rb +37 -34
  29. data/lib/asciidoctor/stylesheets.rb +16 -10
  30. data/lib/asciidoctor/substitutors.rb +98 -21
  31. data/lib/asciidoctor/table.rb +21 -17
  32. data/lib/asciidoctor/timings.rb +3 -3
  33. data/lib/asciidoctor/version.rb +1 -1
  34. data/man/asciidoctor.1 +155 -89
  35. data/man/asciidoctor.adoc +19 -11
  36. data/test/attributes_test.rb +86 -0
  37. data/test/blocks_test.rb +203 -15
  38. data/test/converter_test.rb +15 -2
  39. data/test/document_test.rb +290 -36
  40. data/test/extensions_test.rb +22 -3
  41. data/test/fixtures/circle.svg +8 -0
  42. data/test/fixtures/subs-docinfo.html +2 -0
  43. data/test/fixtures/subs.adoc +7 -0
  44. data/test/invoker_test.rb +25 -0
  45. data/test/links_test.rb +17 -0
  46. data/test/lists_test.rb +173 -0
  47. data/test/options_test.rb +2 -2
  48. data/test/paragraphs_test.rb +2 -2
  49. data/test/parser_test.rb +56 -13
  50. data/test/reader_test.rb +35 -3
  51. data/test/sections_test.rb +59 -0
  52. data/test/substitutions_test.rb +53 -14
  53. data/test/tables_test.rb +158 -2
  54. data/test/test_helper.rb +7 -2
  55. metadata +22 -11
  56. data/benchmark/benchmark.rb +0 -129
  57. data/benchmark/sample-data/mdbasics.adoc +0 -334
  58. data/lib/asciidoctor/opal_ext.rb +0 -26
  59. data/lib/asciidoctor/opal_ext/comparable.rb +0 -38
  60. data/lib/asciidoctor/opal_ext/dir.rb +0 -13
  61. data/lib/asciidoctor/opal_ext/error.rb +0 -2
  62. data/lib/asciidoctor/opal_ext/file.rb +0 -145
@@ -1377,6 +1377,22 @@ content
1377
1377
  end
1378
1378
  assert_equal "ifdef::holygrail[]\ncontent\nendif::holygrail[]", (lines * ::Asciidoctor::EOL)
1379
1379
  end
1380
+
1381
+ test 'ifeval comparing missing attribute to nil is included' do
1382
+ input = <<-EOS
1383
+ ifeval::['{foo}' == '']
1384
+ No foo for you!
1385
+ endif::[]
1386
+ EOS
1387
+
1388
+ doc = Asciidoctor::Document.new input
1389
+ reader = doc.reader
1390
+ lines = []
1391
+ while reader.has_more_lines?
1392
+ lines << reader.read_line
1393
+ end
1394
+ assert_equal 'No foo for you!', (lines * ::Asciidoctor::EOL)
1395
+ end
1380
1396
 
1381
1397
  test 'ifeval comparing double-quoted attribute to matching string is included' do
1382
1398
  input = <<-EOS
@@ -1460,7 +1476,7 @@ endif::[]
1460
1476
 
1461
1477
  test 'ifeval arguments can be transposed' do
1462
1478
  input = <<-EOS
1463
- ifeval::["0.1.0" <= "{asciidoctor-version}"]
1479
+ ifeval::['0.1.0' <= '{asciidoctor-version}']
1464
1480
  That version will do!
1465
1481
  endif::[]
1466
1482
  EOS
@@ -1474,14 +1490,30 @@ endif::[]
1474
1490
  assert_equal 'That version will do!', (lines * ::Asciidoctor::EOL)
1475
1491
  end
1476
1492
 
1477
- test 'ifeval matching numeric comparison is included' do
1493
+ test 'ifeval matching numeric equality is included' do
1478
1494
  input = <<-EOS
1479
1495
  ifeval::[{rings} == 1]
1480
1496
  One ring to rule them all!
1481
1497
  endif::[]
1482
1498
  EOS
1483
1499
 
1484
- doc = Asciidoctor::Document.new input, :attributes => { 'rings' => 1 }
1500
+ doc = Asciidoctor::Document.new input, :attributes => { 'rings' => '1' }
1501
+ reader = doc.reader
1502
+ lines = []
1503
+ while reader.has_more_lines?
1504
+ lines << reader.read_line
1505
+ end
1506
+ assert_equal 'One ring to rule them all!', (lines * ::Asciidoctor::EOL)
1507
+ end
1508
+
1509
+ test 'ifeval matching numeric inequality is included' do
1510
+ input = <<-EOS
1511
+ ifeval::[{rings} != 0]
1512
+ One ring to rule them all!
1513
+ endif::[]
1514
+ EOS
1515
+
1516
+ doc = Asciidoctor::Document.new input, :attributes => { 'rings' => '1' }
1485
1517
  reader = doc.reader
1486
1518
  lines = []
1487
1519
  while reader.has_more_lines?
@@ -163,6 +163,42 @@ content
163
163
  refute_nil reftext
164
164
  assert_equal 'Install Procedure', reftext
165
165
  end
166
+
167
+ test 'should not overwrite existing id entry in references table' do
168
+ input = <<-EOS
169
+ [#install]
170
+ == First Install
171
+
172
+ content
173
+
174
+ [#install]
175
+ == Second Install
176
+
177
+ content
178
+ EOS
179
+
180
+ doc = document_from_string input
181
+ reftext = doc.references[:ids]['install']
182
+ refute_nil reftext
183
+ assert_equal 'First Install', reftext
184
+ end
185
+
186
+ test 'should not overwrite existing id entry with generated reftext in references table' do
187
+ input = <<-EOS
188
+ [#install]
189
+ == First Install
190
+
191
+ content
192
+
193
+ [#install]
194
+ content
195
+ EOS
196
+
197
+ doc = document_from_string input
198
+ reftext = doc.references[:ids]['install']
199
+ refute_nil reftext
200
+ assert_equal 'First Install', reftext
201
+ end
166
202
  end
167
203
 
168
204
  context "document title (level 0)" do
@@ -2086,6 +2122,29 @@ They couldn't believe their eyes when...
2086
2122
  assert_css '#preamble:root .paragraph + #toc', output, 1
2087
2123
  end
2088
2124
 
2125
+ test 'should render table of contents at default location in embedded document if toc attribute is set' do
2126
+ input = <<-EOS
2127
+ = Article
2128
+ :showtitle:
2129
+ :toc:
2130
+
2131
+ Once upon a time...
2132
+
2133
+ == Section One
2134
+
2135
+ It was a dark and stormy night...
2136
+
2137
+ == Section Two
2138
+
2139
+ They couldn't believe their eyes when...
2140
+ EOS
2141
+
2142
+ output = render_string input, :header_footer => false
2143
+ assert_css 'h1:root', output, 1
2144
+ assert_css 'h1:root + #toc:root', output, 1
2145
+ assert_css 'h1:root + #toc:root + #preamble:root', output, 1
2146
+ end
2147
+
2089
2148
  test 'should not activate toc macro if toc-placement is not set' do
2090
2149
  input = <<-EOS
2091
2150
  = Article
@@ -627,11 +627,50 @@ context 'Substitutions' do
627
627
  assert_equal %{<span class="image"><img src="tiger.png" alt="tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
628
628
  end
629
629
 
630
+ test 'should replace underscore and hyphen with space in generated alt text for an inline image' do
631
+ para = block_from_string('image:tiger-with-family_1.png[]')
632
+ assert_equal %{<span class="image"><img src="tiger-with-family_1.png" alt="tiger with family 1"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
633
+ end
634
+
630
635
  test 'a single-line image macro with text should be interpreted as an image with alt text' do
631
636
  para = block_from_string('image:tiger.png[Tiger]')
632
637
  assert_equal %{<span class="image"><img src="tiger.png" alt="Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
633
638
  end
634
639
 
640
+ test 'an image macro with SVG image and text should be interpreted as an image with alt text' do
641
+ para = block_from_string('image:tiger.svg[Tiger]')
642
+ assert_equal %{<span class="image"><img src="tiger.svg" alt="Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
643
+ end
644
+
645
+ test 'an image macro with an interactive SVG image and alt text should be converted to an object element' do
646
+ para = block_from_string('image:tiger.svg[Tiger,opts=interactive]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'imagesdir' => 'images' })
647
+ assert_equal %{<span class="image"><object type="image/svg+xml" data="images/tiger.svg"><span class="alt">Tiger</span></object></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
648
+ end
649
+
650
+ test 'an image macro with an interactive SVG image, fallback and alt text should be converted to an object element' do
651
+ para = block_from_string('image:tiger.svg[Tiger,fallback=tiger.png,opts=interactive]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'imagesdir' => 'images' })
652
+ assert_equal %{<span class="image"><object type="image/svg+xml" data="images/tiger.svg"><img src="images/tiger.png" alt="Tiger"></object></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
653
+ end
654
+
655
+ test 'an image macro with an inline SVG image should be converted to an svg element' do
656
+ para = block_from_string('image:circle.svg[Tiger,100,opts=inline]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'imagesdir' => 'fixtures', 'docdir' => ::File.dirname(__FILE__) })
657
+ result = para.sub_macros(para.source).gsub(/>\s+</, '><')
658
+ assert_match(/<svg [^>]*width="100px"[^>]*>/, result)
659
+ refute_match(/<svg [^>]*width="500px"[^>]*>/, result)
660
+ refute_match(/<svg [^>]*height="500px"[^>]*>/, result)
661
+ refute_match(/<svg [^>]*style="width:500px;height:500px"[^>]*>/, result)
662
+ end
663
+
664
+ test 'an image macro with an inline SVG image should be converted to an svg element even when data-uri is set' do
665
+ para = block_from_string('image:circle.svg[Tiger,100,opts=inline]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'data-uri' => '', 'imagesdir' => 'fixtures', 'docdir' => ::File.dirname(__FILE__) })
666
+ assert_match(/<svg [^>]*width="100px">/, para.sub_macros(para.source).gsub(/>\s+</, '><'))
667
+ end
668
+
669
+ test 'an image macro with an SVG image should not use an object element when safe mode is secure' do
670
+ para = block_from_string('image:tiger.svg[Tiger,opts=interactive]', :attributes => { 'imagesdir' => 'images' })
671
+ assert_equal %{<span class="image"><img src="images/tiger.svg" alt="Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
672
+ end
673
+
635
674
  test 'a single-line image macro with text containing escaped square bracket should be interpreted as an image with alt text' do
636
675
  para = block_from_string(%(image:tiger.png[[Another#{BACKSLASH}] Tiger]))
637
676
  assert_equal %{<span class="image"><img src="tiger.png" alt="[Another] Tiger"></span>}, para.sub_macros(para.source).gsub(/>\s+</, '><')
@@ -730,7 +769,7 @@ context 'Substitutions' do
730
769
 
731
770
  test 'a single-line footnote macro should be registered and rendered as a footnote' do
732
771
  para = block_from_string('Sentence text footnote:[An example footnote.].')
733
- 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)
772
+ assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
734
773
  assert_equal 1, para.document.references[:footnotes].size
735
774
  footnote = para.document.references[:footnotes].first
736
775
  assert_equal 1, footnote.index
@@ -740,7 +779,7 @@ context 'Substitutions' do
740
779
 
741
780
  test 'a multi-line footnote macro should be registered and rendered as a footnote without endline' do
742
781
  para = block_from_string("Sentence text footnote:[An example footnote\nwith wrapped text.].")
743
- 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)
782
+ assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
744
783
  assert_equal 1, para.document.references[:footnotes].size
745
784
  footnote = para.document.references[:footnotes].first
746
785
  assert_equal 1, footnote.index
@@ -750,7 +789,7 @@ context 'Substitutions' do
750
789
 
751
790
  test 'an escaped closing square bracket in a footnote should be unescaped when rendered' do
752
791
  para = block_from_string(%(footnote:[a #{BACKSLASH}] b].))
753
- 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)
792
+ assert_equal %(<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
754
793
  assert_equal 1, para.document.references[:footnotes].size
755
794
  footnote = para.document.references[:footnotes].first
756
795
  assert_equal "a ] b", footnote.text
@@ -758,7 +797,7 @@ context 'Substitutions' do
758
797
 
759
798
  test 'a footnote macro can be directly adjacent to preceding word' do
760
799
  para = block_from_string('Sentence textfootnote:[An example footnote.].')
761
- 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)
800
+ assert_equal %(Sentence text<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
762
801
  end
763
802
 
764
803
  test 'a footnote macro may contain an escaped backslash' do
@@ -775,7 +814,7 @@ context 'Substitutions' do
775
814
 
776
815
  test 'a footnote macro may contain a link macro' do
777
816
  para = block_from_string('Share your code. footnote:[http://github.com[GitHub]]')
778
- 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)
817
+ assert_equal %(Share your code. <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
779
818
  assert_equal 1, para.document.references[:footnotes].size
780
819
  footnote1 = para.document.references[:footnotes][0]
781
820
  assert_equal '<a href="http://github.com">GitHub</a>', footnote1.text
@@ -784,7 +823,7 @@ context 'Substitutions' do
784
823
  test 'a footnote macro may contain a plain URL' do
785
824
  para = block_from_string %(the JLine footnote:[https://github.com/jline/jline2]\nlibrary.)
786
825
  result = para.sub_macros para.source
787
- assert_equal %(the JLine <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>\nlibrary.), result
826
+ assert_equal %(the JLine <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>\nlibrary.), result
788
827
  assert_equal 1, para.document.references[:footnotes].size
789
828
  fn1 = para.document.references[:footnotes].first
790
829
  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
@@ -793,7 +832,7 @@ context 'Substitutions' do
793
832
  test 'a footnote macro followed by a semi-colon may contain a plain URL' do
794
833
  para = block_from_string %(the JLine footnote:[https://github.com/jline/jline2];\nlibrary.)
795
834
  result = para.sub_macros para.source
796
- assert_equal %(the JLine <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>;\nlibrary.), result
835
+ assert_equal %(the JLine <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>;\nlibrary.), result
797
836
  assert_equal 1, para.document.references[:footnotes].size
798
837
  fn1 = para.document.references[:footnotes].first
799
838
  assert_equal '<a href="https://github.com/jline/jline2" class="bare">https://github.com/jline/jline2</a>', fn1.text
@@ -802,7 +841,7 @@ context 'Substitutions' do
802
841
  test 'a footnote macro may contain an xref macro' do
803
842
  # specialcharacters escaping is simulated
804
843
  para = block_from_string('text footnote:[&lt;&lt;_install,Install&gt;&gt;]')
805
- 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)
844
+ assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
806
845
  assert_equal 1, para.document.references[:footnotes].size
807
846
  footnote1 = para.document.references[:footnotes][0]
808
847
  assert_equal '<a href="#_install">Install</a>', footnote1.text
@@ -810,7 +849,7 @@ context 'Substitutions' do
810
849
 
811
850
  test 'a footnote macro may contain an anchor macro' do
812
851
  para = block_from_string('text footnote:[a [[b\]\] \[[c\]\] d]')
813
- 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)
852
+ assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
814
853
  assert_equal 1, para.document.references[:footnotes].size
815
854
  footnote1 = para.document.references[:footnotes][0]
816
855
  assert_equal 'a <a id="b"></a> [[c]] d', footnote1.text
@@ -827,7 +866,7 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
827
866
 
828
867
  test 'a footnote macro may contain a bibliographic anchor macro' do
829
868
  para = block_from_string('text footnote:[a [[[b\]\]\] c]')
830
- 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)
869
+ assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
831
870
  assert_equal 1, para.document.references[:footnotes].size
832
871
  footnote1 = para.document.references[:footnotes][0]
833
872
  assert_equal 'a <a id="b"></a>[b] c', footnote1.text
@@ -835,7 +874,7 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
835
874
 
836
875
  test 'should increment index of subsequent footnote macros' do
837
876
  para = block_from_string("Sentence text footnote:[An example footnote.]. Sentence text footnote:[Another footnote.].")
838
- assert_equal %(Sentence text <span class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>. Sentence text <span class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnote_2" title="View footnote.">2</a>]</span>.), para.sub_macros(para.source)
877
+ assert_equal %(Sentence text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>. Sentence text <sup class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnote_2" title="View footnote.">2</a>]</sup>.), para.sub_macros(para.source)
839
878
  assert_equal 2, para.document.references[:footnotes].size
840
879
  footnote1 = para.document.references[:footnotes][0]
841
880
  assert_equal 1, footnote1.index
@@ -849,7 +888,7 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
849
888
 
850
889
  test 'a footnoteref macro with id and single-line text should be registered and rendered as a footnote' do
851
890
  para = block_from_string('Sentence text footnoteref:[ex1, An example footnote.].')
852
- 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)
891
+ assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
853
892
  assert_equal 1, para.document.references[:footnotes].size
854
893
  footnote = para.document.references[:footnotes].first
855
894
  assert_equal 1, footnote.index
@@ -859,7 +898,7 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
859
898
 
860
899
  test 'a footnoteref macro with id and multi-line text should be registered and rendered as a footnote without endlines' do
861
900
  para = block_from_string("Sentence text footnoteref:[ex1, An example footnote\nwith wrapped text.].")
862
- 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)
901
+ assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
863
902
  assert_equal 1, para.document.references[:footnotes].size
864
903
  footnote = para.document.references[:footnotes].first
865
904
  assert_equal 1, footnote.index
@@ -869,7 +908,7 @@ foofootnote:[+http://example.com+]barfootnote:[+http://acme.com+]baz
869
908
 
870
909
  test 'a footnoteref macro with id should refer to footnoteref with same id' do
871
910
  para = block_from_string('Sentence text footnoteref:[ex1, An example footnote.]. Sentence text footnoteref:[ex1].')
872
- 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>. Sentence text <span class="footnoteref">[<a class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</span>.), para.sub_macros(para.source)
911
+ assert_equal %(Sentence text <sup class="footnote" id="_footnote_ex1">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>. Sentence text <sup class="footnoteref">[<a class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>.), para.sub_macros(para.source)
873
912
  assert_equal 1, para.document.references[:footnotes].size
874
913
  footnote = para.document.references[:footnotes].first
875
914
  assert_equal 1, footnote.index
@@ -102,6 +102,28 @@ context 'Tables' do
102
102
  assert_xpath '/table/tbody/tr/td[2]/p[text()="a | there"]', output, 1
103
103
  end
104
104
 
105
+ test 'preserves escaped delimiters at the end of the line' do
106
+ input = <<-EOS
107
+ [%header,cols="1,1"]
108
+ |====
109
+ |A |B\\|
110
+ |A1 |B1\\|
111
+ |A2 |B2\\|
112
+ |====
113
+ EOS
114
+ output = render_embedded_string input
115
+ assert_css 'table', output, 1
116
+ assert_css 'table > colgroup > col', output, 2
117
+ assert_css 'table > thead > tr', output, 1
118
+ assert_css 'table > thead > tr:nth-child(1) > th', output, 2
119
+ assert_xpath '/table/thead/tr[1]/th[2][text()="B|"]', output, 1
120
+ assert_css 'table > tbody > tr', output, 2
121
+ assert_css 'table > tbody > tr:nth-child(1) > td', output, 2
122
+ assert_xpath '/table/tbody/tr[1]/td[2]/p[text()="B1|"]', output, 1
123
+ assert_css 'table > tbody > tr:nth-child(2) > td', output, 2
124
+ assert_xpath '/table/tbody/tr[2]/td[2]/p[text()="B2|"]', output, 1
125
+ end
126
+
105
127
  test 'should treat trailing pipe as an empty cell' do
106
128
  input = <<-EOS
107
129
  |====
@@ -181,7 +203,7 @@ A | here| a | there
181
203
  assert_css 'table > tbody > tr:nth-child(2) > td', output, 4
182
204
  end
183
205
 
184
- test 'colspec attribute sets number of columns' do
206
+ test 'colspec attribute using asterisk syntax sets number of columns' do
185
207
  input = <<-EOS
186
208
  [cols="3*"]
187
209
  |===
@@ -207,7 +229,7 @@ A | here| a | there
207
229
  assert_css 'table > tbody > tr', output, 2
208
230
  end
209
231
 
210
- test 'table with explicit deprecated syntax column count can have multiple rows on a single line' do
232
+ test 'table with explicit deprecated colspec syntax can have multiple rows on a single line' do
211
233
  input = <<-EOS
212
234
  [cols="3"]
213
235
  |===
@@ -221,6 +243,35 @@ A | here| a | there
221
243
  assert_css 'table > tbody > tr', output, 2
222
244
  end
223
245
 
246
+ test 'columns are added for empty records in colspec attribute' do
247
+ input = <<-EOS
248
+ [cols="<,"]
249
+ |===
250
+ |one |two
251
+ |1 |2 |a |b
252
+ |===
253
+ EOS
254
+ output = render_embedded_string input
255
+ assert_css 'table', output, 1
256
+ assert_css 'table > colgroup > col', output, 2
257
+ assert_css 'table > tbody > tr', output, 3
258
+ end
259
+
260
+ test 'empty cols attribute should be ignored' do
261
+ input = <<-EOS
262
+ [cols=""]
263
+ |===
264
+ |one |two
265
+ |1 |2 |a |b
266
+ |===
267
+ EOS
268
+ output = render_embedded_string input
269
+ assert_css 'table', output, 1
270
+ assert_css 'table > colgroup > col', output, 2
271
+ assert_css 'col[style="width: 50%;"]', output, 2
272
+ assert_css 'table > tbody > tr', output, 3
273
+ end
274
+
224
275
  test 'table with header and footer' do
225
276
  input = <<-EOS
226
277
  [frame="topbot",options="header,footer"]
@@ -550,6 +601,59 @@ d|9 2+>|10
550
601
  assert_xpath '/table/tbody/tr[3]/td[3]/p[text()="c"]', output, 1
551
602
  end
552
603
 
604
+ test 'calculates colnames correctly when using implicit column count and single cell with colspan' do
605
+ input = <<-EOS
606
+ |===
607
+ 2+|Two Columns
608
+ |One Column |One Column
609
+ |===
610
+ EOS
611
+
612
+ output = render_embedded_string input, :backend => 'docbook'
613
+ assert_xpath '//colspec', output, 2
614
+ assert_xpath '(//colspec)[1][@colname="col_1"]', output, 1
615
+ assert_xpath '(//colspec)[2][@colname="col_2"]', output, 1
616
+ assert_xpath '//row', output, 2
617
+ assert_xpath '(//row)[1]/entry', output, 1
618
+ assert_xpath '(//row)[1]/entry[@namest="col_1"][@nameend="col_2"]', output, 1
619
+ end
620
+
621
+ test 'calculates colnames correctly when using implicit column count and cells with mixed colspans' do
622
+ input = <<-EOS
623
+ |===
624
+ 2+|Two Columns | One Column
625
+ |One Column |One Column |One Column
626
+ |===
627
+ EOS
628
+
629
+ output = render_embedded_string input, :backend => 'docbook'
630
+ assert_xpath '//colspec', output, 3
631
+ assert_xpath '(//colspec)[1][@colname="col_1"]', output, 1
632
+ assert_xpath '(//colspec)[2][@colname="col_2"]', output, 1
633
+ assert_xpath '(//colspec)[3][@colname="col_3"]', output, 1
634
+ assert_xpath '//row', output, 2
635
+ assert_xpath '(//row)[1]/entry', output, 2
636
+ assert_xpath '(//row)[1]/entry[@namest="col_1"][@nameend="col_2"]', output, 1
637
+ assert_xpath '(//row)[2]/entry[@namest]', output, 0
638
+ assert_xpath '(//row)[2]/entry[@nameend]', output, 0
639
+ end
640
+
641
+ test 'ignores cell with colspan that exceeds colspec' do
642
+ input = <<-EOS
643
+ [cols="1,1"]
644
+ |===
645
+ 3+|A
646
+ |B
647
+ a|C
648
+
649
+ more C
650
+ |===
651
+ EOS
652
+ output = render_embedded_string input
653
+ assert_css 'table', output, 1
654
+ assert_css 'table *', output, 0
655
+ end
656
+
553
657
  test 'paragraph, verse and literal content' do
554
658
  input = <<-EOS
555
659
  [cols=",^v,^l",options="header"]
@@ -960,5 +1064,57 @@ single cell
960
1064
  output = render_embedded_string input
961
1065
  assert_css 'table td', output, 1
962
1066
  end
1067
+
1068
+ test 'table with breakable db45' do
1069
+ input = <<-EOS
1070
+ .Table with breakable
1071
+ [options="breakable"]
1072
+ |===
1073
+ |Item |Quantity
1074
+ |Item 1 |1
1075
+ |===
1076
+ EOS
1077
+ output = render_embedded_string input, :backend => 'docbook45'
1078
+ assert output.include?('<?dbfo keep-together="auto"?>')
1079
+ end
1080
+
1081
+ test 'table with breakable db5' do
1082
+ input = <<-EOS
1083
+ .Table with breakable
1084
+ [options="breakable"]
1085
+ |===
1086
+ |Item |Quantity
1087
+ |Item 1 |1
1088
+ |===
1089
+ EOS
1090
+ output = render_embedded_string input, :backend => 'docbook5'
1091
+ assert output.include?('<?dbfo keep-together="auto"?>')
1092
+ end
1093
+
1094
+ test 'table with unbreakable db5' do
1095
+ input = <<-EOS
1096
+ .Table with unbreakable
1097
+ [options="unbreakable"]
1098
+ |===
1099
+ |Item |Quantity
1100
+ |Item 1 |1
1101
+ |===
1102
+ EOS
1103
+ output = render_embedded_string input, :backend => 'docbook5'
1104
+ assert output.include?('<?dbfo keep-together="always"?>')
1105
+ end
1106
+
1107
+ test 'table with unbreakable db45' do
1108
+ input = <<-EOS
1109
+ .Table with unbreakable
1110
+ [options="unbreakable"]
1111
+ |===
1112
+ |Item |Quantity
1113
+ |Item 1 |1
1114
+ |===
1115
+ EOS
1116
+ output = render_embedded_string input, :backend => 'docbook45'
1117
+ assert output.include?('<?dbfo keep-together="always"?>')
1118
+ end
963
1119
  end
964
1120
  end