asciidoctor 0.1.1 → 0.1.2

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -1
  3. data/LICENSE +2 -2
  4. data/README.adoc +461 -0
  5. data/asciidoctor.gemspec +27 -16
  6. data/compat/asciidoc.conf +139 -0
  7. data/lib/asciidoctor.rb +212 -69
  8. data/lib/asciidoctor/abstract_block.rb +41 -0
  9. data/lib/asciidoctor/abstract_node.rb +128 -81
  10. data/lib/asciidoctor/attribute_list.rb +5 -2
  11. data/lib/asciidoctor/backends/base_template.rb +16 -4
  12. data/lib/asciidoctor/backends/docbook45.rb +112 -42
  13. data/lib/asciidoctor/backends/html5.rb +206 -90
  14. data/lib/asciidoctor/block.rb +5 -5
  15. data/lib/asciidoctor/cli/invoker.rb +38 -34
  16. data/lib/asciidoctor/cli/options.rb +3 -3
  17. data/lib/asciidoctor/document.rb +115 -13
  18. data/lib/asciidoctor/helpers.rb +16 -0
  19. data/lib/asciidoctor/lexer.rb +486 -359
  20. data/lib/asciidoctor/path_resolver.rb +360 -0
  21. data/lib/asciidoctor/reader.rb +122 -23
  22. data/lib/asciidoctor/renderer.rb +1 -33
  23. data/lib/asciidoctor/section.rb +1 -1
  24. data/lib/asciidoctor/substituters.rb +103 -19
  25. data/lib/asciidoctor/version.rb +1 -1
  26. data/man/asciidoctor.1 +6 -6
  27. data/man/asciidoctor.ad +5 -3
  28. data/stylesheets/asciidoctor.css +274 -0
  29. data/test/attributes_test.rb +133 -10
  30. data/test/blocks_test.rb +302 -17
  31. data/test/document_test.rb +269 -6
  32. data/test/fixtures/basic-docinfo.html +1 -0
  33. data/test/fixtures/basic-docinfo.xml +4 -0
  34. data/test/fixtures/basic.asciidoc +4 -0
  35. data/test/fixtures/docinfo.html +1 -0
  36. data/test/fixtures/docinfo.xml +2 -0
  37. data/test/fixtures/include-file.asciidoc +22 -1
  38. data/test/fixtures/stylesheets/custom.css +3 -0
  39. data/test/invoker_test.rb +38 -6
  40. data/test/lexer_test.rb +64 -21
  41. data/test/links_test.rb +4 -0
  42. data/test/lists_test.rb +251 -12
  43. data/test/paragraphs_test.rb +225 -30
  44. data/test/paths_test.rb +174 -0
  45. data/test/reader_test.rb +89 -2
  46. data/test/sections_test.rb +518 -16
  47. data/test/substitutions_test.rb +121 -10
  48. data/test/tables_test.rb +53 -13
  49. data/test/test_helper.rb +2 -2
  50. data/test/text_test.rb +5 -5
  51. metadata +46 -50
  52. data/README.asciidoc +0 -296
  53. data/lib/asciidoctor/errors.rb +0 -5
@@ -153,13 +153,14 @@ This is a paragraph outside the block.
153
153
  end
154
154
 
155
155
  context 'Include Macro' do
156
- test 'include macro is disabled by default' do
156
+ test 'include macro is disabled by default and becomes a link' do
157
157
  input = <<-EOS
158
158
  include::include-file.asciidoc[]
159
159
  EOS
160
160
  para = block_from_string input, :attributes => { 'include-depth' => 0 }
161
161
  assert_equal 1, para.buffer.size
162
- assert_equal 'include::include-file.asciidoc[]', para.buffer.join
162
+ #assert_equal 'include::include-file.asciidoc[]', para.buffer.join
163
+ assert_equal 'link:include-file.asciidoc[include-file.asciidoc]', para.buffer.join
163
164
  end
164
165
 
165
166
  test 'include macro is enabled when safe mode is less than SECURE' do
