asciidoctor 1.5.6.2 → 1.5.7

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

Potentially problematic release.


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

Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +330 -143
  3. data/README-fr.adoc +441 -0
  4. data/README-jp.adoc +418 -0
  5. data/README-zh_CN.adoc +430 -0
  6. data/README.adoc +454 -0
  7. data/Rakefile +57 -0
  8. data/asciidoctor.gemspec +7 -1
  9. data/data/locale/attributes-ar.adoc +22 -0
  10. data/data/locale/attributes-bg.adoc +22 -0
  11. data/data/locale/attributes-ca.adoc +22 -0
  12. data/data/locale/attributes-cs.adoc +22 -0
  13. data/data/locale/attributes-da.adoc +22 -0
  14. data/data/locale/attributes-de.adoc +22 -0
  15. data/data/locale/attributes-en.adoc +23 -0
  16. data/data/locale/attributes-es.adoc +22 -0
  17. data/data/locale/attributes-fa.adoc +22 -0
  18. data/data/locale/attributes-fi.adoc +22 -0
  19. data/data/locale/attributes-fr.adoc +22 -0
  20. data/data/locale/attributes-hu.adoc +22 -0
  21. data/data/locale/attributes-id.adoc +22 -0
  22. data/data/locale/attributes-it.adoc +22 -0
  23. data/data/locale/attributes-ja.adoc +22 -0
  24. data/data/locale/attributes-kr.adoc +22 -0
  25. data/data/locale/attributes-nb.adoc +22 -0
  26. data/data/locale/attributes-nl.adoc +22 -0
  27. data/data/locale/attributes-nn.adoc +22 -0
  28. data/data/locale/attributes-pl.adoc +22 -0
  29. data/data/locale/attributes-pt.adoc +22 -0
  30. data/data/locale/attributes-pt_BR.adoc +22 -0
  31. data/data/locale/attributes-ro.adoc +22 -0
  32. data/data/locale/attributes-ru.adoc +22 -0
  33. data/data/locale/attributes-sr.adoc +22 -0
  34. data/data/locale/attributes-sr_Latn.adoc +22 -0
  35. data/data/locale/attributes-tr.adoc +22 -0
  36. data/data/locale/attributes-uk.adoc +22 -0
  37. data/data/locale/attributes-zh_CN.adoc +22 -0
  38. data/data/locale/attributes-zh_TW.adoc +22 -0
  39. data/data/locale/attributes.adoc +8 -649
  40. data/data/stylesheets/asciidoctor-default.css +77 -72
  41. data/features/xref.feature +366 -7
  42. data/lib/asciidoctor.rb +107 -93
  43. data/lib/asciidoctor/abstract_block.rb +247 -239
  44. data/lib/asciidoctor/abstract_node.rb +56 -58
  45. data/lib/asciidoctor/block.rb +3 -3
  46. data/lib/asciidoctor/callouts.rb +1 -1
  47. data/lib/asciidoctor/cli/invoker.rb +36 -9
  48. data/lib/asciidoctor/cli/options.rb +63 -25
  49. data/lib/asciidoctor/converter.rb +23 -13
  50. data/lib/asciidoctor/converter/base.rb +4 -0
  51. data/lib/asciidoctor/converter/docbook45.rb +16 -9
  52. data/lib/asciidoctor/converter/docbook5.rb +115 -97
  53. data/lib/asciidoctor/converter/factory.rb +29 -31
  54. data/lib/asciidoctor/converter/html5.rb +229 -192
  55. data/lib/asciidoctor/converter/manpage.rb +72 -50
  56. data/lib/asciidoctor/converter/template.rb +12 -12
  57. data/lib/asciidoctor/core_ext.rb +5 -1
  58. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +6 -0
  59. data/lib/asciidoctor/document.rb +168 -77
  60. data/lib/asciidoctor/extensions.rb +79 -47
  61. data/lib/asciidoctor/helpers.rb +33 -11
  62. data/lib/asciidoctor/inline.rb +3 -2
  63. data/lib/asciidoctor/list.rb +2 -1
  64. data/lib/asciidoctor/logging.rb +122 -0
  65. data/lib/asciidoctor/parser.rb +406 -382
  66. data/lib/asciidoctor/path_resolver.rb +169 -162
  67. data/lib/asciidoctor/reader.rb +166 -121
  68. data/lib/asciidoctor/section.rb +45 -28
  69. data/lib/asciidoctor/stylesheets.rb +13 -5
  70. data/lib/asciidoctor/substitutors.rb +328 -254
  71. data/lib/asciidoctor/table.rb +105 -48
  72. data/lib/asciidoctor/timings.rb +34 -6
  73. data/lib/asciidoctor/version.rb +1 -1
  74. data/man/asciidoctor.1 +41 -23
  75. data/man/asciidoctor.adoc +14 -8
  76. data/test/api_test.rb +1004 -0
  77. data/test/attributes_test.rb +241 -50
  78. data/test/blocks_test.rb +549 -124
  79. data/test/converter_test.rb +170 -78
  80. data/test/document_test.rb +208 -767
  81. data/test/extensions_test.rb +188 -53
  82. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +1 -1
  83. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +1 -1
  84. data/test/fixtures/file-with-missing-include.adoc +1 -0
  85. data/test/fixtures/include-file.jsx +8 -0
  86. data/test/fixtures/lists.adoc +96 -0
  87. data/test/fixtures/other-chapters.adoc +11 -0
  88. data/test/fixtures/outer-include.adoc +5 -0
  89. data/test/fixtures/sample.asciidoc +5 -1
  90. data/test/fixtures/subdir/index.adoc +3 -0
  91. data/test/fixtures/subdir/inner-include.adoc +3 -0
  92. data/test/fixtures/subdir/middle-include.adoc +5 -0
  93. data/test/fixtures/tagged-class-enclosed.rb +0 -1
  94. data/test/fixtures/unclosed-tag.adoc +3 -0
  95. data/test/fixtures/unexpected-end-tag.adoc +4 -0
  96. data/test/invoker_test.rb +101 -40
  97. data/test/links_test.rb +266 -72
  98. data/test/lists_test.rb +243 -45
  99. data/test/logger_test.rb +211 -0
  100. data/test/manpage_test.rb +124 -6
  101. data/test/options_test.rb +46 -1
  102. data/test/paragraphs_test.rb +23 -10
  103. data/test/parser_test.rb +30 -1
  104. data/test/paths_test.rb +115 -33
  105. data/test/preamble_test.rb +1 -1
  106. data/test/reader_test.rb +337 -81
  107. data/test/sections_test.rb +656 -72
  108. data/test/substitutions_test.rb +182 -57
  109. data/test/tables_test.rb +324 -57
  110. data/test/test_helper.rb +77 -32
  111. data/test/text_test.rb +7 -7
  112. metadata +67 -3
@@ -9,59 +9,65 @@ context 'Converter' do
9
9
 
10
10
  context 'View options' do
11
11
  test 'should set Haml format to html5 for html5 backend' do
12
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
13
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
12
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
13
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
14
14
  selected = doc.converter.find_converter('paragraph')
15
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
16
- assert selected.templates['paragraph'].is_a? Tilt::HamlTemplate
15
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
16
+ assert_kind_of Tilt::HamlTemplate, selected.templates['paragraph']
17
17
  assert_equal :html5, selected.templates['paragraph'].options[:format]
18
18
  end
19
19
 
20
20
  test 'should set Haml format to xhtml for docbook backend' do
21
- doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
22
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
21
+ doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
22
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
23
23
  selected = doc.converter.find_converter('paragraph')
24
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
25
- assert selected.templates['paragraph'].is_a? Tilt::HamlTemplate
24
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
25
+ assert_kind_of Tilt::HamlTemplate, selected.templates['paragraph']
26
26
  assert_equal :xhtml, selected.templates['paragraph'].options[:format]
27
27
  end
28
28
 
29
29
  test 'should configure Slim to resolve includes in specified template dirs' do
30
- template_dirs = [
31
- File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'),
32
- File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim-overrides'),
33
- ]
30
+ template_dirs = [(fixture_path 'custom-backends/slim'), (fixture_path 'custom-backends/slim-overrides')]
34
31
  doc = Asciidoctor::Document.new [], :template_dirs => template_dirs, :template_cache => false
35
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
32
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
36
33
  selected = doc.converter.find_converter('paragraph')
37
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
38
- assert selected.templates['paragraph'].is_a? Slim::Template
34
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
35
+ assert_kind_of Slim::Template, selected.templates['paragraph']
39
36
  assert_equal template_dirs.reverse.map {|dir| File.expand_path dir }, selected.templates['paragraph'].options[:include_dirs]
40
37
  end
41
38
 
39
+ test 'should coerce template_dirs option to an Array' do
40
+ template_dirs = fixture_path 'custom-backends/slim'
41
+ doc = Asciidoctor::Document.new [], :template_dirs => template_dirs, :template_cache => false
42
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
43
+ selected = doc.converter.find_converter('paragraph')
44
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
45
+ assert_kind_of Array, (selected.instance_variable_get :@template_dirs)
46
+ end
47
+
42
48
  test 'should set Slim format to html for html5 backend' do
43
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false
44
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
49
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false
50
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
45
51
  selected = doc.converter.find_converter('paragraph')
46
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
47
- assert selected.templates['paragraph'].is_a? Slim::Template
52
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
53
+ assert_kind_of Slim::Template, selected.templates['paragraph']
48
54
  assert_equal :html, selected.templates['paragraph'].options[:format]
49
55
  end
50
56
 
51
57
  test 'should set Slim format to nil for docbook backend' do
52
- doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false
53
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
58
+ doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false
59
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
54
60
  selected = doc.converter.find_converter('paragraph')
55
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
56
- assert selected.templates['paragraph'].is_a? Slim::Template
61
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
62
+ assert_kind_of Slim::Template, selected.templates['paragraph']
57
63
  assert_nil selected.templates['paragraph'].options[:format]
