asciidoctor 0.1.4 → 1.5.0

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +209 -25
  3. data/{LICENSE → LICENSE.adoc} +4 -3
  4. data/README.adoc +392 -395
  5. data/Rakefile +94 -137
  6. data/benchmark/benchmark.rb +127 -0
  7. data/benchmark/sample-data/mdbasics.adoc +334 -0
  8. data/bin/asciidoctor +5 -8
  9. data/bin/asciidoctor-safe +4 -8
  10. data/compat/asciidoc.conf +78 -11
  11. data/compat/font-awesome-3-compat.css +397 -0
  12. data/data/stylesheets/asciidoctor-default.css +399 -0
  13. data/data/stylesheets/coderay-asciidoctor.css +89 -0
  14. data/features/open_block.feature +92 -0
  15. data/features/pass_block.feature +66 -0
  16. data/features/step_definitions.rb +42 -0
  17. data/features/text_formatting.feature +55 -0
  18. data/features/xref.feature +116 -0
  19. data/lib/asciidoctor.rb +1155 -605
  20. data/lib/asciidoctor/abstract_block.rb +157 -71
  21. data/lib/asciidoctor/abstract_node.rb +150 -93
  22. data/lib/asciidoctor/attribute_list.rb +85 -90
  23. data/lib/asciidoctor/block.rb +51 -24
  24. data/lib/asciidoctor/callouts.rb +4 -7
  25. data/lib/asciidoctor/cli.rb +3 -0
  26. data/lib/asciidoctor/cli/invoker.rb +86 -76
  27. data/lib/asciidoctor/cli/options.rb +111 -61
  28. data/lib/asciidoctor/converter.rb +232 -0
  29. data/lib/asciidoctor/converter/base.rb +58 -0
  30. data/lib/asciidoctor/converter/composite.rb +66 -0
  31. data/lib/asciidoctor/converter/docbook45.rb +94 -0
  32. data/lib/asciidoctor/converter/docbook5.rb +684 -0
  33. data/lib/asciidoctor/converter/factory.rb +225 -0
  34. data/lib/asciidoctor/converter/html5.rb +1081 -0
  35. data/lib/asciidoctor/converter/template.rb +296 -0
  36. data/lib/asciidoctor/core_ext.rb +7 -0
  37. data/lib/asciidoctor/core_ext/object/nil_or_empty.rb +23 -0
  38. data/lib/asciidoctor/core_ext/string/chr.rb +6 -0
  39. data/lib/asciidoctor/core_ext/symbol/length.rb +6 -0
  40. data/lib/asciidoctor/document.rb +590 -304
  41. data/lib/asciidoctor/extensions.rb +1100 -308
  42. data/lib/asciidoctor/helpers.rb +109 -46
  43. data/lib/asciidoctor/inline.rb +16 -9
  44. data/lib/asciidoctor/list.rb +23 -15
  45. data/lib/asciidoctor/opal_ext.rb +4 -0
  46. data/lib/asciidoctor/opal_ext/comparable.rb +38 -0
  47. data/lib/asciidoctor/opal_ext/dir.rb +13 -0
  48. data/lib/asciidoctor/opal_ext/error.rb +2 -0
  49. data/lib/asciidoctor/opal_ext/file.rb +125 -0
  50. data/lib/asciidoctor/{lexer.rb → parser.rb} +646 -455
  51. data/lib/asciidoctor/path_resolver.rb +141 -77
  52. data/lib/asciidoctor/reader.rb +257 -187
  53. data/lib/asciidoctor/section.rb +12 -16
  54. data/lib/asciidoctor/stylesheets.rb +91 -0
  55. data/lib/asciidoctor/substitutors.rb +1548 -0
  56. data/lib/asciidoctor/table.rb +73 -57
  57. data/lib/asciidoctor/timings.rb +39 -0
  58. data/lib/asciidoctor/version.rb +1 -1
  59. data/man/asciidoctor.1 +22 -14
  60. data/man/asciidoctor.adoc +18 -10
  61. data/test/attributes_test.rb +314 -14
  62. data/test/blocks_test.rb +763 -118
  63. data/test/converter_test.rb +352 -0
  64. data/test/document_test.rb +518 -199
  65. data/test/extensions_test.rb +273 -103
  66. data/test/fixtures/asciidoc_index.txt +27 -13
  67. data/test/fixtures/basic-docinfo.xml +1 -1
  68. data/test/fixtures/chapter-a.adoc +3 -0
  69. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
  70. data/test/fixtures/docinfo.xml +1 -1
  71. data/test/fixtures/include-file.asciidoc +2 -0
  72. data/test/fixtures/master.adoc +5 -0
  73. data/test/invoker_test.rb +173 -61
  74. data/test/links_test.rb +97 -21
  75. data/test/lists_test.rb +181 -22
  76. data/test/options_test.rb +86 -2
  77. data/test/paragraphs_test.rb +47 -5
  78. data/test/{lexer_test.rb → parser_test.rb} +128 -57
  79. data/test/paths_test.rb +36 -1
  80. data/test/preamble_test.rb +25 -17
  81. data/test/reader_test.rb +404 -249
  82. data/test/sections_test.rb +623 -58
  83. data/test/substitutions_test.rb +609 -132
  84. data/test/tables_test.rb +198 -24
  85. data/test/test_helper.rb +101 -31
  86. data/test/text_test.rb +88 -31
  87. metadata +160 -64
  88. data/Gemfile +0 -12
  89. data/Guardfile +0 -18
  90. data/asciidoctor.gemspec +0 -143
  91. data/lib/asciidoctor/backends/_stylesheets.rb +0 -466
  92. data/lib/asciidoctor/backends/base_template.rb +0 -114
  93. data/lib/asciidoctor/backends/docbook45.rb +0 -774
  94. data/lib/asciidoctor/backends/docbook5.rb +0 -103
  95. data/lib/asciidoctor/backends/html5.rb +0 -1214
  96. data/lib/asciidoctor/renderer.rb +0 -259
  97. data/lib/asciidoctor/substituters.rb +0 -1083
  98. data/test/fixtures/asciidoc.txt +0 -105
  99. data/test/fixtures/ascshort.txt +0 -32
  100. data/test/fixtures/list_elements.asciidoc +0 -10
  101. data/test/renderer_test.rb +0 -162