@@ -172,6 +173,76 @@ include::fixtures/include-file.asciidoc[]
172
173
  assert_match(/included content/, output)
173
174
  end
174
175
 
176
+ test 'missing file referenced by include macro does not crash processor' do
177
+ input = <<-EOS
178
+ include::fixtures/no-such-file.ad[]
179
+ EOS
180
+
181
+ begin
182
+ doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => File.dirname(__FILE__)}
183
+ assert_equal 0, doc.blocks.size
184
+ rescue
185
+ flunk('include macro should not raise exception on missing file')
186
+ end
187
+ end
188
+
189
+ test 'include macro supports line selection' do
190
+ input = <<-EOS
191
+ include::fixtures/include-file.asciidoc[lines=1;3..4;6..-1]
192
+ EOS
193
+
194
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :attributes => {'docdir' => File.dirname(__FILE__)}
195
+ assert_match(/first line/, output)
196
+ assert_no_match(/second line/, output)
197
+ assert_match(/third line/, output)
198
+ assert_match(/fourth line/, output)
199
+ assert_no_match(/fifth line/, output)
200
+ assert_match(/sixth line/, output)
201
+ assert_match(/seventh line/, output)
202
+ assert_match(/eighth line/, output)
203
+ assert_match(/last line of included content/, output)
204
+ end
205
+
206
+ test 'include macro supports line selection using quoted attribute value' do
207
+ input = <<-EOS
208
+ include::fixtures/include-file.asciidoc[lines="1, 3..4 , 6 .. -1"]
209
+ EOS
210
+
211
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :attributes => {'docdir' => File.dirname(__FILE__)}
212
+ assert_match(/first line/, output)
213
+ assert_no_match(/second line/, output)
214
+ assert_match(/third line/, output)
215
+ assert_match(/fourth line/, output)
216
+ assert_no_match(/fifth line/, output)
217
+ assert_match(/sixth line/, output)
218
+ assert_match(/seventh line/, output)
219
+ assert_match(/eighth line/, output)
220
+ assert_match(/last line of included content/, output)
221
+ end
222
+
223
+ test 'include macro supports tagged selection' do
224
+ input = <<-EOS
225
+ include::fixtures/include-file.asciidoc[tags=snippetA;snippetB]
226
+ EOS
227
+
228
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :attributes => {'docdir' => File.dirname(__FILE__)}
229
+ assert_match(/snippetA content/, output)
230
+ assert_match(/snippetB content/, output)
231
+ assert_no_match(/non-tagged content/, output)
232
+ assert_no_match(/included content/, output)
233
+ end
234
+
235
+ test 'lines attribute takes precedence over tags attribute in include macro' do
236
+ input = <<-EOS
237
+ include::fixtures/include-file.asciidoc[lines=1, tags=snippetA;snippetB]
238
+ EOS
239
+
240
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :attributes => {'docdir' => File.dirname(__FILE__)}
241
+ assert_match(/first line of included content/, output)
242
+ assert_no_match(/snippetA content/, output)
243
+ assert_no_match(/snippetB content/, output)
244
+ end
245
+
175
246
  test "block is called to handle an include macro" do
176
247
  input = <<-EOS
177
248
  first line
@@ -329,6 +400,22 @@ There was much rejoicing.
329
400
  assert_equal "On our quest we go...\nThere is a holy grail!\nThere was much rejoicing.", lines.join.strip
330
401
  end
331
402
 
403
+ test 'ifndef with defined attribute does not include text in brackets' do
404
+ input = <<-EOS
405
+ On our quest we go...
406
+ ifndef::hardships[There is a holy grail!]
407
+ There was no rejoicing.
408
+ EOS
409
+
410
+ doc = Asciidoctor::Document.new [], :attributes => {'hardships' => ''}
411
+ reader = Asciidoctor::Reader.new(input.lines.entries, doc, true)
412
+ lines = []
413
+ while reader.has_more_lines?
414
+ lines << reader.get_line
415
+ end
416
+ assert_equal "On our quest we go...\nThere was no rejoicing.", lines.join.strip
417
+ end
418
+
332
419
  test 'include with non-matching nested exclude' do
