asciidoctor 1.5.6.2 → 1.5.7

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +330 -143
  3. data/README-fr.adoc +441 -0
  4. data/README-jp.adoc +418 -0
  5. data/README-zh_CN.adoc +430 -0
  6. data/README.adoc +454 -0
  7. data/Rakefile +57 -0
  8. data/asciidoctor.gemspec +7 -1
  9. data/data/locale/attributes-ar.adoc +22 -0
  10. data/data/locale/attributes-bg.adoc +22 -0
  11. data/data/locale/attributes-ca.adoc +22 -0
  12. data/data/locale/attributes-cs.adoc +22 -0
  13. data/data/locale/attributes-da.adoc +22 -0
  14. data/data/locale/attributes-de.adoc +22 -0
  15. data/data/locale/attributes-en.adoc +23 -0
  16. data/data/locale/attributes-es.adoc +22 -0
  17. data/data/locale/attributes-fa.adoc +22 -0
  18. data/data/locale/attributes-fi.adoc +22 -0
  19. data/data/locale/attributes-fr.adoc +22 -0
  20. data/data/locale/attributes-hu.adoc +22 -0
  21. data/data/locale/attributes-id.adoc +22 -0
  22. data/data/locale/attributes-it.adoc +22 -0
  23. data/data/locale/attributes-ja.adoc +22 -0
  24. data/data/locale/attributes-kr.adoc +22 -0
  25. data/data/locale/attributes-nb.adoc +22 -0
  26. data/data/locale/attributes-nl.adoc +22 -0
  27. data/data/locale/attributes-nn.adoc +22 -0
  28. data/data/locale/attributes-pl.adoc +22 -0
  29. data/data/locale/attributes-pt.adoc +22 -0
  30. data/data/locale/attributes-pt_BR.adoc +22 -0
  31. data/data/locale/attributes-ro.adoc +22 -0
  32. data/data/locale/attributes-ru.adoc +22 -0
  33. data/data/locale/attributes-sr.adoc +22 -0
  34. data/data/locale/attributes-sr_Latn.adoc +22 -0
  35. data/data/locale/attributes-tr.adoc +22 -0
  36. data/data/locale/attributes-uk.adoc +22 -0
  37. data/data/locale/attributes-zh_CN.adoc +22 -0
  38. data/data/locale/attributes-zh_TW.adoc +22 -0
  39. data/data/locale/attributes.adoc +8 -649
  40. data/data/stylesheets/asciidoctor-default.css +77 -72
  41. data/features/xref.feature +366 -7
  42. data/lib/asciidoctor.rb +107 -93
  43. data/lib/asciidoctor/abstract_block.rb +247 -239
  44. data/lib/asciidoctor/abstract_node.rb +56 -58
  45. data/lib/asciidoctor/block.rb +3 -3
  46. data/lib/asciidoctor/callouts.rb +1 -1
  47. data/lib/asciidoctor/cli/invoker.rb +36 -9
  48. data/lib/asciidoctor/cli/options.rb +63 -25
  49. data/lib/asciidoctor/converter.rb +23 -13
  50. data/lib/asciidoctor/converter/base.rb +4 -0
  51. data/lib/asciidoctor/converter/docbook45.rb +16 -9
  52. data/lib/asciidoctor/converter/docbook5.rb +115 -97
  53. data/lib/asciidoctor/converter/factory.rb +29 -31
  54. data/lib/asciidoctor/converter/html5.rb +229 -192
  55. data/lib/asciidoctor/converter/manpage.rb +72 -50
  56. data/lib/asciidoctor/converter/template.rb +12 -12
  57. data/lib/asciidoctor/core_ext.rb +5 -1
  58. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +6 -0
  59. data/lib/asciidoctor/document.rb +168 -77
  60. data/lib/asciidoctor/extensions.rb +79 -47
  61. data/lib/asciidoctor/helpers.rb +33 -11
  62. data/lib/asciidoctor/inline.rb +3 -2
  63. data/lib/asciidoctor/list.rb +2 -1
  64. data/lib/asciidoctor/logging.rb +122 -0
  65. data/lib/asciidoctor/parser.rb +406 -382
  66. data/lib/asciidoctor/path_resolver.rb +169 -162
  67. data/lib/asciidoctor/reader.rb +166 -121
  68. data/lib/asciidoctor/section.rb +45 -28
  69. data/lib/asciidoctor/stylesheets.rb +13 -5
  70. data/lib/asciidoctor/substitutors.rb +328 -254
  71. data/lib/asciidoctor/table.rb +105 -48
  72. data/lib/asciidoctor/timings.rb +34 -6
  73. data/lib/asciidoctor/version.rb +1 -1
  74. data/man/asciidoctor.1 +41 -23
  75. data/man/asciidoctor.adoc +14 -8
  76. data/test/api_test.rb +1004 -0
  77. data/test/attributes_test.rb +241 -50
  78. data/test/blocks_test.rb +549 -124
  79. data/test/converter_test.rb +170 -78
  80. data/test/document_test.rb +208 -767
  81. data/test/extensions_test.rb +188 -53
  82. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +1 -1
  83. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +1 -1
  84. data/test/fixtures/file-with-missing-include.adoc +1 -0
  85. data/test/fixtures/include-file.jsx +8 -0
  86. data/test/fixtures/lists.adoc +96 -0
  87. data/test/fixtures/other-chapters.adoc +11 -0
  88. data/test/fixtures/outer-include.adoc +5 -0
  89. data/test/fixtures/sample.asciidoc +5 -1
  90. data/test/fixtures/subdir/index.adoc +3 -0
  91. data/test/fixtures/subdir/inner-include.adoc +3 -0
  92. data/test/fixtures/subdir/middle-include.adoc +5 -0
  93. data/test/fixtures/tagged-class-enclosed.rb +0 -1
  94. data/test/fixtures/unclosed-tag.adoc +3 -0
  95. data/test/fixtures/unexpected-end-tag.adoc +4 -0
  96. data/test/invoker_test.rb +101 -40
  97. data/test/links_test.rb +266 -72
  98. data/test/lists_test.rb +243 -45
  99. data/test/logger_test.rb +211 -0
  100. data/test/manpage_test.rb +124 -6
  101. data/test/options_test.rb +46 -1
  102. data/test/paragraphs_test.rb +23 -10
  103. data/test/parser_test.rb +30 -1
  104. data/test/paths_test.rb +115 -33
  105. data/test/preamble_test.rb +1 -1
  106. data/test/reader_test.rb +337 -81
  107. data/test/sections_test.rb +656 -72
  108. data/test/substitutions_test.rb +182 -57
  109. data/test/tables_test.rb +324 -57
  110. data/test/test_helper.rb +77 -32
  111. data/test/text_test.rb +7 -7
  112. metadata +67 -3
