asciidoctor 1.5.5 → 1.5.6

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +216 -1
  3. data/CONTRIBUTING.adoc +2 -2
  4. data/Gemfile +20 -1
  5. data/LICENSE.adoc +1 -1
  6. data/README-fr.adoc +4 -3
  7. data/README-jp.adoc +11 -10
  8. data/README-zh_CN.adoc +4 -3
  9. data/README.adoc +17 -202
  10. data/Rakefile +41 -25
  11. data/asciidoctor.gemspec +9 -10
  12. data/data/locale/attributes.adoc +216 -34
  13. data/data/stylesheets/asciidoctor-default.css +23 -16
  14. data/features/step_definitions.rb +15 -19
  15. data/features/xref.feature +584 -20
  16. data/lib/asciidoctor.rb +292 -278
  17. data/lib/asciidoctor/abstract_block.rb +155 -94
  18. data/lib/asciidoctor/abstract_node.rb +108 -94
  19. data/lib/asciidoctor/attribute_list.rb +30 -22
  20. data/lib/asciidoctor/block.rb +7 -7
  21. data/lib/asciidoctor/cli/invoker.rb +47 -34
  22. data/lib/asciidoctor/cli/options.rb +22 -11
  23. data/lib/asciidoctor/converter.rb +3 -3
  24. data/lib/asciidoctor/converter/base.rb +2 -2
  25. data/lib/asciidoctor/converter/composite.rb +1 -1
  26. data/lib/asciidoctor/converter/docbook45.rb +2 -2
  27. data/lib/asciidoctor/converter/docbook5.rb +132 -87
  28. data/lib/asciidoctor/converter/factory.rb +0 -1
  29. data/lib/asciidoctor/converter/html5.rb +116 -98
  30. data/lib/asciidoctor/converter/manpage.rb +51 -52
  31. data/lib/asciidoctor/converter/template.rb +47 -36
  32. data/lib/asciidoctor/core_ext.rb +8 -2
  33. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
  34. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
  35. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
  36. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
  37. data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
  38. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
  39. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
  40. data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
  41. data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
  42. data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
  43. data/lib/asciidoctor/document.rb +216 -213
  44. data/lib/asciidoctor/extensions.rb +318 -185
  45. data/lib/asciidoctor/helpers.rb +35 -35
  46. data/lib/asciidoctor/inline.rb +32 -1
  47. data/lib/asciidoctor/list.rb +22 -6
  48. data/lib/asciidoctor/parser.rb +1008 -1038
  49. data/lib/asciidoctor/path_resolver.rb +46 -50
  50. data/lib/asciidoctor/reader.rb +275 -251
  51. data/lib/asciidoctor/section.rb +86 -58
  52. data/lib/asciidoctor/stylesheets.rb +6 -6
  53. data/lib/asciidoctor/substitutors.rb +567 -649
  54. data/lib/asciidoctor/table.rb +163 -108
  55. data/lib/asciidoctor/version.rb +1 -1
  56. data/man/asciidoctor.1 +18 -16
  57. data/man/asciidoctor.adoc +15 -13
  58. data/test/attributes_test.rb +138 -22
  59. data/test/blocks_test.rb +377 -97
  60. data/test/converter_test.rb +13 -0
  61. data/test/document_test.rb +244 -34
  62. data/test/extensions_test.rb +409 -42
  63. data/test/fixtures/asciidoc_index.txt +521 -0
  64. data/test/fixtures/basic-docinfo-footer.html +6 -0
  65. data/test/fixtures/basic-docinfo-footer.xml +8 -0
  66. data/test/fixtures/basic-docinfo.html +1 -0
  67. data/test/fixtures/basic-docinfo.xml +4 -0
  68. data/test/fixtures/basic.asciidoc +5 -0
  69. data/test/fixtures/chapter-a.adoc +3 -0
  70. data/test/fixtures/child-include.adoc +5 -0
  71. data/test/fixtures/circle.svg +9 -0
  72. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
  73. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
  74. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
  75. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
  76. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
  77. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
  78. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
  79. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
  80. data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
  81. data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
  82. data/test/fixtures/docinfo-footer.html +1 -0
  83. data/test/fixtures/docinfo-footer.xml +9 -0
  84. data/test/fixtures/docinfo.html +1 -0
  85. data/test/fixtures/docinfo.xml +3 -0
  86. data/test/fixtures/dot.gif +0 -0
  87. data/test/fixtures/encoding.asciidoc +13 -0
  88. data/test/fixtures/grandchild-include.adoc +3 -0
  89. data/test/fixtures/hello-asciidoctor.pdf +69 -0
  90. data/test/fixtures/include-file.asciidoc +24 -0
  91. data/test/fixtures/include-file.ml +3 -0
  92. data/test/fixtures/include-file.xml +5 -0
  93. data/test/fixtures/master.adoc +5 -0
  94. data/test/fixtures/mismatched-end-tag.adoc +7 -0
  95. data/test/fixtures/parent-include-restricted.adoc +5 -0
  96. data/test/fixtures/parent-include.adoc +5 -0
  97. data/test/fixtures/sample.asciidoc +26 -0
  98. data/test/fixtures/stylesheets/custom.css +3 -0
  99. data/test/fixtures/subs-docinfo.html +2 -0
  100. data/test/fixtures/subs.adoc +7 -0
  101. data/test/fixtures/tagged-class-enclosed.rb +26 -0
  102. data/test/fixtures/tagged-class.rb +23 -0
  103. data/test/fixtures/tip.gif +0 -0
  104. data/test/invoker_test.rb +82 -4
  105. data/test/links_test.rb +312 -37
  106. data/test/lists_test.rb +204 -25
  107. data/test/manpage_test.rb +191 -4
  108. data/test/options_test.rb +18 -1
  109. data/test/paragraphs_test.rb +32 -7
  110. data/test/parser_test.rb +150 -30
  111. data/test/paths_test.rb +47 -13
  112. data/test/preamble_test.rb +1 -1
  113. data/test/reader_test.rb +366 -126
  114. data/test/sections_test.rb +203 -56
  115. data/test/substitutions_test.rb +339 -131
  116. data/test/tables_test.rb +315 -15
  117. data/test/test_helper.rb +400 -0
  118. data/test/text_test.rb +5 -5
  119. metadata +110 -22