333
420
  input = <<-EOS
334
421
  ifdef::grail[]
@@ -257,6 +257,23 @@ not in section
257
257
  assert floatingtitle.is_a?(Asciidoctor::Block)
258
258
  assert !floatingtitle.is_a?(Asciidoctor::Section)
259
259
  assert_equal :floating_title, floatingtitle.context
260
+ assert_equal '_plain_ol_heading', floatingtitle.id
261
+ assert doc.references[:ids].has_key?('_plain_ol_heading')
262
+ end
263
+
264
+ test 'can assign explicit id to floating title' do
265
+ input = <<-EOS
266
+ [[unchained]]
267
+ [float]
268
+ === Plain Ol' Heading
269
+
270
+ not in section
271
+ EOS
272
+
273
+ doc = document_from_string input
274
+ floating_title = doc.blocks.first
275
+ assert_equal 'unchained', floating_title.id
276
+ assert doc.references[:ids].has_key?('unchained')
260
277
  end
261
278
 
262
279
  test 'should not include floating title in toc' do
@@ -321,6 +338,115 @@ not in section
321
338
  end
322
339
  end
323
340
 
341
+ context 'Level offset' do
342
+ test 'should print error if standalone document is included without level offset' do
343
+ input = <<-EOS
344
+ = Master Document
345
+ Doc Writer
346
+
347
+ text in master
348
+
349
+ // begin simulated include::[]
350
+ = Standalone Document
351
+ :author: Junior Writer
352
+
353
+ text in standalone
354
+
355
+ // end simulated include::[]
356
+ EOS
357
+
358
+ output = nil
359
+ errors = nil
360
+ redirect_streams do |stdout, stderr|
361
+ output = render_string input
362
+ errors = stdout.string
363
+ end
364
+
365
+ assert !errors.empty?
366
+ assert_match(/section title out of sequence/, errors)
367
+ end
368
+
369
+ test 'should add level offset to section level' do
370
+ input = <<-EOS
371
+ = Master Document
372
+ Doc Writer
373
+
374
+ Master document written by {author}.
375
+
376
+ :leveloffset: 1
377
+
378
+ // begin simulated include::[]
379
+ = Standalone Document
380
+ :author: Junior Writer
381
+
382
+ Standalone document written by {author}.
383
+
384
+ == Section in Standalone
385
+
386
+ Standalone section text.
387
+ // end simulated include::[]
388
+
389
+ :leveloffset!:
390
+
391
+ == Section in Master
392
+
393
+ Master section text.
394
+ EOS
395
+
396
+ output = nil
397
+ errors = nil
398
+ redirect_streams do |stdout, stderr|
399
+ output = render_string input
400
+ errors = stdout.string
401
+ end
402
+
403
+ assert errors.empty?
404
+ assert_match(/Master document written by Doc Writer/, output)
405
+ assert_match(/Standalone document written by Junior Writer/, output)
406
+ assert_xpath '//*[@class="sect1"]/h2[text() = "Standalone Document"]', output, 1
407
+ assert_xpath '//*[@class="sect2"]/h3[text() = "Section in Standalone"]', output, 1
408
+ assert_xpath '//*[@class="sect1"]/h2[text() = "Section in Master"]', output, 1
409
+ end
410
+
411
+ test 'level offset should be added to floating title' do
412
+ input = <<-EOS
413
+ = Master Document
414
+ Doc Writer
415
+
416
+ :leveloffset: 1
417
+
418
+ [float]
419
+ = Floating Title
420
+ EOS
421
+
422
+ output = render_string input
423
+ assert_xpath '//h2[@class="float"][text() = "Floating Title"]', output, 1
424
+ end
425
+
426
+ test 'should be able to reset level offset' do
427
+ input = <<-EOS
428
+ = Master Document
429
+ Doc Writer
430
+
431
+ Master preamble.
432
+
433
+ :leveloffset: 1
434
+
435
+ = Standalone Document
436
+
437
+ Standalone preamble.
438
+
439
+ :leveloffset!:
440
+
441
+ == Level 1 Section
442
+ EOS
443
+
444
+ output = render_string input
445
+ assert_xpath '//*[@class = "sect1"]/h2[text() = "Standalone Document"]', output, 1
446
+ assert_xpath '//*[@class = "sect1"]/h2[text() = "Level 1 Section"]', output, 1
447
+ end
448
+ end
449
+
324
450
  context 'Section Numbering' do