@@ -11,12 +11,12 @@ context 'Sections' do
11
11
  assert_equal '_section_one', sec.id
12
12
  end
13
13
 
14
- test 'synthetic id replaces non-word characters with underscores' do
15
- sec = block_from_string("== We're back!")
16
- assert_equal '_we_re_back', sec.id
14
+ test 'synthetic id removes non-word characters' do
15
+ sec = block_from_string("== Were back!")
16
+ assert_equal '_were_back', sec.id
17
17
  end
18
18
 
19
- test 'synthetic id removes repeating underscores' do
19
+ test 'synthetic id removes repeating separators' do
20
20
  sec = block_from_string('== Section $ One')
21
21
  assert_equal '_section_one', sec.id
22
22
  end
@@ -31,6 +31,26 @@ context 'Sections' do
31
31
  assert_equal '_a_b', sec.id
32
32
  end
33
33
 
34
+ test 'synthetic id removes XML tags' do
35
+ sec = block_from_string('== Use the `run` command to make it icon:gear[]')
36
+ assert_equal '_use_the_run_command_to_make_it_gear', sec.id
37
+ end
38
+
39
+ test 'synthetic id collapses repeating spaces' do
40
+ sec = block_from_string('== Go Far')
41
+ assert_equal '_go_far', sec.id
42
+ end
43
+
44
+ test 'synthetic id replaces hyphens with separator' do
45
+ sec = block_from_string('== State-of-the-art design')
46
+ assert_equal '_state_of_the_art_design', sec.id
47
+ end
48
+
49
+ test 'synthetic id replaces dots with separator' do
50
+ sec = block_from_string("== Section 1.1.1")
51
+ assert_equal '_section_1_1_1', sec.id
52
+ end
53
+
34
54
  test 'synthetic id prefix can be customized' do
35
55
  sec = block_from_string(":idprefix: id_\n\n== Section One")
36
56
  assert_equal 'id_section_one', sec.id
@@ -42,7 +62,7 @@ context 'Sections' do
42
62
  end
43
63
 
44
64
  test 'synthetic id prefix is stripped from beginning of id if set to blank' do
45
- sec = block_from_string(":idprefix:\n\n== & More")
65
+ sec = block_from_string(":idprefix:\n\n== & ! More")
46
66
  assert_equal 'more', sec.id
47
67
  end
48
68
 
@@ -51,6 +71,26 @@ context 'Sections' do
51
71
  assert_equal '_section-one', sec.id
52
72
  end
53
73
 
74
+ test 'synthetic id separator can be hyphen and hyphens are preserved' do
75
+ sec = block_from_string(":idseparator: -\n\n== State-of-the-art design")
76
+ assert_equal '_state-of-the-art-design', sec.id
77
+ end
78
+
79
+ test 'synthetic id separator can be dot and dots are preserved' do
80
+ sec = block_from_string(":idseparator: .\n\n== Version 5.0.1")
81
+ assert_equal '_version.5.0.1', sec.id
82
+ end
83
+
84
+ test 'synthetic id separator can only be one character' do
85
+ input = <<-EOS
86
+ :idseparator: -=-
87
+
88
+ == This Section Is All You Need
89
+ EOS
90
+ sec = block_from_string input
91
+ assert_equal '_this-section-is-all-you-need', sec.id
92
+ end
93
+
54
94
  test 'synthetic id separator can be set to blank' do
55
95
  sec = block_from_string(":idseparator:\n\n== Section One")
56
96
  assert_equal '_sectionone', sec.id
@@ -76,6 +116,26 @@ context 'Sections' do
76
116
  assert_equal 'one', sec.id
77
117
  end
78
118
 