@@ -10,6 +10,10 @@ context 'Links' do
10
10
  assert_xpath "//a[@href='http://asciidoc.org'][@class='bare'][text() = 'http://asciidoc.org']", render_string("The AsciiDoc project is located at http://asciidoc.org.")
11
11
  end
12
12
 
13
+ test 'qualified url with role inline with text' do
14
+ assert_xpath "//a[@href='http://asciidoc.org'][@class='bare project'][text() = 'http://asciidoc.org']", render_string("The AsciiDoc project is located at http://asciidoc.org[,role=project].", :attributes => {'linkattrs' => ''})
15
+ end
16
+
13
17
  test 'qualified http url inline with hide-uri-scheme set' do
14
18
  assert_xpath "//a[@href='http://asciidoc.org'][@class='bare'][text() = 'asciidoc.org']", render_string("The AsciiDoc project is located at http://asciidoc.org.", :attributes => {'hide-uri-scheme' => ''})
15
19
  end
@@ -30,10 +34,18 @@ context 'Links' do
30
34
  assert_xpath "//a[@href='http://asciidoc.org'][text() = '[Ascii]Doc']", render_string("We're parsing http://asciidoc.org[[Ascii\\]Doc] markup")
31
35
  end
32
36
 
37
+ test 'qualified url with backslash label' do
38
+ assert_xpath "//a[@href='https://google.com'][text() = 'Google for \\']", render_string("I advise you to https://google.com[Google for +\\+]")
39
+ end
40
+
33
41
  test 'qualified url with label using link macro' do
34
42
  assert_xpath "//a[@href='http://asciidoc.org'][text() = 'AsciiDoc']", render_string("We're parsing link:http://asciidoc.org[AsciiDoc] markup")
35
43
  end
36
44
 
45
+ test 'qualified url with role using link macro' do
46
+ assert_xpath "//a[@href='http://asciidoc.org'][@class='bare project'][text() = 'http://asciidoc.org']", render_string("We're parsing link:http://asciidoc.org[,role=project] markup", :attributes => {'linkattrs' => ''})
47
+ end
48
+
37
49
  test 'qualified url using macro syntax with multi-line label inline with text' do