325
451
  test 'should create section number with one entry for level 1' do
326
452
  sect1 = Asciidoctor::Section.new(nil)
@@ -560,6 +686,28 @@ Terms
560
686
  assert_xpath '//*[@id="toc"]/ol//li/a[text()="Gotchas"]', output, 1
561
687
  assert_xpath '//*[@id="toc"]/ol//li/a[text()="Glossary"]', output, 1
562
688
  end
689
+
690
+ test 'level 0 special sections in multipart book should be rendered as level 1' do
691
+ input = <<-EOS
692
+ = Multipart Book
693
+ Doc Writer
694
+ :doctype: book
695
+
696
+ [preface]
697
+ = Preface
698
+
699
+ Preface text
700
+
701
+ [appendix]
702
+ = Appendix
703
+
704
+ Appendix text
705
+ EOS
706
+
707
+ output = render_string input
708
+ assert_xpath '//h2[@id = "_preface"]', output, 1
709
+ assert_xpath '//h2[@id = "_appendix"]', output, 1
710
+ end
563
711
  end
564
712
 
565
713
  context "heading patterns in blocks" do
@@ -606,7 +754,7 @@ This should be a tip, not a heading.
606
754
  ====
607
755
  EOS
608
756
  output = render_string input
609
- assert_xpath "//*[@class='admonitionblock']//p[text() = 'This should be a tip, not a heading.']", output, 1
757
+ assert_xpath "//*[@class='admonitionblock tip']//p[text() = 'This should be a tip, not a heading.']", output, 1
610
758
  end
611
759
 
612
760
  test "should not match a heading in a labeled list" do
@@ -669,10 +817,9 @@ fin.
669
817
  end
670
818
 
671
819
  context 'Table of Contents' do
672
- test 'should render table of contents if toc attribute is set' do
820
+ test 'should render table of contents in header if toc attribute is set' do
673
821
  input = <<-EOS
674
- Article
675
- =======
822
+ = Article
676
823
  :toc:
677
824
 
678
825
  == Section One
@@ -692,22 +839,288 @@ While they were waiting...
692
839
  That's all she wrote!
693
840
  EOS
694
841
  output = render_string input
