asciidoctor 1.5.8 → 2.0.0.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +162 -17
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +12 -13
  5. data/README-fr.adoc +11 -12
  6. data/README-jp.adoc +11 -12
  7. data/README-zh_CN.adoc +12 -13
  8. data/README.adoc +6 -7
  9. data/asciidoctor.gemspec +19 -24
  10. data/bin/asciidoctor +5 -4
  11. data/data/reference/syntax.adoc +283 -0
  12. data/data/stylesheets/asciidoctor-default.css +56 -52
  13. data/data/stylesheets/coderay-asciidoctor.css +7 -9
  14. data/lib/asciidoctor.rb +171 -232
  15. data/lib/asciidoctor/abstract_block.rb +96 -105
  16. data/lib/asciidoctor/abstract_node.rb +118 -139
  17. data/lib/asciidoctor/attribute_list.rb +10 -14
  18. data/lib/asciidoctor/block.rb +20 -19
  19. data/lib/asciidoctor/callouts.rb +4 -2
  20. data/lib/asciidoctor/cli.rb +3 -2
  21. data/lib/asciidoctor/cli/invoker.rb +14 -21
  22. data/lib/asciidoctor/cli/options.rb +64 -54
  23. data/lib/asciidoctor/converter.rb +357 -185
  24. data/lib/asciidoctor/converter/composite.rb +40 -48
  25. data/lib/asciidoctor/converter/docbook5.rb +604 -640
  26. data/lib/asciidoctor/converter/html5.rb +949 -963
  27. data/lib/asciidoctor/converter/manpage.rb +569 -548
  28. data/lib/asciidoctor/converter/template.rb +231 -272
  29. data/lib/asciidoctor/core_ext.rb +5 -18
  30. data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
  31. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  32. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  33. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  34. data/lib/asciidoctor/document.rb +399 -377
  35. data/lib/asciidoctor/extensions.rb +72 -140
  36. data/lib/asciidoctor/helpers.rb +122 -83
  37. data/lib/asciidoctor/inline.rb +5 -1
  38. data/lib/asciidoctor/list.rb +13 -11
  39. data/lib/asciidoctor/logging.rb +17 -16
  40. data/lib/asciidoctor/parser.rb +390 -423
  41. data/lib/asciidoctor/path_resolver.rb +10 -5
  42. data/lib/asciidoctor/reader.rb +286 -263
  43. data/lib/asciidoctor/rouge_ext.rb +39 -0
  44. data/lib/asciidoctor/section.rb +9 -8
  45. data/lib/asciidoctor/stylesheets.rb +19 -37
  46. data/lib/asciidoctor/substitutors.rb +364 -509
  47. data/lib/asciidoctor/syntax_highlighter.rb +238 -0
  48. data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
  49. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
  50. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  51. data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
  52. data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
  53. data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
  54. data/lib/asciidoctor/table.rb +73 -66
  55. data/lib/asciidoctor/timings.rb +4 -2
  56. data/lib/asciidoctor/version.rb +2 -1
  57. data/lib/asciidoctor/writer.rb +30 -0
  58. data/man/asciidoctor.1 +19 -15
  59. data/man/asciidoctor.adoc +14 -12
  60. metadata +69 -216
  61. data/CONTRIBUTING.adoc +0 -185
  62. data/Gemfile +0 -60
  63. data/Rakefile +0 -129
  64. data/bin/asciidoctor-safe +0 -15
  65. data/features/open_block.feature +0 -92
  66. data/features/pass_block.feature +0 -66
  67. data/features/step_definitions.rb +0 -49
  68. data/features/text_formatting.feature +0 -57
  69. data/features/xref.feature +0 -1039
  70. data/lib/asciidoctor/converter/base.rb +0 -59
  71. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  72. data/lib/asciidoctor/converter/factory.rb +0 -226
  73. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  74. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  75. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  76. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  77. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  78. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  79. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  80. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  81. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  82. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  83. data/test/api_test.rb +0 -1240
  84. data/test/attribute_list_test.rb +0 -242
  85. data/test/attributes_test.rb +0 -1623
  86. data/test/blocks_test.rb +0 -3870
  87. data/test/converter_test.rb +0 -470
  88. data/test/document_test.rb +0 -1853
  89. data/test/extensions_test.rb +0 -1560
  90. data/test/fixtures/asciidoc_index.txt +0 -521
  91. data/test/fixtures/basic-docinfo-footer.html +0 -6
  92. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  93. data/test/fixtures/basic-docinfo.html +0 -1
  94. data/test/fixtures/basic-docinfo.xml +0 -4
  95. data/test/fixtures/basic.asciidoc +0 -5
  96. data/test/fixtures/chapter-a.adoc +0 -3
  97. data/test/fixtures/child-include.adoc +0 -5
  98. data/test/fixtures/circle.svg +0 -9
  99. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  100. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  101. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  102. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  103. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  104. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  105. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  106. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  107. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  108. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  109. data/test/fixtures/docinfo-footer.html +0 -1
  110. data/test/fixtures/docinfo-footer.xml +0 -9
  111. data/test/fixtures/docinfo.html +0 -1
  112. data/test/fixtures/docinfo.xml +0 -3
  113. data/test/fixtures/doctime-localtime.adoc +0 -2
  114. data/test/fixtures/dot.gif +0 -0
  115. data/test/fixtures/encoding.asciidoc +0 -13
  116. data/test/fixtures/file-with-missing-include.adoc +0 -1
  117. data/test/fixtures/grandchild-include.adoc +0 -3
  118. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  119. data/test/fixtures/include-file.asciidoc +0 -24
  120. data/test/fixtures/include-file.jsx +0 -8
  121. data/test/fixtures/include-file.ml +0 -3
  122. data/test/fixtures/include-file.xml +0 -5
  123. data/test/fixtures/lists.adoc +0 -96
  124. data/test/fixtures/master.adoc +0 -5
  125. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  126. data/test/fixtures/other-chapters.adoc +0 -11
  127. data/test/fixtures/outer-include.adoc +0 -5
  128. data/test/fixtures/parent-include-restricted.adoc +0 -5
  129. data/test/fixtures/parent-include.adoc +0 -5
  130. data/test/fixtures/sample.asciidoc +0 -30
  131. data/test/fixtures/section-a.adoc +0 -4
  132. data/test/fixtures/stylesheets/custom.css +0 -3
  133. data/test/fixtures/subdir/index.adoc +0 -3
  134. data/test/fixtures/subdir/inner-include.adoc +0 -3
  135. data/test/fixtures/subdir/middle-include.adoc +0 -5
  136. data/test/fixtures/subs-docinfo.html +0 -2
  137. data/test/fixtures/subs.adoc +0 -6
  138. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  139. data/test/fixtures/tagged-class.rb +0 -23
  140. data/test/fixtures/tip.gif +0 -0
  141. data/test/fixtures/unclosed-tag.adoc +0 -3
  142. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  143. data/test/invoker_test.rb +0 -745
  144. data/test/links_test.rb +0 -855
  145. data/test/lists_test.rb +0 -5151
  146. data/test/logger_test.rb +0 -211
  147. data/test/manpage_test.rb +0 -660
  148. data/test/options_test.rb +0 -262
  149. data/test/paragraphs_test.rb +0 -562
  150. data/test/parser_test.rb +0 -742
  151. data/test/paths_test.rb +0 -395
  152. data/test/preamble_test.rb +0 -173
  153. data/test/reader_test.rb +0 -2161
  154. data/test/sections_test.rb +0 -3575
  155. data/test/substitutions_test.rb +0 -2066
  156. data/test/tables_test.rb +0 -2036
  157. data/test/test_helper.rb +0 -447
  158. data/test/text_test.rb +0 -309
@@ -1,55 +1,47 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A {Converter} implementation that delegates to the chain of {Converter}
4
- # objects passed to the constructor. Selects the first {Converter} that
5
- # identifies itself as the handler for a given transform.
6
- class Converter::CompositeConverter < Converter::Base
3
+ # A {Converter} implementation that delegates to the chain of {Converter}
4
+ # objects passed to the constructor. Selects the first {Converter} that
5
+ # identifies itself as the handler for a given transform.
6
+ class Converter::CompositeConverter < Converter::Base
7
+ # Get the Array of Converter objects in the chain
8
+ attr_reader :converters
7
9
 
8
- # Get the Array of Converter objects in the chain
9
- attr_reader :converters
10
-
11
- def initialize backend, *converters
12
- @backend = backend
13
- (@converters = converters.flatten.compact).each do |converter|
14
- converter.composed self if converter.respond_to? :composed
15
- end
16
- @converter_map = {}
17
- end
18
-
19
- # Public: Delegates to the first converter that identifies itself as the
20
- # handler for the given transform. The optional Hash is passed as the last
21
- # option to the delegate's convert method.
22
- #
23
- # node - the AbstractNode to convert
24
- # transform - the optional String transform, or the name of the node if no
25
- # transform is specified. (default: nil)
26
- # opts - an optional Hash that is passed to the delegate's convert method. (default: {})
27
- #
28
- # Returns the String result returned from the delegate's convert method
29
- def convert node, transform = nil, opts = {}
30
- transform ||= node.node_name
31
- (converter_for transform).convert node, transform, opts
32
- end
10
+ def initialize backend, *converters, backend_traits_source: nil
11
+ @backend = backend
12
+ (@converters = converters).each {|converter| converter.composed self if converter.respond_to? :composed }
13
+ init_backend_traits backend_traits_source.backend_traits if backend_traits_source
14
+ @converter_cache = ::Hash.new {|hash, key| hash[key] = find_converter key }
15
+ end
33
16
 