@@ -1,5 +1,8 @@
1
1
  # encoding: UTF-8
2
- require 'test_helper'
2
+ unless defined? ASCIIDOCTOR_PROJECT_DIR
3
+ $: << File.dirname(__FILE__); $:.uniq!
4
+ require 'test_helper'
5
+ end
3
6
 
4
7
  context 'Sections' do
5
8
  context 'Ids' do
@@ -19,8 +22,8 @@ context 'Sections' do
19
22
  end
20
23
 
21
24
  test 'synthetic id removes entities' do
22
- sec = block_from_string('== Ben & Jerry &#34;Ice Cream Brothers&#34;')
23
- assert_equal '_ben_jerry_ice_cream_brothers', sec.id
25
+ sec = block_from_string('== Ben & Jerry &amp; Company &#34;Ice Cream Brothers&#34; &#10046;')
26
+ assert_equal '_ben_jerry_company_ice_cream_brothers', sec.id
24
27
  end
25
28
 
26
29
  test 'synthetic id prefix can be customized' do
@@ -58,12 +61,39 @@ context 'Sections' do
58
61
  assert_equal 'one', sec.id
59
62
  end
60
63
 
61
- test 'explicit id can be defined using an inline anchor' do
64
+ test 'explicit id can be defined using an embedded anchor' do
62
65
  sec = block_from_string("== Section One [[one]] ==")
63
66
  assert_equal 'one', sec.id
64
67
  assert_equal 'Section One', sec.title
65
68
  end
66
69
 
70
+ test 'explicit id can be defined using an embedded anchor with reftext' do
71
+ sec = block_from_string("== Section One [[one,Section Uno]] ==")
72
+ assert_equal 'one', sec.id
73
+ assert_equal 'Section One', sec.title
74
+ assert_equal 'Section Uno', (sec.attr 'reftext')
75
+ end
76
+
77
+ test 'id and reftext in embedded anchor cannot be quoted' do
78
+ sec = block_from_string(%(== Section One [["one","Section Uno"]] ==))
79
+ refute_equal 'one', sec.id
80
+ assert_equal 'Section One [["one","Section Uno"]]', sec.title
81
+ assert_nil(sec.attr 'reftext')
82
+ end
83
+
84
+ test 'reftext in embedded anchor may contain comma' do
85
+ sec = block_from_string(%(== Section One [[one, Section,Uno]] ==))
86
+ assert_equal 'one', sec.id
87
+ assert_equal 'Section One', sec.title
88
+ assert_equal 'Section,Uno', (sec.attr 'reftext')
89
+ end
90
+
91
+ test 'should unescape but not process inline anchor' do
92
+ sec = block_from_string(%(== Section One \\[[one]] ==))
93
+ refute_equal 'one', sec.id
94
+ assert_equal 'Section One [[one]]', sec.title
95
+ end
96
+
67
97
  test 'title substitutions are applied before generating id' do
68
98
  sec = block_from_string("== Section{sp}One\n")
69
99
  assert_equal '_section_one', sec.id
@@ -83,6 +113,34 @@ text
83
113
  assert_equal '_some_section', doc.blocks[0].id
84
114
  assert_equal '_some_section_2', doc.blocks[1].id
85
115
  end
116
+
117
+ test 'should use specified id and reftext when registering section reference' do
118
+ input = <<-EOS
119
+ [[install,Install Procedure]]
120
+ == Install
121
+
122
+ content
123
+ EOS
124
+
125
+ doc = document_from_string input
126
+ reftext = doc.references[:ids]['install']
127
+ refute_nil reftext
128
+ assert_equal 'Install Procedure', reftext
129
+ end
130
+
131
+ test 'should use specified reftext when registering section reference' do
132
+ input = <<-EOS
133
+ [reftext="Install Procedure"]
134
+ == Install
135
+
136
+ content
137
+ EOS
138
+
139
+ doc = document_from_string input
140
+ reftext = doc.references[:ids]['_install']
141
+ refute_nil reftext
142
+ assert_equal 'Install Procedure', reftext
143
+ end
86
144
  end
87
145
 
88
146
  context "document title (level 0)" do
@@ -173,9 +231,13 @@ preamble
173
231
  assert_xpath "//h2[@id='_my_title'][text() = 'My Title ===']", render_string("== My Title ===")
174
232
  end
175
233
 
176
- test "with non-word character" do
234
+ test "with XML entity" do
177
235
  assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where#{[8217].pack('U*')}s the love?\"]", render_string("== Where's the love?")
178
236
  end
237
+
238
+ test "with non-word character" do
239
+ assert_xpath "//h2[@id='_where_s_the_love'][text() = \"Where’s the love?\"]", render_string("== Where’s the love?")
240
+ end
179
241
 
180
242
  test "with sequential non-word characters" do
181
243
  assert_xpath "//h2[@id='_what_the_is_this'][text() = 'What the \#@$ is this?']", render_string('== What the #@$ is this?')
@@ -198,8 +260,37 @@ preamble
198
260
  == Asciidoctor in 中文
199
261
  EOS
200
262
  output = render_string input
201
- assert_xpath '//h2[@id="_asciidoctor_in"][text()="Asciidoctor in 中文"]', output
263
+ if ::RUBY_MIN_VERSION_1_9
264
+ assert_xpath '//h2[@id="_asciidoctor_in_中文"][text()="Asciidoctor in 中文"]', output
265
+ else
266
+ assert_xpath '//h2[@id="_asciidoctor_in"][text()="Asciidoctor in 中文"]', output
267
+ end
202
268
  end