119
+ test 'explicit id in block attributes above section title overrides synthetic id' do
120
+ sec = block_from_string("[id=one]\n== Section One")
121
+ assert_equal 'one', sec.id
122
+ end
123
+
124
+ test 'explicit id set using shorthand in style above section title overrides synthetic id' do
125
+ sec = block_from_string("[#one]\n== Section One")
126
+ assert_equal 'one', sec.id
127
+ end
128
+
129
+ test 'should use explicit id from last block attribute line above section title that defines an explicit id' do
130
+ input = <<-EOS
131
+ [#un]
132
+ [#one]
133
+ == Section One
134
+ EOS
135
+ sec = block_from_string input
136
+ assert_equal 'one', sec.id
137
+ end
138
+
79
139
  test 'explicit id can be defined using an embedded anchor' do
80
140
  sec = block_from_string("== Section One [[one]] ==")
81
141
  assert_equal 'one', sec.id
@@ -120,6 +180,12 @@ Section Title [[refid,reftext]]
120
180
  assert_equal 'Section One [[one]]', sec.title
121
181
  end
122
182
 
183
+ test 'should not process inline anchor in section title if section has explicit ID' do
184
+ sec = block_from_string(%([#sect-one]\n== Section One [[one]]))
185
+ assert_equal 'sect-one', sec.id
186
+ assert_equal 'Section One <a id="one"></a>', sec.title
187
+ end
188
+
123
189
  test 'title substitutions are applied before generating id' do
124
190
  sec = block_from_string("== Section{sp}One\n")
125
191
  assert_equal '_section_one', sec.id
@@ -219,11 +285,13 @@ content
219
285
  content
220
286
  EOS
221
287
 
222
- doc, warnings = redirect_streams {|_, err| [(document_from_string input), err.string]}
223
- reftext = doc.catalog[:ids]['install']
224
- refute_nil reftext
225
- assert_equal 'First Install', reftext
226
- assert_includes warnings, 'line 7: id assigned to section already in use: install'
288
+ using_memory_logger do |logger|
289
+ doc = document_from_string input
290
+ reftext = doc.catalog[:ids]['install']
291
+ refute_nil reftext
292
+ assert_equal 'First Install', reftext
293
+ assert_message logger, :WARN, '<stdin>: line 7: id assigned to section already in use: install', Hash
294
+ end
227
295
  end
228
296
 
229
297
  test 'duplicate block id should not overwrite existing section id entry in references table' do
@@ -237,11 +305,13 @@ content
237
305
  content
238
306
  EOS
239
307
 
240
- doc, warnings = redirect_streams {|_, err| [(document_from_string input), err.string] }
241
- reftext = doc.catalog[:ids]['install']
242
- refute_nil reftext
243
- assert_equal 'First Install', reftext
244
- assert_includes warnings, 'line 7: id assigned to block already in use: install'
308
+ using_memory_logger do |logger|
309
+ doc = document_from_string input
310
+ reftext = doc.catalog[:ids]['install']
311
+ refute_nil reftext
312
+ assert_equal 'First Install', reftext
313
+ assert_message logger, :WARN, '<stdin>: line 7: id assigned to block already in use: install', Hash
314
+ end
245
315
  end
246
316
  end
247
317
 
@@ -284,21 +354,39 @@ preamble
284
354
  test "not enough chars for a multiline document title" do
285
355
  title = "My Title"
286
356
  chars = "=" * (title.length - 2)
287
- assert_xpath '//h1', render_string(title + "\n" + chars), 0
288
- assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
357
+ using_memory_logger do |logger|
358
+ output = render_string(title + "\n" + chars)
359
+ assert_xpath '//h1', output, 0
360
+ refute logger.empty?
361
+ logger.clear
362
+ output = render_string(title + "\n" + chars + "\n")
363
+ assert_xpath '//h1', output, 0
364
+ refute logger.empty?
365
+ end
289
366
  end
290
367
 
291
368
  test "too many chars for a multiline document title" do
292
369
  title = "My Title"
293
370
  chars = "=" * (title.length + 2)
294
- assert_xpath '//h1', render_string(title + "\n" + chars), 0
295
- assert_xpath '//h1', render_string(title + "\n" + chars + "\n"), 0
371
+ using_memory_logger do |logger|
372
+ output = render_string(title + "\n" + chars)
373
+ assert_xpath '//h1', output, 0
374
+ refute logger.empty?
375
+ logger.clear
376
+ output = render_string(title + "\n" + chars + "\n")
377
+ assert_xpath '//h1', output, 0
378
+ refute logger.empty?
379
+ end
296
380
  end
297
381
 
298
382
  test "document title with multiline syntax cannot begin with a dot" do
299
383
  title = ".My Title"
300
384
  chars = "=" * title.length
301
- assert_xpath '//h1', render_string(title + "\n" + chars), 0
385
+ using_memory_logger do |logger|
386
+ output = render_string(title + "\n" + chars)
387
+ assert_xpath '//h1', output, 0
388
+ refute logger.empty?
389
+ end
302
390
  end
303
391
 
304
392
  test "document title with atx syntax" do
@@ -339,7 +427,7 @@ content
339
427
  assert_css 'body#idname', output, 1
340
428
  end
341
429
 
342
- test 'should use inline id instead of id defined in block attributes' do
430
+ test 'should use ID defined in block attributes instead of ID defined inline' do
343
431
  input = <<-EOS
344
432
  [#idname-block]
345
433
  = Document Title [[idname-inline]]
@@ -347,7 +435,7 @@ content
347
435
  content
348
436
  EOS
349
437
  output = render_string input
350
- assert_css 'body#idname-inline', output, 1
438
+ assert_css 'body#idname-block', output, 1
351
439
  end
352
440
 
353
441
  test 'block id above document title sets id on document' do
@@ -361,10 +449,23 @@ preamble
361
449
  doc = document_from_string input
362
450
  assert_equal 'reference', doc.id
363
451
  assert_equal 'refguide', doc.attr('css-signature')
364
- output = doc.render
452
+ output = doc.convert
365
453
  assert_css 'body#reference', output, 1
366
454
  end
367
455
 
456
+ test 'should register document in catalog if id is set' do
457
+ input = <<-EOS
458
+ [[manual,Manual]]
459
+ = Reference Manual
460
+
461
+ preamble
462
+ EOS
463
+ doc = document_from_string input
464
+ assert_equal 'manual', doc.id
465
+ assert_equal 'Manual', doc.attributes['reftext']
466
+ assert_equal doc, doc.catalog[:refs]['manual']
467
+ end
468
+
368
469
  test 'should discard style, role and options shorthand attributes defined on document title' do
369
470
  input = <<-EOS
370
471
  [style#idname.rolename%optionname]
@@ -375,8 +476,10 @@ content
375
476
  doc = document_from_string input
376
477
  assert_empty doc.blocks[0].attributes
377
478
  output = doc.convert
479
+ assert_css '#idname', output, 1
378
480
  assert_css 'body#idname', output, 1
379
- assert_css '.rolename', output, 0
481
+ assert_css '.rolename', output, 1
482
+ assert_css 'body.rolename', output, 1
380
483
  end
381
484
  end
382
485
 
@@ -410,7 +513,11 @@ endif::[]
410
513
  test "heading title with multiline syntax cannot begin with a dot" do
411
514
  title = ".My Title"
412
515
  chars = "-" * title.length
413
- assert_xpath '//h2', render_string(title + "\n" + chars), 0
516
+ using_memory_logger do |logger|
517
+ output = render_string(title + "\n" + chars)
518
+ assert_xpath '//h2', output, 0
519
+ refute logger.empty?
520
+ end
414
521
  end
415
522
 
416
523
  test "with atx syntax" do
@@ -426,11 +533,11 @@ endif::[]
426
533
  end
427
534
 
428
535
  test "with XML entity" do
429
- assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where#{decode_char 8217}s the love?\"]", render_string("== Where's the love?")
536
+ assert_xpath "//h2[@id='_whats_new'][text() = \"What#{decode_char 8217}s new?\"]", render_string("== What's new?")
430
537
  end
431
538
 
432
539
  test "with non-word character" do
433
- assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where’s the love?\"]", render_string("== Where’s the love?")
540
+ assert_xpath "//h2[@id='_whats_new'][text() = \"What’s new?\"]", render_string("== What’s new?")
434
541
  end
435
542
 
436
543
  test "with sequential non-word characters" do
@@ -523,6 +630,191 @@ content
523
630
  end
524
631
  end
525
632
 
633
+ context 'Nesting' do
634
+ test 'should warn if section title is out of sequence' do
635
+ input = <<-EOS
636
+ = Document Title
637
+
638
+ == Section A
639
+
640
+ ==== Nested Section
641
+
642
+ content
643
+
644
+ == Section B
645
+
646
+ content
647
+ EOS
648
+
649
+ using_memory_logger do |logger|
650
+ result = render_embedded_string input
651
+ assert_xpath '//h4[text()="Nested Section"]', result, 1
652
+ assert_message logger, :WARN, '<stdin>: line 5: section title out of sequence: expected level 2, got level 3', Hash
653
+ end
654
+ end
655
+
656
+ test 'should warn if chapter title is out of sequence' do
657
+ input = <<-EOS
658
+ = Document Title
659
+ :doctype: book
660
+
661
+ === Not a Chapter
662
+
663
+ content
664
+ EOS
665
+
666
+ using_memory_logger do |logger|
667
+ result = render_embedded_string input
668
+ assert_xpath '//h3[text()="Not a Chapter"]', result, 1
669
+ assert_message logger, :WARN, '<stdin>: line 4: section title out of sequence: expected levels 0 or 1, got level 2', Hash
670
+ end
671
+ end
672
+
673
+ test 'should not warn if top-level section title is out of sequence when fragment attribute is set on document' do
674
+ input = <<-EOS
675
+ = Document Title
676
+
677
+ === First Section
678
+
679
+ content
680
+ EOS
681
+
682
+ using_memory_logger do |logger|
683
+ render_embedded_string input, :attributes => { 'fragment' => '' }
684
+ assert logger.empty?
685
+ end
686
+ end
687
+
688
+ test 'should warn if nested section title is out of sequence when fragment attribute is set on document' do
689
+ input = <<-EOS
690
+ = Document Title
691
+
692
+ === First Section
693
+
694
+ ===== Nested Section
695
+ EOS
696
+
697
+ using_memory_logger do |logger|
698
+ render_embedded_string input, :attributes => { 'fragment' => '' }
699
+ assert_message logger, :WARN, '<stdin>: line 5: section title out of sequence: expected level 3, got level 4', Hash
700
+ end
701
+ end
702
+ test 'should log error if subsections are found in special sections in article that do not support subsections' do
703
+ input = <<-EOS
704
+ = Document Title
705
+
706
+ == Section
707
+
708
+ === Subsection of Section
709
+
710
+ allowed
711
+
712
+ [appendix]
713
+ == Appendix
714
+
715
+ === Subsection of Appendix
716
+
717
+ allowed
718
+
719
+ [glossary]
720
+ == Glossary
721
+
722
+ === Subsection of Glossary
723
+
724
+ not allowed
725
+
726
+ [bibliography]
727
+ == Bibliography
728
+
729
+ === Subsection of Bibliography
730
+
731
+ not allowed
732
+ EOS
733
+
734
+ using_memory_logger do |logger|
735
+ render_embedded_string input
736
+ assert_messages logger, [
737
+ [:ERROR, '<stdin>: line 19: glossary sections do not support nested sections', Hash],
738
+ [:ERROR, '<stdin>: line 26: bibliography sections do not support nested sections', Hash],
739
+ ]
740
+ end
741
+ end
742
+
743
+ test 'should log error if subsections are found in special sections in book that do not support subsections' do
744
+ input = <<-EOS
745
+ = Document Title
746
+ :doctype: book
747
+
748
+ [preface]
749
+ = Preface
750
+
751
+ === Subsection of Preface
752
+
753
+ allowed
754
+
755
+ [colophon]
756
+ = Colophon
757
+
758
+ === Subsection of Colophon
759
+
760
+ not allowed
761
+
762
+ [dedication]
763
+ = Dedication
764
+
765
+ === Subsection of Dedication
766
+
767
+ not allowed
768
+
769
+ = Part 1
770
+
771
+ [abstract]
772
+ == Abstract
773
+
774
+ === Subsection of Abstract
775
+
776
+ allowed
777
+
778
+ == Chapter 1
779
+
780
+ === Subsection of Chapter
781
+
782
+ allowed
783
+
784
+ [appendix]
785
+ = Appendix
786
+
787
+ === Subsection of Appendix
788
+
789
+ allowed
790
+
791
+ [glossary]
792
+ = Glossary
793
+
794
+ === Subsection of Glossary
795
+
796
+ not allowed
797
+
798
+ [bibliography]
799
+ = Bibliography
800
+
801
+ === Subsection of Bibliography
802
+
803
+ not allowed
804
+ EOS
805
+
806
+ using_memory_logger do |logger|
807
+ render_embedded_string input
808
+ assert_messages logger, [
809
+ [:ERROR, '<stdin>: line 14: colophon sections do not support nested sections', Hash],
810
+ [:ERROR, '<stdin>: line 21: dedication sections do not support nested sections', Hash],
811
+ [:ERROR, '<stdin>: line 50: glossary sections do not support nested sections', Hash],
812
+ [:ERROR, '<stdin>: line 57: bibliography sections do not support nested sections', Hash]
813
+ ]
814
+ end
815
+ end
816
+ end
817
+
526
818
  context 'Markdown-style headings' do
527
819
  test 'atx document title with leading marker' do
528
820
  input = <<-EOS
@@ -664,7 +956,7 @@ not in section
664
956
 
665
957
  doc = document_from_string input
666
958
  heading = doc.blocks.first
667
- assert heading.is_a?(Asciidoctor::Block)
959
+ assert_kind_of Asciidoctor::Block, heading
668
960
  assert_equal :floating_title, heading.context
669
961
  assert_equal '_independent_heading', heading.id
670
962
  assert doc.catalog[:ids].has_key?('_independent_heading')
@@ -801,6 +1093,19 @@ content
801
1093
  refute_nil reftext
802
1094
  assert_equal 'Install Procedure', reftext
803
1095
  end
1096
+
1097
+ test 'should not process inline anchor in discrete heading if explicit ID is assigned' do
1098
+ input = <<-EOS
1099
+ [discrete#install]
1100
+ == Install [[installation]]
1101
+
1102
+ content
1103
+ EOS
1104
+
1105
+ block = block_from_string input
1106
+ assert_equal block.id, 'install'
1107
+ assert_equal 'Install <a id="installation"></a>', block.title
1108
+ end
804
1109
  end
805
1110
 
806
1111
  context 'Level offset' do
@@ -820,14 +1125,10 @@ text in standalone
820
1125
  // end simulated include::[]
821
1126
  EOS
822
1127
 
823
- warnings = nil
824
- redirect_streams do |out, err|
1128
+ using_memory_logger do |logger|
825
1129
  render_string input
826
- warnings = err.string
1130
+ assert_message logger, :ERROR, '<stdin>: line 7: level 0 sections can only be used when doctype is book', Hash
827
1131
  end
828
-
829
- refute_empty warnings
830
- assert_match(/only book doctypes can contain level 0 sections/, warnings)
831
1132
  end
832
1133
 
833
1134
  test 'should add level offset to section level' do
@@ -857,13 +1158,12 @@ Standalone section text.
857
1158
  Master section text.
858
1159
  EOS
859
1160
 
860
- output = warnings = nil
861
- redirect_streams do |out, err|
1161
+ output = nil
1162
+ using_memory_logger do |logger|
862
1163
  output = render_string input
863
- warnings = err.string
1164
+ assert logger.empty?
864
1165
  end
865
1166
 
866
- assert_empty warnings
867
1167
  assert_match(/Master document written by Doc Writer/, output)
868
1168
  assert_match(/Standalone document written by Junior Writer/, output)
869
1169
  assert_xpath '//*[@class="sect1"]/h2[text() = "Standalone Document"]', output, 1
@@ -937,40 +1237,50 @@ content
937
1237
 
938
1238
  context 'Section Numbering' do
939
1239
  test 'should create section number with one entry for level 1' do
940
- sect1 = Asciidoctor::Section.new
1240
+ doc = empty_document
1241
+ sect1 = Asciidoctor::Section.new nil, nil, true
1242
+ doc << sect1
941
1243
  assert_equal '1.', sect1.sectnum
942
1244
  end
943
1245
 
944
1246
  test 'should create section number with two entries for level 2' do
945
- sect1 = Asciidoctor::Section.new
946
- sect1_1 = Asciidoctor::Section.new(sect1)
1247
+ doc = empty_document
1248
+ sect1 = Asciidoctor::Section.new nil, nil, true
1249
+ doc << sect1
1250
+ sect1_1 = Asciidoctor::Section.new sect1, nil, true
947
1251
  sect1 << sect1_1
948
1252
  assert_equal '1.1.', sect1_1.sectnum
949
1253
  end
950
1254
 
951
1255
  test 'should create section number with three entries for level 3' do
952
- sect1 = Asciidoctor::Section.new
953
- sect1_1 = Asciidoctor::Section.new(sect1)
1256
+ doc = empty_document
1257
+ sect1 = Asciidoctor::Section.new nil, nil, true
1258
+ doc << sect1
1259
+ sect1_1 = Asciidoctor::Section.new sect1, nil, true
954
1260
  sect1 << sect1_1
955
- sect1_1_1 = Asciidoctor::Section.new(sect1_1)
1261
+ sect1_1_1 = Asciidoctor::Section.new sect1_1, nil, true
956
1262
  sect1_1 << sect1_1_1
957
1263
  assert_equal '1.1.1.', sect1_1_1.sectnum
958
1264
  end
959
1265
 
960
1266
  test 'should create section number for second section in level' do
961
- sect1 = Asciidoctor::Section.new
962
- sect1_1 = Asciidoctor::Section.new(sect1)
1267
+ doc = empty_document
1268
+ sect1 = Asciidoctor::Section.new nil, nil, true
1269
+ doc << sect1
1270
+ sect1_1 = Asciidoctor::Section.new sect1, nil, true
963
1271
  sect1 << sect1_1
964
- sect1_2 = Asciidoctor::Section.new(sect1)
1272
+ sect1_2 = Asciidoctor::Section.new sect1, nil, true
965
1273
  sect1 << sect1_2
966
1274
  assert_equal '1.2.', sect1_2.sectnum
967
1275
  end
968
1276
 
969
1277
  test 'sectnum should use specified delimiter and append string' do
970
- sect1 = Asciidoctor::Section.new
971
- sect1_1 = Asciidoctor::Section.new(sect1)
1278
+ doc = empty_document
1279
+ sect1 = Asciidoctor::Section.new nil, nil, true
1280
+ doc << sect1
1281
+ sect1_1 = Asciidoctor::Section.new sect1, nil, true
972
1282
  sect1 << sect1_1
973
- sect1_1_1 = Asciidoctor::Section.new(sect1_1)
1283
+ sect1_1_1 = Asciidoctor::Section.new sect1_1, nil, true
974
1284
  sect1_1 << sect1_1_1
975
1285
  assert_equal '1,1,1,', sect1_1_1.sectnum(',')
976
1286
  assert_equal '1:1:1', sect1_1_1.sectnum(':', false)
@@ -1054,6 +1364,31 @@ text
1054
1364
  assert_xpath '//h3[@id="_section_2_2"][starts-with(text(), "2.2. ")]', output, 1
1055
1365
  end
1056
1366
 
1367
+ test 'should number parts when doctype is book and partnums attributes is set' do
1368
+ input = <<-EOS
1369
+ = Book Title
1370
+ :doctype: book
1371
+ :sectnums:
1372
+ :partnums:
1373
+
1374
+ = Language
1375
+
1376
+ == Syntax
1377
+
1378
+ content
1379
+
1380
+ = Processor
1381
+
1382
+ == CLI
1383
+
1384
+ content
1385
+ EOS
1386
+
1387
+ output = render_string input
1388
+ assert_xpath '//h1[@id="_language"][text() = "I. Language"]', output, 1
1389
+ assert_xpath '//h1[@id="_processor"][text() = "II. Processor"]', output, 1
1390
+ end
1391
+
1057
1392
  test 'blocks should have level' do
1058
1393
  input = <<-EOS
1059
1394
  = Title
@@ -1313,7 +1648,7 @@ content
1313
1648
  EOS
1314
1649
 
1315
1650
  doc = document_from_string input
1316
- second_section = Asciidoctor::Section.new doc
1651
+ second_section = Asciidoctor::Section.new doc, nil, true
1317
1652
  doc.blocks.insert 1, second_section
1318
1653
  doc.reindex_sections
1319
1654
  sections = doc.sections
@@ -1345,6 +1680,26 @@ Linux installation instructions.
1345
1680
  assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a/following-sibling::text()="Linux"', output, true
1346
1681
  end
1347
1682
 
1683
+ test 'should position after title text if sectanchors is set to after' do
1684
+ input = <<-EOS
1685
+ == Installation
1686
+
1687
+ Installation section.
1688
+
1689
+ === Linux
1690
+
1691
+ Linux installation instructions.
1692
+ EOS
1693
+
1694
+ output = render_embedded_string input, :attributes => {'sectanchors' => 'after'}
1695
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a', output, 1
1696
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a[@class="anchor"][@href="#_installation"]', output, 1
1697
+ assert_xpath '/*[@class="sect1"]/h2[@id="_installation"]/a/preceding-sibling::text()="Installation"', output, true
1698
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a', output, 1
1699
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a[@class="anchor"][@href="#_linux"]', output, 1
1700
+ assert_xpath '//*[@class="sect2"]/h3[@id="_linux"]/a/preceding-sibling::text()="Linux"', output, true
1701
+ end
1702
+
1348
1703
  test 'should link section if sectlinks document attribute is set' do
1349
1704
  input = <<-EOS
1350
1705
  == Installation
@@ -1394,6 +1749,32 @@ Details
1394
1749
  assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
1395
1750
  end
1396
1751
 
1752
+ test 'should use style from last block attribute line above section that defines a style' do
1753
+ input = <<-EOS
1754
+ [glossary]
1755
+ [appendix]
1756
+ == Attribute Options
1757
+
1758
+ Details
1759
+ EOS
1760
+
1761
+ output = render_embedded_string input
1762
+ assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
1763
+ end
1764
+
1765
+ test 'setting ID using style shorthand should not clear section style' do
1766
+ input = <<-EOS
1767
+ [appendix]
1768
+ [#attribute-options]
1769
+ == Attribute Options
1770
+
1771
+ Details
1772
+ EOS
1773
+
1774
+ output = render_embedded_string input
1775
+ assert_xpath '//h2[@id="attribute-options"][text()="Appendix A: Attribute Options"]', output, 1
1776
+ end
1777
+
1397
1778
  test 'should use custom appendix caption if specified' do
1398
1779
  input = <<-EOS
1399
1780
  :appendix-caption: App
@@ -1624,17 +2005,20 @@ Terms
1624
2005
 
1625
2006
  test 'should not number special sections or their subsections by default except for appendices' do
1626
2007
  input = <<-EOS
2008
+ :doctype: book
1627
2009
  :sectnums:
1628
2010
 
1629
- [dedication]
1630
- == Dedication
2011
+ [preface]
2012
+ == Preface
1631
2013
 
1632
- === Dedication Subsection
2014
+ === Preface Subsection
1633
2015
 
1634
2016
  content
1635
2017
 
1636
2018
  == Section One
1637
2019
 
2020
+ content
2021
+
1638
2022
  [appendix]
1639
2023
  == Attribute Options
1640
2024
 
@@ -1656,8 +2040,8 @@ Terms
1656
2040
  EOS
1657
2041
 
1658
2042
  output = render_embedded_string input
1659
- assert_xpath '(//h2)[1][text()="Dedication"]', output, 1
1660
- assert_xpath '(//h3)[1][text()="Dedication Subsection"]', output, 1
2043
+ assert_xpath '(//h2)[1][text()="Preface"]', output, 1
2044
+ assert_xpath '(//h3)[1][text()="Preface Subsection"]', output, 1
1661
2045
  assert_xpath '(//h2)[2][text()="1. Section One"]', output, 1
1662
2046
  assert_xpath '(//h2)[3][text()="Appendix A: Attribute Options"]', output, 1
1663
2047
  assert_xpath '(//h2)[4][text()="Appendix B: Migration"]', output, 1
@@ -1667,18 +2051,21 @@ Terms
1667
2051
 
1668
2052
  test 'should not number special sections or their subsections in toc by default except for appendices' do
1669
2053
  input = <<-EOS
2054
+ :doctype: book
1670
2055
  :sectnums:
1671
2056
  :toc:
1672
2057
 
1673
- [dedication]
1674
- == Dedication
2058
+ [preface]
2059
+ == Preface
1675
2060
 
1676
- === Dedication Subsection
2061
+ === Preface Subsection
1677
2062
 
1678
2063
  content
1679
2064
 
1680
2065
  == Section One
1681
2066
 
2067
+ content
2068
+
1682
2069
  [appendix]
1683
2070
  == Attribute Options
1684
2071
 
@@ -1700,8 +2087,8 @@ Terms
1700
2087
  EOS
1701
2088
 
1702
2089
  output = render_string input
1703
- assert_xpath '//*[@id="toc"]/ul//li/a[text()="Dedication"]', output, 1
1704
- assert_xpath '//*[@id="toc"]/ul//li/a[text()="Dedication Subsection"]', output, 1
2090
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="Preface"]', output, 1
2091
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="Preface Subsection"]', output, 1
1705
2092
  assert_xpath '//*[@id="toc"]/ul//li/a[text()="1. Section One"]', output, 1
1706
2093
  assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix A: Attribute Options"]', output, 1
1707
2094
  assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix B: Migration"]', output, 1
@@ -1709,6 +2096,99 @@ Terms
1709
2096
  assert_xpath '//*[@id="toc"]/ul//li/a[text()="Glossary"]', output, 1
1710
2097
  end
1711
2098
 
2099
+ test 'should number special sections and their subsections when sectnums is all' do
2100
+ input = <<-EOS
2101
+ :doctype: book
2102
+ :sectnums: all
2103
+
2104
+ [preface]
2105
+ == Preface
2106
+
2107
+ === Preface Subsection
2108
+
2109
+ content
2110
+
2111
+ == Section One
2112
+
2113
+ content
2114
+
2115
+ [appendix]
2116
+ == Attribute Options
2117
+
2118
+ Details
2119
+
2120
+ [appendix]
2121
+ == Migration
2122
+
2123
+ Details
2124
+
2125
+ === Gotchas
2126
+
2127
+ Details
2128
+
2129
+ [glossary]
2130
+ == Glossary
2131
+
2132
+ Terms
2133
+ EOS
2134
+
2135
+ output = render_embedded_string input
2136
+ assert_xpath '(//h2)[1][text()="1. Preface"]', output, 1
2137
+ assert_xpath '(//h3)[1][text()="1.1. Preface Subsection"]', output, 1
2138
+ assert_xpath '(//h2)[2][text()="2. Section One"]', output, 1
2139
+ assert_xpath '(//h2)[3][text()="Appendix A: Attribute Options"]', output, 1
2140
+ assert_xpath '(//h2)[4][text()="Appendix B: Migration"]', output, 1
2141
+ assert_xpath '(//h3)[2][text()="B.1. Gotchas"]', output, 1
2142
+ assert_xpath '(//h2)[5][text()="3. Glossary"]', output, 1
2143
+ end
2144
+
2145
+ test 'should number special sections and their subsections in toc when sectnums is all' do
2146
+ input = <<-EOS
2147
+ :doctype: book
2148
+ :sectnums: all
2149
+ :toc:
2150
+
2151
+ [preface]
2152
+ == Preface
2153
+
2154
+ === Preface Subsection
2155
+
2156
+ content
2157
+
2158
+ == Section One
2159
+
2160
+ content
2161
+
2162
+ [appendix]
2163
+ == Attribute Options
2164
+
2165
+ Details
2166
+
2167
+ [appendix]
2168
+ == Migration
2169
+
2170
+ Details
2171
+
2172
+ === Gotchas
2173
+
2174
+ Details
2175
+
2176
+ [glossary]
2177
+ == Glossary
2178
+
2179
+ Terms
2180
+ EOS
2181
+
2182
+ output = render_string input
2183
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="1. Preface"]', output, 1
2184
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="1.1. Preface Subsection"]', output, 1
2185
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="2. Section One"]', output, 1
2186
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix A: Attribute Options"]', output, 1
2187
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="Appendix B: Migration"]', output, 1
2188
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="B.1. Gotchas"]', output, 1
2189
+ assert_xpath '//*[@id="toc"]/ul//li/a[text()="3. Glossary"]', output, 1
2190
+ end
2191
+
1712
2192
  test 'level 0 special sections in multipart book should be rendered as level 1' do
1713
2193
  input = <<-EOS
1714
2194
  = Multipart Book
@@ -1883,6 +2363,19 @@ The corresponding definition.
1883
2363
  assert_xpath '//glossary/title[text()="Glossary A"]', output, 1
1884
2364
  assert_xpath '//glossary/glossentry', output, 2
1885
2365
  end
2366
+
2367
+ test 'should drop title on special section in DocBook output if untitled option is set' do
2368
+ input = <<-EOS
2369
+ [dedication%untitled]
2370
+ == Dedication
2371
+
2372
+ content
2373
+ EOS
2374
+
2375
+ output = render_embedded_string input, :backend => :docbook
2376
+ assert_xpath '/dedication', output, 1
2377
+ assert_xpath '/dedication/title', output, 0
2378
+ end
1886
2379
  end
1887
2380
 
1888
2381
  context "heading patterns in blocks" do
@@ -2567,6 +3060,61 @@ It only has content.
2567
3060
  assert_css '#toctitle', output, 0
2568
3061
  end
2569
3062
  end
3063
+
3064
+ test 'should drop anchors from contents of entries in table of contents' do
3065
+ input = <<-EOS
3066
+ = Document Title
3067
+ :toc:
3068
+
3069
+ == [[un]]Section One
3070
+
3071
+ content
3072
+
3073
+ == [[two]][[deux]]Section Two
3074
+
3075
+ content
3076
+
3077
+ == Plant Trees by https://ecosia.org[Searching]
3078
+
3079
+ content
3080
+ EOS
3081
+
3082
+ output = render_embedded_string input
3083
+ assert_xpath '/*[@id="toc"]', output, 1
3084
+ toc_links = xmlnodes_at_xpath '/*[@id="toc"]//li', output
3085
+ assert_equal 3, toc_links.size
3086
+ assert_equal '<a href="#_section_one">Section One</a>', toc_links[0].inner_html
3087
+ assert_equal '<a href="#_section_two">Section Two</a>', toc_links[1].inner_html
3088
+ assert_equal '<a href="#_plant_trees_by_searching">Plant Trees by Searching</a>', toc_links[2].inner_html
3089
+ end
3090
+
3091
+ test 'should not remove non-anchor tags from contents of entries in table of contents' do
3092
+ input = <<-EOS
3093
+ = Document Title
3094
+ :toc:
3095
+ :icons: font
3096
+
3097
+ == `run` command
3098
+
3099
+ content
3100
+
3101
+ == icon:bug[] Issues
3102
+
3103
+ content
3104
+
3105
+ == https://ecosia.org[_Sustainable_ Searches]
3106
+
3107
+ content
3108
+ EOS
3109
+
3110
+ output = render_embedded_string input, :safe => :safe
3111
+ assert_xpath '/*[@id="toc"]', output, 1
3112
+ toc_links = xmlnodes_at_xpath '/*[@id="toc"]//li', output
3113
+ assert_equal 3, toc_links.size
3114
+ assert_equal '<a href="#_run_command"><code>run</code> command</a>', toc_links[0].inner_html
3115
+ assert_equal '<a href="#_issues"><span class="icon"><i class="fa fa-bug"></i></span> Issues</a>', toc_links[1].inner_html
3116
+ assert_equal '<a href="#_sustainable_searches"><em>Sustainable</em> Searches</a>', toc_links[2].inner_html
3117
+ end
2570
3118
  end
2571
3119
 
2572
3120
  context 'article doctype' do
@@ -2657,6 +3205,48 @@ That's all she wrote!
2657
3205
  assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1
2658
3206
  end
2659
3207
 
3208
+ test 'should print error if level 0 section comes after nested section and doctype is not book' do
3209
+ input = <<-EOS
3210
+ = Document Title
3211
+
3212
+ == Level 1 Section
3213
+
3214
+ === Level 2 Section
3215
+
3216
+ = Level 0 Section
3217
+ EOS
3218
+
3219
+ using_memory_logger do |logger|
3220
+ render_string input
3221
+ assert_message logger, :ERROR, '<stdin>: line 7: level 0 sections can only be used when doctype is book', Hash
3222
+ end
3223
+ end
3224
+
3225
+ test 'should add class matching role to part' do
3226
+ input = <<-EOS
3227
+ = Book Title
3228
+ :doctype: book
3229
+
3230
+ [.newbie]
3231
+ = Part 1
3232
+
3233
+ == Chapter A
3234
+
3235
+ content
3236
+
3237
+ = Part 2
3238
+
3239
+ == Chapter B
3240
+
3241
+ content
3242
+ EOS
3243
+
3244
+ result = render_embedded_string input
3245
+ assert_css 'h1.sect0', result, 2
3246
+ assert_css 'h1.sect0.newbie', result, 1
3247
+ assert_css 'h1.sect0.newbie#_part_1', result, 1
3248
+ end
3249
+
2660
3250
  test 'should assign appropriate sectname for section type' do
2661
3251
  input = <<-EOS
2662
3252
  = Book Title
@@ -2761,15 +3351,10 @@ more part intro
2761
3351
  intro
2762
3352
  EOS
2763
3353
 
2764
- warnings = nil
2765
- redirect_streams do |out, err|
3354
+ using_memory_logger do |logger|
2766
3355
  document_from_string input
2767
- warnings = err.string
3356
+ assert_message logger, :ERROR, '<stdin>: line 8: invalid part, must have at least one section (e.g., chapter, appendix, etc.)', Hash
2768
3357
  end
2769
-
2770
- refute_nil warnings
2771
- refute_empty warnings
2772
- assert_match(/ERROR:.*section/, warnings)
2773
3358
  end
2774
3359
 
2775
3360
  test 'should create parts and chapters in docbook backend' do
@@ -2850,12 +3435,11 @@ Appendix content
2850
3435
  Appendix subsection content
2851
3436
  EOS
2852
3437
 
2853
- output = warnings = nil
2854
- redirect_streams do |out, err|
3438
+ output = nil
3439
+ using_memory_logger do |logger|
2855
3440
  output = render_string input, :backend => 'docbook'
2856
- warnings = err.string
3441
+ assert logger.empty?
2857
3442
  end
2858
- assert_empty warnings
2859
3443
  assert_xpath '/book/preface', output, 1
2860
3444
  assert_xpath '/book/preface/section', output, 1
2861
3445
  assert_xpath '/book/part', output, 1