34
- # Alias for backward compatibility.
35
- alias convert_with_options convert
17
+ # Public: Delegates to the first converter that identifies itself as the
18
+ # handler for the given transform. The optional Hash is passed as the last
19
+ # option to the delegate's convert method.
20
+ #
21
+ # node - the AbstractNode to convert
22
+ # transform - the optional String transform, or the name of the node if no
23
+ # transform is specified. (default: nil)
24
+ # opts - an optional Hash that is passed to the delegate's convert method. (default: nil)
25
+ #
26
+ # Returns the String result returned from the delegate's convert method
27
+ def convert node, transform = nil, opts = nil
28
+ (converter_for transform ||= node.node_name).convert node, transform, opts
29
+ end
36
30
 
37
- # Public: Retrieve the converter for the specified transform.
38
- #
39
- # Returns the matching [Converter] object
40
- def converter_for transform
41
- @converter_map[transform] ||= (find_converter transform)
42
- end
31
+ # Public: Retrieve the converter for the specified transform.
32
+ #
33
+ # Returns the matching [Converter] object
34
+ def converter_for transform
35
+ @converter_cache[transform]
36
+ end
43
37
 
44
- # Internal: Find the converter for the specified transform.
45
- # Raise an exception if no converter is found.
46
- #
47
- # Returns the matching [Converter] object
48
- def find_converter transform
49
- @converters.each do |candidate|
50
- return candidate if candidate.handles? transform
51
- end
52
- raise %(Could not find a converter to handle transform: #{transform})
53
- end
38
+ # Public: Find the converter for the specified transform.
39
+ # Raise an exception if no converter is found.
40
+ #
41
+ # Returns the matching [Converter] object
42
+ def find_converter transform
43
+ @converters.each {|candidate| return candidate if candidate.handles? transform }
44
+ raise %(Could not find a converter to handle transform: #{transform})
54
45
  end
55
46
  end
47
+ end
@@ -1,815 +1,779 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A built-in {Converter} implementation that generates DocBook 5 output
4
- # similar to the docbook45 backend from AsciiDoc Python, but migrated to the
5
- # DocBook 5 specification.
6
- class Converter::DocBook5Converter < Converter::BuiltIn
7
- CopyrightRx = /^(.+?)(?: ((?:\d{4}\-)?\d{4}))?$/
8
- ImageMacroRx = /^image::?(.+?)\[(.*?)\]$/
9
-
10
- def document node
11
- result = []
12
- if (root_tag_name = node.doctype) == 'manpage'
13
- root_tag_name = 'refentry'
14
- end
15
- result << '<?xml version="1.0" encoding="UTF-8"?>'
16
- if (doctype_line = doctype_declaration root_tag_name)
17
- result << doctype_line
18
- end
19
- if node.attr? 'toc'
20
- if node.attr? 'toclevels'
21
- result << %(<?asciidoc-toc maxdepth="#{node.attr 'toclevels'}"?>)
22
- else
23
- result << '<?asciidoc-toc?>'
24
- end
25
- end
26
- if node.attr? 'sectnums'
27
- if node.attr? 'sectnumlevels'
28
- result << %(<?asciidoc-numbered maxdepth="#{node.attr 'sectnumlevels'}"?>)
29
- else
30
- result << '<?asciidoc-numbered?>'
31
- end
3
+ # A built-in {Converter} implementation that generates DocBook 5 output. The output is inspired by the output produced
4
+ # by the docbook45 backend from AsciiDoc Python, except it has been migrated to the DocBook 5 specification.
5
+ class Converter::DocBook5Converter < Converter::Base
6
+ register_for 'docbook5'
7
+
8
+ # default represents variablelist
9
+ (DLIST_TAGS = {
10
+ 'qanda' => { list: 'qandaset', entry: 'qandaentry', label: 'question', term: 'simpara', item: 'answer' },
11
+ 'glossary' => { list: nil, entry: 'glossentry', term: 'glossterm', item: 'glossdef' },
12
+ }).default = { list: 'variablelist', entry: 'varlistentry', term: 'term', item: 'listitem' }
13
+
14
+ (QUOTE_TAGS = {
15
+ monospaced: ['<literal>', '</literal>'],
16
+ emphasis: ['<emphasis>', '</emphasis>', true],
17
+ strong: ['<emphasis role="strong">', '</emphasis>', true],
18
+ double: ['<quote>', '</quote>', true],
19
+ single: ['<quote>', '</quote>', true],
20
+ mark: ['<emphasis role="marked">', '</emphasis>'],
21
+ superscript: ['<superscript>', '</superscript>'],
22
+ subscript: ['<subscript>', '</subscript>'],
23
+ }).default = ['', '', true]
24
+
25
+ MANPAGE_SECTION_TAGS = { 'section' => 'refsection', 'synopsis' => 'refsynopsisdiv' }
26
+ TABLE_PI_NAMES = ['dbhtml', 'dbfo', 'dblatex']
27
+
28
+ CopyrightRx = /^(.+?)(?: ((?:\d{4}\-)?\d{4}))?$/
29
+ ImageMacroRx = /^image::?(.+?)\[(.*?)\]$/
30
+
31
+ def initialize backend, opts = {}
32
+ @backend = backend
33
+ init_backend_traits basebackend: 'docbook', filetype: 'xml', outfilesuffix: '.xml', supports_templates: true
34
+ end
35
+
36
+ def document node
37
+ result = ['<?xml version="1.0" encoding="UTF-8"?>']
38
+ if node.attr? 'toc'
39
+ if node.attr? 'toclevels'
40
+ result << %(<?asciidoc-toc maxdepth="#{node.attr 'toclevels'}"?>)
41
+ else
42
+ result << '<?asciidoc-toc?>'
32
43
  end
33
- lang_attribute = (node.attr? 'nolang') ? '' : %( #{lang_attribute_name}="#{node.attr 'lang', 'en'}")
34
- result << %(<#{root_tag_name}#{document_ns_attributes node}#{lang_attribute}>)
35
- result << (document_info_tag node, root_tag_name) unless node.noheader
36
- result << node.content if node.blocks?
37
- unless (footer_docinfo = node.docinfo :footer).empty?
38
- result << footer_docinfo
44
+ end
45
+ if node.attr? 'sectnums'
46
+ if node.attr? 'sectnumlevels'
47
+ result << %(<?asciidoc-numbered maxdepth="#{node.attr 'sectnumlevels'}"?>)
48
+ else
49
+ result << '<?asciidoc-numbered?>'
39
50
  end
40
- result << %(</#{root_tag_name}>)
41
- result.join LF
42
51
  end
52
+ lang_attribute = (node.attr? 'nolang') ? '' : %( xml:lang="#{node.attr 'lang', 'en'}")
53
+ if (root_tag_name = node.doctype) == 'manpage'
54
+ root_tag_name = 'refentry'
55
+ end
56
+ result << %(<#{root_tag_name} xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"#{lang_attribute}#{_common_attributes node.id}>)
57
+ result << (_document_info_tag node) unless node.noheader
58
+ unless (docinfo_content = node.docinfo :header).empty?
59
+ result << docinfo_content
60
+ end
61
+ result << node.content if node.blocks?
62
+ unless (docinfo_content = node.docinfo :footer).empty?
63
+ result << docinfo_content
64
+ end
65
+ result << %(</#{root_tag_name}>)
66
+ result.join LF
67
+ end
43
68
 
44
- alias embedded content
45
-
46
- MANPAGE_SECTION_TAGS = { 'section' => 'refsection', 'synopsis' => 'refsynopsisdiv' }
69
+ alias embedded _content_only
47
70
 
48
- def section node
49
- if node.document.doctype == 'manpage'
50
- tag_name = MANPAGE_SECTION_TAGS[tag_name = node.sectname] || tag_name
51
- else
52
- tag_name = node.sectname
53
- end
54
- title_el = node.special && (node.option? 'untitled') ? '' : %(<title>#{node.title}</title>\n)
55
- %(<#{tag_name}#{common_attributes node.id, node.role, node.reftext}>
71
+ def section node
72
+ if node.document.doctype == 'manpage'
73
+ tag_name = MANPAGE_SECTION_TAGS[tag_name = node.sectname] || tag_name
74
+ else
75
+ tag_name = node.sectname
76
+ end
77
+ title_el = node.special && (node.option? 'untitled') ? '' : %(<title>#{node.title}</title>\n)
78
+ %(<#{tag_name}#{_common_attributes node.id, node.role, node.reftext}>
56
79
  #{title_el}#{node.content}
57
80
  </#{tag_name}>)
58
- end
81
+ end
59
82
 
60
- def admonition node
61
- %(<#{tag_name = node.attr 'name'}#{common_attributes node.id, node.role, node.reftext}>
62
- #{title_tag node}#{resolve_content node}
83
+ def admonition node
84
+ %(<#{tag_name = node.attr 'name'}#{_common_attributes node.id, node.role, node.reftext}>
85
+ #{_title_tag node}#{_enclose_content node}
63
86
  </#{tag_name}>)
64
- end
87
+ end
65
88
 
66
- alias audio skip
89
+ alias audio _skip
67
90
 
68
- def colist node
69
- result = []
70
- result << %(<calloutlist#{common_attributes node.id, node.role, node.reftext}>)
71
- result << %(<title>#{node.title}</title>) if node.title?
72
- node.items.each do |item|
73
- result << %(<callout arearefs="#{item.attr 'coids'}">)
74
- result << %(<para>#{item.text}</para>)
75
- result << item.content if item.blocks?
76
- result << '</callout>'
77
- end
78
- result << %(</calloutlist>)
79
- result.join LF
91
+ def colist node
92
+ result = []
93
+ result << %(<calloutlist#{_common_attributes node.id, node.role, node.reftext}>)
94
+ result << %(<title>#{node.title}</title>) if node.title?
95
+ node.items.each do |item|
96
+ result << %(<callout arearefs="#{item.attr 'coids'}">)
97
+ result << %(<para>#{item.text}</para>)
98
+ result << item.content if item.blocks?
99
+ result << '</callout>'
80
100
  end
101
+ result << %(</calloutlist>)
102
+ result.join LF
103
+ end
81
104
 
82
- (DLIST_TAGS = {
83
- 'qanda' => {
84
- :list => 'qandaset',
85
- :entry => 'qandaentry',
86
- :label => 'question',
87
- :term => 'simpara',
88
- :item => 'answer'
89
- },
90
- 'glossary' => {
91
- :list => nil,
92
- :entry => 'glossentry',
93
- :term => 'glossterm',
94
- :item => 'glossdef'
95
- }
96
- }).default = { # default is variable
97
- :list => 'variablelist',
98
- :entry => 'varlistentry',
99
- :term => 'term',
100
- :item => 'listitem'
101
- }
102
-
103
- def dlist node
104
- result = []
105
- if node.style == 'horizontal'
106
- result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext} tabstyle="horizontal" frame="none" colsep="0" rowsep="0">
107
- #{title_tag node}<tgroup cols="2">
105
+ def dlist node
106
+ result = []
107
+ if node.style == 'horizontal'
108
+ result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{_common_attributes node.id, node.role, node.reftext} tabstyle="horizontal" frame="none" colsep="0" rowsep="0">
109
+ #{_title_tag node}<tgroup cols="2">
108
110
  <colspec colwidth="#{node.attr 'labelwidth', 15}*"/>
109
111
  <colspec colwidth="#{node.attr 'itemwidth', 85}*"/>
110
112
  <tbody valign="top">)
111
- node.items.each do |terms, dd|
112
- result << %(<row>
113
+ node.items.each do |terms, dd|
114
+ result << %(<row>
113
115
  <entry>)
114
- [*terms].each do |dt|
115
- result << %(<simpara>#{dt.text}</simpara>)
116
- end
117
- result << %(</entry>
116
+ terms.each {|dt| result << %(<simpara>#{dt.text}</simpara>) }
117
+ result << %(</entry>
118
118
  <entry>)
119
- if dd
120
- result << %(<simpara>#{dd.text}</simpara>) if dd.text?
121
- result << dd.content if dd.blocks?
122
- end
123
- result << %(</entry>
124
- </row>)
119
+ if dd
120
+ result << %(<simpara>#{dd.text}</simpara>) if dd.text?
121
+ result << dd.content if dd.blocks?
125
122
  end
126
- result << %(</tbody>
123
+ result << %(</entry>
124
+ </row>)
125
+ end
126
+ result << %(</tbody>
127
127
  </tgroup>
128
128
  </#{tag_name}>)
129
- else
130
- tags = DLIST_TAGS[node.style]
131
- list_tag = tags[:list]
132
- entry_tag = tags[:entry]
133
- label_tag = tags[:label]
134
- term_tag = tags[:term]
135
- item_tag = tags[:item]
136
- if list_tag
137
- result << %(<#{list_tag}#{common_attributes node.id, node.role, node.reftext}>)
138
- result << %(<title>#{node.title}</title>) if node.title?
139
- end
140
-
141
- node.items.each do |terms, dd|
142
- result << %(<#{entry_tag}>)
143
- result << %(<#{label_tag}>) if label_tag
144
-
145
- [*terms].each do |dt|
146
- result << %(<#{term_tag}>#{dt.text}</#{term_tag}>)
147
- end
129
+ else
130
+ tags = DLIST_TAGS[node.style]
131
+ list_tag = tags[:list]
132
+ entry_tag = tags[:entry]
133
+ label_tag = tags[:label]
134
+ term_tag = tags[:term]
135
+ item_tag = tags[:item]
136
+ if list_tag
137
+ result << %(<#{list_tag}#{_common_attributes node.id, node.role, node.reftext}>)
138
+ result << %(<title>#{node.title}</title>) if node.title?
139
+ end
148
140
 
149
- result << %(</#{label_tag}>) if label_tag
150
- result << %(<#{item_tag}>)
151
- if dd
152
- result << %(<simpara>#{dd.text}</simpara>) if dd.text?
153
- result << dd.content if dd.blocks?
154
- end
155
- result << %(</#{item_tag}>)
156
- result << %(</#{entry_tag}>)
141
+ node.items.each do |terms, dd|
142
+ result << %(<#{entry_tag}>)
143
+ result << %(<#{label_tag}>) if label_tag
144
+ terms.each {|dt| result << %(<#{term_tag}>#{dt.text}</#{term_tag}>) }
145
+ result << %(</#{label_tag}>) if label_tag
146
+ result << %(<#{item_tag}>)
147
+ if dd
148
+ result << %(<simpara>#{dd.text}</simpara>) if dd.text?
149
+ result << dd.content if dd.blocks?
157
150
  end
158
-
159
- result << %(</#{list_tag}>) if list_tag
151
+ result << %(</#{item_tag}>)
152
+ result << %(</#{entry_tag}>)
160
153
  end
161
154
 
162
- result.join LF
155
+ result << %(</#{list_tag}>) if list_tag
163
156
  end
164
157
 
165
- def example node
166
- if node.title?
167
- %(<example#{common_attributes node.id, node.role, node.reftext}>
158
+ result.join LF
159
+ end
160
+
161
+ def example node
162
+ if node.title?
163
+ %(<example#{_common_attributes node.id, node.role, node.reftext}>
168
164
  <title>#{node.title}</title>
169
- #{resolve_content node}
165
+ #{_enclose_content node}
170
166
  </example>)
171
- else
172
- %(<informalexample#{common_attributes node.id, node.role, node.reftext}>
173
- #{resolve_content node}
167
+ else
168
+ %(<informalexample#{_common_attributes node.id, node.role, node.reftext}>
169
+ #{_enclose_content node}
174
170
  </informalexample>)
175
- end
176
171
  end
172
+ end
177
173
 
178
- def floating_title node
179
- %(<bridgehead#{common_attributes node.id, node.role, node.reftext} renderas="sect#{node.level}">#{node.title}</bridgehead>)
180
- end
174
+ def floating_title node
175
+ %(<bridgehead#{_common_attributes node.id, node.role, node.reftext} renderas="sect#{node.level}">#{node.title}</bridgehead>)
176
+ end
181
177
 
182
- def image node
183
- # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
184
- # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
185
- if node.attr? 'scaledwidth'
186
- width_attribute = %( width="#{node.attr 'scaledwidth'}")
187
- depth_attribute = ''
188
- scale_attribute = ''
189
- elsif node.attr? 'scale'
190
- # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
191
- #width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
192
- #depth_attribute = (node.attr? 'height') ? %( depth="#{node.attr 'height'}") : ''
193
- scale_attribute = %( scale="#{node.attr 'scale'}")
194
- else
195
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
196
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
197
- scale_attribute = ''
198
- end
199
- align_attribute = (node.attr? 'align') ? %( align="#{node.attr 'align'}") : ''
178
+ def image node
179
+ # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
180
+ # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
181
+ if node.attr? 'scaledwidth'
182
+ width_attribute = %( width="#{node.attr 'scaledwidth'}")
183
+ depth_attribute = ''
184
+ scale_attribute = ''
185
+ elsif node.attr? 'scale'
186
+ # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
187
+ #width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
188
+ #depth_attribute = (node.attr? 'height') ? %( depth="#{node.attr 'height'}") : ''
189
+ scale_attribute = %( scale="#{node.attr 'scale'}")
190
+ else
191
+ width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
192
+ depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
193
+ scale_attribute = ''
194
+ end
195
+ align_attribute = (node.attr? 'align') ? %( align="#{node.attr 'align'}") : ''
200
196
 
201
- mediaobject = %(<mediaobject>
197
+ mediaobject = %(<mediaobject>
202
198
  <imageobject>
203
199
  <imagedata fileref="#{node.image_uri(node.attr 'target')}"#{width_attribute}#{depth_attribute}#{scale_attribute}#{align_attribute}/>
204
200
  </imageobject>
205
201
  <textobject><phrase>#{node.alt}</phrase></textobject>
206
202
  </mediaobject>)
207
203
 
208
- if node.title?
209
- %(<figure#{common_attributes node.id, node.role, node.reftext}>
204
+ if node.title?
205
+ %(<figure#{_common_attributes node.id, node.role, node.reftext}>
210
206
  <title>#{node.title}</title>
211
207
  #{mediaobject}
212
208
  </figure>)
213
- else
214
- %(<informalfigure#{common_attributes node.id, node.role, node.reftext}>
209
+ else
210
+ %(<informalfigure#{_common_attributes node.id, node.role, node.reftext}>
215
211
  #{mediaobject}
216
212
  </informalfigure>)
217
- end
218
213
  end
214
+ end
219
215
 
220
- def listing node
221
- informal = !node.title?
222
- listing_attributes = (common_attributes node.id, node.role, node.reftext)
223
- if node.style == 'source' && ((attrs = node.attributes).key? 'language')
224
- if attrs.key? 'linenums'
225
- if attrs.key? 'start'
226
- numbering_attributes = %( linenumbering="numbered" startinglinenumber="#{attrs['start'].to_i}")
227
- else
228
- numbering_attributes = ' linenumbering="numbered"'
229
- end
230
- else
231
- numbering_attributes = ' linenumbering="unnumbered"'
232
- end
233
- listing_content = %(<programlisting#{informal ? listing_attributes : ''} language="#{attrs['language']}"#{numbering_attributes}>#{node.content}</programlisting>)
216
+ def listing node
217
+ informal = !node.title?
218
+ common_attrs = _common_attributes node.id, node.role, node.reftext
219
+ if node.style == 'source'
220
+ if (attrs = node.attributes).key? 'linenums'
221
+ numbering_attrs = (attrs.key? 'start') ? %( linenumbering="numbered" startinglinenumber="#{attrs['start'].to_i}") : ' linenumbering="numbered"'
234
222
  else
235
- listing_content = %(<screen#{informal ? listing_attributes : ''}>#{node.content}</screen>)
223
+ numbering_attrs = ' linenumbering="unnumbered"'
236
224
  end
237
- if informal
238
- listing_content
225
+ if attrs.key? 'language'
226
+ wrapped_content = %(<programlisting#{informal ? common_attrs : ''} language="#{attrs['language']}"#{numbering_attrs}>#{node.content}</programlisting>)
239
227
  else
240
- %(<formalpara#{listing_attributes}>
228
+ wrapped_content = %(<screen#{informal ? common_attrs : ''}#{numbering_attrs}>#{node.content}</screen>)
229
+ end
230
+ else
231
+ wrapped_content = %(<screen#{informal ? common_attrs : ''}>#{node.content}</screen>)
232
+ end
233
+ informal ? wrapped_content : %(<formalpara#{common_attrs}>
241
234
  <title>#{node.title}</title>
242
235
  <para>
243
- #{listing_content}
236
+ #{wrapped_content}
244
237
  </para>
245
238
  </formalpara>)
246
- end
247
- end
239
+ end
248
240
 
249
- def literal node
250
- if node.title?
251
- %(<formalpara#{common_attributes node.id, node.role, node.reftext}>
241
+ def literal node
242
+ if node.title?
243
+ %(<formalpara#{_common_attributes node.id, node.role, node.reftext}>
252
244
  <title>#{node.title}</title>
253
245
  <para>
254
246
  <literallayout class="monospaced">#{node.content}</literallayout>
255
247
  </para>
256
248
  </formalpara>)
257
- else
258
- %(<literallayout#{common_attributes node.id, node.role, node.reftext} class="monospaced">#{node.content}</literallayout>)
259
- end
249
+ else
250
+ %(<literallayout#{_common_attributes node.id, node.role, node.reftext} class="monospaced">#{node.content}</literallayout>)
260
251
  end
252
+ end
261
253
 
262
- def stem node
263
- if (idx = node.subs.index :specialcharacters)
264
- node.subs.delete_at idx
265
- equation = node.content
266
- idx > 0 ? (node.subs.insert idx, :specialcharacters) : (node.subs.unshift :specialcharacters)
267
- else
268
- equation = node.content
269
- end
270
- if node.style == 'asciimath'
271
- if (@asciimath ||= ((defined? ::AsciiMath) || (Helpers.require_library 'asciimath', true, :warn)).nil? ? :unavailable : :loaded) == :loaded
272
- # NOTE fop requires jeuclid to process raw mathml
273
- equation_data = (::AsciiMath.parse equation).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'
274
- else
275
- equation_data = %(<mathphrase><![CDATA[#{equation}]]></mathphrase>)
276
- end
277
- else
278
- # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
279
- equation_data = %(<alt><![CDATA[#{equation}]]></alt>
254
+ alias pass _content_only
255
+
256
+ def stem node
257
+ if (idx = node.subs.index :specialcharacters)
258
+ node.subs.delete_at idx
259
+ equation = node.content || ''
260
+ idx > 0 ? (node.subs.insert idx, :specialcharacters) : (node.subs.unshift :specialcharacters)
261
+ else
262
+ equation = node.content || ''
263
+ end
264
+ if node.style == 'asciimath'
265
+ # NOTE fop requires jeuclid to process mathml markup
266
+ equation_data = _asciimath_available? ? ((::AsciiMath.parse equation).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML') : %(<mathphrase><![CDATA[#{equation}]]></mathphrase>)
267
+ else
268
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
269
+ equation_data = %(<alt><![CDATA[#{equation}]]></alt>
280
270
  <mathphrase><![CDATA[#{equation}]]></mathphrase>)
281
- end
282
- if node.title?
283
- %(<equation#{common_attributes node.id, node.role, node.reftext}>
271
+ end
272
+ if node.title?
273
+ %(<equation#{_common_attributes node.id, node.role, node.reftext}>
284
274
  <title>#{node.title}</title>
285
275
  #{equation_data}
286
276
  </equation>)
287
- else
288
- # WARNING dblatex displays the <informalequation> element inline instead of block as documented (except w/ mathml)
289
- %(<informalequation#{common_attributes node.id, node.role, node.reftext}>
277
+ else
278
+ # WARNING dblatex displays the <informalequation> element inline instead of block as documented (except w/ mathml)
279
+ %(<informalequation#{_common_attributes node.id, node.role, node.reftext}>
290
280
  #{equation_data}
291
281
  </informalequation>)
292
- end
293
282
  end
283
+ end
294
284
 
295
- def olist node
296
- result = []
297
- num_attribute = node.style ? %( numeration="#{node.style}") : ''
298
- start_attribute = (node.attr? 'start') ? %( startingnumber="#{node.attr 'start'}") : ''
299
- result << %(<orderedlist#{common_attributes node.id, node.role, node.reftext}#{num_attribute}#{start_attribute}>)
300
- result << %(<title>#{node.title}</title>) if node.title?
301
- node.items.each do |item|
302
- result << '<listitem>'
303
- result << %(<simpara>#{item.text}</simpara>)
304
- result << item.content if item.blocks?
305
- result << '</listitem>'
306
- end
307
- result << %(</orderedlist>)
308
- result.join LF
309
- end
285
+ def olist node
286
+ result = []
287
+ num_attribute = node.style ? %( numeration="#{node.style}") : ''
288
+ start_attribute = (node.attr? 'start') ? %( startingnumber="#{node.attr 'start'}") : ''
289
+ result << %(<orderedlist#{_common_attributes node.id, node.role, node.reftext}#{num_attribute}#{start_attribute}>)
290
+ result << %(<title>#{node.title}</title>) if node.title?
291
+ node.items.each do |item|
292
+ result << %(<listitem#{_common_attributes item.id, item.role}>)
293
+ result << %(<simpara>#{item.text}</simpara>)
294
+ result << item.content if item.blocks?
295
+ result << '</listitem>'
296
+ end
297
+ result << %(</orderedlist>)
298
+ result.join LF
299
+ end
310
300
 
311
- def open node
312
- case node.style
313
- when 'abstract'
314
- if node.parent == node.document && node.document.doctype == 'book'
315
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
316
- ''
317
- else
318
- %(<abstract>
319
- #{title_tag node}#{resolve_content node}
301
+ def open node
302
+ case node.style
303
+ when 'abstract'
304
+ if node.parent == node.document && node.document.doctype == 'book'
305
+ logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
306
+ ''
307
+ else
308
+ %(<abstract>
309
+ #{_title_tag node}#{_enclose_content node}
320
310
  </abstract>)
321
- end
322
- when 'partintro'
323
- unless node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
324
- logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
325
- ''
326
- else
327
- %(<partintro#{common_attributes node.id, node.role, node.reftext}>
328
- #{title_tag node}#{resolve_content node}
329
- </partintro>)
330
- end
311
+ end
312
+ when 'partintro'
313
+ unless node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
314
+ logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
315
+ ''
331
316
  else
332
- reftext = node.reftext if (id = node.id)
333
- role = node.role
334
- if node.title?
335
- %(<formalpara#{common_attributes id, role, reftext}>
317
+ %(<partintro#{_common_attributes node.id, node.role, node.reftext}>
318
+ #{_title_tag node}#{_enclose_content node}
319
+ </partintro>)
320
+ end
321
+ else
322
+ reftext = node.reftext if (id = node.id)
323
+ role = node.role
324
+ if node.title?
325
+ %(<formalpara#{_common_attributes id, role, reftext}>
336
326
  <title>#{node.title}</title>
337
327
  <para>#{content_spacer = node.content_model == :compound ? LF : ''}#{node.content}#{content_spacer}</para>
338
328
  </formalpara>)
339
- elsif id || role
340
- if node.content_model == :compound
341
- %(<para#{common_attributes id, role, reftext}>
329
+ elsif id || role
330
+ if node.content_model == :compound
331
+ %(<para#{_common_attributes id, role, reftext}>
342
332
  #{node.content}
343
333
  </para>)
344
- else
345
- %(<simpara#{common_attributes id, role, reftext}>#{node.content}</simpara>)
346
- end
347
334
  else
348
- resolve_content node
335
+ %(<simpara#{_common_attributes id, role, reftext}>#{node.content}</simpara>)
349
336
  end
337
+ else
338
+ _enclose_content node
350
339
  end
351
340
  end
341
+ end
352
342
 
353
- def page_break node
354
- '<simpara><?asciidoc-pagebreak?></simpara>'
355
- end
343
+ def page_break node
344
+ '<simpara><?asciidoc-pagebreak?></simpara>'
345
+ end
356
346
 
357
- def paragraph node
358
- if node.title?
359
- %(<formalpara#{common_attributes node.id, node.role, node.reftext}>
347
+ def paragraph node
348
+ if node.title?
349
+ %(<formalpara#{_common_attributes node.id, node.role, node.reftext}>
360
350
  <title>#{node.title}</title>
361
351
  <para>#{node.content}</para>
362
352
  </formalpara>)
363
- else
364
- %(<simpara#{common_attributes node.id, node.role, node.reftext}>#{node.content}</simpara>)
365
- end
353
+ else
354
+ %(<simpara#{_common_attributes node.id, node.role, node.reftext}>#{node.content}</simpara>)
366
355
  end
356
+ end
367
357
 
368
- def preamble node
369
- if node.document.doctype == 'book'
370
- %(<preface#{common_attributes node.id, node.role, node.reftext}>
371
- #{title_tag node, false}#{node.content}
358
+ def preamble node
359
+ if node.document.doctype == 'book'
360
+ %(<preface#{_common_attributes node.id, node.role, node.reftext}>
361
+ #{_title_tag node, false}#{node.content}
372
362
  </preface>)
373
- else
374
- node.content
375
- end
363
+ else
364
+ node.content
376
365
  end
366
+ end
377
367
 
378
- def quote node
379
- blockquote_tag(node, (node.has_role? 'epigraph') && 'epigraph') { resolve_content node }
380
- end
368
+ def quote node
369
+ _blockquote_tag(node, (node.has_role? 'epigraph') && 'epigraph') { _enclose_content node }
370
+ end
381
371
 
382
- def thematic_break node
383
- '<simpara><?asciidoc-hr?></simpara>'
384
- end
372
+ def thematic_break node
373
+ '<simpara><?asciidoc-hr?></simpara>'
374
+ end
385
375
 
386
- def sidebar node
387
- %(<sidebar#{common_attributes node.id, node.role, node.reftext}>
388
- #{title_tag node}#{resolve_content node}
376
+ def sidebar node
377
+ %(<sidebar#{_common_attributes node.id, node.role, node.reftext}>
378
+ #{_title_tag node}#{_enclose_content node}
389
379
  </sidebar>)
390
- end
391
-
392
- TABLE_PI_NAMES = ['dbhtml', 'dbfo', 'dblatex']
380
+ end
393
381
 
394
- def table node
395
- has_body = false
396
- result = []
397
- pgwide_attribute = (node.option? 'pgwide') ? ' pgwide="1"' : ''
398
- if (frame = node.attr 'frame', 'all') == 'ends'
399
- frame = 'topbot'
400
- end
401
- result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{frame}" rowsep="#{['none', 'cols'].include?(node.attr 'grid') ? 0 : 1}" colsep="#{['none', 'rows'].include?(node.attr 'grid') ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', false) ? ' orient="land"' : ''}>)
402
- if (node.option? 'unbreakable')
403
- result << '<?dbfo keep-together="always"?>'
404
- elsif (node.option? 'breakable')
405
- result << '<?dbfo keep-together="auto"?>'
406
- end
407
- result << %(<title>#{node.title}</title>) if tag_name == 'table'
408
- col_width_key = if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
409
- TABLE_PI_NAMES.each do |pi_name|
410
- result << %(<?#{pi_name} table-width="#{width}"?>)
411
- end
412
- 'colabswidth'
413
- else
414
- 'colpcwidth'
415
- end
416
- result << %(<tgroup cols="#{node.attr 'colcount'}">)
417
- node.columns.each do |col|
418
- result << %(<colspec colname="col_#{col.attr 'colnumber'}" colwidth="#{col.attr col_width_key}*"/>)
419
- end
420
- node.rows.by_section.each do |tsec, rows|
421
- next if rows.empty?
422
- has_body = true if tsec == :body
423
- result << %(<t#{tsec}>)
424
- rows.each do |row|
425
- result << '<row>'
426
- row.each do |cell|
427
- halign_attribute = (cell.attr? 'halign') ? %( align="#{cell.attr 'halign'}") : ''
428
- valign_attribute = (cell.attr? 'valign') ? %( valign="#{cell.attr 'valign'}") : ''
429
- colspan_attribute = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{colnum + cell.colspan - 1}") : ''
430
- rowspan_attribute = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
431
- # NOTE <entry> may not have whitespace (e.g., line breaks) as a direct descendant according to DocBook rules
432
- entry_start = %(<entry#{halign_attribute}#{valign_attribute}#{colspan_attribute}#{rowspan_attribute}>)
433
- if tsec == :head
434
- cell_content = cell.text
382
+ def table node
383
+ has_body = false
384
+ result = []
385
+ pgwide_attribute = (node.option? 'pgwide') ? ' pgwide="1"' : ''
386
+ if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
387
+ frame = 'topbot'
388
+ end
389
+ grid = node.attr 'grid', nil, 'table-grid'
390
+ result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{_common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{frame}" rowsep="#{['none', 'cols'].include?(grid) ? 0 : 1}" colsep="#{['none', 'rows'].include?(grid) ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', 'table-orientation') ? ' orient="land"' : ''}>)
391
+ if (node.option? 'unbreakable')
392
+ result << '<?dbfo keep-together="always"?>'
393
+ elsif (node.option? 'breakable')
394
+ result << '<?dbfo keep-together="auto"?>'
395
+ end
396
+ result << %(<title>#{node.title}</title>) if tag_name == 'table'
397
+ col_width_key = if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
398
+ TABLE_PI_NAMES.each do |pi_name|
399
+ result << %(<?#{pi_name} table-width="#{width}"?>)
400
+ end
401
+ 'colabswidth'
402
+ else
403
+ 'colpcwidth'
404
+ end
405
+ result << %(<tgroup cols="#{node.attr 'colcount'}">)
406
+ node.columns.each do |col|
407
+ result << %(<colspec colname="col_#{col.attr 'colnumber'}" colwidth="#{col.attr col_width_key}*"/>)
408
+ end
409
+ node.rows.to_h.each do |tsec, rows|
410
+ next if rows.empty?
411
+ has_body = true if tsec == :body
412
+ result << %(<t#{tsec}>)
413
+ rows.each do |row|
414
+ result << '<row>'
415
+ row.each do |cell|
416
+ halign_attribute = (cell.attr? 'halign') ? %( align="#{cell.attr 'halign'}") : ''
417
+ valign_attribute = (cell.attr? 'valign') ? %( valign="#{cell.attr 'valign'}") : ''
418
+ colspan_attribute = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{colnum + cell.colspan - 1}") : ''
419
+ rowspan_attribute = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
420
+ # NOTE <entry> may not have whitespace (e.g., line breaks) as a direct descendant according to DocBook rules
421
+ entry_start = %(<entry#{halign_attribute}#{valign_attribute}#{colspan_attribute}#{rowspan_attribute}>)
422
+ if tsec == :head
423
+ cell_content = cell.text
424
+ else
425
+ case cell.style
426
+ when :asciidoc
427
+ cell_content = cell.content
428
+ when :literal
429
+ cell_content = %(<literallayout class="monospaced">#{cell.text}</literallayout>)
430
+ when :header
431
+ cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara><emphasis role="strong">#{cell_content.join '</emphasis></simpara><simpara><emphasis role="strong">'}</emphasis></simpara>)
435
432
  else
436
- case cell.style
437
- when :asciidoc
438
- cell_content = cell.content
439
- when :verse
440
- cell_content = %(<literallayout>#{cell.text}</literallayout>)
441
- when :literal
442
- cell_content = %(<literallayout class="monospaced">#{cell.text}</literallayout>)
443
- when :header
444
- cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara><emphasis role="strong">#{cell_content.join '</emphasis></simpara><simpara><emphasis role="strong">'}</emphasis></simpara>)
445
- else
446
- cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara>#{cell_content.join '</simpara><simpara>'}</simpara>)
447
- end
433
+ cell_content = (cell_content = cell.content).empty? ? '' : %(<simpara>#{cell_content.join '</simpara><simpara>'}</simpara>)
448
434
  end
449
- entry_end = (node.document.attr? 'cellbgcolor') ? %(<?dbfo bgcolor="#{node.document.attr 'cellbgcolor'}"?></entry>) : '</entry>'
450
- result << %(#{entry_start}#{cell_content}#{entry_end})
451
435
  end
452
- result << '</row>'
436
+ entry_end = (node.document.attr? 'cellbgcolor') ? %(<?dbfo bgcolor="#{node.document.attr 'cellbgcolor'}"?></entry>) : '</entry>'
437
+ result << %(#{entry_start}#{cell_content}#{entry_end})
453
438
  end
454
- result << %(</t#{tsec}>)
439
+ result << '</row>'
455
440
  end
456
- result << '</tgroup>'
457
- result << %(</#{tag_name}>)
458
-
459
- logger.warn 'tables must have at least one body row' unless has_body
460
- result.join LF
441
+ result << %(</t#{tsec}>)
461
442
  end
443
+ result << '</tgroup>'
444
+ result << %(</#{tag_name}>)
462
445
 
463
- alias toc skip
446
+ logger.warn 'tables must have at least one body row' unless has_body
447
+ result.join LF
448
+ end
464
449
 
465
- def ulist node
466
- result = []
467
- if node.style == 'bibliography'
468
- result << %(<bibliodiv#{common_attributes node.id, node.role, node.reftext}>)
469
- result << %(<title>#{node.title}</title>) if node.title?
470
- node.items.each do |item|
471
- result << '<bibliomixed>'
472
- result << %(<bibliomisc>#{item.text}</bibliomisc>)
473
- result << item.content if item.blocks?
474
- result << '</bibliomixed>'
475
- end
476
- result << '</bibliodiv>'
477
- else
478
- mark_type = (checklist = node.option? 'checklist') ? 'none' : node.style
479
- mark_attribute = mark_type ? %( mark="#{mark_type}") : ''
480
- result << %(<itemizedlist#{common_attributes node.id, node.role, node.reftext}#{mark_attribute}>)
481
- result << %(<title>#{node.title}</title>) if node.title?
482
- node.items.each do |item|
483
- text_marker = if checklist && (item.attr? 'checkbox')
484
- (item.attr? 'checked') ? '&#10003; ' : '&#10063; '
485
- else
486
- ''
487
- end
488
- result << '<listitem>'
489
- result << %(<simpara>#{text_marker}#{item.text}</simpara>)
490
- result << item.content if item.blocks?
491
- result << '</listitem>'
492
- end
493
- result << '</itemizedlist>'
494
- end
450
+ alias toc _skip
495
451
 
496
- result.join LF
452
+ def ulist node
453
+ result = []
454
+ if node.style == 'bibliography'
455
+ result << %(<bibliodiv#{_common_attributes node.id, node.role, node.reftext}>)
456
+ result << %(<title>#{node.title}</title>) if node.title?
457
+ node.items.each do |item|
458
+ result << '<bibliomixed>'
459
+ result << %(<bibliomisc>#{item.text}</bibliomisc>)
460
+ result << item.content if item.blocks?
461
+ result << '</bibliomixed>'
462
+ end
463
+ result << '</bibliodiv>'
464
+ else
465
+ mark_type = (checklist = node.option? 'checklist') ? 'none' : node.style
466
+ mark_attribute = mark_type ? %( mark="#{mark_type}") : ''
467
+ result << %(<itemizedlist#{_common_attributes node.id, node.role, node.reftext}#{mark_attribute}>)
468
+ result << %(<title>#{node.title}</title>) if node.title?
469
+ node.items.each do |item|
470
+ text_marker = (item.attr? 'checked') ? '&#10003; ' : '&#10063; ' if checklist && (item.attr? 'checkbox')
471
+ result << %(<listitem#{_common_attributes item.id, item.role}>)
472
+ result << %(<simpara>#{text_marker || ''}#{item.text}</simpara>)
473
+ result << item.content if item.blocks?
474
+ result << '</listitem>'
475
+ end
476
+ result << '</itemizedlist>'
497
477
  end
478
+ result.join LF
479
+ end
498
480
 
499
- def verse node
500
- blockquote_tag(node, (node.has_role? 'epigraph') && 'epigraph') { %(<literallayout>#{node.content}</literallayout>) }
501
- end
481
+ def verse node
482
+ _blockquote_tag(node, (node.has_role? 'epigraph') && 'epigraph') { %(<literallayout>#{node.content}</literallayout>) }
483
+ end
502
484
 
503
- alias video skip
485
+ alias video _skip
504
486
 
505
- def inline_anchor node
506
- case node.type
507
- when :ref
508
- %(<anchor#{common_attributes((id = node.id), nil, node.reftext || %([#{id}]))}/>)
509
- when :xref
510
- if (path = node.attributes['path'])
511
- # QUESTION should we use refid as fallback text instead? (like the html5 backend?)
512
- %(<link xl:href="#{node.target}">#{node.text || path}</link>)
513
- else
514
- linkend = node.attributes['fragment'] || node.target
515
- (text = node.text) ? %(<link linkend="#{linkend}">#{text}</link>) : %(<xref linkend="#{linkend}"/>)
516
- end
517
- when :link
518
- %(<link xl:href="#{node.target}">#{node.text}</link>)
519
- when :bibref
520
- # NOTE technically node.text should be node.reftext, but subs have already been applied to text
521
- %(<anchor#{common_attributes node.id, nil, (text = node.text)}/>#{text})
487
+ def inline_anchor node
488
+ case node.type
489
+ when :ref
490
+ %(<anchor#{_common_attributes((id = node.id), nil, node.reftext || %([#{id}]))}/>)
491
+ when :xref
492
+ if (path = node.attributes['path'])
493
+ # QUESTION should we use refid as fallback text instead? (like the html5 backend?)
494
+ %(<link xl:href="#{node.target}">#{node.text || path}</link>)
522
495
  else
523
- logger.warn %(unknown anchor type: #{node.type.inspect})
524
- nil
525
- end
496
+ linkend = node.attributes['fragment'] || node.target
497
+ (text = node.text) ? %(<link linkend="#{linkend}">#{text}</link>) : %(<xref linkend="#{linkend}"/>)
498
+ end
499
+ when :link
500
+ %(<link xl:href="#{node.target}">#{node.text}</link>)
501
+ when :bibref
502
+ %(<anchor#{_common_attributes node.id, nil, "[#{node.reftext || node.id}]"}/>#{text})
503
+ else
504
+ logger.warn %(unknown anchor type: #{node.type.inspect})
505
+ nil
526
506
  end
507
+ end
527
508
 
528
- def inline_break node
529
- %(#{node.text}<?asciidoc-br?>)
530
- end
509
+ def inline_break node
510
+ %(#{node.text}<?asciidoc-br?>)
511
+ end
531
512
 
532
- def inline_button node
533
- %(<guibutton>#{node.text}</guibutton>)
534
- end
513
+ def inline_button node
514
+ %(<guibutton>#{node.text}</guibutton>)
515
+ end
535
516
 
536
- def inline_callout node
537
- %(<co#{common_attributes node.id}/>)
538
- end
517
+ def inline_callout node
518
+ %(<co#{_common_attributes node.id}/>)
519
+ end
539
520
 
540
- def inline_footnote node
541
- if node.type == :xref
542
- %(<footnoteref linkend="#{node.target}"/>)
543
- else
544
- %(<footnote#{common_attributes node.id}><simpara>#{node.text}</simpara></footnote>)
545
- end
521
+ def inline_footnote node
522
+ if node.type == :xref
523
+ %(<footnoteref linkend="#{node.target}"/>)
524
+ else
525
+ %(<footnote#{_common_attributes node.id}><simpara>#{node.text}</simpara></footnote>)
546
526
  end
527
+ end
547
528
 
548
- def inline_image node
549
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
550
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
551
- %(<inlinemediaobject>
529
+ def inline_image node
530
+ width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
531
+ depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
532
+ %(<inlinemediaobject>
552
533
  <imageobject>
553
534
  <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{width_attribute}#{depth_attribute}/>
554
535
  </imageobject>
555
536
  <textobject><phrase>#{node.alt}</phrase></textobject>
556
537
  </inlinemediaobject>)
557
- end
538
+ end
558
539
 
559
- def inline_indexterm node
560
- if node.type == :visible
561
- %(<indexterm><primary>#{node.text}</primary></indexterm>#{node.text})
562
- else
563
- terms = node.attr 'terms'
564
- result = []
565
- if (numterms = terms.size) > 2
566
- result << %(<indexterm>
540
+ def inline_indexterm node
541
+ if node.type == :visible
542
+ %(<indexterm><primary>#{node.text}</primary></indexterm>#{node.text})
543
+ else
544
+ terms = node.attr 'terms'
545
+ result = []
546
+ if (numterms = terms.size) > 2
547
+ result << %(<indexterm>
567
548
  <primary>#{terms[0]}</primary><secondary>#{terms[1]}</secondary><tertiary>#{terms[2]}</tertiary>
568
549
  </indexterm>)
569
- end
570
- if numterms > 1
571
- result << %(<indexterm>
550
+ end
551
+ if numterms > 1
552
+ result << %(<indexterm>
572
553
  <primary>#{terms[-2]}</primary><secondary>#{terms[-1]}</secondary>
573
554
  </indexterm>)
574
- end
575
- result << %(<indexterm>
555
+ end
556
+ result << %(<indexterm>
576
557
  <primary>#{terms[-1]}</primary>
577
558
  </indexterm>)
578
- result.join LF
579
- end
559
+ result.join LF
580
560
  end
561
+ end
581
562
 
582
- def inline_kbd node
583
- if (keys = node.attr 'keys').size == 1
584
- %(<keycap>#{keys[0]}</keycap>)
585
- else
586
- %(<keycombo><keycap>#{keys.join '</keycap><keycap>'}</keycap></keycombo>)
587
- end
563
+ def inline_kbd node
564
+ if (keys = node.attr 'keys').size == 1
565
+ %(<keycap>#{keys[0]}</keycap>)
566
+ else
567
+ %(<keycombo><keycap>#{keys.join '</keycap><keycap>'}</keycap></keycombo>)
588
568
  end
569
+ end
589
570
 
590
- def inline_menu node
591
- menu = node.attr 'menu'
592
- if (submenus = node.attr 'submenus').empty?
593
- if (menuitem = node.attr 'menuitem', nil, false)
594
- %(<menuchoice><guimenu>#{menu}</guimenu> <guimenuitem>#{menuitem}</guimenuitem></menuchoice>)
595
- else
596
- %(<guimenu>#{menu}</guimenu>)
597
- end
571
+ def inline_menu node
572
+ menu = node.attr 'menu'
573
+ if (submenus = node.attr 'submenus').empty?
574
+ if (menuitem = node.attr 'menuitem')
575
+ %(<menuchoice><guimenu>#{menu}</guimenu> <guimenuitem>#{menuitem}</guimenuitem></menuchoice>)
598
576
  else
599
- %(<menuchoice><guimenu>#{menu}</guimenu> <guisubmenu>#{submenus.join '</guisubmenu> <guisubmenu>'}</guisubmenu> <guimenuitem>#{node.attr 'menuitem'}</guimenuitem></menuchoice>)
577
+ %(<guimenu>#{menu}</guimenu>)
600
578
  end
579
+ else
580
+ %(<menuchoice><guimenu>#{menu}</guimenu> <guisubmenu>#{submenus.join '</guisubmenu> <guisubmenu>'}</guisubmenu> <guimenuitem>#{node.attr 'menuitem'}</guimenuitem></menuchoice>)
601
581
  end
582
+ end
602
583
 
603
- (QUOTE_TAGS = {
604
- :monospaced => ['<literal>', '</literal>', false],
605
- :emphasis => ['<emphasis>', '</emphasis>', true],
606
- :strong => ['<emphasis role="strong">', '</emphasis>', true],
607
- :double => ['<quote>', '</quote>', true],
608
- :single => ['<quote>', '</quote>', true],
609
- :mark => ['<emphasis role="marked">', '</emphasis>', false],
610
- :superscript => ['<superscript>', '</superscript>', false],
611
- :subscript => ['<subscript>', '</subscript>', false]
612
- }).default = ['', '', true]
613
-
614
- def inline_quoted node
615
- if (type = node.type) == :asciimath
616
- if (@asciimath ||= ((defined? ::AsciiMath) || (Helpers.require_library 'asciimath', true, :warn)).nil? ? :unavailable : :loaded) == :loaded
617
- # NOTE fop requires jeuclid to process raw mathml
618
- %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>)
584
+ def inline_quoted node
585
+ if (type = node.type) == :asciimath
586
+ # NOTE fop requires jeuclid to process mathml markup
587
+ _asciimath_available? ? %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>) : %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
588
+ elsif type == :latexmath
589
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
590
+ %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
591
+ else
592
+ open, close, supports_phrase = QUOTE_TAGS[type]
593
+ text = node.text
594
+ if node.role
595
+ if supports_phrase
596
+ quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
619
597
  else
620
- %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
598
+ quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
621
599
  end
622
- elsif type == :latexmath
623
- # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
624
- %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
625
600
  else
626
- open, close, supports_phrase = QUOTE_TAGS[type]
627
- text = node.text
628
- if node.role
629
- if supports_phrase
630
- quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
631
- else
632
- quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
633
- end
634
- else
635
- quoted_text = %(#{open}#{text}#{close})
636
- end
637
-
638
- node.id ? %(<anchor#{common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
601
+ quoted_text = %(#{open}#{text}#{close})
639
602
  end
603
+
604
+ node.id ? %(<anchor#{_common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
640
605
  end
606
+ end
641
607
 
642
- def common_attributes id, role = nil, reftext = nil
643
- attrs = id ? %( xml:id="#{id}") : ''
644
- attrs = %(#{attrs} role="#{role}") if role
645
- if reftext
646
- if (reftext.include? '<') && ((reftext = reftext.gsub XmlSanitizeRx, '').include? ' ')
647
- reftext = (reftext.squeeze ' ').strip
648
- end
649
- reftext = (reftext.gsub '"', '&quot;') if reftext.include? '"'
650
- attrs = %(#{attrs} xreflabel="#{reftext}")
608
+ private
609
+
610
+ def _common_attributes id, role = nil, reftext = nil
611
+ if id
612
+ attrs = %( xml:id="#{id}"#{role ? %[ role="#{role}"] : ''})
613
+ elsif role
614
+ attrs = %( role="#{role}")
615
+ else
616
+ attrs = ''
617
+ end
618
+ if reftext
619
+ if (reftext.include? '<') && ((reftext = reftext.gsub XmlSanitizeRx, '').include? ' ')
620
+ reftext = (reftext.squeeze ' ').strip
651
621
  end
622
+ reftext = (reftext.gsub '"', '&quot;') if reftext.include? '"'
623
+ %(#{attrs} xreflabel="#{reftext}")
624
+ else
652
625
  attrs
653
626
  end
627
+ end
654
628
 
655
- def doctype_declaration root_tag_name
656
- nil
657
- end
658
-
659
- def author_tag author
660
- result = []
661
- result << '<author>'
662
- result << '<personname>'
663
- result << %(<firstname>#{author.firstname}</firstname>) if author.firstname
664
- result << %(<othername>#{author.middlename}</othername>) if author.middlename
665
- result << %(<surname>#{author.lastname}</surname>) if author.lastname
666
- result << '</personname>'
667
- result << %(<email>#{author.email}</email>) if author.email
668
- result << '</author>'
669
- result.join LF
670
- end
629
+ def _author_tag author
630
+ result = []
631
+ result << '<author>'
632
+ result << '<personname>'
633
+ result << %(<firstname>#{author.firstname}</firstname>) if author.firstname
634
+ result << %(<othername>#{author.middlename}</othername>) if author.middlename
635
+ result << %(<surname>#{author.lastname}</surname>) if author.lastname
636
+ result << '</personname>'
637
+ result << %(<email>#{author.email}</email>) if author.email
638
+ result << '</author>'
639
+ result.join LF
640
+ end
671
641
 
672
- def document_info_tag doc, info_tag_prefix, use_info_tag_prefix = false
673
- info_tag_prefix = '' unless use_info_tag_prefix
674
- result = []
675
- result << %(<#{info_tag_prefix}info>)
676
- result << document_title_tags(doc.doctitle :partition => true, :use_fallback => true) unless doc.notitle
677
- if (date = (doc.attr? 'revdate') ? (doc.attr 'revdate') : ((doc.attr? 'reproducible') ? nil : (doc.attr 'docdate')))
678
- result << %(<date>#{date}</date>)
679
- end
680
- if doc.attr? 'copyright'
681
- CopyrightRx =~ (doc.attr 'copyright')
682
- result << '<copyright>'
683
- result << %(<holder>#{$1}</holder>)
684
- result << %(<year>#{$2}</year>) if $2
685
- result << '</copyright>'
642
+ def _document_info_tag doc
643
+ result = ['<info>']
644
+ unless doc.notitle
645
+ if (title = doc.doctitle partition: true, use_fallback: true).subtitle?
646
+ result << %(<title>#{title.main}</title>
647
+ <subtitle>#{title.subtitle}</subtitle>)
648
+ else
649
+ result << %(<title>#{title}</title>)
686
650
  end
687
- if doc.has_header?
688
- unless (authors = doc.authors).empty?
689
- if authors.size > 1
690
- result << '<authorgroup>'
691
- authors.each {|author| result << (author_tag author) }
692
- result << '</authorgroup>'
693
- else
694
- result << author_tag(author = authors[0])
695
- result << %(<authorinitials>#{author.initials}</authorinitials>) if author.initials
696
- end
651
+ end
652
+ if (date = (doc.attr? 'revdate') ? (doc.attr 'revdate') : ((doc.attr? 'reproducible') ? nil : (doc.attr 'docdate')))
653
+ result << %(<date>#{date}</date>)
654
+ end
655
+ if doc.attr? 'copyright'
656
+ CopyrightRx =~ (doc.attr 'copyright')
657
+ result << '<copyright>'
658
+ result << %(<holder>#{$1}</holder>)
659
+ result << %(<year>#{$2}</year>) if $2
660
+ result << '</copyright>'
661
+ end
662
+ if doc.header?
663
+ unless (authors = doc.authors).empty?
664
+ if authors.size > 1
665
+ result << '<authorgroup>'
666
+ authors.each {|author| result << (_author_tag author) }
667
+ result << '</authorgroup>'
668
+ else
669
+ result << _author_tag(author = authors[0])
670
+ result << %(<authorinitials>#{author.initials}</authorinitials>) if author.initials
697
671
  end
698
- if (doc.attr? 'revdate') && ((doc.attr? 'revnumber') || (doc.attr? 'revremark'))
699
- result << %(<revhistory>
672
+ end
673
+ if (doc.attr? 'revdate') && ((doc.attr? 'revnumber') || (doc.attr? 'revremark'))
674
+ result << %(<revhistory>
700
675
  <revision>)
701
- result << %(<revnumber>#{doc.attr 'revnumber'}</revnumber>) if doc.attr? 'revnumber'
702
- result << %(<date>#{doc.attr 'revdate'}</date>) if doc.attr? 'revdate'
703
- result << %(<authorinitials>#{doc.attr 'authorinitials'}</authorinitials>) if doc.attr? 'authorinitials'
704
- result << %(<revremark>#{doc.attr 'revremark'}</revremark>) if doc.attr? 'revremark'
705
- result << %(</revision>
676
+ result << %(<revnumber>#{doc.attr 'revnumber'}</revnumber>) if doc.attr? 'revnumber'
677
+ result << %(<date>#{doc.attr 'revdate'}</date>) if doc.attr? 'revdate'
678
+ result << %(<authorinitials>#{doc.attr 'authorinitials'}</authorinitials>) if doc.attr? 'authorinitials'
679
+ result << %(<revremark>#{doc.attr 'revremark'}</revremark>) if doc.attr? 'revremark'
680
+ result << %(</revision>
706
681
  </revhistory>)
682
+ end
683
+ if (doc.attr? 'front-cover-image') || (doc.attr? 'back-cover-image')
684
+ if (back_cover_tag = _cover_tag doc, 'back')
685
+ result << (_cover_tag doc, 'front', true)
686
+ result << back_cover_tag
687
+ elsif (front_cover_tag = _cover_tag doc, 'front')
688
+ result << front_cover_tag
707
689
  end
708
- unless use_info_tag_prefix
709
- if (doc.attr? 'front-cover-image') || (doc.attr? 'back-cover-image')
710
- if (back_cover_tag = cover_tag doc, 'back')
711
- result << (cover_tag doc, 'front', true)
712
- result << back_cover_tag
713
- elsif (front_cover_tag = cover_tag doc, 'front')
714
- result << front_cover_tag
715
- end
716
- end
717
- end
718
- unless (head_docinfo = doc.docinfo).empty?
719
- result << head_docinfo
720
- end
721
- result << %(<orgname>#{doc.attr 'orgname'}</orgname>) if doc.attr? 'orgname'
722
690
  end
723
- result << %(</#{info_tag_prefix}info>)
724
-
725
- if doc.doctype == 'manpage'
726
- result << '<refmeta>'
727
- result << %(<refentrytitle>#{doc.attr 'mantitle'}</refentrytitle>) if doc.attr? 'mantitle'
728
- result << %(<manvolnum>#{doc.attr 'manvolnum'}</manvolnum>) if doc.attr? 'manvolnum'
729
- result << %(<refmiscinfo class="source">#{doc.attr 'mansource', '&#160;'}</refmiscinfo>)
730
- result << %(<refmiscinfo class="manual">#{doc.attr 'manmanual', '&#160;'}</refmiscinfo>)
731
- result << '</refmeta>'
732
- result << '<refnamediv>'
733
- result += (doc.attr 'mannames').map {|n| %(<refname>#{n}</refname>) } if doc.attr? 'mannames'
734
- result << %(<refpurpose>#{doc.attr 'manpurpose'}</refpurpose>) if doc.attr? 'manpurpose'
735
- result << '</refnamediv>'
691
+ result << %(<orgname>#{doc.attr 'orgname'}</orgname>) if doc.attr? 'orgname'
692
+ unless (docinfo_content = doc.docinfo).empty?
693
+ result << docinfo_content
736
694
  end
737
-
738
- result.join LF
739
695
  end
696
+ result << '</info>'
740
697
 
741
- def document_ns_attributes doc
742
- ' xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"'
698
+ if doc.doctype == 'manpage'
699
+ result << '<refmeta>'
700
+ result << %(<refentrytitle>#{doc.attr 'mantitle'}</refentrytitle>) if doc.attr? 'mantitle'
701
+ result << %(<manvolnum>#{doc.attr 'manvolnum'}</manvolnum>) if doc.attr? 'manvolnum'
702
+ result << %(<refmiscinfo class="source">#{doc.attr 'mansource', '&#160;'}</refmiscinfo>)
703
+ result << %(<refmiscinfo class="manual">#{doc.attr 'manmanual', '&#160;'}</refmiscinfo>)
704
+ result << '</refmeta>'
705
+ result << '<refnamediv>'
706
+ result += (doc.attr 'mannames').map {|n| %(<refname>#{n}</refname>) } if doc.attr? 'mannames'
707
+ result << %(<refpurpose>#{doc.attr 'manpurpose'}</refpurpose>) if doc.attr? 'manpurpose'
708
+ result << '</refnamediv>'
743
709
  end
744
710
 
745
- def lang_attribute_name
746
- 'xml:lang'
747
- end
748
-
749
- def document_title_tags title
750
- if title.subtitle?
751
- %(<title>#{title.main}</title>
752
- <subtitle>#{title.subtitle}</subtitle>)
753
- else
754
- %(<title>#{title}</title>)
755
- end
756
- end
711
+ result.join LF
712
+ end
757
713
 
758
- # FIXME this should be handled through a template mechanism
759
- def resolve_content node
760
- node.content_model == :compound ? node.content : %(<simpara>#{node.content}</simpara>)
761
- end
714
+ # FIXME this should be handled through a template mechanism
715
+ def _enclose_content node
716
+ node.content_model == :compound ? node.content : %(<simpara>#{node.content}</simpara>)
717
+ end
762
718
 
763
- def title_tag node, optional = true
764
- !optional || node.title? ? %(<title>#{node.title}</title>\n) : ''
765
- end
719
+ def _title_tag node, optional = true
720
+ !optional || node.title? ? %(<title>#{node.title}</title>\n) : ''
721
+ end
766
722
 
767
- def cover_tag doc, face, use_placeholder = false
768
- if (cover_image = doc.attr %(#{face}-cover-image))
769
- width_attr = ''
770
- depth_attr = ''
771
- if (cover_image.include? ':') && ImageMacroRx =~ cover_image
772
- cover_image = doc.image_uri $1
773
- unless $2.empty?
774
- attrs = (AttributeList.new $2).parse ['alt', 'width', 'height']
775
- if attrs.key? 'scaledwidth'
776
- # NOTE scalefit="1" is the default in this case
777
- width_attr = %( width="#{attrs['scaledwidth']}")
778
- else
779
- width_attr = %( contentwidth="#{attrs['width']}") if attrs.key? 'width'
780
- depth_attr = %( contentdepth="#{attrs['height']}") if attrs.key? 'height'
781
- end
723
+ def _cover_tag doc, face, use_placeholder = false
724
+ if (cover_image = doc.attr %(#{face}-cover-image))
725
+ width_attr = ''
726
+ depth_attr = ''
727
+ if (cover_image.include? ':') && ImageMacroRx =~ cover_image
728
+ cover_image = doc.image_uri $1
729
+ unless $2.empty?
730
+ attrs = (AttributeList.new $2).parse ['alt', 'width', 'height']
731
+ if attrs.key? 'scaledwidth'
732
+ # NOTE scalefit="1" is the default in this case
733
+ width_attr = %( width="#{attrs['scaledwidth']}")
734
+ else
735
+ width_attr = %( contentwidth="#{attrs['width']}") if attrs.key? 'width'
736
+ depth_attr = %( contentdepth="#{attrs['height']}") if attrs.key? 'height'
782
737
  end
783
738
  end
784
- %(<cover role="#{face}">
739
+ end
740
+ %(<cover role="#{face}">
785
741
  <mediaobject>
786
742
  <imageobject>
787
743
  <imagedata fileref="#{cover_image}"#{width_attr}#{depth_attr}/>
788
744
  </imageobject>
789
745
  </mediaobject>
790
746
  </cover>)
791
- elsif use_placeholder
792
- %(<cover role="#{face}"/>)
793
- end
747
+ elsif use_placeholder
748
+ %(<cover role="#{face}"/>)
794
749
  end
750
+ end
795
751
 
796
- def blockquote_tag node, tag_name = nil
797
- if tag_name
798
- start_tag, end_tag = %(<#{tag_name}), %(</#{tag_name}>)
799
- else
800
- start_tag, end_tag = '<blockquote', '</blockquote>'
801
- end
802
- result = [%(#{start_tag}#{common_attributes node.id, node.role, node.reftext}>)]
803
- result << %(<title>#{node.title}</title>) if node.title?
804
- if (node.attr? 'attribution') || (node.attr? 'citetitle')
805
- result << '<attribution>'
806
- result << (node.attr 'attribution') if node.attr? 'attribution'
807
- result << %(<citetitle>#{node.attr 'citetitle'}</citetitle>) if node.attr? 'citetitle'
808
- result << '</attribution>'
809
- end
810
- result << yield
811
- result << end_tag
812
- result.join LF
813
- end
752
+ def _blockquote_tag node, tag_name = nil
753
+ if tag_name
754
+ start_tag, end_tag = %(<#{tag_name}), %(</#{tag_name}>)
755
+ else
756
+ start_tag, end_tag = '<blockquote', '</blockquote>'
757
+ end
758
+ result = [%(#{start_tag}#{_common_attributes node.id, node.role, node.reftext}>)]
759
+ result << %(<title>#{node.title}</title>) if node.title?
760
+ if (node.attr? 'attribution') || (node.attr? 'citetitle')
761
+ result << '<attribution>'
762
+ result << (node.attr 'attribution') if node.attr? 'attribution'
763
+ result << %(<citetitle>#{node.attr 'citetitle'}</citetitle>) if node.attr? 'citetitle'
764
+ result << '</attribution>'
765
+ end
766
+ result << yield
767
+ result << end_tag
768
+ result.join LF
769
+ end
770
+
771
+ def _asciimath_available?
772
+ (@asciimath_status ||= _load_asciimath) == :loaded
773
+ end
774
+
775
+ def _load_asciimath
776
+ (defined? ::AsciiMath.parse) ? :loaded : (Helpers.require_library 'asciimath', true, :warn).nil? ? :unavailable : :loaded
814
777
  end
815
778
  end
779
+ end