38
50
  assert_xpath %{//a[@href='http://asciidoc.org'][text() = 'AsciiDoc\nmarkup']}, render_string("We're parsing link:http://asciidoc.org[AsciiDoc\nmarkup]")
39
51
  end
@@ -48,6 +60,19 @@ context 'Links' do
48
60
  assert_match '<ulink url="http://example.com">[bracket1]</ulink>', doc.convert, 1
49
61
  end
50
62
 
63
+ test 'link macro with empty target' do
64
+ input = 'Link to link:[this page].'
65
+ output = render_embedded_string input
66
+ assert_xpath '//a', output, 1
67
+ assert_xpath '//a[@href=""]', output, 1
68
+ end
69
+
70
+ test 'should not recognize link macro with double colons' do
71
+ input = 'The link::http://example.org[example domain] is reserved for tests and documentation.'
72
+ output = render_embedded_string input
73
+ assert_includes output, 'link::http://example.org[example domain]'
74
+ end
75
+
51
76
  test 'qualified url surrounded by angled brackets' do
52
77
  assert_xpath '//a[@href="http://asciidoc.org"][text()="http://asciidoc.org"]', render_string('<http://asciidoc.org> is the project page for AsciiDoc.'), 1
53
78
  end
@@ -72,6 +97,24 @@ context 'Links' do
72
97
  assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]', render_string('(http://asciidoctor.org): where text gets parsed'), 1
73
98
  end
74
99
 
100
+ test 'qualified url with trailing round bracket followed by colon' do
101
+ result = render_embedded_string '(from http://asciidoctor.org): where text gets parsed'
102
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]', result, 1
103
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]/preceding-sibling::text()[.="(from "]', result, 1
104
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]/following-sibling::text()[.="): where text gets parsed"]', result, 1
105
+ end
106
+
107
+ test 'qualified url in round brackets with trailing semi-colon' do
108
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]', render_string('(http://asciidoctor.org); where text gets parsed'), 1
109
+ end
110
+
111
+ test 'qualified url with trailing round bracket followed by semi-colon' do
112
+ result = render_embedded_string '(from http://asciidoctor.org); where text gets parsed'
113
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]', result, 1
114
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]/preceding-sibling::text()[.="(from "]', result, 1
115
+ assert_xpath '//a[@href="http://asciidoctor.org"][text()="http://asciidoctor.org"]/following-sibling::text()[.="); where text gets parsed"]', result, 1
116
+ end
117
+
75
118
  test 'qualified url containing round brackets' do
76
119
  assert_xpath '//a[@href="http://jruby.org/apidocs/org/jruby/Ruby.html#addModule(org.jruby.RubyModule)"][text()="addModule() adds a Ruby module"]', render_string('http://jruby.org/apidocs/org/jruby/Ruby.html#addModule(org.jruby.RubyModule)[addModule() adds a Ruby module]'), 1
77
120
  end
@@ -84,6 +127,10 @@ context 'Links' do
84
127
  assert_xpath '//a[@href="http://asciidoc.org"][text()="AsciiDoc"]', render_string(')http://asciidoc.org[AsciiDoc] project page.'), 1
85
128
  end
86
129
 