695
- assert_xpath '//*[@id="toc"]', output, 1
696
- assert_xpath '//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
697
- assert_xpath '//*[@id="toc"]/ol', output, 1
698
- assert_xpath '//*[@id="toc"]//ol', output, 2
699
- assert_xpath '//*[@id="toc"]/ol/li', output, 4
700
- assert_xpath '//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
701
- assert_xpath '//*[@id="toc"]/ol/li/ol/li', output, 1
702
- assert_xpath '//*[@id="toc"]/ol/li/ol/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
842
+ assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc"]', output, 1
843
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Table of Contents"]', output, 1
844
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol', output, 1
845
+ assert_xpath '//*[@id="header"]//*[@id="toc"]//ol', output, 2
846
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li', output, 4
847
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
848
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li', output, 1
849
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li/ol/li/a[@href="#_interlude"][text()="2.1. Interlude"]', output, 1
850
+ end
851
+
852
+ test 'should render table of contents in header if toc2 attribute is set' do
853
+ input = <<-EOS
854
+ = Article
855
+ :toc2:
856
+
857
+ == Section One
858
+
859
+ It was a dark and stormy night...
860
+
861
+ == Section Two
862
+
863
+ They couldn't believe their eyes when...
864
+ EOS
865
+
866
+ output = render_string input
867
+ assert_xpath '//*[@id="header"]//*[@id="toc"][@class="toc2"]', output, 1
868
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/ol/li[1]/a[@href="#_section_one"][text()="1. Section One"]', output, 1
869
+ end
870
+
871
+ test 'should use document attributes toc-class, toc-title and toclevels to create toc' do
872
+ input = <<-EOS
873
+ = Article
874
+ :toc:
875
+ :toc-title: Contents
876
+ :toc-class: toc2
877
+ :toclevels: 1
878
+
879
+ == Section 1
880
+
881
+ === Section 1.1
882
+
883
+ ==== Section 1.1.1
884
+
885
+ ==== Section 1.1.2
886
+
887
+ === Section 1.2
888
+
889
+ == Section 2
890
+
891
+ Fin.
892
+ EOS
893
+ output = render_string input
894
+ assert_css '#header #toc', output, 1
895
+ assert_css '#header #toc.toc2', output, 1
896
+ assert_css '#header #toc li', output, 2
897
+ assert_css '#header #toc #toctitle', output, 1
898
+ assert_xpath '//*[@id="header"]//*[@id="toc"]/*[@id="toctitle"][text()="Contents"]', output, 1
899
+ end
900
+
901
+ test 'should not render table of contents if toc-placement attribute is unset' do
902
+ input = <<-EOS
903
+ = Article
904
+ :toc-placement!:
905
+
906
+ == Section One
907
+
908
+ It was a dark and stormy night...
909
+
910
+ == Section Two
911
+
912
+ They couldn't believe their eyes when...
913
+ EOS
914
+
915
+ output = render_string input
916
+ assert_xpath '//*[@id="toc"]', output, 0
917
+ end
918
+
919
+ test 'should render table of contents at location of toc macro' do
920
+ input = <<-EOS
921
+ = Article
922
+ :toc:
923
+ :toc-placement!:
924
+
925
+ Once upon a time...
926
+
927
+ toc::[]
928
+
929
+ == Section One
930
+
931
+ It was a dark and stormy night...
932
+
933
+ == Section Two
934
+
935
+ They couldn't believe their eyes when...
936
+ EOS
937
+
938
+ output = render_string input
939
+ assert_css '#preamble #toc', output, 1
940
+ assert_css '#preamble .paragraph + #toc', output, 1
941
+ end
942
+
943
+ test 'should render table of contents at location of toc macro in embedded document' do
944
+ input = <<-EOS
945
+ = Article
946
+ :toc:
947
+ :toc-placement!:
948
+
949
+ Once upon a time...
950
+
951
+ toc::[]
952
+
953
+ == Section One
954
+
955
+ It was a dark and stormy night...
956
+
957
+ == Section Two
958
+
959
+ They couldn't believe their eyes when...
960
+ EOS
961
+
962
+ output = render_string input, :header_footer => false
963
+ assert_css '#preamble:root #toc', output, 1
964
+ assert_css '#preamble:root .paragraph + #toc', output, 1
965
+ end
966
+
967
+ test 'should not assign toc id to more than one toc' do
968
+ input = <<-EOS
969
+ = Article
970
+ :toc:
971
+
972
+ Once upon a time...
973
+
974
+ toc::[]
975
+
976
+ == Section One
977
+
978
+ It was a dark and stormy night...
979
+
980
+ == Section Two
981
+
982
+ They couldn't believe their eyes when...
983
+ EOS
984
+
985
+ output = render_string input
986
+
987
+ assert_css '#toc', output, 1
988
+ assert_css '#toctitle', output, 1
989
+ assert_xpath '(//*[@class="toc"])[2][not(@id)]', output, 1
990
+ assert_xpath '(//*[@class="toc"])[2]/*[@class="title"][not(@id)]', output, 1
991
+ end
992
+
993
+ test 'should use global attributes for toc-title, toc-class and toclevels for toc macro' do
994
+ input = <<-EOS
995
+ = Article
996
+ :toc:
997
+ :toc-placement!:
998
+ :toc-title: Contents
999
+ :toc-class: contents
1000
+ :toclevels: 1
1001
+
1002
+ Preamble.
1003
+
1004
+ toc::[]
1005
+
1006
+ == Section 1
1007
+
1008
+ === Section 1.1
1009
+
1010
+ ==== Section 1.1.1
1011
+
1012
+ ==== Section 1.1.2
1013
+
1014
+ === Section 1.2
1015
+
1016
+ == Section 2
1017
+
1018
+ Fin.
1019
+ EOS
1020
+
1021
+ output = render_string input
1022
+ assert_css '#toc', output, 1
1023
+ assert_css '#toctitle', output, 1
1024
+ assert_css '#preamble #toc', output, 1
1025
+ assert_css '#preamble #toc.contents', output, 1
1026
+ assert_xpath '//*[@id="toc"]/*[@class="title"][text() = "Contents"]', output, 1
1027
+ assert_css '#toc li', output, 2
1028
+ assert_xpath '(//*[@id="toc"]//li)[1]/a[text() = "1. Section 1"]', output, 1
1029
+ assert_xpath '(//*[@id="toc"]//li)[2]/a[text() = "2. Section 2"]', output, 1
1030
+ end
1031
+
1032
+ test 'should honor id, title, role and level attributes on toc macro' do
1033
+ input = <<-EOS
1034
+ = Article
1035
+ :toc:
1036
+ :toc-placement!:
1037
+ :toc-title: Ignored
1038
+ :toc-class: ignored
1039
+ :toclevels: 5
1040
+ :tocdepth: 1
1041
+
1042
+ Preamble.
1043
+
1044
+ [[contents]]
1045
+ [role="contents"]
1046
+ .Contents
1047
+ toc::[levels={tocdepth}]
1048
+
1049
+ == Section 1
1050
+
1051
+ === Section 1.1
1052
+
1053
+ ==== Section 1.1.1
1054
+
1055
+ ==== Section 1.1.2
1056
+
1057
+ === Section 1.2
1058
+
1059
+ == Section 2
1060
+
1061
+ Fin.
1062
+ EOS
1063
+
1064
+ output = render_string input
1065
+ assert_css '#toc', output, 0
1066
+ assert_css '#toctitle', output, 0
1067
+ assert_css '#preamble #contents', output, 1
1068
+ assert_css '#preamble #contents.contents', output, 1
1069
+ assert_xpath '//*[@id="contents"]/*[@class="title"][text() = "Contents"]', output, 1
1070
+ assert_css '#contents li', output, 2
1071
+ assert_xpath '(//*[@id="contents"]//li)[1]/a[text() = "1. Section 1"]', output, 1
1072
+ assert_xpath '(//*[@id="contents"]//li)[2]/a[text() = "2. Section 2"]', output, 1
703
1073
  end