58
64
  end
59
65
 
60
66
  test 'should set safe mode of Slim AsciiDoc engine to match document safe mode when Slim >= 3' do
61
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false, :safe => :unsafe
62
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
67
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false, :safe => :unsafe
68
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
63
69
  selected = doc.converter.find_converter('paragraph')
64
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
70
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
65
71
  slim_asciidoc_opts = selected.instance_variable_get(:@engine_options)[:slim][:asciidoc]
66
72
  if ::Slim::VERSION >= '3.0'
67
73
  assert_equal({ :safe => Asciidoctor::SafeMode::UNSAFE }, slim_asciidoc_opts)
@@ -71,20 +77,20 @@ context 'Converter' do
71
77
  end
72
78
 
73
79
  test 'should support custom template engine options for known engine' do
74
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false, :template_engine_options => { :slim => { :pretty => true } }
75
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
80
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false, :template_engine_options => { :slim => { :pretty => true } }
81
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
76
82
  selected = doc.converter.find_converter('paragraph')
77
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
78
- assert selected.templates['paragraph'].is_a? Slim::Template
83
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
84
+ assert_kind_of Slim::Template, selected.templates['paragraph']
79
85
  assert_equal true, selected.templates['paragraph'].options[:pretty]
80
86
  end
81
87
 
82
88
  test 'should support custom template engine options' do
83
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false, :template_engine_options => { :slim => { :pretty => true } }
84
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
89
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false, :template_engine_options => { :slim => { :pretty => true } }
90
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
85
91
  selected = doc.converter.find_converter('paragraph')
86
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
87
- assert selected.templates['paragraph'].is_a? Slim::Template
92
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
93
+ assert_kind_of Slim::Template, selected.templates['paragraph']
88
94
  assert_equal false, selected.templates['paragraph'].options[:sort_attrs]
89
95
  assert_equal true, selected.templates['paragraph'].options[:pretty]
90
96
  end
@@ -92,43 +98,43 @@ context 'Converter' do
92
98
 
93
99
  context 'Custom backends' do
94
100
  test 'should load Haml templates for default backend' do
95
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
96
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
101
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
102
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
97
103
  ['paragraph', 'sidebar'].each do |node_name|
98
104
  selected = doc.converter.find_converter node_name
99
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
100
- assert selected.templates[node_name].is_a? Tilt::HamlTemplate
105
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
106
+ assert_kind_of Tilt::HamlTemplate, selected.templates[node_name]
101
107
  assert_equal %(block_#{node_name}.html.haml), File.basename(selected.templates[node_name].file)
102
108
  end
103
109
  end
104
110
 
105
111
  test 'should set outfilesuffix according to backend info' do
106
112
  doc = Asciidoctor.load 'content'
107
- doc.render
113
+ doc.convert
108
114
  assert_equal '.html', doc.attributes['outfilesuffix']
109
115
 
110
- doc = Asciidoctor.load 'content', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
111
- doc.render
116
+ doc = Asciidoctor.load 'content', :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
117
+ doc.convert
112
118
  assert_equal '.html', doc.attributes['outfilesuffix']
113
119
  end
114
120
 
115
121
  test 'should not override outfilesuffix attribute if locked' do
116
122
  doc = Asciidoctor.load 'content', :attributes => {'outfilesuffix' => '.foo'}
117
- doc.render
123
+ doc.convert
118
124
  assert_equal '.foo', doc.attributes['outfilesuffix']
119
125
 
120
- doc = Asciidoctor.load 'content', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false, :attributes => {'outfilesuffix' => '.foo'}
121
- doc.render
126
+ doc = Asciidoctor.load 'content', :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false, :attributes => {'outfilesuffix' => '.foo'}
127
+ doc.convert
122
128
  assert_equal '.foo', doc.attributes['outfilesuffix']
123
129
  end
124
130
 
125
131
  test 'should load Haml templates for docbook45 backend' do
126
- doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
127
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
132
+ doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
133
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
128
134
  ['paragraph'].each do |node_name|
129
135
  selected = doc.converter.find_converter node_name
130
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
131
- assert selected.templates[node_name].is_a? Tilt::HamlTemplate
136
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
137
+ assert_kind_of Tilt::HamlTemplate, selected.templates[node_name]
132
138
  assert_equal %(block_#{node_name}.xml.haml), File.basename(selected.templates[node_name].file)
133
139
  end
134
140
  end
@@ -148,7 +154,7 @@ Sidebar content
148
154
  ****
149
155
  EOS
150
156
 
151
- output = render_embedded_string input, :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'), :template_cache => false
157
+ output = render_embedded_string input, :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
152
158
  assert_xpath '/*[@class="sect1"]/*[@class="sectionbody"]/p', output, 1
153
159
  assert_xpath '//aside', output, 1
154
160
  assert_xpath '/*[@class="sect1"]/*[@class="sectionbody"]/p/following-sibling::aside', output, 1
@@ -161,12 +167,12 @@ Sidebar content
161
167
  # clear out any cache, just to be sure
162
168
  Asciidoctor::Converter::TemplateConverter.clear_caches if defined? Asciidoctor::Converter::TemplateConverter
163
169
 
164
- template_dir = File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml')
170
+ template_dir = fixture_path 'custom-backends/haml'
165
171
  doc = Asciidoctor::Document.new [], :template_dir => template_dir
166
172
  doc.converter
167
173
  caches = Asciidoctor::Converter::TemplateConverter.caches
168
174
  if defined? ::ThreadSafe::Cache
169
- assert caches[:templates].is_a?(::ThreadSafe::Cache)
175
+ assert_kind_of ::ThreadSafe::Cache, caches[:templates]
170
176
  refute_empty caches[:templates]
171
177
  paragraph_template_before = caches[:templates].values.find {|t| File.basename(t.file) == 'block_paragraph.html.haml' }
172
178
  refute_nil paragraph_template_before
@@ -194,7 +200,7 @@ Sidebar content
194
200
  end
195
201
 
196
202
  test 'should use custom cache to cache templates' do
197
- template_dir = File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml')
203
+ template_dir = fixture_path 'custom-backends/haml'
198
204
  Asciidoctor::PathResolver.new.system_path(File.join(template_dir, 'html5', 'block_paragraph.html.haml'), nil)
199
205
  caches = { :scans => {}, :templates => {} }
200
206
  doc = Asciidoctor::Document.new [], :template_dir => template_dir, :template_cache => caches
@@ -203,7 +209,7 @@ Sidebar content
203
209
  refute_empty caches[:templates]
204
210
  paragraph_template = caches[:templates].values.find {|t| File.basename(t.file) == 'block_paragraph.html.haml' }
205
211
  refute_nil paragraph_template
206
- assert paragraph_template.is_a? ::Tilt::HamlTemplate
212
+ assert_kind_of ::Tilt::HamlTemplate, paragraph_template
207
213
  end
208
214
 
209
215
  test 'should be able to disable template cache' do
@@ -211,8 +217,7 @@ Sidebar content
211
217
  # clear out any cache, just to be sure
212
218
  Asciidoctor::Converter::TemplateConverter.clear_caches if defined? Asciidoctor::Converter::TemplateConverter
213
219
 
214
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'haml'),
215
- :template_cache => false
220
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/haml'), :template_cache => false
216
221
  doc.converter
217
222
  caches = Asciidoctor::Converter::TemplateConverter.caches
218
223
  assert caches.empty? || caches[:scans].empty?
@@ -224,51 +229,51 @@ Sidebar content
224
229
  end
225
230
 
226
231
  test 'should load ERB templates using ERBTemplate if eruby is not set' do
227
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'erb'), :template_cache => false
228
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
232
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/erb'), :template_cache => false
233
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
229
234
  ['paragraph'].each do |node_name|
230
235
  selected = doc.converter.find_converter node_name
231
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
236
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
232
237
  template = selected.templates[node_name]
233
- assert template.is_a? Tilt::ERBTemplate
234
- refute template.is_a? Tilt::ErubisTemplate
235
- assert template.instance_variable_get('@engine').is_a? ::ERB
238
+ assert_kind_of Tilt::ERBTemplate, template
239
+ refute_kind_of Tilt::ErubisTemplate, template
240
+ assert_kind_of ::ERB, template.instance_variable_get('@engine')
236
241
  assert_equal %(block_#{node_name}.html.erb), File.basename(selected.templates[node_name].file)
237
242
  end
238
243
  end
239
244
 
240
245
  test 'should load ERB templates using ErubisTemplate if eruby is set to erubis' do
241
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'erb'), :template_cache => false, :eruby => 'erubis'
242
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
246
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/erb'), :template_cache => false, :eruby => 'erubis'
247
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
243
248
  ['paragraph'].each do |node_name|
244
249
  selected = doc.converter.find_converter node_name
245
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
250
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
246
251
  template = selected.templates[node_name]