269
+
270
+ test 'with only multibyte characters' do
271
+ input = <<-EOS
272
+ == 视图
273
+ EOS
274
+ output = render_embedded_string input
275
+ assert_xpath '//h2[@id="_视图"][text()="视图"]', output
276
+ end if ::RUBY_MIN_VERSION_1_9
277
+
278
+ test 'multiline syntax with only multibyte characters' do
279
+ input = <<-EOS
280
+ 视图
281
+ --
282
+
283
+ content
284
+
285
+ 连接器
286
+ ---
287
+
288
+ content
289
+ EOS
290
+ output = render_embedded_string input
291
+ assert_xpath '//h2[@id="_视图"][text()="视图"]', output
292
+ assert_xpath '//h2[@id="_连接器"][text()="连接器"]', output
293
+ end if ::RUBY_MIN_VERSION_1_9
203
294
  end
204
295
 
205
296
  context "level 2" do
@@ -280,15 +371,15 @@ blah blah
280
371
  test 'should create floating title if style is float' do
281
372
  input = <<-EOS
282
373
  [float]
283
- = Plain Ol' Heading
374
+ = Independent Heading!
284
375
 
285
376
  not in section
286
377
  EOS
287
378
 
288
379
  output = render_embedded_string input
289
- assert_xpath '/h1[@id="_plain_ol_heading"]', output, 1
380
+ assert_xpath '/h1[@id="_independent_heading"]', output, 1
290
381
  assert_xpath '/h1[@class="float"]', output, 1
291
- assert_xpath %(/h1[@class="float"][text()="Plain Ol' Heading"]), output, 1
382
+ assert_xpath %(/h1[@class="float"][text()="Independent Heading!"]), output, 1
292
383
  assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
293
384
  assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
294
385
  assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
@@ -297,25 +388,59 @@ not in section
297
388
  test 'should create floating title if style is discrete' do
298
389
  input = <<-EOS
299
390
  [discrete]
300
- === Plain Ol' Heading
391
+ === Independent Heading!
301
392
 
302
393
  not in section
303
394
  EOS
304
395
 
305
396
  output = render_embedded_string input
306
397
  assert_xpath '/h3', output, 1
307
- assert_xpath '/h3[@id="_plain_ol_heading"]', output, 1
398
+ assert_xpath '/h3[@id="_independent_heading"]', output, 1
308
399
  assert_xpath '/h3[@class="discrete"]', output, 1
309
- assert_xpath %(/h3[@class="discrete"][text()="Plain Ol' Heading"]), output, 1
400
+ assert_xpath %(/h3[@class="discrete"][text()="Independent Heading!"]), output, 1
310
401
  assert_xpath '/h3/following-sibling::*[@class="paragraph"]', output, 1
311
402
  assert_xpath '/h3/following-sibling::*[@class="paragraph"]/p', output, 1
312
403
  assert_xpath '/h3/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
313
404
  end
314
405
 