704
1074
  end
705
1075
 
706
- context "book doctype" do
707
- test "document title with level 0 headings" do
1076
+ context 'article doctype' do
1077
+ test 'should create sections only in docbook backend' do
708
1078
  input = <<-EOS
709
- Book
710
- ====
1079
+ = Article
1080
+ Doc Writer
1081
+
1082
+ == Section 1
1083
+
1084
+ The adventure.
1085
+
1086
+ === Subsection One
1087
+
1088
+ It was a dark and stormy night...
1089
+
1090
+ === Subsection Two
1091
+
1092
+ They couldn't believe their eyes when...
1093
+
1094
+ == Section 2
1095
+
1096
+ The return.
1097
+
1098
+ === Subsection Three
1099
+
1100
+ While they were returning...
1101
+
1102
+ === Subsection Four
1103
+
1104
+ That's all she wrote!
1105
+ EOS
1106
+
1107
+ output = render_string input, :backend => 'docbook'
1108
+ assert_xpath '//part', output, 0
1109
+ assert_xpath '//chapter', output, 0
1110
+ assert_xpath '/article/section', output, 2
1111
+ assert_xpath '/article/section[1]/title[text() = "Section 1"]', output, 1
1112
+ assert_xpath '/article/section[2]/title[text() = "Section 2"]', output, 1
1113
+ assert_xpath '/article/section/section', output, 4
1114
+ assert_xpath '/article/section[1]/section[1]/title[text() = "Subsection One"]', output, 1
1115
+ assert_xpath '/article/section[2]/section[1]/title[text() = "Subsection Three"]', output, 1
1116
+ end
1117
+ end
1118
+
1119
+ context 'book doctype' do
1120
+ test 'document title with level 0 headings' do
1121
+ input = <<-EOS
1122
+ = Book
1123
+ Doc Writer
711
1124
  :doctype: book