247
- assert template.is_a? Tilt::ERBTemplate
248
- assert template.is_a? Tilt::ErubisTemplate
249
- assert template.instance_variable_get('@engine').is_a? ::Erubis::FastEruby
252
+ assert_kind_of Tilt::ERBTemplate, template
253
+ assert_kind_of Tilt::ErubisTemplate, template
254
+ assert_kind_of ::Erubis::FastEruby, template.instance_variable_get('@engine')
250
255
  assert_equal %(block_#{node_name}.html.erb), File.basename(selected.templates[node_name].file)
251
256
  end
252
257
  end
253
258
 
254
259
  test 'should load Slim templates for default backend' do
255
- doc = Asciidoctor::Document.new [], :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false
256
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
260
+ doc = Asciidoctor::Document.new [], :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false
261
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
257
262
  ['paragraph', 'sidebar'].each do |node_name|
258
263
  selected = doc.converter.find_converter node_name
259
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
260
- assert selected.templates[node_name].is_a? Slim::Template
264
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
265
+ assert_kind_of Slim::Template, selected.templates[node_name]
261
266
  assert_equal %(block_#{node_name}.html.slim), File.basename(selected.templates[node_name].file)
262
267
  end
263
268
  end
264
269
 
265
270
  test 'should load Slim templates for docbook45 backend' do
266
- doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false
267
- assert doc.converter.is_a?(Asciidoctor::Converter::CompositeConverter)
271
+ doc = Asciidoctor::Document.new [], :backend => 'docbook45', :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false
272
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
268
273
  ['paragraph'].each do |node_name|
269
274
  selected = doc.converter.find_converter node_name
270
- assert selected.is_a? Asciidoctor::Converter::TemplateConverter
271
- assert selected.templates[node_name].is_a? Slim::Template
275
+ assert_kind_of Asciidoctor::Converter::TemplateConverter, selected
276
+ assert_kind_of Slim::Template, selected.templates[node_name]
272
277
  assert_equal %(block_#{node_name}.xml.slim), File.basename(selected.templates[node_name].file)
273
278
  end
274
279
  end
@@ -288,7 +293,7 @@ Sidebar content
288
293
  ****
289
294
  EOS
290
295
 
291
- output = render_embedded_string input, :template_dir => File.join(File.dirname(__FILE__), 'fixtures', 'custom-backends', 'slim'), :template_cache => false
296
+ output = render_embedded_string input, :template_dir => (fixture_path 'custom-backends/slim'), :template_cache => false
292
297
  assert_xpath '/*[@class="sect1"]/*[@class="sectionbody"]/p', output, 1
293
298
  assert_xpath '//aside', output, 1
294
299
  assert_xpath '/*[@class="sect1"]/*[@class="sectionbody"]/p/following-sibling::aside', output, 1
@@ -350,6 +355,93 @@ content
350
355
  end
351
356
  end
352
357
 
358
+ test 'should map handles? method on converter to respond_to? by default' do
359
+ class CustomConverterC
360
+ include Asciidoctor::Converter
361
+ def paragraph node
362
+ 'paragraph'
363
+ end
364
+ end
365
+
366
+ converter = CustomConverterC.new 'myhtml'
367
+ assert_respond_to converter, :handles?
368
+ assert converter.handles?(:paragraph)
369
+ end
370
+
371
+ test 'should not configure converter to support templates by default' do
372
+ input = <<-EOS
373
+ paragraph
374
+ EOS
375
+
376
+ begin
377
+ Asciidoctor::Converter::Factory.unregister_all
378
+ class CustomConverterD
379
+ include Asciidoctor::Converter
380
+ register_for 'myhtml'
381
+ def convert node, transform = nil, opts = {}
382
+ transform ||= node.node_name
383
+ send transform, node
384
+ end
385
+
386
+ def document node
387
+ ['<!DOCTYPE html>', '<html>', '<body>', node.content, '</body>', '</html>'] * %(\n)
388
+ end
389
+
390
+ def paragraph node
391
+ ['<div class="paragraph">', %(<p>#{node.content}</p>), '</div>'] * %(\n)
392
+ end
393
+ end
394
+
395
+ doc = document_from_string input, :backend => 'myhtml', :template_dir => (fixture_path 'custom-backends/slim/html5'), :template_cache => false
396
+ assert_kind_of CustomConverterD, doc.converter
397
+ refute doc.converter.supports_templates?
398
+ output = doc.convert
399
+ assert_xpath '//*[@class="paragraph"]/p[text()="paragraph"]', output, 1
400
+ ensure
401
+ Asciidoctor::Converter::Factory.unregister_all
402
+ end
403
+ end
404
+
405
+ test 'should wrap converter in composite converter with template converter if it declares that it supports templates' do
406
+ input = <<-EOS
407
+ paragraph
408
+ EOS
409
+
410
+ begin
411
+ Asciidoctor::Converter::Factory.unregister_all
412
+ class CustomConverterE
413
+ include Asciidoctor::Converter
414
+ register_for 'myhtml'
415
+
416
+ def initialize *args
417
+ super
418
+ supports_templates
419
+ end
420
+
421
+ def convert node, transform = nil, opts = {}
422
+ transform ||= node.node_name
423
+ send transform, node
424
+ end
425
+
426
+ def document node
427
+ ['<!DOCTYPE html>', '<html>', '<body>', node.content, '</body>', '</html>'] * %(\n)
428
+ end
429
+
430
+ def paragraph node
431
+ ['<div class="paragraph">', %(<p>#{node.content}</p>), '</div>'] * %(\n)
432
+ end
433
+ end
434
+
435
+ doc = document_from_string input, :backend => 'myhtml', :template_dir => (fixture_path 'custom-backends/slim/html5'), :template_cache => false
436
+ assert_kind_of Asciidoctor::Converter::CompositeConverter, doc.converter
437
+ output = doc.convert
438
+ assert_xpath '//*[@class="paragraph"]/p[text()="paragraph"]', output, 0
439
+ assert_xpath '//body/p[text()="paragraph"]', output, 1
440
+ ensure
441
+ Asciidoctor::Converter::Factory.unregister_all
442
+ end
443
+ end
444
+
353
445
  test 'should fall back to catch all converter' do
354
446
  input = <<-EOS
355
447
  content
@@ -358,7 +450,7 @@ content
358
450
  begin
359
451
  Asciidoctor::Converter::Factory.unregister_all
360
452
 
361
- class CustomConverterC
453
+ class CustomConverterF
362
454
  include Asciidoctor::Converter
363
455
  register_for '*'
364
456
  def convert node, name = nil
@@ -367,7 +459,7 @@ content
367
459
  end
368
460
 
369
461
  converters = Asciidoctor::Converter::Factory.converters
370
- assert converters['*'] == CustomConverterC
462
+ assert converters['*'] == CustomConverterF
371
463
  output = render_string input, :backend => 'foobaz'
372
464
  assert 'foobaz content', output
373
465
  ensure
@@ -131,718 +131,6 @@ content
131
131
  end
132
132
  end
133
133
 
134
- context 'Load APIs' do
135
- test 'should load input file' do
136
- sample_input_path = fixture_path('sample.asciidoc')
137
- doc = File.open(sample_input_path) {|file| Asciidoctor.load file, :safe => Asciidoctor::SafeMode::SAFE }
138
- assert_equal 'Document Title', doc.doctitle
139
- assert_equal File.expand_path(sample_input_path), doc.attr('docfile')
140
- assert_equal File.expand_path(File.dirname(sample_input_path)), doc.attr('docdir')
141
- assert_equal '.asciidoc', doc.attr('docfilesuffix')
142
- end
143
-
144
- test 'should load input file from filename' do
145
- sample_input_path = fixture_path('sample.asciidoc')
146
- doc = Asciidoctor.load_file(sample_input_path, :safe => Asciidoctor::SafeMode::SAFE)
147
- assert_equal 'Document Title', doc.doctitle
148
- assert_equal File.expand_path(sample_input_path), doc.attr('docfile')
149
- assert_equal File.expand_path(File.dirname(sample_input_path)), doc.attr('docdir')
150
- assert_equal '.asciidoc', doc.attr('docfilesuffix')
151
- end
152
-
153
- test 'should not load invalid file' do
154
- sample_input_path = fixture_path('hello-asciidoctor.pdf')
155
- exception = assert_raises ArgumentError do
156
- Asciidoctor.load_file(sample_input_path, :safe => Asciidoctor::SafeMode::SAFE)
157
- end
158
- assert_match(/Failed to load AsciiDoc document/, exception.message)
159
- # verify we have the correct backtrace (should be in at least first 5 lines)
160
- assert_match((RUBY_ENGINE == 'rbx' ? /parser\.rb/ : /helpers\.rb/), exception.backtrace[0..4].join("\n"))
161
- end if RUBY_MIN_VERSION_1_9
162
-
163
- test 'should load input IO' do
164
- input = StringIO.new(<<-EOS)
165
- Document Title
166
- ==============
167
-
168
- preamble
169
- EOS
170
- doc = Asciidoctor.load(input, :safe => Asciidoctor::SafeMode::SAFE)
171
- assert_equal 'Document Title', doc.doctitle
172
- refute doc.attr?('docfile')
173
- assert_equal doc.base_dir, doc.attr('docdir')
174
- end
175
-
176
- test 'should load input string' do
177
- input = <<-EOS
178
- Document Title
179
- ==============
180
-
181
- preamble
182
- EOS
183
- doc = Asciidoctor.load(input, :safe => Asciidoctor::SafeMode::SAFE)
184
- assert_equal 'Document Title', doc.doctitle
185
- refute doc.attr?('docfile')
186
- assert_equal doc.base_dir, doc.attr('docdir')
187
- end
188
-
189
- test 'should load input string array' do
190
- input = <<-EOS
191
- Document Title
192
- ==============
193
-
194
- preamble
195
- EOS
196
- doc = Asciidoctor.load(input.lines.entries, :safe => Asciidoctor::SafeMode::SAFE)
197
- assert_equal 'Document Title', doc.doctitle
198
- refute doc.attr?('docfile')
199
- assert_equal doc.base_dir, doc.attr('docdir')
200
- end
201
-
202
- test 'should accept attributes as array' do
203
- # NOTE there's a tab character before idseparator
204
- doc = Asciidoctor.load('text', :attributes => %w(toc sectnums source-highlighter=coderay idprefix idseparator=-))
205
- assert_kind_of Hash, doc.attributes
206
- assert doc.attr?('toc')
207
- assert_equal '', doc.attr('toc')
208
- assert doc.attr?('sectnums')
209
- assert_equal '', doc.attr('sectnums')
210
- assert doc.attr?('source-highlighter')
211
- assert_equal 'coderay', doc.attr('source-highlighter')
212
- assert doc.attr?('idprefix')
213
- assert_equal '', doc.attr('idprefix')
214
- assert doc.attr?('idseparator')
215
- assert_equal '-', doc.attr('idseparator')
216
- end
217
-
218
- test 'should accept attributes as empty array' do
219
- doc = Asciidoctor.load('text', :attributes => [])
220
- assert_kind_of Hash, doc.attributes
221
- end
222
-
223
- test 'should accept attributes as string' do
224
- doc = Asciidoctor.load('text', :attributes => 'toc sectnums
225
- source-highlighter=coderay
226
- idprefix
227
- idseparator=-')
228
- assert_kind_of Hash, doc.attributes
229
- assert doc.attr?('toc')
230
- assert_equal '', doc.attr('toc')
231
- assert doc.attr?('sectnums')
232
- assert_equal '', doc.attr('sectnums')
233
- assert doc.attr?('source-highlighter')
234
- assert_equal 'coderay', doc.attr('source-highlighter')
235
- assert doc.attr?('idprefix')
236
- assert_equal '', doc.attr('idprefix')
237
- assert doc.attr?('idseparator')
238
- assert_equal '-', doc.attr('idseparator')
239
- end
240
-
241
- test 'should accept values containing spaces in attributes string' do
242
- doc = Asciidoctor.load('text', :attributes => %(idprefix idseparator=- note-caption=Note\\ to\\\tself toc))
243
- assert_kind_of Hash, doc.attributes
244
- assert doc.attr?('idprefix')
245
- assert_equal '', doc.attr('idprefix')
246
- assert doc.attr?('idseparator')
247
- assert_equal '-', doc.attr('idseparator')
248
- assert doc.attr?('note-caption')
249
- assert_equal "Note to\tself", doc.attr('note-caption')
250
- end
251
-
252
- test 'should accept attributes as empty string' do
253
- doc = Asciidoctor.load('text', :attributes => '')
254
- assert_kind_of Hash, doc.attributes
255
- end
256
-
257
- test 'should accept attributes as nil' do
258
- doc = Asciidoctor.load('text', :attributes => nil)
259
- assert_kind_of Hash, doc.attributes
260
- end
261
-
262
- test 'should accept attributes if hash like' do
263
- class Hashish
264
- def initialize
265
- @table = {'toc' => ''}
266
- end
267
-
268
- def keys
269
- @table.keys
270
- end
271
-
272
- def [](key)
273
- @table[key]
274
- end
275
- end
276
-
277
- doc = Asciidoctor.load('text', :attributes => Hashish.new)
278
- assert_kind_of Hash, doc.attributes
279
- assert doc.attributes.has_key?('toc')
280
- end
281
-
282
- test 'should output timestamps by default' do
283
- doc = document_from_string 'text', :backend => :html5, :attributes => nil
284
- result = doc.convert
285
- assert doc.attr?('docdate')
286
- refute doc.attr? 'reproducible'
287
- assert_xpath '//div[@id="footer-text" and contains(string(.//text()), "Last updated")]', result, 1
288
- end
289
-
290
- test 'should not output timestamps if reproducible attribute is set in HTML 5' do
291
- doc = document_from_string 'text', :backend => :html5, :attributes => { 'reproducible' => '' }
292
- result = doc.convert
293
- assert doc.attr?('docdate')
294
- assert doc.attr?('reproducible')
295
- assert_xpath '//div[@id="footer-text" and contains(string(.//text()), "Last updated")]', result, 0
296
- end
297
-
298
- test 'should not output timestamps if reproducible attribute is set in DocBook' do
299
- doc = document_from_string 'text', :backend => :docbook, :attributes => { 'reproducible' => '' }
300
- result = doc.convert
301
- assert doc.attr?('docdate')
302
- assert doc.attr?('reproducible')
303
- assert_xpath '/article/info/date', result, 0
304
- end
305
-
306
- test 'should not modify options argument' do
307
- options = {
308
- :safe => Asciidoctor::SafeMode::SAFE
309
- }
310
- options.freeze
311
- sample_input_path = fixture_path('sample.asciidoc')
312
- begin
313
- Asciidoctor.load_file sample_input_path, options
314
- rescue
315
- flunk %(options argument should not be modified)
316
- end
317
- end
318
-
319
- test 'should not modify attributes Hash argument' do
320
- attributes = {}
321
- attributes.freeze
322
- options = {
323
- :safe => Asciidoctor::SafeMode::SAFE,
324
- :attributes => attributes
325
- }
326
- sample_input_path = fixture_path('sample.asciidoc')
327
- begin
328
- Asciidoctor.load_file sample_input_path, options
329
- rescue
330
- flunk %(attributes argument should not be modified)
331
- end
332
- end
333
-
334
- test 'should track file and line information with blocks if sourcemap option is set' do
335
- doc = Asciidoctor.load_file fixture_path('sample.asciidoc'), :sourcemap => true
336
-
337
- section_1 = doc.sections[0]
338
- assert_equal 'Section A', section_1.title
339
- refute_nil section_1.source_location
340
- assert_equal 'sample.asciidoc', section_1.file
341
- assert_equal 10, section_1.lineno
342
-
343
- section_2 = doc.sections[1]
344
- assert_equal 'Section B', section_2.title
345
- refute_nil section_2.source_location
346
- assert_equal 'sample.asciidoc', section_2.file
347
- assert_equal 18, section_2.lineno
348
-
349
- last_block = section_2.blocks[-1]
350
- assert_equal :ulist, last_block.context
351
- refute_nil last_block.source_location
352
- assert_equal 'sample.asciidoc', last_block.file
353
- assert_equal 23, last_block.lineno
354
-
355
- doc = Asciidoctor.load_file fixture_path('master.adoc'), :sourcemap => true, :safe => :safe
356
-
357
- section_1 = doc.sections[0]
358
- assert_equal 'Chapter A', section_1.title
359
- refute_nil section_1.source_location
360
- assert_equal fixture_path('chapter-a.adoc'), section_1.file
361
- assert_equal 1, section_1.lineno
362
- end
363
-
364
- test 'should assign correct source location if section occurs on last line of input' do
365
- input = <<-EOS
366
- = Document Title
367
-
368
- == Section A
369
-
370
- content
371
-
372
- == Section B
373
- EOS
374
-
375
- doc = document_from_string input, :sourcemap => true
376
- assert_equal [1, 3, 7], (doc.find_by :context => :section).map(&:lineno)
377
- end
378
-
379
- test 'should allow sourcemap option on document to be modified' do
380
- doc = Asciidoctor.load_file fixture_path('sample.asciidoc'), :parse => false
381
- doc.sourcemap = true
382
- doc = doc.parse
383
-
384
- section_1 = doc.sections[0]
385
- assert_equal 'Section A', section_1.title
386
- refute_nil section_1.source_location
387
- assert_equal 'sample.asciidoc', section_1.file
388
- assert_equal 10, section_1.lineno
389
- end
390
-
391
- test 'find_by should return Array of blocks anywhere in document tree that match criteria' do
392
- input = <<-EOS
393
- = Document Title
394
-
395
- preamble
396
-
397
- == Section A
398
-
399
- paragraph
400
-
401
- --
402
- Exhibit A::
403
- +
404
- [#tiger.animal]
405
- image::tiger.png[Tiger]
406
- --
407
-
408
- image::shoe.png[Shoe]
409
-
410
- == Section B
411
-
412
- paragraph
413
- EOS
414
-
415
- doc = Asciidoctor.load input
416
- result = doc.find_by :context => :image
417
- assert_equal 2, result.size
418
- assert_equal :image, result[0].context
419
- assert_equal 'tiger.png', result[0].attr('target')
420
- assert_equal :image, result[1].context
421
- assert_equal 'shoe.png', result[1].attr('target')
422
- end
423
-
424
- test 'find_by should return an empty Array if no matches are found' do
425
- input = <<-EOS
426
- paragraph
427
- EOS
428
- doc = Asciidoctor.load input
429
- result = doc.find_by :context => :section
430
- refute_nil result
431
- assert_equal 0, result.size
432
- end
433
-
434
- test 'find_by should return Array of blocks that match style criteria' do
435
- input = <<-EOS
436
- [square]
437
- * one
438
- * two
439
- * three
440
-
441
- ---
442
-
443
- * apples
444
- * bananas
445
- * pears
446
- EOS
447
-
448
- doc = Asciidoctor.load input
449
- result = doc.find_by :context => :ulist, :style => 'square'
450
- assert_equal 1, result.size
451
- assert_equal :ulist, result[0].context
452
- end
453
-
454
- test 'find_by should return Array of blocks that match role criteria' do
455
- input = <<-EOS
456
- [#tiger.animal]
457
- image::tiger.png[Tiger]
458
-
459
- image::shoe.png[Shoe]
460
- EOS
461
-
462
- doc = Asciidoctor.load input
463
- result = doc.find_by :context => :image, :role => 'animal'
464
- assert_equal 1, result.size
465
- assert_equal :image, result[0].context
466
- assert_equal 'tiger.png', result[0].attr('target')
467
- end
468
-
469
- test 'find_by should return the document title section if context selector is :section' do
470
- input = <<-EOS
471
- = Document Title
472
-
473
- preamble
474
-
475
- == Section One
476
-
477
- content
478
- EOS
479
- doc = Asciidoctor.load input
480
- result = doc.find_by :context => :section
481
- refute_nil result
482
- assert_equal 2, result.size
483
- assert_equal :section, result[0].context
484
- assert_equal 'Document Title', result[0].title
485
- end
486
-
487
- test 'find_by should only return results for which the block argument yields true' do
488
- input = <<-EOS
489
- == Section
490
-
491
- content
492
-
493
- === Subsection
494
-
495
- content
496
- EOS
497
- doc = Asciidoctor.load input
498
- result = doc.find_by(:context => :section) {|sect| sect.level == 1 }
499
- refute_nil result
500
- assert_equal 1, result.size
501
- assert_equal :section, result[0].context
502
- assert_equal 'Section', result[0].title
503
- end
504
-
505
- test 'find_by should only return one result when matching by id' do
506
- input = <<-EOS
507
- == Section
508
-
509
- content
510
-
511
- [#subsection]
512
- === Subsection
513
-
514
- content
515
- EOS
516
- doc = Asciidoctor.load input
517
- result = doc.find_by(:context => :section, :id => 'subsection')
518
- refute_nil result
519
- assert_equal 1, result.size
520
- assert_equal :section, result[0].context
521
- assert_equal 'Subsection', result[0].title
522
- end
523
-
524
- test 'find_by should return an empty Array if the id criteria matches but the block argument yields false' do
525
- input = <<-EOS
526
- == Section
527
-
528
- content
529
-
530
- [#subsection]
531
- === Subsection
532
-
533
- content
534
- EOS
535
- doc = Asciidoctor.load input
536
- result = doc.find_by(:context => :section, :id => 'subsection') {|sect| false }
537
- refute_nil result
538
- assert_equal 0, result.size
539
- end
540
-
541
- test 'find_by should not crash if dlist entry does not have description' do
542
- input = <<-EOS
543
- term without description::
544
- EOS
545
- doc = Asciidoctor.load input
546
- result = doc.find_by
547
- refute_nil result
548
- assert_equal 3, result.size
549
- assert_kind_of Asciidoctor::Document, result[0]
550
- assert_kind_of Asciidoctor::List, result[1]
551
- assert_kind_of Asciidoctor::ListItem, result[2]
552
- end
553
- end
554
-
555
- context 'Convert APIs' do
556
- test 'should convert source document to string when to_file is false' do
557
- sample_input_path = fixture_path('sample.asciidoc')
558
-
559
- output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :to_file => false
560
- refute_empty output
561
- assert_xpath '/html', output, 1
562
- assert_xpath '/html/head', output, 1
563
- assert_xpath '/html/body', output, 1
564
- assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
565
- assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
566
- end
567
-
568
- test 'lines in output should be separated by line feed' do
569
- sample_input_path = fixture_path('sample.asciidoc')
570
-
571
- output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :to_file => false
572
- refute_empty output
573
- lines = output.split("\n")
574
- assert_equal lines.size, output.split(/\r\n|\r|\n/).size
575
- raw_lengths = lines.map(&:length)
576
- trimmed_lengths = lines.map {|line| line.rstrip.length }
577
- assert_equal raw_lengths, trimmed_lengths
578
- end
579
-
580
- test 'should accept attributes as array' do
581
- sample_input_path = fixture_path('sample.asciidoc')
582
- output = Asciidoctor.convert_file sample_input_path, :attributes => %w(sectnums idprefix idseparator=-), :to_file => false
583
- assert_css '#section-a', output, 1
584
- end
585
-
586
- test 'should accept attributes as string' do
587
- sample_input_path = fixture_path('sample.asciidoc')
588
- output = Asciidoctor.convert_file sample_input_path, :attributes => 'sectnums idprefix idseparator=-', :to_file => false
589
- assert_css '#section-a', output, 1
590
- end
591
-
592
- test 'should link to default stylesheet by default when safe mode is SECURE or greater' do
593
- sample_input_path = fixture_path('basic.asciidoc')
594
- output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :to_file => false
595
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 1
596
- assert_css 'html:root > head > link[rel="stylesheet"][href="./asciidoctor.css"]', output, 1
597
- end
598
-
599
- test 'should embed default stylesheet by default if SafeMode is less than SECURE' do
600
- input = <<-EOS
601
- = Document Title
602
-
603
- text
604
- EOS
605
-
606
- output = Asciidoctor.render(input, :safe => Asciidoctor::SafeMode::SERVER, :header_footer => true)
607
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 1
608
- assert_css 'html:root > head > link[rel="stylesheet"][href="./asciidoctor.css"]', output, 0
609
- stylenode = xmlnodes_at_css 'html:root > head > style', output, 1
610
- styles = stylenode.content
611
- refute_nil styles
612
- refute_empty styles.strip
613
- end
614
-
615
- test 'should link to default stylesheet by default even if linkcss is unset in document' do
616
- input = <<-EOS
617
- = Document Title
618
- :linkcss!:
619
-
620
- text
621
- EOS
622
-
623
- output = Asciidoctor.render(input, :header_footer => true)
624
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 1
625
- assert_css 'html:root > head > link[rel="stylesheet"][href="./asciidoctor.css"]', output, 1
626
- end
627
-
628
- test 'should link to default stylesheet by default if linkcss is unset' do
629
- input = <<-EOS
630
- = Document Title
631
-
632
- text
633
- EOS
634
-
635
- output = Asciidoctor.render(input, :header_footer => true, :attributes => {'linkcss!' => ''})
636
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 1
637
- assert_css 'html:root > head > link[rel="stylesheet"][href="./asciidoctor.css"]', output, 1
638
- end
639
-
640
- test 'should embed default stylesheet if safe mode is less than secure and linkcss is unset' do
641
- sample_input_path = fixture_path('basic.asciidoc')
642
- output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :to_file => false,
643
- :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'linkcss!' => ''}
644
- assert_css 'html:root > head > style', output, 1
645
- stylenode = xmlnodes_at_css 'html:root > head > style', output, 1
646
- styles = stylenode.content
647
- refute_nil styles
648
- refute_empty styles.strip
649
- end
650
-
651
- test 'should not link to stylesheet if stylesheet is unset' do
652
- input = <<-EOS
653
- = Document Title
654
-
655
- text
656
- EOS
657
-
658
- output = Asciidoctor.render(input, :header_footer => true, :attributes => {'stylesheet!' => ''})
659
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 0
660
- assert_css 'html:root > head > link[rel="stylesheet"]', output, 0
661
- end
662
-
663
- test 'should link to custom stylesheet if specified in stylesheet attribute' do
664
- input = <<-EOS
665
- = Document Title
666
-
667
- text
668
- EOS
669
-
670
- output = Asciidoctor.render(input, :header_footer => true, :attributes => {'stylesheet' => './custom.css'})
671
- assert_css 'html:root > head > link[rel="stylesheet"][href^="https://fonts.googleapis.com"]', output, 0
672
- assert_css 'html:root > head > link[rel="stylesheet"][href="./custom.css"]', output, 1
673
-
674
- output = Asciidoctor.render(input, :header_footer => true, :attributes => {'stylesheet' => 'file:///home/username/custom.css'})
675
- assert_css 'html:root > head > link[rel="stylesheet"][href="file:///home/username/custom.css"]', output, 1
676
- end
677
-
678
- test 'should resolve custom stylesheet relative to stylesdir' do
679
- input = <<-EOS
680
- = Document Title
681
-
682
- text
683
- EOS
684
-
685
- output = Asciidoctor.render(input, :header_footer => true, :attributes => {'stylesheet' => 'custom.css', 'stylesdir' => './stylesheets'})
686
- assert_css 'html:root > head > link[rel="stylesheet"][href="./stylesheets/custom.css"]', output, 1
687
- end
688
-
689
- test 'should resolve custom stylesheet to embed relative to stylesdir' do
690
- sample_input_path = fixture_path('basic.asciidoc')
691
- output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :safe => Asciidoctor::SafeMode::SAFE, :to_file => false,
692
- :attributes => {'stylesheet' => 'custom.css', 'stylesdir' => './stylesheets', 'linkcss!' => ''}
693
- stylenode = xmlnodes_at_css 'html:root > head > style', output, 1
694
- styles = stylenode.content
695
- refute_nil styles
696
- refute_empty styles.strip
697
- end
698
-
699
- test 'should convert source file and write result to adjacent file by default' do
700
- sample_input_path = fixture_path('sample.asciidoc')
701
- sample_output_path = fixture_path('sample.html')
702
- begin
703
- Asciidoctor.convert_file sample_input_path
704
- assert File.exist?(sample_output_path)
705
- output = IO.read(sample_output_path)
706
- refute_empty output
707
- assert_xpath '/html', output, 1
708
- assert_xpath '/html/head', output, 1
709
- assert_xpath '/html/body', output, 1
710
- assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
711
- assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
712
- ensure
713
- FileUtils.rm(sample_output_path)
714
- end
715
- end
716
-
717
- test 'should convert source file and write to specified file' do
718
- sample_input_path = fixture_path('sample.asciidoc')
719
- sample_output_path = fixture_path('result.html')
720
- begin
721
- Asciidoctor.convert_file sample_input_path, :to_file => sample_output_path
722
- assert File.exist?(sample_output_path)
723
- output = IO.read(sample_output_path)
724
- refute_empty output
725
- assert_xpath '/html', output, 1
726
- assert_xpath '/html/head', output, 1
727
- assert_xpath '/html/body', output, 1
728
- assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
729
- assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
730
- ensure
731
- FileUtils.rm(sample_output_path)
732
- end
733
- end
734
-
735
- test 'should convert source file and write to specified file in base_dir' do
736
- sample_input_path = fixture_path('sample.asciidoc')
737
- sample_output_path = fixture_path('result.html')
738
- fixture_dir = fixture_path('')
739
- begin
740
- Asciidoctor.convert_file sample_input_path, :to_file => 'result.html', :base_dir => fixture_dir
741
- assert File.exist?(sample_output_path)
742
- output = IO.read(sample_output_path)
743
- refute_empty output
744
- assert_xpath '/html', output, 1
745
- assert_xpath '/html/head', output, 1
746
- assert_xpath '/html/body', output, 1
747
- assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
748
- assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
749
- rescue => e
750
- flunk e.message
751
- ensure
752
- FileUtils.rm(sample_output_path, :force => true)
753
- end
754
- end
755
-
756
- test 'in_place option is ignored when to_file is specified' do
757
- sample_input_path = fixture_path('sample.asciidoc')
758
- sample_output_path = fixture_path('result.html')
759
- begin
760
- Asciidoctor.convert_file sample_input_path, :to_file => sample_output_path, :in_place => true
761
- assert File.exist?(sample_output_path)
762
- ensure
763
- FileUtils.rm(sample_output_path) if File.exist? sample_output_path
764
- end
765
- end
766
-
767
- test 'in_place option is ignored when to_dir is specified' do
768
- sample_input_path = fixture_path('sample.asciidoc')
769
- sample_output_path = fixture_path('sample.html')
770
- begin
771
- Asciidoctor.convert_file sample_input_path, :to_dir => File.dirname(sample_output_path), :in_place => true
772
- assert File.exist?(sample_output_path)
773
- ensure
774
- FileUtils.rm(sample_output_path) if File.exist? sample_output_path
775
- end
776
- end
777
-
778
- test 'output should be relative to to_dir option' do
779
- sample_input_path = fixture_path('sample.asciidoc')
780
- output_dir = File.join(File.dirname(sample_input_path), 'test_output')
781
- Dir.mkdir output_dir if !File.exist? output_dir
782
- sample_output_path = File.join(output_dir, 'sample.html')
783
- begin
784
- Asciidoctor.convert_file sample_input_path, :to_dir => output_dir
785
- assert File.exist? sample_output_path
786
- ensure
787
- FileUtils.rm(sample_output_path) if File.exist? sample_output_path
788
- FileUtils.rmdir output_dir
789
- end
790
- end
791
-
792
- test 'missing directories should be created if mkdirs is enabled' do
793
- sample_input_path = fixture_path('sample.asciidoc')
794
- output_dir = File.join(File.join(File.dirname(sample_input_path), 'test_output'), 'subdir')
795
- sample_output_path = File.join(output_dir, 'sample.html')
796
- begin
797
- Asciidoctor.convert_file sample_input_path, :to_dir => output_dir, :mkdirs => true
798
- assert File.exist? sample_output_path
799
- ensure
800
- FileUtils.rm(sample_output_path) if File.exist? sample_output_path
801
- FileUtils.rmdir output_dir
802
- FileUtils.rmdir File.dirname(output_dir)
803
- end
804
- end
805
-
806
- # TODO need similar test for when to_dir is specified
807
- test 'should raise exception if an attempt is made to overwrite input file' do
808
- sample_input_path = fixture_path('sample.asciidoc')
809
-
810
- assert_raises IOError do
811
- Asciidoctor.convert_file sample_input_path, :attributes => { 'outfilesuffix' => '.asciidoc' }
812
- end
813
- end
814
-
815
- test 'to_file should be relative to to_dir when both given' do
816
- sample_input_path = fixture_path('sample.asciidoc')
817
- base_dir = File.dirname(sample_input_path)
818
- sample_rel_output_path = File.join('test_output', 'result.html')
819
- output_dir = File.dirname(File.join(base_dir, sample_rel_output_path))
820
- Dir.mkdir output_dir if !File.exist? output_dir
821
- sample_output_path = File.join(base_dir, sample_rel_output_path)
822
- begin
823
- Asciidoctor.convert_file sample_input_path, :to_dir => base_dir, :to_file => sample_rel_output_path
824
- assert File.exist? sample_output_path
825
- ensure
826
- FileUtils.rm(sample_output_path) if File.exist? sample_output_path
827
- FileUtils.rmdir output_dir
828
- end
829
- end
830
-
831
- test 'should not modify options argument' do
832
- options = {
833
- :safe => Asciidoctor::SafeMode::SAFE,
834
- :to_file => false
835
- }
836
- options.freeze
837
- sample_input_path = fixture_path('sample.asciidoc')
838
- begin
839
- Asciidoctor.convert_file sample_input_path, options
840
- rescue
841
- flunk %(options argument should not be modified)
842
- end
843
- end
844
- end
845
-
846
134
  context 'Docinfo files' do
847
135
  test 'should include docinfo files for html backend' do
848
136
  sample_input_path = fixture_path('basic.asciidoc')
@@ -1048,18 +336,17 @@ text
1048
336
 
1049
337
  test 'should substitute attributes in docinfo files by default' do
1050
338
  sample_input_path = fixture_path 'subs.adoc'
1051
- output, warnings = redirect_streams do |_, err|
339
+ using_memory_logger do |logger|
1052
340
  output = Asciidoctor.convert_file sample_input_path,
1053
341
  :to_file => false,
1054
342
  :header_footer => true,
1055
343
  :safe => :server,
1056
344
  :attributes => { 'docinfo' => '', 'bootstrap-version' => nil, 'linkcss' => '', 'attribute-missing' => 'drop-line' }
1057
- [output, err.string]
345
+ refute_empty output
346
+ assert_css 'script', output, 0
347
+ assert_xpath %(//meta[@name="copyright"][@content="(C) OpenDevise"]), output, 1
348
+ assert_message logger, :WARN, 'dropping line containing reference to missing attribute: bootstrap-version'
1058
349
  end
1059
- refute_empty output
1060
- assert_css 'script', output, 0
1061
- assert_xpath %(//meta[@name="copyright"][@content="(C) OpenDevise"]), output, 1
1062
- assert_includes warnings, 'dropping line containing reference to missing attribute'
1063
350
  end
1064
351
 
1065
352
  test 'should apply explicit substitutions to docinfo files' do
@@ -1134,9 +421,9 @@ text
1134
421
  '/img/favicon.png' => %w(/img/favicon.png image/png)
1135
422
  }.each {|val, (href, type)|
1136
423
  result = render_string %(= Untitled), :attributes => { 'favicon' => val }
1137
- assert_css 'link[rel="shortcut icon"]', result, 1
1138
- assert_css %(link[rel="shortcut icon"][href="#{href}"]), result, 1
1139
- assert_css %(link[rel="shortcut icon"][type="#{type}"]), result, 1
424
+ assert_css 'link[rel="icon"]', result, 1
425
+ assert_css %(link[rel="icon"][href="#{href}"]), result, 1
426
+ assert_css %(link[rel="icon"][type="#{type}"]), result, 1
1140
427
  }
1141
428
  end
1142
429
  end
@@ -1302,7 +589,25 @@ Block content
1302
589
  assert doc.has_header?
1303
590
  assert_equal 'Document Title', doc.header.title
1304
591
  assert_equal 'Document Title', doc.first_section.title
1305
- assert_xpath '//*[@id="preamble"]//p[text()="Document Title"]', doc.render, 1
592
+ assert_xpath '//*[@id="preamble"]//p[text()="Document Title"]', doc.convert, 1
593
+ end
594
+
595
+ test 'document with blank title attribute entry overrides doctitle' do
596
+ input = <<-EOS
597
+ = Document Title
598
+ :title:
599
+
600
+ {doctitle}
601
+
602
+ == First Section
603
+ EOS
604
+ doc = document_from_string input
605
+ assert_equal '', doc.doctitle
606
+ assert_equal '', doc.title
607
+ assert doc.has_header?
608
+ assert_equal 'Document Title', doc.header.title
609
+ assert_equal 'Document Title', doc.first_section.title
610
+ assert_xpath '//*[@id="preamble"]//p[text()="Document Title"]', doc.convert, 1
1306
611
  end
1307
612
 
1308
613
  test 'document with title attribute entry overrides doctitle attribute entry' do
@@ -1322,7 +627,7 @@ Block content
1322
627
  assert doc.has_header?
1323
628
  assert_equal 'doctitle', doc.header.title
1324
629
  assert_equal 'doctitle', doc.first_section.title
1325
- assert_xpath '//*[@id="preamble"]//p[text()="Document Title, doctitle"]', doc.render, 1
630
+ assert_xpath '//*[@id="preamble"]//p[text()="Document Title, doctitle"]', doc.convert, 1
1326
631
  end
1327
632
 
1328
633
  test 'document with doctitle attribute entry overrides header title and doctitle' do
@@ -1337,11 +642,11 @@ Block content
1337
642
  EOS
1338
643
  doc = document_from_string input
1339
644
  assert_equal 'Override', doc.doctitle
1340
- assert_nil doc.title
645
+ assert_nil doc.attributes['title']
1341
646
  assert doc.has_header?
1342
647
  assert_equal 'Override', doc.header.title
1343
648
  assert_equal 'Override', doc.first_section.title
1344
- assert_xpath '//*[@id="preamble"]//p[text()="Document Title, Override"]', doc.render, 1
649
+ assert_xpath '//*[@id="preamble"]//p[text()="Document Title, Override"]', doc.convert, 1
1345
650
  end
1346
651
 
1347
652
  test 'doctitle attribute entry above header overrides header title and doctitle' do
@@ -1355,11 +660,11 @@ Block content
1355
660
  EOS
1356
661
  doc = document_from_string input
1357
662
  assert_equal 'Override', doc.doctitle
1358
- assert_nil doc.title
663
+ assert_nil doc.attributes['title']
1359
664
  assert doc.has_header?
1360
665
  assert_equal 'Override', doc.header.title
1361
666
  assert_equal 'Override', doc.first_section.title
1362
- assert_xpath '//*[@id="preamble"]//p[text()="Override"]', doc.render, 1
667
+ assert_xpath '//*[@id="preamble"]//p[text()="Override"]', doc.convert, 1
1363
668
  end
1364
669
 
1365
670
  test 'should recognize document title when preceded by blank lines' do
@@ -1568,6 +873,18 @@ content
1568
873
  assert_xpath '//meta[@name="author"][@content="Ze Product team"]', output, 1
1569
874
  end
1570
875
 
876
+ test 'should not double escape ampersand in author attribute' do
877
+ input = <<-EOS
878
+ = Document Title
879
+ R&D Lab
880
+
881
+ {author}
882
+ EOS
883
+
884
+ output = render_string input
885
+ assert_includes output, 'R&amp;D Lab', 2
886
+ end
887
+
1571
888
  test 'should include multiple authors in HTML output' do
1572
889
  input = <<-EOS
1573
890
  = Document Title
@@ -1605,6 +922,19 @@ content
1605
922
  assert_xpath '//articleinfo/authorgroup/author[2]/firstname[text() = "Junior"]', output, 1
1606
923
  end
1607
924
 
925
+ test 'with author defined by indexed attribute name' do
926
+ input = <<-EOS
927
+ = Document Title
928
+ :author_1: Doc Writer
929
+
930
+ {author}
931
+ EOS
932
+
933
+ doc = document_from_string input
934
+ assert_equal 'Doc Writer', (doc.attr 'author')
935
+ assert_equal 'Doc Writer', (doc.attr 'author_1')
936
+ end
937
+
1608
938
  test 'with authors defined using attribute entry to DocBook' do
1609
939
  input = <<-EOS
1610
940
  = Document Title
@@ -1625,10 +955,50 @@ content
1625
955
  assert_xpath '(//articleinfo/authorgroup/author)[2]/email[text() = "junior@asciidoc.org"]', output, 1
1626
956
  end
1627
957
 
958
+ test 'should populate copyright element in DocBook output if copyright attribute is defined' do
959
+ input = <<-EOS
960
+ = Jet Bike
961
+ :copyright: ACME, Inc.
962
+
963
+ Essential for catching road runners.
964
+ EOS
965
+ output = render_string input, :backend => 'docbook5'
966
+ assert_xpath '/article/info/copyright', output, 1
967
+ assert_xpath '/article/info/copyright/holder[text()="ACME, Inc."]', output, 1
968
+ end
969
+
970
+ test 'should populate copyright element in DocBook output if copyright attribute is defined with year' do
971
+ input = <<-EOS
972
+ = Jet Bike
973
+ :copyright: ACME, Inc. 1956
974
+
975
+ Essential for catching road runners.
976
+ EOS
977
+ output = render_string input, :backend => 'docbook5'
978
+ assert_xpath '/article/info/copyright', output, 1
979
+ assert_xpath '/article/info/copyright/holder[text()="ACME, Inc."]', output, 1
980
+ assert_xpath '/article/info/copyright/year', output, 1
981
+ assert_xpath '/article/info/copyright/year[text()="1956"]', output, 1
982
+ end
983
+
984
+ test 'should populate copyright element in DocBook output if copyright attribute is defined with year range' do
985
+ input = <<-EOS
986
+ = Jet Bike
987
+ :copyright: ACME, Inc. 1956-2018
988
+
989
+ Essential for catching road runners.
990
+ EOS
991
+ output = render_string input, :backend => 'docbook5'
992
+ assert_xpath '/article/info/copyright', output, 1
993
+ assert_xpath '/article/info/copyright/holder[text()="ACME, Inc."]', output, 1
994
+ assert_xpath '/article/info/copyright/year', output, 1
995
+ assert_xpath '/article/info/copyright/year[text()="1956-2018"]', output, 1
996
+ end
997
+
1628
998
  test 'with header footer' do
1629
999
  doc = document_from_string "= Title\n\nparagraph"
1630
1000
  refute doc.attr?('embedded')
1631
- result = doc.render
1001
+ result = doc.convert
1632
1002
  assert_xpath '/html', result, 1
1633
1003
  assert_xpath '//*[@id="header"]', result, 1
1634
1004
  assert_xpath '//*[@id="header"]/h1', result, 1
@@ -1649,7 +1019,7 @@ content
1649
1019
 
1650
1020
  test 'can disable last updated in footer' do
1651
1021
  doc = document_from_string "= Document Title\n\npreamble", :attributes => {'last-update-label!' => ''}
1652
- result = doc.render
1022
+ result = doc.convert
1653
1023
  assert_xpath '//*[@id="footer-text"]', result, 1
1654
1024
  assert_xpath '//*[@id="footer-text"][normalize-space(text())=""]', result, 1
1655
1025
  end
@@ -1657,7 +1027,7 @@ content
1657
1027
  test 'no header footer' do
1658
1028
  doc = document_from_string "= Document Title\n\ncontent", :header_footer => false
1659
1029
  assert doc.attr?('embedded')
1660
- result = doc.render
1030
+ result = doc.convert
1661
1031
  assert_xpath '/html', result, 0
1662
1032
  assert_xpath '/h1', result, 0
1663
1033
  assert_xpath '/*[@id="header"]', result, 0
@@ -1726,13 +1096,13 @@ finally a reference to the second footnote footnoteref:[note2].
1726
1096
  output = render_string input
1727
1097
  assert_css '#footnotes', output, 1
1728
1098
  assert_css '#footnotes .footnote', output, 2
1729
- assert_css '#footnotes .footnote#_footnote_1', output, 1
1730
- assert_xpath '//div[@id="footnotes"]/div[@id="_footnote_1"]/a[@href="#_footnoteref_1"][text()="1"]', output, 1
1731
- text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnote_1"]/text()', output
1099
+ assert_css '#footnotes .footnote#_footnotedef_1', output, 1
1100
+ assert_xpath '//div[@id="footnotes"]/div[@id="_footnotedef_1"]/a[@href="#_footnoteref_1"][text()="1"]', output, 1
1101
+ text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnotedef_1"]/text()', output
1732
1102
  assert_equal '. An example footnote.', text.text.strip
1733
- assert_css '#footnotes .footnote#_footnote_2', output, 1
1734
- assert_xpath '//div[@id="footnotes"]/div[@id="_footnote_2"]/a[@href="#_footnoteref_2"][text()="2"]', output, 1
1735
- text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnote_2"]/text()', output
1103
+ assert_css '#footnotes .footnote#_footnotedef_2', output, 1
1104
+ assert_xpath '//div[@id="footnotes"]/div[@id="_footnotedef_2"]/a[@href="#_footnoteref_2"][text()="2"]', output, 1
1105
+ text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnotedef_2"]/text()', output
1736
1106
  assert_equal '. Second footnote.', text.text.strip
1737
1107
  end
1738
1108
 
@@ -1744,9 +1114,9 @@ Text that has supporting information{empty}footnote:[An example footnote.].
1744
1114
  output = render_embedded_string input
1745
1115
  assert_css '#footnotes', output, 1
1746
1116
  assert_css '#footnotes .footnote', output, 1
1747
- assert_css '#footnotes .footnote#_footnote_1', output, 1
1748
- assert_xpath '/div[@id="footnotes"]/div[@id="_footnote_1"]/a[@href="#_footnoteref_1"][text()="1"]', output, 1
1749
- text = xmlnodes_at_xpath '/div[@id="footnotes"]/div[@id="_footnote_1"]/text()', output
1117
+ assert_css '#footnotes .footnote#_footnotedef_1', output, 1
1118
+ assert_xpath '/div[@id="footnotes"]/div[@id="_footnotedef_1"]/a[@href="#_footnoteref_1"][text()="1"]', output, 1
1119
+ text = xmlnodes_at_xpath '/div[@id="footnotes"]/div[@id="_footnotedef_1"]/text()', output
1750
1120
  assert_equal '. An example footnote.', text.text.strip
1751
1121
  end
1752
1122
 
@@ -1776,12 +1146,29 @@ content{blank}footnote:[commentary]
1776
1146
 
1777
1147
  doc = document_from_string input
1778
1148
  refute_nil doc.catalog
1779
- assert_equal [:footnotes, :ids, :images, :includes, :indexterms, :links, :refs].to_set, doc.catalog.keys.to_set
1149
+ assert_equal [:footnotes, :ids, :images, :includes, :indexterms, :links, :refs, :callouts].to_set, doc.catalog.keys.to_set
1780
1150
  assert_same doc.catalog, doc.references
1781
1151
  assert_same doc.catalog[:footnotes], doc.references[:footnotes]
1782
1152
  assert_same doc.catalog[:ids], doc.references[:ids]
1783
1153
  assert_equal 'Section A', doc.references[:ids]['_section_a']
1784
1154
  end
1155
+
1156
+ test 'should catalog assets inside nested document' do
1157
+ input = <<-EOS
1158
+ image::outer.png[]
1159
+
1160
+ |===
1161
+ a|
1162
+ image::inner.png[]
1163
+ |===
1164
+ EOS
1165
+
1166
+ doc = document_from_string input, :catalog_assets => true
1167
+ images = doc.catalog[:images]
1168
+ refute_empty images
1169
+ assert_equal 2, images.size
1170
+ assert_equal images, ['outer.png', 'inner.png']
1171
+ end
1785
1172
  end
1786
1173
 
1787
1174
  context 'Backends and Doctypes' do
@@ -1861,6 +1248,7 @@ content
1861
1248
  Author Name
1862
1249
  v1.0, 2001-01-01
1863
1250
  :icons:
1251
+ :favicon:
1864
1252
 
1865
1253
  image:tiger.png[]
1866
1254
 
@@ -2057,6 +1445,8 @@ section body
2057
1445
  test 'docbook5 backend doctype manpage' do
2058
1446
  input = <<-EOS
2059
1447
  = asciidoctor(1)
1448
+ :mansource: Asciidoctor
1449
+ :manmanual: Asciidoctor Manual
2060
1450
 
2061
1451
  == NAME
2062
1452
 
@@ -2079,6 +1469,8 @@ section body
2079
1469
  assert_xpath '/xmlns:refentry/xmlns:info/xmlns:title[text() = "asciidoctor(1)"]', result, 1
2080
1470
  assert_xpath '/xmlns:refentry/xmlns:refmeta/xmlns:refentrytitle[text() = "asciidoctor"]', result, 1
2081
1471
  assert_xpath '/xmlns:refentry/xmlns:refmeta/xmlns:manvolnum[text() = "1"]', result, 1
1472
+ assert_xpath '/xmlns:refentry/xmlns:refmeta/xmlns:refmiscinfo[@class="source"][text() = "Asciidoctor"]', result, 1
1473
+ assert_xpath '/xmlns:refentry/xmlns:refmeta/xmlns:refmiscinfo[@class="manual"][text() = "Asciidoctor Manual"]', result, 1
2082
1474
  assert_xpath '/xmlns:refentry/xmlns:refnamediv/xmlns:refname[text() = "asciidoctor"]', result, 1
2083
1475
  assert_xpath '/xmlns:refentry/xmlns:refnamediv/xmlns:refpurpose[text() = "Process text"]', result, 1
2084
1476
  assert_xpath '/xmlns:refentry/xmlns:refsynopsisdiv', result, 1
@@ -2093,6 +1485,23 @@ section body
2093
1485
  assert_equal '_first_section', id_attr.value
2094
1486
  end
2095
1487
 
1488
+ test 'should output non-breaking space for source and manual in docbook5 manpage output if absent from source' do
1489
+ input = <<-EOS
1490
+ = asciidoctor(1)
1491
+
1492
+ == NAME
1493
+
1494
+ asciidoctor - Process text
1495
+
1496
+ == SYNOPSIS
1497
+
1498
+ some text
1499
+ EOS
1500
+ result = render_string(input, :keep_namespaces => true, :attributes => {'backend' => 'docbook5', 'doctype' => 'manpage'})
1501
+ assert_xpath %(/xmlns:refentry/xmlns:refmeta/xmlns:refmiscinfo[@class="source"][text() = "#{decode_char 160}"]), result, 1
1502
+ assert_xpath %(/xmlns:refentry/xmlns:refmeta/xmlns:refmiscinfo[@class="manual"][text() = "#{decode_char 160}"]), result, 1
1503
+ end
1504
+
2096
1505
  test 'docbook5 backend doctype book' do
2097
1506
  input = <<-EOS
2098
1507
  = Title
@@ -2122,6 +1531,30 @@ chapter body
2122
1531
  assert_equal '_first_chapter', id_attr.value
2123
1532
  end
2124
1533
 
1534
+ test 'adds refname to DocBook output for each name defined in NAME section of manpage' do
1535
+ input = <<-EOS
1536
+ = eve(1)
1537
+ Andrew Stanton
1538
+ v1.0.0
1539
+ :doctype: manpage
1540
+ :manmanual: EVE
1541
+ :mansource: EVE
1542
+
1543
+ == NAME
1544
+
1545
+ eve, islifeform - analyzes an image to determine if it's a picture of a life form
1546
+
1547
+ == SYNOPSIS
1548
+
1549
+ *eve* ['OPTION']... 'FILE'...
1550
+ EOS
1551
+
1552
+ result = render_string input, :backend => 'docbook5'
1553
+ assert_xpath '/refentry/refnamediv/refname', result, 2
1554
+ assert_xpath '(/refentry/refnamediv/refname)[1][text()="eve"]', result, 1
1555
+ assert_xpath '(/refentry/refnamediv/refname)[2][text()="islifeform"]', result, 1
1556
+ end
1557
+
2125
1558
  test 'adds a front and back cover image to DocBook 5 when doctype is book' do
2126
1559
  input = <<-EOS
2127
1560
  = Title
@@ -2214,24 +1647,24 @@ preamble
2214
1647
  asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2215
1648
  EOS
2216
1649
 
2217
- doc = document_from_string input
2218
- assert_equal 'asciidoctor', doc.attr('mantitle')
2219
- assert_equal '1', doc.attr('manvolnum')
1650
+ doc = document_from_string input
1651
+ assert_equal 'asciidoctor', doc.attr('mantitle')
1652
+ assert_equal '1', doc.attr('manvolnum')
2220
1653
  end
2221
1654
 
2222
1655
  test 'should perform attribute substitution on mantitle in manpage doctype' do
2223
1656
  input = <<-EOS
2224
1657
  = {app}(1)
2225
1658
  :doctype: manpage
2226
- :app: asciidoctor
1659
+ :app: Asciidoctor
2227
1660
 
2228
1661
  == NAME
2229
1662
 
2230
1663
  asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2231
1664
  EOS
2232
1665
 
2233
- doc = document_from_string input
2234
- assert_equal 'asciidoctor', doc.attr('mantitle')
1666
+ doc = document_from_string input
1667
+ assert_equal 'asciidoctor', doc.attr('mantitle')
2235
1668
  end
2236
1669
 
2237
1670
  test 'should consume name section as manname and manpurpose for manpage doctype' do
@@ -2244,10 +1677,11 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2244
1677
  asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2245
1678
  EOS
2246
1679
 
2247
- doc = document_from_string input
2248
- assert_equal 'asciidoctor', doc.attr('manname')
2249
- assert_equal 'converts AsciiDoc source files to HTML, DocBook and other formats', doc.attr('manpurpose')
2250
- assert_equal 0, doc.blocks.size
1680
+ doc = document_from_string input
1681
+ assert_equal 'asciidoctor', doc.attr('manname')
1682
+ assert_equal 'converts AsciiDoc source files to HTML, DocBook and other formats', doc.attr('manpurpose')
1683
+ assert_equal '_name', doc.attr('manname-id')
1684
+ assert_equal 0, doc.blocks.size
2251
1685
  end
2252
1686
 
2253
1687
  test 'should set docname and outfilesuffix from manname and manvolnum for manpage backend and doctype' do
@@ -2260,9 +1694,9 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2260
1694
  asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2261
1695
  EOS
2262
1696
 
2263
- doc = document_from_string input, :backend => 'manpage'
2264
- assert_equal 'asciidoctor', doc.attributes['docname']
2265
- assert_equal '.1', doc.attributes['outfilesuffix']
1697
+ doc = document_from_string input, :backend => 'manpage'
1698
+ assert_equal 'asciidoctor', doc.attributes['docname']
1699
+ assert_equal '.1', doc.attributes['outfilesuffix']
2266
1700
  end
2267
1701
 
2268
1702
  test 'should mark synopsis as special section in manpage doctype' do
@@ -2279,12 +1713,12 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2279
1713
  *asciidoctor* ['OPTION']... 'FILE'..
2280
1714
  EOS
2281
1715
 
2282
- doc = document_from_string input
2283
- synopsis_section = doc.blocks.first
2284
- refute_nil synopsis_section
2285
- assert_equal :section, synopsis_section.context
2286
- assert synopsis_section.special
2287
- assert_equal 'synopsis', synopsis_section.sectname
1716
+ doc = document_from_string input
1717
+ synopsis_section = doc.blocks.first
1718
+ refute_nil synopsis_section
1719
+ assert_equal :section, synopsis_section.context
1720
+ assert synopsis_section.special
1721
+ assert_equal 'synopsis', synopsis_section.sectname
2288
1722
  end
2289
1723
 
2290
1724
  test 'should output special header block in HTML for manpage doctype' do
@@ -2305,6 +1739,7 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2305
1739
  assert_css 'body.manpage', output, 1
2306
1740
  assert_xpath '//body/*[@id="header"]/h1[text()="asciidoctor(1) Manual Page"]', output, 1
2307
1741
  assert_xpath '//body/*[@id="header"]/h1/following-sibling::h2[text()="NAME"]', output, 1
1742
+ assert_xpath '//h2[@id="_name"][text()="NAME"]', output, 1
2308
1743
  assert_xpath '//h2[text()="NAME"]/following-sibling::*[@class="sectionbody"]', output, 1
2309
1744
  assert_xpath '//h2[text()="NAME"]/following-sibling::*[@class="sectionbody"]/p[text()="asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats"]', output, 1
2310
1745
  assert_xpath '//*[@id="content"]/*[@class="sect1"]/h2[text()="SYNOPSIS"]', output, 1
@@ -2328,6 +1763,7 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2328
1763
  output = render_embedded_string input
2329
1764
  assert_xpath '/h1[text()="asciidoctor(1) Manual Page"]', output, 1
2330
1765
  assert_xpath '/h1/following-sibling::h2[text()="NAME"]', output, 1
1766
+ assert_xpath '/h2[@id="_name"][text()="NAME"]', output, 1
2331
1767
  assert_xpath '/h2[text()="NAME"]/following-sibling::*[@class="sectionbody"]', output, 1
2332
1768
  assert_xpath '/h2[text()="NAME"]/following-sibling::*[@class="sectionbody"]/p[text()="asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats"]', output, 1
2333
1769
  end
@@ -2342,18 +1778,23 @@ asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
2342
1778
 
2343
1779
  test 'keeps naughty absolute paths from getting outside' do
2344
1780
  naughty_path = "#{disk_root}etc/passwd"
2345
- doc = empty_document
2346
- secure_path = doc.normalize_asset_path(naughty_path)
2347
- refute_equal naughty_path, secure_path
2348
- assert_match(/^#{doc.base_dir}/, secure_path)
1781
+ using_memory_logger do |logger|
1782
+ doc = empty_document
1783
+ secure_path = doc.normalize_asset_path naughty_path
1784
+ refute_equal naughty_path, secure_path
1785
+ assert_equal (::File.join doc.base_dir, 'etc/passwd'), secure_path
1786
+ assert_message logger, :WARN, 'path is outside of jail; recovering automatically'
1787
+ end
2349
1788
  end
2350
1789
 
2351
1790
  test 'keeps naughty relative paths from getting outside' do
2352
1791
  naughty_path = 'safe/ok/../../../../../etc/passwd'
2353
- doc = empty_document
2354
- secure_path = redirect_streams { doc.normalize_asset_path(naughty_path) }
2355
- refute_equal naughty_path, secure_path
2356
- assert_match(/^#{doc.base_dir}/, secure_path)
1792
+ using_memory_logger do
1793
+ doc = empty_document
1794
+ secure_path = doc.normalize_asset_path naughty_path
1795
+ refute_equal naughty_path, secure_path
1796
+ assert_match(/^#{doc.base_dir}/, secure_path)
1797
+ end
2357
1798
  end
2358
1799
 
2359
1800
  test 'should raise an exception when a converter cannot be resolved before conversion' do