406
+ test 'should create floating title if style is float with shorthand role and id' do
407
+ input = <<-EOS
408
+ [float.independent#first]
409
+ = Independent Heading!
410
+
411
+ not in section
412
+ EOS
413
+
414
+ output = render_embedded_string input
415
+ assert_xpath '/h1[@id="first"]', output, 1
416
+ assert_xpath '/h1[@class="float independent"]', output, 1
417
+ assert_xpath %(/h1[@class="float independent"][text()="Independent Heading!"]), output, 1
418
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
419
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
420
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
421
+ end
422
+
423
+ test 'should create floating title if style is discrete with shorthand role and id' do
424
+ input = <<-EOS
425
+ [discrete.independent#first]
426
+ = Independent Heading!
427
+
428
+ not in section
429
+ EOS
430
+
431
+ output = render_embedded_string input
432
+ assert_xpath '/h1[@id="first"]', output, 1
433
+ assert_xpath '/h1[@class="discrete independent"]', output, 1
434
+ assert_xpath %(/h1[@class="discrete independent"][text()="Independent Heading!"]), output, 1
435
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]', output, 1
436
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p', output, 1
437
+ assert_xpath '/h1/following-sibling::*[@class="paragraph"]/p[text()="not in section"]', output, 1
438
+ end
439
+
315
440
  test 'floating title should be a block with context floating_title' do
316
441
  input = <<-EOS
317
442
  [float]
318
- === Plain Ol' Heading
443
+ === Independent Heading!
319
444
 
320
445
  not in section
321
446
  EOS
@@ -323,17 +448,17 @@ not in section
323
448
  doc = document_from_string input
324
449
  floatingtitle = doc.blocks.first
325
450
  assert floatingtitle.is_a?(Asciidoctor::Block)
326
- assert !floatingtitle.is_a?(Asciidoctor::Section)
451
+ assert floatingtitle.context != :section
327
452
  assert_equal :floating_title, floatingtitle.context
328
- assert_equal '_plain_ol_heading', floatingtitle.id
329
- assert doc.references[:ids].has_key?('_plain_ol_heading')
453
+ assert_equal '_independent_heading', floatingtitle.id
454
+ assert doc.references[:ids].has_key?('_independent_heading')
330
455
  end
331
456
 
332
457
  test 'can assign explicit id to floating title' do
333
458
  input = <<-EOS
334
459
  [[unchained]]
335
460
  [float]
336
- === Plain Ol' Heading
461
+ === Independent Heading!
337
462
 
338
463
  not in section
339
464
  EOS
@@ -365,14 +490,14 @@ not in section
365
490
  test 'should not set id on floating title if sectids attribute is unset' do
366
491
  input = <<-EOS
367
492
  [float]
368
- === Plain Ol' Heading
493
+ === Independent Heading!
369
494
 
370
495
  not in section
371
496
  EOS
372
497
 
373
498
  output = render_embedded_string input, :attributes => {'sectids' => nil}
374
499
  assert_xpath '/h3', output, 1
375
- assert_xpath '/h3[@id="_plain_ol_heading"]', output, 0
500
+ assert_xpath '/h3[@id="_independent_heading"]', output, 0
376
501
  assert_xpath '/h3[@class="float"]', output, 1
377
502
  end
378
503
 
@@ -380,7 +505,7 @@ not in section
380
505
  input = <<-EOS
381
506
  [[free]]
382
507
  [float]
383
- == Plain Ol' Heading
508
+ == Independent Heading!
384
509
 
385
510
  not in section
386
511
  EOS
@@ -394,16 +519,46 @@ not in section
394
519
  test 'should add role to class attribute on floating title' do
395
520
  input = <<-EOS
396
521
  [float, role="isolated"]
397
- == Plain Ol' Heading
522
+ == Independent Heading!
398
523
 
399
524
  not in section
400
525
  EOS
401
526
 
402
527
  output = render_embedded_string input
403
528
  assert_xpath '/h2', output, 1
404
- assert_xpath '/h2[@id="_plain_ol_heading"]', output, 1
529
+ assert_xpath '/h2[@id="_independent_heading"]', output, 1
405
530
  assert_xpath '/h2[@class="float isolated"]', output, 1
406
531
  end
532
+
533
+ test 'should use specified id and reftext when registering discrete section reference' do
534
+ input = <<-EOS
535
+ [[install,Install Procedure]]
536
+ [discrete]
537
+ == Install
538
+
539
+ content
540
+ EOS
541
+
542
+ doc = document_from_string input
543
+ reftext = doc.references[:ids]['install']
544
+ refute_nil reftext
545
+ assert_equal 'Install Procedure', reftext
546
+ end
547
+
548
+ test 'should use specified reftext when registering discrete section reference' do
549
+ input = <<-EOS
550
+ [reftext="Install Procedure"]
551
+ [discrete]
552
+ == Install
553
+
554
+ content
555
+ EOS
556
+
557
+ doc = document_from_string input
558
+ reftext = doc.references[:ids]['_install']
559
+ refute_nil reftext
560
+ assert_equal 'Install Procedure', reftext
561
+ end
407
562
  end
408
563
 
409
564
  context 'Level offset' do
@@ -424,9 +579,9 @@ text in standalone
424
579
  EOS
425
580
 
426
581
  output, errors = nil
427
- redirect_streams do |stdout, stderr|
582
+ redirect_streams do |out, err|
428
583
  output = render_string input
429
- errors = stderr.string
584
+ errors = err.string
430
585
  end
431
586
 
432
587
  assert !errors.empty?
@@ -462,9 +617,9 @@ Master section text.
462
617
 
463
618
  output = nil
464
619
  errors = nil
465
- redirect_streams do |stdout, stderr|
620
+ redirect_streams do |out, err|
466
621
  output = render_string input
467
- errors = stdout.string
622
+ errors = out.string
468
623
  end
469
624
 
470
625
  assert errors.empty?
@@ -512,6 +667,31 @@ Standalone preamble.
512
667
  assert_xpath '//*[@class = "sect1"]/h2[text() = "Standalone Document"]', output, 1
513
668
  assert_xpath '//*[@class = "sect1"]/h2[text() = "Level 1 Section"]', output, 1
514
669
  end
670
+
671
+ test 'should add relative offset value to current leveloffset' do
672
+ input = <<-EOS
673
+ = Master Document
674
+ Doc Writer
675
+
676
+ Master preamble.
677
+
678
+ :leveloffset: 1
679
+
680
+ = Chapter 1
681
+
682
+ content
683
+
684
+ :leveloffset: +1
685
+
686
+ = Standalone Section
687
+
688
+ content
689
+ EOS
690
+
691
+ output = render_string input
692
+ assert_xpath '//*[@class = "sect1"]/h2[text() = "Chapter 1"]', output, 1
693
+ assert_xpath '//*[@class = "sect2"]/h3[text() = "Standalone Section"]', output, 1
694
+ end
515
695
  end
516
696
 
517
697
  context 'Section Numbering' do
@@ -555,6 +735,45 @@ Standalone preamble.
555
735
  assert_equal '1:1:1', sect1_1_1.sectnum(':', false)
556
736
  end
557
737
 
738
+ test 'should render section numbers when sectnums attribute is set' do
739
+ input = <<-EOS
740
+ = Title
741
+ :sectnums:
742
+
743
+ == Section_1
744
+
745
+ text
746
+
747
+ === Section_1_1
748
+
749
+ text
750
+
751
+ ==== Section_1_1_1
752
+
753
+ text
754
+
755
+ == Section_2
756
+
757
+ text
758
+
759
+ === Section_2_1
760
+
761
+ text
762
+
763
+ === Section_2_2
764
+
765
+ text
766
+ EOS
767
+
768
+ output = render_string input
769
+ assert_xpath '//h2[@id="_section_1"][starts-with(text(), "1. ")]', output, 1
770
+ assert_xpath '//h3[@id="_section_1_1"][starts-with(text(), "1.1. ")]', output, 1
771
+ assert_xpath '//h4[@id="_section_1_1_1"][starts-with(text(), "1.1.1. ")]', output, 1
772
+ assert_xpath '//h2[@id="_section_2"][starts-with(text(), "2. ")]', output, 1
773
+ assert_xpath '//h3[@id="_section_2_1"][starts-with(text(), "2.1. ")]', output, 1
774
+ assert_xpath '//h3[@id="_section_2_2"][starts-with(text(), "2.2. ")]', output, 1
775
+ end
776
+
558
777
  test 'should render section numbers when numbered attribute is set' do
559
778
  input = <<-EOS
560
779
  = Title
@@ -786,19 +1005,57 @@ content
786
1005
 
787
1006
  = Part 1
788
1007
 
789
- == Part 1: Chapter 1
1008
+ == Chapter 1
1009
+
1010
+ content
790
1011
 
791
1012
  = Part 2
792
1013
 
793
- == Part 2: Chapter 1
1014
+ == Chapter 2
1015
+
1016
+ content
794
1017
  EOS
795
1018
 
796
1019
  output = render_string input
797
1020
  assert_xpath '(//h1)[1][text()="Document Title"]', output, 1
798
1021
  assert_xpath '(//h1)[2][text()="Part 1"]', output, 1
799
1022
  assert_xpath '(//h1)[3][text()="Part 2"]', output, 1
800
- assert_xpath '(//h2)[1][text()="1. Part 1: Chapter 1"]', output, 1
801
- assert_xpath '(//h2)[2][text()="1. Part 2: Chapter 1"]', output, 1
1023
+ assert_xpath '(//h2)[1][text()="1. Chapter 1"]', output, 1
1024
+ assert_xpath '(//h2)[2][text()="2. Chapter 2"]', output, 1
1025
+ end
1026
+
1027
+ test 'should number chapters sequentially even when divided into parts' do
1028
+ input = <<-EOS
1029
+ = Document Title
1030
+ :doctype: book
1031
+ :numbered:
1032
+
1033
+ == Chapter 1
1034
+
1035
+ content
1036
+
1037
+ = Part 1
1038
+
1039
+ == Chapter 2
1040
+
1041
+ content
1042
+
1043
+ = Part 2
1044
+
1045
+ == Chapter 3
1046
+
1047
+ content
1048
+
1049
+ == Chapter 4
1050
+
1051
+ content
1052
+ EOS
1053
+
1054
+ result = render_string input
1055
+ (1..4).each do |num|
1056
+ assert_xpath %(//h2[@id="_chapter_#{num}"]), result, 1
1057
+ assert_xpath %(//h2[@id="_chapter_#{num}"][text()="#{num}. Chapter #{num}"]), result, 1
1058
+ end
802
1059
  end
803
1060
  end
804
1061
 
@@ -870,6 +1127,49 @@ Details
870
1127
  assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
871
1128
  end
872
1129
 
1130
+ test 'should prefix appendix title by label and letter only when numbered is enabled' do
1131
+ input = <<-EOS
1132
+ :numbered:
1133
+
1134
+ [appendix]
1135
+ == Attribute Options
1136
+
1137
+ Details
1138
+ EOS
1139
+
1140
+ output = render_embedded_string input
1141
+ assert_xpath '//h2[text()="Appendix A: Attribute Options"]', output, 1
1142
+ end
1143
+
1144
+ test 'should use custom appendix caption if specified' do
1145
+ input = <<-EOS
1146
+ :appendix-caption: App
1147
+
1148
+ [appendix]
1149
+ == Attribute Options
1150
+
1151
+ Details
1152
+ EOS
1153
+
1154
+ output = render_embedded_string input
1155
+ assert_xpath '//h2[text()="App A: Attribute Options"]', output, 1
1156
+ end
1157
+
1158
+ test 'should only assign letter to appendix when numbered is enabled and appendix caption is empty' do
1159
+ input = <<-EOS
1160
+ :numbered:
1161
+ :appendix-caption:
1162
+
1163
+ [appendix]
1164
+ == Attribute Options
1165
+
1166
+ Details
1167
+ EOS
1168
+
1169
+ output = render_embedded_string input
1170
+ assert_xpath '//h2[text()="A. Attribute Options"]', output, 1
1171
+ end
1172
+
873
1173
  test 'should increment appendix number for each appendix section' do
874
1174
  input = <<-EOS
875
1175
  [appendix]
@@ -888,9 +1188,72 @@ Details
888
1188
  assert_xpath '(//h2)[2][text()="Appendix B: Migration"]', output, 1
889
1189
  end
890
1190
 
891
- test 'should not number level 4 section' do
1191
+ test 'should continue numbering after appendix' do
1192
+ input = <<-EOS
1193
+ :numbered:
1194
+
1195
+ == First Section
1196
+
1197
+ content
1198
+
1199
+ [appendix]
1200
+ == Attribute Options
1201
+
1202
+ content
1203
+
1204
+ == Migration
1205
+
1206
+ content
1207
+ EOS
1208
+
1209
+ output = render_embedded_string input
1210
+ assert_xpath '(//h2)[1][text()="1. First Section"]', output, 1
1211
+ assert_xpath '(//h2)[2][text()="Appendix A: Attribute Options"]', output, 1
1212
+ assert_xpath '(//h2)[3][text()="2. Migration"]', output, 1
1213
+ end
1214
+
1215
+ test 'should number appendix subsections using appendix letter' do
1216
+ input = <<-EOS
1217
+ :numbered:
1218
+
1219
+ [appendix]
1220
+ == Attribute Options
1221
+
1222
+ Details
1223
+
1224
+ === Optional Attributes
1225
+
1226
+ Details
1227
+ EOS
1228
+
1229
+ output = render_embedded_string input
1230
+ assert_xpath '(//h2)[1][text()="Appendix A: Attribute Options"]', output, 1
1231
+ assert_xpath '(//h3)[1][text()="A.1. Optional Attributes"]', output, 1
1232
+ end
1233
+
1234
+ test 'should not number level 4 section by default' do
1235
+ input = <<-EOS
1236
+ :numbered:
1237
+
1238
+ == Level_1
1239
+
1240
+ === Level_2
1241
+
1242
+ ==== Level_3
1243
+
1244
+ ===== Level_4
1245
+
1246
+ text
1247
+ EOS
1248
+ output = render_embedded_string input
1249
+ assert_xpath '//h5', output, 1
1250
+ assert_xpath '//h5[text()="Level_4"]', output, 1
1251
+ end
1252
+
1253
+ test 'should only number levels up to value defined by sectnumlevels attribute' do
892
1254
  input = <<-EOS
893
1255
  :numbered:
1256
+ :sectnumlevels: 2
894
1257
 
895
1258
  == Level_1
896
1259
 
@@ -903,6 +1266,12 @@ Details
903
1266
  text
904
1267
  EOS
905
1268
  output = render_embedded_string input
1269
+ assert_xpath '//h2', output, 1
1270
+ assert_xpath '//h2[text()="1. Level_1"]', output, 1
1271
+ assert_xpath '//h3', output, 1
1272
+ assert_xpath '//h3[text()="1.1. Level_2"]', output, 1
1273
+ assert_xpath '//h4', output, 1
1274
+ assert_xpath '//h4[text()="Level_3"]', output, 1
906
1275
  assert_xpath '//h5', output, 1
907
1276
  assert_xpath '//h5[text()="Level_4"]', output, 1
908
1277
  end
@@ -980,6 +1349,26 @@ Terms
980
1349
  assert_xpath '//*[@id="toc"]/ul//li/a[text()="Glossary"]', output, 1
981
1350
  end
982
1351
 
1352
+ test 'should only number sections in toc up to value defined by sectnumlevels attribute' do
1353
+ input = <<-EOS
1354
+ :numbered:
1355
+ :toc:
1356
+ :sectnumlevels: 2
1357
+ :toclevels: 3
1358
+
1359
+ == Level 1
1360
+
1361
+ === Level 2
1362
+
1363
+ ==== Level 3
1364
+ EOS
1365
+
1366
+ output = render_string input
1367
+ assert_xpath '//*[@id="toc"]//a[@href="#_level_1"][text()="1. Level 1"]', output, 1
1368
+ assert_xpath '//*[@id="toc"]//a[@href="#_level_2"][text()="1.1. Level 2"]', output, 1
1369
+ assert_xpath '//*[@id="toc"]//a[@href="#_level_3"][text()="Level 3"]', output, 1
1370
+ end
1371
+
983
1372
  # reenable once we have :specialnumbered!: implemented
984
1373
  =begin
985
1374
  test 'should not number special sections or subsections' do
@@ -1117,6 +1506,7 @@ blah blah
1117
1506
 
1118
1507
  = Part 2
1119
1508
 
1509
+ [partintro]
1120
1510
  blah blah
1121
1511
 
1122
1512
  == Chapter 3
@@ -1155,7 +1545,7 @@ Colophon content
1155
1545
  = Index Title
1156
1546
  EOS
1157
1547
 
1158
- output = render_embedded_string input, :backend => 'docbook'
1548
+ output = render_embedded_string input, :backend => 'docbook45'
1159
1549
  assert_xpath '/chapter[@id="abstract_title"]', output, 1
1160
1550
  assert_xpath '/chapter[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
1161
1551
  assert_xpath '/chapter/following-sibling::dedication[@id="dedication_title"]', output, 1
@@ -1195,7 +1585,7 @@ Colophon content
1195
1585
  Abstract content
1196
1586
  EOS
1197
1587
 
1198
- output = render_embedded_string input, :backend => 'docbook'
1588
+ output = render_embedded_string input, :backend => 'docbook45'
1199
1589
  assert_xpath '/abstract[@id="abstract_title"]', output, 1
1200
1590
  assert_xpath '/abstract[@id="abstract_title"]/title[text()="Abstract Title"]', output, 1
1201
1591
  end
@@ -1335,13 +1725,13 @@ That's all she wrote!
1335
1725
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
1336
1726
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul[@class="sectlevel1"]', output, 1
1337
1727
  assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
1338
- assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li', output, 4
1728
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
1339
1729
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="Section One"]', output, 1
1340
1730
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul', output, 1
1341
1731
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul[@class="sectlevel2"]', output, 1
1342
1732
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
1343
1733
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="Interlude"]', output, 1
1344
- assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[4]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1734
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1345
1735
  end
1346
1736
 
1347
1737
  test 'should render numbered table of contents in header if toc and numbered attributes are set' do
@@ -1371,11 +1761,11 @@ That's all she wrote!
1371
1761
  assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
1372
1762
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
1373
1763
  assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
1374
- assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li', output, 4
1764
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
1375
1765
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
1376
1766
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
1377
1767
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
1378
- assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[4]/a[@href="#_section_three"][text()="3. Section Three"]', output, 1
1768
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="3. Section Three"]', output, 1
1379
1769
  end