712
1125
 
713
1126
  = Chapter One
@@ -734,5 +1147,94 @@ That's all she wrote!
734
1147
  assert_xpath '//h1[@id="_chapter_two"][text() = "Chapter Two"]', output, 1
735
1148
  assert_xpath '//h1[@id="_chapter_three"][text() = "Chapter Three"]', output, 1
736
1149
  end
1150
+
1151
+ test 'should create parts and chapters in docbook backend' do
1152
+ input = <<-EOS
1153
+ = Book
1154
+ Doc Writer
1155
+ :doctype: book
1156
+
1157
+ = Part 1
1158
+
1159
+ The adventure.
1160
+
1161
+ == Chapter One
1162
+
1163
+ It was a dark and stormy night...
1164
+
1165
+ == Chapter Two
1166
+
1167
+ They couldn't believe their eyes when...
1168
+
1169
+ = Part 2
1170
+
1171
+ The return.
1172
+
1173
+ == Chapter Three
1174
+
1175
+ While they were returning...
1176
+
1177
+ == Chapter Four
1178
+
1179
+ That's all she wrote!
1180
+ EOS
1181
+
1182
+ output = render_string input, :backend => 'docbook'
1183
+ assert_xpath '//chapter/chapter', output, 0
1184
+ assert_xpath '/book/part', output, 2
1185
+ assert_xpath '/book/part[1]/title[text() = "Part 1"]', output, 1
1186
+ assert_xpath '/book/part[2]/title[text() = "Part 2"]', output, 1
1187
+ assert_xpath '/book/part/chapter', output, 4
1188
+ assert_xpath '/book/part[1]/chapter[1]/title[text() = "Chapter One"]', output, 1
1189
+ assert_xpath '/book/part[2]/chapter[1]/title[text() = "Chapter Three"]', output, 1
1190
+ end
1191
+
1192
+ test 'subsections in preface and appendix should start at level 2' do
1193
+ input = <<-EOS
1194
+ = Multipart Book
1195
+ Doc Writer
1196
+ :doctype: book
1197
+
1198
+ [preface]
1199
+ = Preface
1200
+
1201
+ Preface content
1202
+
1203
+ === Preface subsection
1204
+
1205
+ Preface subsection content
1206
+
1207
+ = Part 1
1208
+
1209
+ .Part intro title
1210
+ [partintro]
1211
+ Part intro content
1212
+
1213
+ [appendix]
1214
+ = Appendix
1215
+
1216
+ Appendix content
1217
+
1218
+ === Appendix subsection
1219
+
1220
+ Appendix subsection content
1221
+ EOS
1222
+
1223
+ output = nil
1224
+ errors = nil
1225
+ redirect_streams do |stdout, stderr|
1226
+ output = render_string input, :backend => 'docbook'
1227
+ errors = stdout.string
1228
+ end
1229
+ assert errors.empty?
1230
+ assert_xpath '/book/preface', output, 1
1231
+ assert_xpath '/book/preface/section', output, 1
1232
+ assert_xpath '/book/part', output, 1
1233
+ assert_xpath '/book/part/partintro', output, 1
1234
+ assert_xpath '/book/part/partintro/title', output, 1
1235
+ assert_xpath '/book/part/partintro/simpara', output, 1
1236
+ assert_xpath '/book/appendix', output, 1
1237
+ assert_xpath '/book/appendix/section', output, 1
1238
+ end
737
1239
  end
738
1240
  end