130
+ test 'qualified url following no-break space' do
131
+ assert_xpath '//a[@href="http://asciidoc.org"][text()="AsciiDoc"]', render_string(%(#{[0xa0].pack 'U1'}http://asciidoc.org[AsciiDoc] project page.)), 1
132
+ end if ::RUBY_MIN_VERSION_1_9
133
+
87
134
  test 'qualified url following smart apostrophe' do
88
135
  output = render_embedded_string("l&#8217;http://www.irit.fr[IRIT]")
89
136
  assert_match(/l&#8217;<a href=/, output)
@@ -110,11 +157,11 @@ context 'Links' do
110
157
  end
111
158
 
112
159
  test 'inline qualified url followed by an endline should not include endline in link' do
113
- assert_xpath '//a[@href="http://github.com/asciidoctor"]', render_string("The source code for Asciidoctor can be found at http://github.com/asciidoctor\nwhich is a GitHub organization."), 1
160
+ assert_xpath '//a[@href="https://github.com/asciidoctor"]', render_string("The source code for Asciidoctor can be found at https://github.com/asciidoctor\nwhich is a GitHub organization."), 1
114
161
  end
115
162
 
116
163
  test 'qualified url divided by endline using macro syntax should not create link' do
117
- assert_xpath '//a', render_string("The source code for Asciidoctor can be found at link:http://github.com/asciidoctor\n[]which is a GitHub organization."), 0
164
+ assert_xpath '//a', render_string("The source code for Asciidoctor can be found at link:https://github.com/asciidoctor\n[]which is a GitHub organization."), 0
118
165
  end
119
166
 
120
167
  test 'qualified url containing whitespace using macro syntax should not create link' do
@@ -126,7 +173,7 @@ context 'Links' do
126
173
  end
127
174
 
128
175
  test 'inline quoted qualified url should not consume surrounding angled brackets' do
129
- assert_xpath '//a[@href="http://github.com/asciidoctor"]', render_string('Asciidoctor GitHub organization: <**http://github.com/asciidoctor**>'), 1
176
+ assert_xpath '//a[@href="https://github.com/asciidoctor"]', render_string('Asciidoctor GitHub organization: <**https://github.com/asciidoctor**>'), 1
130
177
  end
131
178
 
132
179
  test 'link with quoted text should not be separated into attributes when linkattrs is set' do
@@ -141,10 +188,34 @@ context 'Links' do
141
188
  assert_xpath '//a[@href="http://google.com"][@class="external"][@target="_blank"]', render_embedded_string('http://google.com[Google, role="external", window="_blank"]', :attributes => {'linkattrs' => ''}), 1
142
189
  end
143
190
 
191
+ test 'link macro with attributes but no text should use URL as text when linkattrs is set' do
192
+ url = 'https://fonts.googleapis.com/css?family=Roboto:400,400italic,'
193
+ assert_xpath %(//a[@href="#{url}"][text()="#{url}"]), render_embedded_string(%(link:#{url}[family=Roboto,weight=400]), :attributes => {'linkattrs' => ''}), 1
194
+ end
195
+
196
+ test 'link macro with comma but no explicit attributes in text should not parse text when linkattrs is set' do
197
+ url = 'https://fonts.googleapis.com/css?family=Roboto:400,400italic,'
198
+ assert_xpath %(//a[@href="#{url}"][text()="Roboto,400"]), render_embedded_string(%(link:#{url}[Roboto,400]), :attributes => {'linkattrs' => ''}), 1
199
+ end
200
+
144
201
  test 'link text that ends in ^ should set link window to _blank' do
145
202
  assert_xpath '//a[@href="http://google.com"][@target="_blank"]', render_embedded_string('http://google.com[Google^]'), 1
146
203
  end
147
204
 
205
+ test 'rel=noopener should be added to a link that targets the _blank window' do
206
+ assert_xpath '//a[@href="http://google.com"][@target="_blank"][@rel="noopener"]', render_embedded_string('http://google.com[Google^]'), 1
207
+ end
208
+
209
+ test 'rel=noopener should be added to a link that targets a named window when the noopener option is set' do
210
+ assert_xpath '//a[@href="http://google.com"][@target="name"][@rel="noopener"]', render_embedded_string('http://google.com[Google,window=name,opts=noopener]', :attributes => {'linkattrs' => ''}), 1
211
+ end
212
+
213
+ test 'rel=noopener should not be added to a link if it does not target a window' do
214
+ result = render_embedded_string 'http://google.com[Google,opts=noopener]', :attributes => {'linkattrs' => ''}
215
+ assert_xpath '//a[@href="http://google.com"]', result, 1
216
+ assert_xpath '//a[@href="http://google.com"][@rel="noopener"]', result, 0
217
+ end
218
+
148
219
  test 'id attribute on link are processed when linkattrs is set' do
149
220
  assert_xpath '//a[@href="http://google.com"][@id="link-1"]', render_embedded_string('http://google.com[Google, id="link-1"]', :attributes => {'linkattrs' => ''}), 1
150
221
  end
@@ -166,45 +237,145 @@ context 'Links' do
166
237
  variations.each do |anchor|
167
238
  doc = document_from_string %(Here you can read about tigers.#{anchor})
168
239
  output = doc.render
169
- assert_equal '[tigers]', doc.references[:ids]['tigers']
240
+ assert_equal '[tigers]', doc.catalog[:ids]['tigers']
241
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
242
+ assert_nil doc.catalog[:refs]['tigers'].text
170
243
  assert_xpath '//a[@id = "tigers"]', output, 1
171
244
  assert_xpath '//a[@id = "tigers"]/child::text()', output, 0
172
245
  end
173
246
  end
174
247
 
175
- test 'inline ref with reftext' do
176
- variations = %w([[tigers,Tigers]] anchor:tigers[Tigers])
248
+ test 'escaped inline ref' do
249
+ variations = %w([[tigers]] anchor:tigers[])
177
250
  variations.each do |anchor|
251
+ doc = document_from_string %(Here you can read about tigers.\\#{anchor})
252
+ output = doc.render
253
+ refute doc.catalog[:ids].key?('tigers')
254
+ refute doc.catalog[:refs].key?('tigers')
255
+ assert_xpath '//a[@id = "tigers"]', output, 0
256
+ end
257
+ end
258
+
259
+ test 'inline ref can start with colon' do
260
+ input = '[[:idname]] text'
261
+ output = render_embedded_string input
262
+ assert_xpath '//a[@id = ":idname"]', output, 1
263
+ end
264
+
265
+ test 'inline ref cannot start with digit' do
266
+ input = '[[1-install]] text'
267
+ output = render_embedded_string input
268
+ assert_includes output, '[[1-install]]'
269
+ assert_xpath '//a[@id = "1-install"]', output, 0
270
+ end
271
+
272
+ test 'inline ref with reftext' do
273
+ %w([[tigers,Tigers]] anchor:tigers[Tigers]).each do |anchor|
178
274
  doc = document_from_string %(Here you can read about tigers.#{anchor})
179
275
  output = doc.render
180
- assert_equal 'Tigers', doc.references[:ids]['tigers']
276
+ assert_equal 'Tigers', doc.catalog[:ids]['tigers']
277
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
278
+ assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
181
279
  assert_xpath '//a[@id = "tigers"]', output, 1
182
280
  assert_xpath '//a[@id = "tigers"]/child::text()', output, 0
183
281
  end
184
282
  end
185
283
 
186
- test 'escaped inline ref' do
187
- variations = %w([[tigers]] anchor:tigers[])
188
- variations.each do |anchor|
189
- doc = document_from_string %(Here you can read about tigers.\\#{anchor})
190
- output = doc.render
191
- assert !doc.references[:ids].has_key?('tigers')
192
- assert_xpath '//a[@id = "tigers"]', output, 0
284
+ test 'should encode double quotes in reftext of anchor macro in DocBook output' do
285
+ input = 'anchor:uncola[the "un"-cola]'
286
+ result = render_inline_string input, :backend => :docbook
287
+ assert_equal '<anchor xml:id="uncola" xreflabel="the &quot;un&quot;-cola"/>', result
288
+ end
289
+
290
+ test 'should substitute attribute references in reftext when registering inline ref' do
291
+ %w([[tigers,{label-tigers}]] anchor:tigers[{label-tigers}]).each do |anchor|
292
+ doc = document_from_string %(Here you can read about tigers.#{anchor}), :attributes => { 'label-tigers' => 'Tigers' }
293
+ doc.render
294
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
295
+ assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
296
+ assert_equal 'Tigers', doc.catalog[:ids]['tigers']
193
297
  end
194
298
  end
195
299
 
300
+ test 'inline ref with reftext converted to DocBook' do
301
+ %w([[tigers,<Tigers>]] anchor:tigers[<Tigers>]).each do |anchor|
302
+ doc = document_from_string %(Here you can read about tigers.#{anchor}), :backend => :docbook45
303
+ output = doc.convert :header_footer => false
304
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
305
+ assert_equal '<Tigers>', doc.catalog[:refs]['tigers'].text
306
+ assert_equal '<Tigers>', doc.references[:ids]['tigers']
307
+ assert_includes output, '<anchor id="tigers" xreflabel="&lt;Tigers&gt;"/>'
308
+ end
309
+ end
310
+
311
+ test 'does not match bibliography anchor in prose when scanning for inline anchor' do
312
+ doc = document_from_string 'Use [[[label]]] to assign a label to a bibliography entry.'
313
+ refute doc.catalog[:ids].key?('label')
314
+ refute doc.catalog[:refs].key?('label')
315
+ end
316
+
317
+ test 'repeating inline anchor macro with empty reftext' do
318
+ input = 'anchor:one[] anchor:two[] anchor:three[]'
319
+ result = render_inline_string input
320
+ assert_equal '<a id="one"></a> <a id="two"></a> <a id="three"></a>', result
321
+ end
322
+
323
+ test 'mixed inline anchor macro and anchor shorthand with empty reftext' do
324
+ input = 'anchor:one[][[two]]anchor:three[][[four]]anchor:five[]'
325
+ result = render_inline_string input
326
+ assert_equal '<a id="one"></a><a id="two"></a><a id="three"></a><a id="four"></a><a id="five"></a>', result
327
+ end
328
+
329
+ test 'assigns xreflabel value for anchor macro without reftext in DocBook output' do
330
+ input = 'anchor:foo[]'
331
+ result = render_inline_string input, :backend => :docbook
332
+ assert_equal '<anchor xml:id="foo" xreflabel="[foo]"/>', result
333
+ end
334
+
335
+ test 'unescapes square bracket in reftext of anchor macro' do
336
+ input = 'see <<foo>>
337
+
338
+ anchor:foo[b[a\]r]text'
339
+ result = render_embedded_string input
340
+ assert_includes result, 'see <a href="#foo">b[a]r</a>'
341
+ end
342
+
343
+ test 'unescapes square bracket in reftext of anchor macro in DocBook output' do
344
+ input = 'anchor:foo[b[a\]r]'
345
+ result = render_inline_string input, :backend => :docbook
346
+ assert_equal '<anchor xml:id="foo" xreflabel="b[a]r"/>', result
347
+ end
348
+
196
349
  test 'xref using angled bracket syntax' do
197
350
  doc = document_from_string '<<tigers>>'
198
- doc.references[:ids]['tigers'] = '[tigers]'
351
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', :type => :ref, :target => 'tigers'), '[tigers]']
199
352
  assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
200
353
  end
201
354
 
355
+ test 'xref using angled bracket syntax with explicit hash' do
356
+ doc = document_from_string '<<#tigers>>'
357
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
358
+ assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.render, 1
359
+ end
360
+
202
361
  test 'xref using angled bracket syntax with label' do
203
- assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', render_string('<<tigers,About Tigers>>'), 1
362
+ input = <<-EOS
363
+ <<tigers,About Tigers>>
364
+
365
+ [#tigers]
366
+ == Tigers
367
+ EOS
368
+ assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', render_string(input), 1
204
369
  end
205
370
 
206
371
  test 'xref using angled bracket syntax with quoted label' do
207
- assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', render_string('<<tigers,"About Tigers">>'), 1
372
+ input = <<-EOS
373
+ <<tigers,"About Tigers">>
374
+
375
+ [#tigers]
376
+ == Tigers
377
+ EOS
378
+ assert_xpath %q(//a[@href="#tigers"][text() = '"About Tigers"']), render_string(input), 1
208
379
  end
209
380
 
210
381
  test 'xref using angled bracket syntax with path sans extension' do
@@ -212,6 +383,16 @@ context 'Links' do
212
383
  assert_xpath '//a[@href="tigers.html"][text() = "[tigers]"]', doc.render, 1
213
384
  end
214
385
 
386
+ test 'inter-document xref should not truncate after period if path has no extension' do
387
+ result = render_embedded_string '<<using-.net-web-services#,Using .NET web services>>'
388
+ assert_xpath '//a[@href="using-.net-web-services.html"][text() = "Using .NET web services"]', result, 1
389
+ end
390
+
391
+ test 'inter-document xref should only remove the file extension part if the path contains a period elsewhere' do
392
+ result = render_embedded_string '<<using-.net-web-services.adoc#,Using .NET web services>>'
393
+ assert_xpath '//a[@href="using-.net-web-services.html"][text() = "Using .NET web services"]', result, 1
394
+ end
395
+
215
396
  test 'xref using angled bracket syntax with path sans extension using docbook backend' do
216
397
  doc = document_from_string '<<tigers#>>', :header_footer => false, :backend => 'docbook'
217
398
  assert_match '<link xl:href="tigers.xml">tigers.xml</link>', doc.render, 1
@@ -252,70 +433,164 @@ context 'Links' do
252
433
 
253
434
  test 'xref using angled bracket syntax with path which has been included in this document' do
254
435
  doc = document_from_string '<<tigers#about,About Tigers>>', :header_footer => false
255
- doc.references[:includes] << 'tigers'
436
+ doc.catalog[:includes] << 'tigers'
256
437
  assert_xpath '//a[@href="#about"][text() = "About Tigers"]', doc.render, 1
257
438
  end
258
439
 
259
440
  test 'xref using angled bracket syntax with nested path which has been included in this document' do
260
441
  doc = document_from_string '<<part1/tigers#about,About Tigers>>', :header_footer => false
261
- doc.references[:includes] << 'part1/tigers'
442
+ doc.catalog[:includes] << 'part1/tigers'
262
443
  assert_xpath '//a[@href="#about"][text() = "About Tigers"]', doc.render, 1
263
444
  end
264
445
 
265
446
  test 'xref using angled bracket syntax inline with text' do
266
- assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', render_string('Want to learn <<tigers,about tigers>>?'), 1
447
+ input = <<-EOS
448
+ Want to learn <<tigers,about tigers>>?
449
+
450
+ [#tigers]
451
+ == Tigers
452
+ EOS
453
+ assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', render_string(input), 1
267
454
  end
268
455
 
269
456
  test 'xref using angled bracket syntax with multi-line label inline with text' do
270
- assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, render_string("Want to learn <<tigers,about\ntigers>>?"), 1
457
+ input = <<-EOS
458
+ Want to learn <<tigers,about
459
+ tigers>>?
460
+
461
+ [#tigers]
462
+ == Tigers
463
+ EOS
464
+ assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, render_string(input), 1
271
465
  end
272
466
 
273
467
  test 'xref with escaped text' do
274
468
  # when \x0 was used as boundary character for passthrough, it was getting stripped
275
469
  # now using unicode marks as boundary characters, which resolves issue
276
- input = 'See the <<tigers , `[tigers]`>> section for data about tigers'
470
+ input = <<-EOS
471
+ See the <<tigers, `+[tigers]+`>> section for details about tigers.
472
+
473
+ [#tigers]
474
+ == Tigers
475
+ EOS
277
476
  output = render_embedded_string input
278
477
  assert_xpath %(//a[@href="#tigers"]/code[text()="[tigers]"]), output, 1
279
478
  end
280
479
 
480
+ test 'xref with target that begins with attribute reference in title' do
481
+ ['<<{lessonsdir}/lesson-1#,Lesson 1>>', 'xref:{lessonsdir}/lesson-1#[Lesson 1]'].each do |xref|
482
+ input = <<-EOS
483
+ :lessonsdir: lessons
484
+
485
+ [#lesson-1-listing]
486
+ == #{xref}
487
+
488
+ A summary of the first lesson.
489
+ EOS
490
+
491
+ output = render_embedded_string input
492
+ assert_xpath '//h2/a[@href="lessons/lesson-1.html"]', output, 1
493
+ end
494
+ end
495
+
281
496
  test 'xref using macro syntax' do
282
497
  doc = document_from_string 'xref:tigers[]'
283
- doc.references[:ids]['tigers'] = '[tigers]'
498
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', :type => :ref, :target => 'tigers'), '[tigers]']
284
499
  assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
285
500
  end
286
501
 
502
+ test 'xref using macro syntax with explicit hash' do
503
+ doc = document_from_string 'xref:#tigers[]'
504
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
505
+ assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.render, 1
506
+ end
507
+
287
508
  test 'xref using macro syntax with label' do
288
- assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', render_string('xref:tigers[About Tigers]'), 1
509
+ input = <<-EOS
510
+ xref:tigers[About Tigers]
511
+
512
+ [#tigers]
513
+ == Tigers
514
+ EOS
515
+ assert_xpath '//a[@href="#tigers"][text() = "About Tigers"]', render_string(input), 1
289
516
  end
290
517
 
291
518
  test 'xref using macro syntax inline with text' do
292
- assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', render_string('Want to learn xref:tigers[about tigers]?'), 1
519
+ input = <<-EOS
520
+ Want to learn xref:tigers[about tigers]?
521
+
522
+ [#tigers]
523
+ == Tigers
524
+ EOS
525
+
526
+ assert_xpath '//a[@href="#tigers"][text() = "about tigers"]', render_string(input), 1
293
527
  end
294
528
 
295
529
  test 'xref using macro syntax with multi-line label inline with text' do
296
- assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, render_string("Want to learn xref:tigers[about\ntigers]?"), 1
530
+ input = <<-EOS
531
+ Want to learn xref:tigers[about
532
+ tigers]?
533
+
534
+ [#tigers]
535
+ == Tigers
536
+ EOS
537
+ assert_xpath %{//a[@href="#tigers"][normalize-space(text()) = "about tigers"]}, render_string(input), 1
538
+ end
539
+
540
+ test 'xref using macro syntax with text that contains an escaped closing bracket' do
541
+ input = <<-EOS
542
+ xref:tigers[[tigers\\]]
543
+
544
+ [#tigers]
545
+ == Tigers
546
+ EOS
547
+ assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', render_string(input), 1
548
+ end
549
+
550
+ test 'unescapes square bracket in reftext used by xref' do
551
+ input = 'anchor:foo[b[a\]r]about
552
+
553
+ see <<foo>>'
554
+ result = render_embedded_string input
555
+ assert_xpath '//a[@href="#foo"]', result, 1
556
+ assert_xpath '//a[@href="#foo"][text()="b[a]r"]', result, 1
297
557
  end
298
558
 
299
559
  test 'xref using invalid macro syntax does not create link' do
300
560
  doc = document_from_string 'xref:tigers'
301
- doc.references[:ids]['tigers'] = '[tigers]'
561
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
302
562
  assert_xpath '//a', doc.render, 0
303
563
  end
304
564
 
305
- test 'xref creates link for unknown reference' do
306
- doc = document_from_string '<<tigers>>'
307
- assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
565
+ test 'should warn and create link if verbose flag is set and reference is not found' do
566
+ input = <<-EOS
567
+ [#foobar]
568
+ == Foobar
569
+
570
+ == Section B
571
+
572
+ See <<foobaz>>.
573
+ EOS
574
+ begin
575
+ old_verbose, $VERBOSE = $VERBOSE, true
576
+ output, warnings = redirect_streams {|_, err| [(render_embedded_string input), err.string] }
577
+ assert_xpath '//a[@href="#foobaz"][text() = "[foobaz]"]', output, 1
578
+ refute warnings.empty?
579
+ assert_includes warnings, 'asciidoctor: WARNING: invalid reference: foobaz'
580
+ ensure
581
+ $VERBOSE = old_verbose
582
+ end
308
583
  end
309
584
 
310
- test 'xref shows label from title of target for forward and backward references in html backend' do
585
+ test 'xref uses title of target as label for forward and backward references in html output' do
311
586
  input = <<-EOS
312
587
  == Section A
313
588
 
314
- <\<_section_b>>
589
+ <<_section_b>>
315
590
 
316
591
  == Section B
317
592
 
318
- <\<_section_a>>
593
+ <<_section_a>>
319
594
  EOS
320
595
 
321
596
  output = render_embedded_string input
@@ -327,21 +602,21 @@ context 'Links' do
327
602
 
328
603
  test 'anchor creates reference' do
329
604
  doc = document_from_string "[[tigers]]Tigers roam here."
330
- assert_equal({'tigers' => '[tigers]'}, doc.references[:ids])
605
+ assert_equal({'tigers' => '[tigers]'}, doc.catalog[:ids])
331
606
  end
332
607
 
333
608
  test 'anchor with label creates reference' do
334
609
  doc = document_from_string "[[tigers,Tigers]]Tigers roam here."
335
- assert_equal({'tigers' => 'Tigers'}, doc.references[:ids])
610
+ assert_equal({'tigers' => 'Tigers'}, doc.catalog[:ids])
336
611
  end
337
612
 
338
613
  test 'anchor with quoted label creates reference with quoted label text' do
339
614
  doc = document_from_string %([[tigers,"Tigers roam here"]]Tigers roam here.)
340
- assert_equal({'tigers' => '"Tigers roam here"'}, doc.references[:ids])
615
+ assert_equal({'tigers' => '"Tigers roam here"'}, doc.catalog[:ids])
341
616
  end
342
617
 
343
618
  test 'anchor with label containing a comma creates reference' do
344
619
  doc = document_from_string %([[tigers,Tigers, scary tigers, roam here]]Tigers roam here.)
345
- assert_equal({'tigers' => 'Tigers, scary tigers, roam here'}, doc.references[:ids])
620
+ assert_equal({'tigers' => 'Tigers, scary tigers, roam here'}, doc.catalog[:ids])
346
621
  end
347
622
  end