1380
1770
 
1381
1771
  test 'should render a table of contents that honors numbered setting at position of section in document' do
@@ -1407,9 +1797,9 @@ That's all she wrote!
1407
1797
  assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
1408
1798
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
1409
1799
  assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
1410
- assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li', output, 4
1800
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
1411
1801
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
1412
- assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[4]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1802
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
1413
1803
  end
1414
1804
 
1415
1805
  test 'should not number parts in table of contents for book doctype when numbered attribute is set' do
@@ -1440,13 +1830,13 @@ blah
1440
1830
  assert_xpath '//*[@id="toc"]', output, 1
1441
1831
  assert_xpath '//*[@id="toc"]/ul', output, 1
1442
1832
  assert_xpath '//*[@id="toc"]/ul[@class="sectlevel0"]', output, 1
1443
- assert_xpath '//*[@id="toc"]/ul[@class="sectlevel0"]/li', output, 4
1833
+ assert_xpath '//*[@id="toc"]/ul[@class="sectlevel0"]/li', output, 2
1444
1834
  assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/a[text()="Part 1"]', output, 1
1445
- assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[3]/a[text()="Part 2"]', output, 1
1446
- assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/ul', output, 1
1447
- assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/ul[@class="sectlevel1"]', output, 1
1448
- assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/ul/li', output, 2
1449
- assert_xpath '((//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/ul/li)[1]/a[text()="1. First Section of Part 1"]', output, 1
1835
+ assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[2]/a[text()="Part 2"]', output, 1
1836
+ assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul', output, 1
1837
+ assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul[@class="sectlevel1"]', output, 1
1838
+ assert_xpath '(//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul/li', output, 2
1839
+ assert_xpath '((//*[@id="toc"]/ul[@class="sectlevel0"]/li)[1]/ul/li)[1]/a[text()="1. First Section of Part 1"]', output, 1
1450
1840
  end
1451
1841
 
1452
1842
  test 'should render table of contents in header if toc2 attribute is set' do
@@ -1470,10 +1860,10 @@ They couldn't believe their eyes when...
1470
1860
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
1471
1861
  end
1472
1862
 
1473
- test 'should set toc position if toc2 attribute is set to position' do
1863
+ test 'should set toc position if toc attribute is set to position' do
1474
1864
  input = <<-EOS
1475
1865
  = Article
1476
- :toc2: >
1866
+ :toc: >
1477
1867
  :numbered:
1478
1868
 
1479
1869
  == Section One
@@ -1556,6 +1946,27 @@ They couldn't believe their eyes when...
1556
1946
  assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
1557
1947
  end
1558
1948
 
1949
+ test 'should set toc placement to preamble if toc attribute is set to preamble' do
1950
+ input = <<-EOS
1951
+ = Article
1952
+ :toc: preamble
1953
+
1954
+ Yada yada
1955
+
1956
+ == Section One
1957
+
1958
+ It was a dark and stormy night...
1959
+
1960
+ == Section Two
1961
+
1962
+ They couldn't believe their eyes when...
1963
+ EOS
1964
+
1965
+ output = render_string input
1966
+ assert_css '#preamble #toc', output, 1
1967
+ assert_css '#preamble .sectionbody + #toc', output, 1
1968
+ end
1969
+
1559
1970
  test 'should use document attributes toc-class, toc-title and toclevels to create toc' do
1560
1971
  input = <<-EOS
1561
1972
  = Article
@@ -1609,7 +2020,7 @@ They couldn't believe their eyes when...
1609
2020
  input = <<-EOS
1610
2021
  = Article
1611
2022
  :toc:
1612
- :toc-placement!:
2023
+ :toc-placement: macro
1613
2024
 
1614
2025
  Once upon a time...
1615
2026
 
@@ -1633,7 +2044,7 @@ They couldn't believe their eyes when...
1633
2044
  input = <<-EOS
1634
2045
  = Article
1635
2046
  :toc:
1636
- :toc-placement!:
2047
+ :toc-placement: macro
1637
2048
 
1638
2049
  Once upon a time...
1639
2050
 
@@ -1653,7 +2064,7 @@ They couldn't believe their eyes when...
1653
2064
  assert_css '#preamble:root .paragraph + #toc', output, 1
1654
2065
  end
1655
2066
 
1656
- test 'should not assign toc id to more than one toc' do
2067
+ test 'should not activate toc macro if toc-placement is not set' do
1657
2068
  input = <<-EOS
1658
2069
  = Article
1659
2070
  :toc:
@@ -1675,15 +2086,41 @@ They couldn't believe their eyes when...
1675
2086
 
1676
2087
  assert_css '#toc', output, 1
1677
2088
  assert_css '#toctitle', output, 1
1678
- assert_xpath '(//*[@class="toc"])[2][not(@id)]', output, 1
1679
- assert_xpath '(//*[@class="toc"])[2]/*[@class="title"][not(@id)]', output, 1
2089
+ assert_css '.toc', output, 1
2090
+ assert_css '#content .toc', output, 0
2091
+ end
2092
+
2093
+ test 'should only output toc at toc macro if toc is macro' do
2094
+ input = <<-EOS
2095
+ = Article
2096
+ :toc: macro
2097
+
2098
+ Once upon a time...
2099
+
2100
+ toc::[]
2101
+
2102
+ == Section One
2103
+
2104
+ It was a dark and stormy night...
2105
+
2106
+ == Section Two
2107
+
2108
+ They couldn't believe their eyes when...
2109
+ EOS
2110
+
2111
+ output = render_string input
2112
+
2113
+ assert_css '#toc', output, 1
2114
+ assert_css '#toctitle', output, 1
2115
+ assert_css '.toc', output, 1
2116
+ assert_css '#content .toc', output, 1
1680
2117
  end
1681
2118
 
1682
2119
  test 'should use global attributes for toc-title, toc-class and toclevels for toc macro' do
1683
2120
  input = <<-EOS
1684
2121
  = Article
1685
2122
  :toc:
1686
- :toc-placement!:
2123
+ :toc-placement: macro
1687
2124
  :toc-title: Contents
1688
2125
  :toc-class: contents
1689
2126
  :toclevels: 1
@@ -1722,7 +2159,7 @@ Fin.
1722
2159
  input = <<-EOS
1723
2160
  = Article
1724
2161
  :toc:
1725
- :toc-placement!:
2162
+ :toc-placement: macro
1726
2163
  :toc-title: Ignored
1727
2164
  :toc-class: ignored
1728
2165
  :toclevels: 5
@@ -1760,6 +2197,40 @@ Fin.
1760
2197
  assert_xpath '(//*[@id="contents"]//li)[1]/a[text() = "Section 1"]', output, 1
1761
2198
  assert_xpath '(//*[@id="contents"]//li)[2]/a[text() = "Section 2"]', output, 1
1762
2199
  end
2200
+
2201
+ test 'child toc levels should not have additional bullet at parent level in html' do
2202
+ input = <<-EOS
2203
+ = Article
2204
+ :toc:
2205
+
2206
+ == Section One
2207
+
2208
+ It was a dark and stormy night...
2209
+
2210
+ == Section Two
2211
+
2212
+ They couldn't believe their eyes when...
2213
+
2214
+ === Interlude
2215
+
2216
+ While they were waiting...
2217
+
2218
+ == Section Three
2219
+
2220
+ That's all she wrote!
2221
+ EOS
2222
+ output = render_string input
2223
+ assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
2224
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
2225
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ul', output, 1
2226
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ul', output, 2
2227
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//li', output, 4
2228
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[2]/a[@href="#_section_two"][text()="Section Two"]', output, 1
2229
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li', output, 1
2230
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li[2]/ul/li', output, 1
2231
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ul/li/ul/li/a[@href="#_interlude"][text()="Interlude"]', output, 1
2232
+ assert_xpath '((//*[@id="header"]//*[@id="toc"]/ul)[1]/li)[3]/a[@href="#_section_three"][text()="Section Three"]', output, 1
2233
+ end
1763
2234
  end
1764
2235
 
1765
2236
  context 'article doctype' do
@@ -1814,10 +2285,16 @@ Doc Writer
1814
2285
 
1815
2286
  = Chapter One
1816
2287
 
2288
+ [partintro]
1817
2289
  It was a dark and stormy night...
1818
2290
 
2291
+ == Scene One
2292
+
2293
+ Someone's gonna get axed.
2294
+
1819
2295
  = Chapter Two
1820
2296
 
2297
+ [partintro]
1821
2298
  They couldn't believe their eyes when...
1822
2299
 
1823
2300
  == Interlude
@@ -1826,6 +2303,8 @@ While they were waiting...
1826
2303
 
1827
2304
  = Chapter Three
1828
2305
 
2306
+ == Scene One
2307
+
1829
2308
  That's all she wrote!
1830
2309
  EOS
1831
2310
 
@@ -1835,13 +2314,97 @@ That's all she wrote!
1835
2314
  assert_css '#header h1', output, 1
1836
2315
  assert_css '#content h1', output, 3
1837
2316
  assert_css '#content h1.sect0', output, 3
1838
- assert_css 'h2', output, 1
1839
- assert_css '#content h2', output, 1
2317
+ assert_css 'h2', output, 3
2318
+ assert_css '#content h2', output, 3
1840
2319
  assert_xpath '//h1[@id="_chapter_one"][text() = "Chapter One"]', output, 1
1841
2320
  assert_xpath '//h1[@id="_chapter_two"][text() = "Chapter Two"]', output, 1
1842
2321
  assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1
1843
2322
  end
1844
2323
 
2324
+ test 'should add partintro style to child paragraph of part' do
2325
+ input = <<-EOS
2326
+ = Book
2327
+ :doctype: book
2328
+
2329
+ = Part 1
2330
+
2331
+ part intro
2332
+
2333
+ == Chapter 1
2334
+ EOS
2335
+
2336
+ doc = document_from_string input
2337
+ partintro = doc.blocks.first.blocks.first
2338
+ assert_equal :open, partintro.context
2339
+ assert_equal 'partintro', partintro.style
2340
+ end
2341
+
2342
+ test 'should add partintro style to child open block of part' do
2343
+ input = <<-EOS
2344
+ = Book
2345
+ :doctype: book
2346
+
2347
+ = Part 1
2348
+
2349
+ --
2350
+ part intro
2351
+ --
2352
+
2353
+ == Chapter 1
2354
+ EOS
2355
+
2356
+ doc = document_from_string input
2357
+ partintro = doc.blocks.first.blocks.first
2358
+ assert_equal :open, partintro.context
2359
+ assert_equal 'partintro', partintro.style
2360
+ end
2361
+
2362
+ test 'should wrap child paragraphs of part in partintro open block' do
2363
+ input = <<-EOS
2364
+ = Book
2365
+ :doctype: book
2366
+
2367
+ = Part 1
2368
+
2369
+ part intro
2370
+
2371
+ more part intro
2372
+
2373
+ == Chapter 1
2374
+ EOS
2375
+
2376
+ doc = document_from_string input
2377
+ partintro = doc.blocks.first.blocks.first
2378
+ assert_equal :open, partintro.context
2379
+ assert_equal 'partintro', partintro.style
2380
+ assert_equal 2, partintro.blocks.size
2381
+ assert_equal :paragraph, partintro.blocks[0].context
2382
+ assert_equal :paragraph, partintro.blocks[1].context
2383
+ end
2384
+
2385
+ test 'should warn if part has no sections' do
2386
+ input = <<-EOS
2387
+ = Book
2388
+ :doctype: book
2389
+
2390
+ = Part 1
2391
+
2392
+ [partintro]
2393
+ intro
2394
+ EOS
2395
+
2396
+ doc = nil
2397
+ warnings = nil
2398
+ redirect_streams do |out, err|
2399
+ doc = document_from_string input
2400
+ warnings = err.string
2401
+ end
2402
+
2403
+ refute_nil warnings
2404
+ assert !warnings.empty?
2405
+ assert_match(/ERROR:.*section/, warnings)
2406
+ end
2407
+
1845
2408
  test 'should create parts and chapters in docbook backend' do
1846
2409
  input = <<-EOS
1847
2410
  = Book
@@ -1850,6 +2413,7 @@ Doc Writer
1850
2413
 
1851
2414
  = Part 1
1852
2415
 
2416
+ [partintro]
1853
2417
  The adventure.
1854
2418
 
1855
2419
  == Chapter One
@@ -1862,6 +2426,7 @@ They couldn't believe their eyes when...
1862
2426
 
1863
2427
  = Part 2
1864
2428
 
2429
+ [partintro]
1865
2430
  The return.
1866
2431
 
1867
2432
  == Chapter Three
@@ -1916,9 +2481,9 @@ Appendix subsection content
1916
2481
 
1917
2482
  output = nil
1918
2483
  errors = nil
1919
- redirect_streams do |stdout, stderr|
2484
+ redirect_streams do |out, err|
1920
2485
  output = render_string input, :backend => 'docbook'
1921
- errors = stdout.string
2486
+ errors = out.string
1922
2487
  end
1923
2488
  assert errors.empty?
1924
2489
  assert_xpath '/book/preface', output, 1