asciidoctor 1.5.8 → 2.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CHANGELOG.adoc +628 -45
  4. data/LICENSE +2 -1
  5. data/README-de.adoc +28 -38
  6. data/README-fr.adoc +30 -43
  7. data/README-jp.adoc +255 -201
  8. data/README-zh_CN.adoc +40 -44
  9. data/README.adoc +170 -143
  10. data/asciidoctor.gemspec +22 -34
  11. data/bin/asciidoctor +5 -4
  12. data/data/locale/attributes-ar.adoc +4 -3
  13. data/data/locale/attributes-be.adoc +23 -0
  14. data/data/locale/attributes-bg.adoc +4 -3
  15. data/data/locale/attributes-ca.adoc +6 -5
  16. data/data/locale/attributes-cs.adoc +4 -3
  17. data/data/locale/attributes-da.adoc +6 -5
  18. data/data/locale/attributes-de.adoc +6 -5
  19. data/data/locale/attributes-en.adoc +4 -4
  20. data/data/locale/attributes-es.adoc +6 -5
  21. data/data/locale/attributes-fa.adoc +4 -3
  22. data/data/locale/attributes-fi.adoc +4 -3
  23. data/data/locale/attributes-fr.adoc +8 -7
  24. data/data/locale/attributes-hu.adoc +4 -3
  25. data/data/locale/attributes-id.adoc +4 -3
  26. data/data/locale/attributes-it.adoc +6 -5
  27. data/data/locale/attributes-ja.adoc +4 -3
  28. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  29. data/data/locale/attributes-nb.adoc +4 -3
  30. data/data/locale/attributes-nl.adoc +6 -5
  31. data/data/locale/attributes-nn.adoc +4 -3
  32. data/data/locale/attributes-pl.adoc +8 -7
  33. data/data/locale/attributes-pt.adoc +6 -5
  34. data/data/locale/attributes-pt_BR.adoc +6 -5
  35. data/data/locale/attributes-ro.adoc +4 -3
  36. data/data/locale/attributes-ru.adoc +6 -5
  37. data/data/locale/attributes-sr.adoc +4 -4
  38. data/data/locale/attributes-sr_Latn.adoc +4 -4
  39. data/data/locale/attributes-sv.adoc +4 -4
  40. data/data/locale/attributes-th.adoc +23 -0
  41. data/data/locale/attributes-tr.adoc +4 -3
  42. data/data/locale/attributes-uk.adoc +6 -5
  43. data/data/locale/attributes-vi.adoc +23 -0
  44. data/data/locale/attributes-zh_CN.adoc +4 -3
  45. data/data/locale/attributes-zh_TW.adoc +4 -3
  46. data/data/reference/syntax.adoc +296 -0
  47. data/data/stylesheets/asciidoctor-default.css +120 -114
  48. data/data/stylesheets/coderay-asciidoctor.css +15 -17
  49. data/lib/asciidoctor/abstract_block.rb +146 -140
  50. data/lib/asciidoctor/abstract_node.rb +152 -170
  51. data/lib/asciidoctor/attribute_list.rb +77 -89
  52. data/lib/asciidoctor/block.rb +29 -28
  53. data/lib/asciidoctor/callouts.rb +4 -2
  54. data/lib/asciidoctor/cli/invoker.rb +20 -24
  55. data/lib/asciidoctor/cli/options.rb +107 -96
  56. data/lib/asciidoctor/cli.rb +3 -2
  57. data/lib/asciidoctor/convert.rb +199 -0
  58. data/lib/asciidoctor/converter/composite.rb +40 -48
  59. data/lib/asciidoctor/converter/docbook5.rb +627 -644
  60. data/lib/asciidoctor/converter/html5.rb +1053 -951
  61. data/lib/asciidoctor/converter/manpage.rb +581 -532
  62. data/lib/asciidoctor/converter/template.rb +232 -271
  63. data/lib/asciidoctor/converter.rb +370 -185
  64. data/lib/asciidoctor/core_ext/float/truncate.rb +20 -0
  65. data/lib/asciidoctor/core_ext/hash/merge.rb +8 -0
  66. data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
  67. data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
  68. data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
  69. data/lib/asciidoctor/core_ext.rb +8 -17
  70. data/lib/asciidoctor/document.rb +503 -461
  71. data/lib/asciidoctor/extensions.rb +127 -174
  72. data/lib/asciidoctor/helpers.rb +184 -107
  73. data/lib/asciidoctor/inline.rb +9 -12
  74. data/lib/asciidoctor/list.rb +11 -29
  75. data/lib/asciidoctor/load.rb +119 -0
  76. data/lib/asciidoctor/logging.rb +22 -17
  77. data/lib/asciidoctor/parser.rb +673 -719
  78. data/lib/asciidoctor/path_resolver.rb +48 -33
  79. data/lib/asciidoctor/reader.rb +383 -338
  80. data/lib/asciidoctor/rouge_ext.rb +39 -0
  81. data/lib/asciidoctor/rx.rb +723 -0
  82. data/lib/asciidoctor/section.rb +17 -16
  83. data/lib/asciidoctor/stylesheets.rb +19 -37
  84. data/lib/asciidoctor/substitutors.rb +926 -1022
  85. data/lib/asciidoctor/syntax_highlighter/coderay.rb +88 -0
  86. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +34 -0
  87. data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
  88. data/lib/asciidoctor/syntax_highlighter/prettify.rb +30 -0
  89. data/lib/asciidoctor/syntax_highlighter/pygments.rb +157 -0
  90. data/lib/asciidoctor/syntax_highlighter/rouge.rb +143 -0
  91. data/lib/asciidoctor/syntax_highlighter.rb +253 -0
  92. data/lib/asciidoctor/table.rb +152 -114
  93. data/lib/asciidoctor/timings.rb +7 -5
  94. data/lib/asciidoctor/version.rb +2 -1
  95. data/lib/asciidoctor/writer.rb +30 -0
  96. data/lib/asciidoctor.rb +266 -1340
  97. data/man/asciidoctor.1 +49 -47
  98. data/man/asciidoctor.adoc +54 -45
  99. metadata +50 -245
  100. data/CONTRIBUTING.adoc +0 -185
  101. data/Gemfile +0 -60
  102. data/Rakefile +0 -129
  103. data/bin/asciidoctor-safe +0 -15
  104. data/features/open_block.feature +0 -92
  105. data/features/pass_block.feature +0 -66
  106. data/features/step_definitions.rb +0 -49
  107. data/features/text_formatting.feature +0 -57
  108. data/features/xref.feature +0 -1039
  109. data/lib/asciidoctor/converter/base.rb +0 -59
  110. data/lib/asciidoctor/converter/docbook45.rb +0 -93
  111. data/lib/asciidoctor/converter/factory.rb +0 -226
  112. data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
  113. data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
  114. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
  115. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
  116. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
  117. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
  118. data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
  119. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
  120. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
  121. data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
  122. data/test/api_test.rb +0 -1240
  123. data/test/attribute_list_test.rb +0 -242
  124. data/test/attributes_test.rb +0 -1623
  125. data/test/blocks_test.rb +0 -3870
  126. data/test/converter_test.rb +0 -470
  127. data/test/document_test.rb +0 -1853
  128. data/test/extensions_test.rb +0 -1560
  129. data/test/fixtures/asciidoc_index.txt +0 -521
  130. data/test/fixtures/basic-docinfo-footer.html +0 -6
  131. data/test/fixtures/basic-docinfo-footer.xml +0 -8
  132. data/test/fixtures/basic-docinfo.html +0 -1
  133. data/test/fixtures/basic-docinfo.xml +0 -4
  134. data/test/fixtures/basic.asciidoc +0 -5
  135. data/test/fixtures/chapter-a.adoc +0 -3
  136. data/test/fixtures/child-include.adoc +0 -5
  137. data/test/fixtures/circle.svg +0 -9
  138. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
  139. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
  140. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
  141. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
  142. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
  143. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
  144. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
  145. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
  146. data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
  147. data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
  148. data/test/fixtures/docinfo-footer.html +0 -1
  149. data/test/fixtures/docinfo-footer.xml +0 -9
  150. data/test/fixtures/docinfo.html +0 -1
  151. data/test/fixtures/docinfo.xml +0 -3
  152. data/test/fixtures/doctime-localtime.adoc +0 -2
  153. data/test/fixtures/dot.gif +0 -0
  154. data/test/fixtures/encoding.asciidoc +0 -13
  155. data/test/fixtures/file-with-missing-include.adoc +0 -1
  156. data/test/fixtures/grandchild-include.adoc +0 -3
  157. data/test/fixtures/hello-asciidoctor.pdf +0 -69
  158. data/test/fixtures/include-file.asciidoc +0 -24
  159. data/test/fixtures/include-file.jsx +0 -8
  160. data/test/fixtures/include-file.ml +0 -3
  161. data/test/fixtures/include-file.xml +0 -5
  162. data/test/fixtures/lists.adoc +0 -96
  163. data/test/fixtures/master.adoc +0 -5
  164. data/test/fixtures/mismatched-end-tag.adoc +0 -7
  165. data/test/fixtures/other-chapters.adoc +0 -11
  166. data/test/fixtures/outer-include.adoc +0 -5
  167. data/test/fixtures/parent-include-restricted.adoc +0 -5
  168. data/test/fixtures/parent-include.adoc +0 -5
  169. data/test/fixtures/sample.asciidoc +0 -30
  170. data/test/fixtures/section-a.adoc +0 -4
  171. data/test/fixtures/stylesheets/custom.css +0 -3
  172. data/test/fixtures/subdir/index.adoc +0 -3
  173. data/test/fixtures/subdir/inner-include.adoc +0 -3
  174. data/test/fixtures/subdir/middle-include.adoc +0 -5
  175. data/test/fixtures/subs-docinfo.html +0 -2
  176. data/test/fixtures/subs.adoc +0 -6
  177. data/test/fixtures/tagged-class-enclosed.rb +0 -25
  178. data/test/fixtures/tagged-class.rb +0 -23
  179. data/test/fixtures/tip.gif +0 -0
  180. data/test/fixtures/unclosed-tag.adoc +0 -3
  181. data/test/fixtures/unexpected-end-tag.adoc +0 -4
  182. data/test/invoker_test.rb +0 -745
  183. data/test/links_test.rb +0 -855
  184. data/test/lists_test.rb +0 -5151
  185. data/test/logger_test.rb +0 -211
  186. data/test/manpage_test.rb +0 -660
  187. data/test/options_test.rb +0 -262
  188. data/test/paragraphs_test.rb +0 -562
  189. data/test/parser_test.rb +0 -742
  190. data/test/paths_test.rb +0 -395
  191. data/test/preamble_test.rb +0 -173
  192. data/test/reader_test.rb +0 -2161
  193. data/test/sections_test.rb +0 -3575
  194. data/test/substitutions_test.rb +0 -2066
  195. data/test/tables_test.rb +0 -2036
  196. data/test/test_helper.rb +0 -447
  197. data/test/text_test.rb +0 -309
@@ -1,1623 +0,0 @@
1
- # encoding: UTF-8
2
- unless defined? ASCIIDOCTOR_PROJECT_DIR
3
- $: << File.dirname(__FILE__); $:.uniq!
4
- require 'test_helper'
5
- end
6
-
7
- context 'Attributes' do
8
- default_logger = Asciidoctor::LoggerManager.logger
9
-
10
- setup do
11
- Asciidoctor::LoggerManager.logger = (@logger = Asciidoctor::MemoryLogger.new)
12
- end
13
-
14
- teardown do
15
- Asciidoctor::LoggerManager.logger = default_logger
16
- end
17
-
18
- context 'Assignment' do
19
- test 'creates an attribute' do
20
- doc = document_from_string(':frog: Tanglefoot')
21
- assert_equal 'Tanglefoot', doc.attributes['frog']
22
- end
23
-
24
- test 'requires a space after colon following attribute name' do
25
- doc = document_from_string 'foo:bar'
26
- assert_nil doc.attributes['foo']
27
- end
28
-
29
- # NOTE AsciiDoc Python recognizes this entry
30
- test 'does not recognize attribute entry if name contains colon' do
31
- input = <<-EOS.chomp
32
- :foo:bar: baz
33
- EOS
34
- doc = document_from_string input
35
- refute doc.attr?('foo:bar')
36
- assert_equal 1, doc.blocks.size
37
- assert_equal :paragraph, doc.blocks[0].context
38
- end
39
-
40
- # NOTE AsciiDoc Python recognizes this entry
41
- test 'does not recognize attribute entry if name ends with colon' do
42
- input = <<-EOS.chomp
43
- :foo:: bar
44
- EOS
45
- doc = document_from_string input
46
- refute doc.attr?('foo:')
47
- assert_equal 1, doc.blocks.size
48
- assert_equal :dlist, doc.blocks[0].context
49
- end
50
-
51
- # NOTE AsciiDoc Python does not recognize this entry
52
- test 'allows any word character defined by Unicode in an attribute name' do
53
- [['café', 'a coffee shop'], ['سمن', %(سازمان مردمنهاد)]].each do |(name, value)|
54
- str = <<-EOS
55
- :#{name}: #{value}
56
-
57
- {#{name}}
58
- EOS
59
- result = convert_string_to_embedded str
60
- assert_includes result, %(<p>#{value}</p>)
61
- end
62
-
63
- end if ::RUBY_MIN_VERSION_1_9
64
-
65
- test 'creates an attribute by fusing a legacy multi-line value' do
66
- str = <<-EOS
67
- :description: This is the first +
68
- Ruby implementation of +
69
- AsciiDoc.
70
- EOS
71
- doc = document_from_string(str)
72
- assert_equal 'This is the first Ruby implementation of AsciiDoc.', doc.attributes['description']
73
- end
74
-
75
- test 'creates an attribute by fusing a multi-line value' do
76
- str = <<-EOS
77
- :description: This is the first \\
78
- Ruby implementation of \\
79
- AsciiDoc.
80
- EOS
81
- doc = document_from_string(str)
82
- assert_equal 'This is the first Ruby implementation of AsciiDoc.', doc.attributes['description']
83
- end
84
-
85
- test 'honors line break characters in multi-line values' do
86
- str = <<-EOS
87
- :signature: Linus Torvalds + \\
88
- Linux Hacker + \\
89
- linus.torvalds@example.com
90
- EOS
91
- doc = document_from_string(str)
92
- assert_equal %(Linus Torvalds +\nLinux Hacker +\nlinus.torvalds@example.com), doc.attributes['signature']
93
- end
94
-
95
- test 'should allow pass macro to surround a multi-line value that contains line breaks' do
96
- str = <<-EOS
97
- :signature: pass:a[{author} + \\
98
- {title} + \\
99
- {email}]
100
- EOS
101
- doc = document_from_string str, :attributes => { 'author' => 'Linus Torvalds', 'title' => 'Linux Hacker', 'email' => 'linus.torvalds@example.com' }
102
- assert_equal %(Linus Torvalds +\nLinux Hacker +\nlinus.torvalds@example.com), (doc.attr 'signature')
103
- end
104
-
105
- test 'should delete an attribute that ends with !' do
106
- doc = document_from_string(":frog: Tanglefoot\n:frog!:")
107
- assert_nil doc.attributes['frog']
108
- end
109
-
110
- test 'should delete an attribute that ends with ! set via API' do
111
- doc = document_from_string(":frog: Tanglefoot", :attributes => {'frog!' => ''})
112
- assert_nil doc.attributes['frog']
113
- end
114
-
115
- test 'should delete an attribute that begins with !' do
116
- doc = document_from_string(":frog: Tanglefoot\n:!frog:")
117
- assert_nil doc.attributes['frog']
118
- end
119
-
120
- test 'should delete an attribute that begins with ! set via API' do
121
- doc = document_from_string(":frog: Tanglefoot", :attributes => {'!frog' => ''})
122
- assert_nil doc.attributes['frog']
123
- end
124
-
125
- test 'should delete an attribute set via API to nil value' do
126
- doc = document_from_string(":frog: Tanglefoot", :attributes => {'frog' => nil})
127
- assert_nil doc.attributes['frog']
128
- end
129
-
130
- test "doesn't choke when deleting a non-existing attribute" do
131
- doc = document_from_string(':frog!:')
132
- assert_nil doc.attributes['frog']
133
- end
134
-
135
- test "replaces special characters in attribute value" do
136
- doc = document_from_string(":xml-busters: <>&")
137
- assert_equal '&lt;&gt;&amp;', doc.attributes['xml-busters']
138
- end
139
-
140
- test "performs attribute substitution on attribute value" do
141
- doc = document_from_string(":version: 1.0\n:release: Asciidoctor {version}")
142
- assert_equal 'Asciidoctor 1.0', doc.attributes['release']
143
- end
144
-
145
- test 'assigns attribute to empty string if substitution fails to resolve attribute' do
146
- input = ':release: Asciidoctor {version}'
147
- document_from_string input, :attributes => { 'attribute-missing' => 'drop-line' }
148
- assert_message @logger, :WARN, 'dropping line containing reference to missing attribute: version'
149
- end
150
-
151
- test 'assigns multi-line attribute to empty string if substitution fails to resolve attribute' do
152
- input = <<-EOS
153
- :release: Asciidoctor +
154
- {version}
155
- EOS
156
- doc = document_from_string input, :attributes => { 'attribute-missing' => 'drop-line' }
157
- assert_equal '', doc.attributes['release']
158
- assert_message @logger, :WARN, 'dropping line containing reference to missing attribute: version'
159
- end
160
-
161
- test 'resolves attributes inside attribute value within header' do
162
- input = <<-EOS
163
- = Document Title
164
- :big: big
165
- :bigfoot: {big}foot
166
-
167
- {bigfoot}
168
- EOS
169
-
170
- result = convert_string_to_embedded input
171
- assert_includes result, 'bigfoot'
172
- end
173
-
174
- test 'resolves attributes and pass macro inside attribute value outside header' do
175
- input = <<-EOS
176
- = Document Title
177
-
178
- content
179
-
180
- :big: pass:a,q[_big_]
181
- :bigfoot: {big}foot
182
- {bigfoot}
183
- EOS
184
-
185
- result = convert_string_to_embedded input
186
- assert_includes result, '<em>big</em>foot'
187
- end
188
-
189
- test 'should limit maximum size of attribute value if safe mode is SECURE' do
190
- expected = 'a' * 4096
191
- input = <<-EOS
192
- :name: #{'a' * 5000}
193
-
194
- {name}
195
- EOS
196
-
197
- result = convert_inline_string input
198
- assert_equal expected, result
199
- assert_equal 4096, result.bytesize
200
- end
201
-
202
- test 'should handle multibyte characters when limiting attribute value size' do
203
- expected = '日本'
204
- input = <<-EOS
205
- :name: 日本語
206
-
207
- {name}
208
- EOS
209
-
210
- result = convert_inline_string input, :attributes => { 'max-attribute-value-size' => 6 }
211
- assert_equal expected, result
212
- assert_equal 6, result.bytesize
213
- end
214
-
215
- test 'should not mangle multibyte characters when limiting attribute value size' do
216
- expected = '日本'
217
- input = <<-EOS
218
- :name: 日本語
219
-
220
- {name}
221
- EOS
222
-
223
- result = convert_inline_string input, :attributes => { 'max-attribute-value-size' => 8 }
224
- assert_equal expected, result
225
- assert_equal 6, result.bytesize
226
- end
227
-
228
- test 'should allow maximize size of attribute value to be disabled' do
229
- expected = 'a' * 5000
230
- input = <<-EOS
231
- :name: #{'a' * 5000}
232
-
233
- {name}
234
- EOS
235
-
236
- result = convert_inline_string input, :attributes => { 'max-attribute-value-size' => nil }
237
- assert_equal expected, result
238
- assert_equal 5000, result.bytesize
239
- end
240
-
241
- test 'resolves user-home attribute if safe mode is less than SERVER' do
242
- input = <<-EOS
243
- :imagesdir: {user-home}/etc/images
244
-
245
- {imagesdir}
246
- EOS
247
- output = convert_inline_string input, :safe => :safe
248
- if RUBY_VERSION >= '1.9'
249
- assert_equal %(#{Dir.home}/etc/images), output
250
- else
251
- assert_equal %(#{ENV['HOME']}/etc/images), output
252
- end
253
- end
254
-
255
- test 'user-home attribute resolves to . if safe mode is SERVER or greater' do
256
- input = <<-EOS
257
- :imagesdir: {user-home}/etc/images
258
-
259
- {imagesdir}
260
- EOS
261
- output = convert_inline_string input, :safe => :server
262
- assert_equal './etc/images', output
263
- end
264
-
265
- test "apply custom substitutions to text in passthrough macro and assign to attribute" do
266
- doc = document_from_string(":xml-busters: pass:[<>&]")
267
- assert_equal '<>&', doc.attributes['xml-busters']
268
- doc = document_from_string(":xml-busters: pass:none[<>&]")
269
- assert_equal '<>&', doc.attributes['xml-busters']
270
- doc = document_from_string(":xml-busters: pass:specialcharacters[<>&]")
271
- assert_equal '&lt;&gt;&amp;', doc.attributes['xml-busters']
272
- end
273
-
274
- test 'should not recognize pass macro with invalid substitution list in attribute value' do
275
- [',', '42', 'a,'].each do |subs|
276
- doc = document_from_string %(:pass-fail: pass:#{subs}[whale])
277
- assert_equal %(pass:#{subs}[whale]), doc.attributes['pass-fail']
278
- end
279
- end
280
-
281
- test "attribute is treated as defined until it's not" do
282
- input = <<-EOS
283
- :holygrail:
284
- ifdef::holygrail[]
285
- The holy grail has been found!
286
- endif::holygrail[]
287
-
288
- :holygrail!:
289
- ifndef::holygrail[]
290
- Buggers! What happened to the grail?
291
- endif::holygrail[]
292
- EOS
293
- output = convert_string input
294
- assert_xpath '//p', output, 2
295
- assert_xpath '(//p)[1][text() = "The holy grail has been found!"]', output, 1
296
- assert_xpath '(//p)[2][text() = "Buggers! What happened to the grail?"]', output, 1
297
- end
298
-
299
- test 'attribute set via API overrides attribute set in document' do
300
- doc = document_from_string(':cash: money', :attributes => {'cash' => 'heroes'})
301
- assert_equal 'heroes', doc.attributes['cash']
302
- end
303
-
304
- test 'attribute set via API cannot be unset by document' do
305
- doc = document_from_string(':cash!:', :attributes => {'cash' => 'heroes'})
306
- assert_equal 'heroes', doc.attributes['cash']
307
- end
308
-
309
- test 'attribute soft set via API using modifier on name can be overridden by document' do
310
- doc = document_from_string(':cash: money', :attributes => {'cash@' => 'heroes'})
311
- assert_equal 'money', doc.attributes['cash']
312
- end
313
-
314
- test 'attribute soft set via API using modifier on value can be overridden by document' do
315
- doc = document_from_string(':cash: money', :attributes => {'cash' => 'heroes@'})
316
- assert_equal 'money', doc.attributes['cash']
317
- end
318
-
319
- test 'attribute soft set via API using modifier on name can be unset by document' do
320
- doc = document_from_string(':cash!:', :attributes => {'cash@' => 'heroes'})
321
- assert_nil doc.attributes['cash']
322
- doc = document_from_string(':cash!:', :attributes => {'cash@' => true})
323
- assert_nil doc.attributes['cash']
324
- end
325
-
326
- test 'attribute soft set via API using modifier on value can be unset by document' do
327
- doc = document_from_string(':cash!:', :attributes => {'cash' => 'heroes@'})
328
- assert_nil doc.attributes['cash']
329
- end
330
-
331
- test 'attribute unset via API cannot be set by document' do
332
- [
333
- { 'cash!' => '' },
334
- { '!cash' => '' },
335
- { 'cash' => nil },
336
- ].each do |attributes|
337
- doc = document_from_string(':cash: money', :attributes => attributes)
338
- assert_nil doc.attributes['cash']
339
- end
340
- end
341
-
342
- test 'attribute soft unset via API can be set by document' do
343
- [
344
- { 'cash!@' => '' },
345
- { '!cash@' => '' },
346
- { 'cash!' => '@' },
347
- { '!cash' => '@' },
348
- { 'cash' => false },
349
- ].each do |attributes|
350
- doc = document_from_string(':cash: money', :attributes => attributes)
351
- assert_equal 'money', doc.attributes['cash']
352
- end
353
- end
354
-
355
- test 'can soft unset built-in attribute from API and still override in document' do
356
- [
357
- { 'sectids!@' => '' },
358
- { '!sectids@' => '' },
359
- { 'sectids!' => '@' },
360
- { '!sectids' => '@' },
361
- { 'sectids' => false },
362
- ].each do |attributes|
363
- doc = document_from_string '== Heading', :attributes => attributes
364
- refute doc.attr?('sectids')
365
- assert_css '#_heading', (doc.convert :header_footer => false), 0
366
- doc = document_from_string %(:sectids:\n\n== Heading), :attributes => attributes
367
- assert doc.attr?('sectids')
368
- assert_css '#_heading', (doc.convert :header_footer => false), 1
369
- end
370
- end
371
-
372
- test 'backend and doctype attributes are set by default in default configuration' do
373
- input = <<-EOS
374
- = Document Title
375
- Author Name
376
-
377
- content
378
- EOS
379
-
380
- doc = document_from_string input
381
- expect = {
382
- 'backend' => 'html5',
383
- 'backend-html5' => '',
384
- 'backend-html5-doctype-article' => '',
385
- 'outfilesuffix' => '.html',
386
- 'basebackend' => 'html',
387
- 'basebackend-html' => '',
388
- 'basebackend-html-doctype-article' => '',
389
- 'doctype' => 'article',
390
- 'doctype-article' => '',
391
- 'filetype' => 'html',
392
- 'filetype-html' => ''
393
- }
394
- expect.each do |key, val|
395
- assert doc.attributes.key? key
396
- assert_equal val, doc.attributes[key]
397
- end
398
- end
399
-
400
- test 'backend and doctype attributes are set by default in custom configuration' do
401
- input = <<-EOS
402
- = Document Title
403
- Author Name
404
-
405
- content
406
- EOS
407
-
408
- doc = document_from_string input, :doctype => 'book', :backend => 'docbook'
409
- expect = {
410
- 'backend' => 'docbook5',
411
- 'backend-docbook5' => '',
412
- 'backend-docbook5-doctype-book' => '',
413
- 'outfilesuffix' => '.xml',
414
- 'basebackend' => 'docbook',
415
- 'basebackend-docbook' => '',
416
- 'basebackend-docbook-doctype-book' => '',
417
- 'doctype' => 'book',
418
- 'doctype-book' => '',
419
- 'filetype' => 'xml',
420
- 'filetype-xml' => ''
421
- }
422
- expect.each do |key, val|
423
- assert doc.attributes.key? key
424
- assert_equal val, doc.attributes[key]
425
- end
426
- end
427
-
428
- test 'backend attributes are updated if backend attribute is defined in document and safe mode is less than SERVER' do
429
- input = <<-EOS
430
- = Document Title
431
- Author Name
432
- :backend: docbook
433
- :doctype: book
434
-
435
- content
436
- EOS
437
-
438
- doc = document_from_string input, :safe => Asciidoctor::SafeMode::SAFE
439
- expect = {
440
- 'backend' => 'docbook5',
441
- 'backend-docbook5' => '',
442
- 'backend-docbook5-doctype-book' => '',
443
- 'outfilesuffix' => '.xml',
444
- 'basebackend' => 'docbook',
445
- 'basebackend-docbook' => '',
446
- 'basebackend-docbook-doctype-book' => '',
447
- 'doctype' => 'book',
448
- 'doctype-book' => '',
449
- 'filetype' => 'xml',
450
- 'filetype-xml' => ''
451
- }
452
- expect.each do |key, val|
453
- assert doc.attributes.key?(key)
454
- assert_equal val, doc.attributes[key]
455
- end
456
-
457
- refute doc.attributes.key?('backend-html5')
458
- refute doc.attributes.key?('backend-html5-doctype-article')
459
- refute doc.attributes.key?('basebackend-html')
460
- refute doc.attributes.key?('basebackend-html-doctype-article')
461
- refute doc.attributes.key?('doctype-article')
462
- refute doc.attributes.key?('filetype-html')
463
- end
464
-
465
- test 'backend attributes defined in document options overrides backend attribute in document' do
466
- doc = document_from_string(':backend: docbook45', :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'backend' => 'html5'})
467
- assert_equal 'html5', doc.attributes['backend']
468
- assert doc.attributes.has_key? 'backend-html5'
469
- assert_equal 'html', doc.attributes['basebackend']
470
- assert doc.attributes.has_key? 'basebackend-html'
471
- end
472
-
473
- test 'can only access a positional attribute from the attributes hash' do
474
- node = Asciidoctor::Block.new nil, :paragraph, :attributes => { 1 => 'position 1' }
475
- assert_nil node.attr(1)
476
- refute node.attr?(1)
477
- assert_equal 'position 1', node.attributes[1]
478
- end
479
-
480
- test 'set_attr should set value to empty string if no value is specified' do
481
- node = Asciidoctor::Block.new nil, :paragraph, :attributes => {}
482
- node.set_attr 'foo'
483
- assert_equal '', (node.attr 'foo')
484
- end
485
-
486
- test 'remove_attr should remove attribute and return previous value' do
487
- doc = empty_document
488
- node = Asciidoctor::Block.new doc, :paragraph, :attributes => { 'foo' => 'bar' }
489
- assert_equal 'bar', (node.remove_attr 'foo')
490
- assert_nil node.attr('foo')
491
- end
492
-
493
- test 'set_attr should not overwrite existing key if overwrite is false' do
494
- node = Asciidoctor::Block.new nil, :paragraph, :attributes => { 'foo' => 'bar' }
495
- assert_equal 'bar', (node.attr 'foo')
496
- node.set_attr 'foo', 'baz', false
497
- assert_equal 'bar', (node.attr 'foo')
498
- end
499
-
500
- test 'set_attr should overwrite existing key by default' do
501
- node = Asciidoctor::Block.new nil, :paragraph, :attributes => { 'foo' => 'bar' }
502
- assert_equal 'bar', (node.attr 'foo')
503
- node.set_attr 'foo', 'baz'
504
- assert_equal 'baz', (node.attr 'foo')
505
- end
506
-
507
- test 'set_attr should set header attribute in loaded document' do
508
- input = <<-EOS
509
- :uri: http://example.org
510
-
511
- {uri}
512
- EOS
513
-
514
- doc = Asciidoctor.load input, :attributes => { 'uri' => 'https://github.com' }
515
- doc.set_attr 'uri', 'https://google.com'
516
- output = doc.convert
517
- assert_xpath '//a[@href="https://google.com"]', output, 1
518
- end
519
-
520
- test 'set_attribute should set attribute if key is not locked' do
521
- doc = empty_document
522
- refute doc.attr? 'foo'
523
- res = doc.set_attribute 'foo', 'baz'
524
- assert res
525
- assert_equal 'baz', (doc.attr 'foo')
526
- end
527
-
528
- test 'set_attribute should not set key if key is locked' do
529
- doc = empty_document :attributes => { 'foo' => 'bar' }
530
- assert_equal 'bar', (doc.attr 'foo')
531
- res = doc.set_attribute 'foo', 'baz'
532
- refute res
533
- assert_equal 'bar', (doc.attr 'foo')
534
- end
535
-
536
- test 'set_attribute should update backend attributes' do
537
- doc = empty_document :attributes => { 'backend' => 'html5@' }
538
- assert_equal '', (doc.attr 'backend-html5')
539
- res = doc.set_attribute 'backend', 'docbook5'
540
- assert res
541
- refute doc.attr? 'backend-html5'
542
- assert_equal '', (doc.attr 'backend-docbook5')
543
- end
544
-
545
- test 'verify toc attribute matrix' do
546
- expected_data = <<-EOS
547
- #attributes |toc|toc-position|toc-placement|toc-class
548
- toc | |nil |auto |nil
549
- toc=header | |nil |auto |nil
550
- toc=beeboo | |nil |auto |nil
551
- toc=left | |left |auto |toc2
552
- toc2 | |left |auto |toc2
553
- toc=right | |right |auto |toc2
554
- toc=preamble | |content |preamble |nil
555
- toc=macro | |content |macro |nil
556
- toc toc-placement=macro toc-position=left | |content |macro |nil
557
- toc toc-placement! | |content |macro |nil
558
- EOS
559
-
560
- expected = expected_data.strip.lines.map {|l|
561
- next if l.start_with? '#'
562
- l.split('|').map {|e| (e = e.strip) == 'nil' ? nil : e }
563
- }.compact
564
-
565
- expected.each do |expect|
566
- raw_attrs, toc, toc_position, toc_placement, toc_class = expect
567
- attrs = Hash[*raw_attrs.split.map {|e| e.include?('=') ? e.split('=', 2) : [e, ''] }.flatten]
568
- doc = document_from_string '', :attributes => attrs
569
- toc ? (assert doc.attr?('toc', toc)) : (refute doc.attr?('toc'))
570
- toc_position ? (assert doc.attr?('toc-position', toc_position)) : (refute doc.attr?('toc-position'))
571
- toc_placement ? (assert doc.attr?('toc-placement', toc_placement)) : (refute doc.attr?('toc-placement'))
572
- toc_class ? (assert doc.attr?('toc-class', toc_class)) : (refute doc.attr?('toc-class'))
573
- end
574
- end
575
- end
576
-
577
- context 'Interpolation' do
578
-
579
- test "convert properly with simple names" do
580
- html = convert_string(":frog: Tanglefoot\n:my_super-hero: Spiderman\n\nYo, {frog}!\nBeat {my_super-hero}!")
581
- result = Nokogiri::HTML(html)
582
- assert_equal "Yo, Tanglefoot!\nBeat Spiderman!", result.css("p").first.content.strip
583
- end
584
-
585
- test 'attribute lookup is not case sensitive' do
586
- input = <<-EOS
587
- :He-Man: The most powerful man in the universe
588
-
589
- He-Man: {He-Man}
590
-
591
- She-Ra: {She-Ra}
592
- EOS
593
- result = convert_string_to_embedded input, :attributes => {'She-Ra' => 'The Princess of Power'}
594
- assert_xpath '//p[text()="He-Man: The most powerful man in the universe"]', result, 1
595
- assert_xpath '//p[text()="She-Ra: The Princess of Power"]', result, 1
596
- end
597
-
598
- test "convert properly with single character name" do
599
- html = convert_string(":r: Ruby\n\nR is for {r}!")
600
- result = Nokogiri::HTML(html)
601
- assert_equal 'R is for Ruby!', result.css("p").first.content.strip
602
- end
603
-
604
- test "collapses spaces in attribute names" do
605
- input = <<-EOS
606
- Main Header
607
- ===========
608
- :My frog: Tanglefoot
609
-
610
- Yo, {myfrog}!
611
- EOS
612
- output = convert_string input
613
- assert_xpath '(//p)[1][text()="Yo, Tanglefoot!"]', output, 1
614
- end
615
-
616
- test 'ignores lines with bad attributes if attribute-missing is drop-line' do
617
- input = <<-EOS
618
- :attribute-missing: drop-line
619
-
620
- This is
621
- blah blah {foobarbaz}
622
- all there is.
623
- EOS
624
- output = convert_string_to_embedded input
625
- para = xmlnodes_at_css 'p', output, 1
626
- refute_includes 'blah blah', para.content
627
- assert_message @logger, :WARN, 'dropping line containing reference to missing attribute: foobarbaz'
628
- end
629
-
630
- test "attribute value gets interpretted when converting" do
631
- doc = document_from_string(":google: http://google.com[Google]\n\n{google}")
632
- assert_equal 'http://google.com[Google]', doc.attributes['google']
633
- output = doc.convert
634
- assert_xpath '//a[@href="http://google.com"][text() = "Google"]', output, 1
635
- end
636
-
637
- test 'should drop line with reference to missing attribute if attribute-missing attribute is drop-line' do
638
- input = <<-EOS
639
- :attribute-missing: drop-line
640
-
641
- Line 1: This line should appear in the output.
642
- Line 2: Oh no, a {bogus-attribute}! This line should not appear in the output.
643
- EOS
644
-
645
- output = convert_string_to_embedded input
646
- assert_match(/Line 1/, output)
647
- refute_match(/Line 2/, output)
648
- assert_message @logger, :WARN, 'dropping line containing reference to missing attribute: bogus-attribute'
649
- end
650
-
651
- test 'should not drop line with reference to missing attribute by default' do
652
- input = <<-EOS
653
- Line 1: This line should appear in the output.
654
- Line 2: A {bogus-attribute}! This time, this line should appear in the output.
655
- EOS
656
-
657
- output = convert_string_to_embedded input
658
- assert_match(/Line 1/, output)
659
- assert_match(/Line 2/, output)
660
- assert_match(/\{bogus-attribute\}/, output)
661
- end
662
-
663
- test 'should drop line with attribute unassignment by default' do
664
- input = <<-EOS
665
- :a:
666
-
667
- Line 1: This line should appear in the output.
668
- Line 2: {set:a!}This line should not appear in the output.
669
- EOS
670
-
671
- output = convert_string_to_embedded input
672
- assert_match(/Line 1/, output)
673
- refute_match(/Line 2/, output)
674
- end
675
-
676
- test 'should not drop line with attribute unassignment if attribute-undefined is drop' do
677
- input = <<-EOS
678
- :attribute-undefined: drop
679
- :a:
680
-
681
- Line 1: This line should appear in the output.
682
- Line 2: {set:a!}This line should appear in the output.
683
- EOS
684
-
685
- output = convert_string_to_embedded input
686
- assert_match(/Line 1/, output)
687
- assert_match(/Line 2/, output)
688
- refute_match(/\{set:a!\}/, output)
689
- end
690
-
691
- test 'should drop line that only contains attribute assignment' do
692
- input = <<-EOS
693
- Line 1
694
- {set:a}
695
- Line 2
696
- EOS
697
-
698
- output = convert_string_to_embedded input
699
- assert_xpath %(//p[text()="Line 1\nLine 2"]), output, 1
700
- end
701
-
702
- test 'should drop line that only contains unresolved attribute when attribute-missing is drop' do
703
- input = <<-EOS
704
- Line 1
705
- {unresolved}
706
- Line 2
707
- EOS
708
-
709
- output = convert_string_to_embedded input, :attributes => { 'attribute-missing' => 'drop' }
710
- assert_xpath %(//p[text()="Line 1\nLine 2"]), output, 1
711
- end
712
-
713
- test "substitutes inside unordered list items" do
714
- html = convert_string(":foo: bar\n* snort at the {foo}\n* yawn")
715
- result = Nokogiri::HTML(html)
716
- assert_match(/snort at the bar/, result.css("li").first.content.strip)
717
- end
718
-
719
- test 'substitutes inside section title' do
720
- output = convert_string(":prefix: Cool\n\n== {prefix} Title\n\ncontent")
721
- result = Nokogiri::HTML(output)
722
- assert_match(/Cool Title/, result.css('h2').first.content)
723
- assert_match(/_cool_title/, result.css('h2').first.attr('id'))
724
- end
725
-
726
- test 'interpolates attribute defined in header inside attribute entry in header' do
727
- input = <<-EOS
728
- = Title
729
- Author Name
730
- :attribute-a: value
731
- :attribute-b: {attribute-a}
732
-
733
- preamble
734
- EOS
735
- doc = document_from_string(input, :parse_header_only => true)
736
- assert_equal 'value', doc.attributes['attribute-b']
737
- end
738
-
739
- test 'interpolates author attribute inside attribute entry in header' do
740
- input = <<-EOS
741
- = Title
742
- Author Name
743
- :name: {author}
744
-
745
- preamble
746
- EOS
747
- doc = document_from_string(input, :parse_header_only => true)
748
- assert_equal 'Author Name', doc.attributes['name']
749
- end
750
-
751
- test 'interpolates revinfo attribute inside attribute entry in header' do
752
- input = <<-EOS
753
- = Title
754
- Author Name
755
- 2013-01-01
756
- :date: {revdate}
757
-
758
- preamble
759
- EOS
760
- doc = document_from_string(input, :parse_header_only => true)
761
- assert_equal '2013-01-01', doc.attributes['date']
762
- end
763
-
764
- test 'attribute entries can resolve previously defined attributes' do
765
- input = <<-EOS
766
- = Title
767
- Author Name
768
- v1.0, 2010-01-01: First release!
769
- :a: value
770
- :a2: {a}
771
- :revdate2: {revdate}
772
-
773
- {a} == {a2}
774
-
775
- {revdate} == {revdate2}
776
- EOS
777
-
778
- doc = document_from_string input
779
- assert_equal '2010-01-01', doc.attr('revdate')
780
- assert_equal '2010-01-01', doc.attr('revdate2')
781
- assert_equal 'value', doc.attr('a')
782
- assert_equal 'value', doc.attr('a2')
783
-
784
- output = doc.convert
785
- assert_includes output, 'value == value'
786
- assert_includes output, '2010-01-01 == 2010-01-01'
787
- end
788
-
789
- test 'should warn if unterminated block comment is detected in document header' do
790
- input = <<-EOS
791
- = Document Title
792
- :foo: bar
793
- ////
794
- :hey: there
795
-
796
- content
797
- EOS
798
- doc = document_from_string input
799
- assert_nil doc.attr('hey')
800
- assert_message @logger, :WARN, '<stdin>: line 3: unterminated comment block', Hash
801
- end
802
-
803
- test 'substitutes inside block title' do
804
- input = <<-EOS
805
- :gem_name: asciidoctor
806
-
807
- .Require the +{gem_name}+ gem
808
- To use {gem_name}, the first thing to do is to import it in your Ruby source file.
809
- EOS
810
- output = convert_string_to_embedded input, :attributes => {'compat-mode' => ''}
811
- assert_xpath '//*[@class="title"]/code[text()="asciidoctor"]', output, 1
812
-
813
- input = <<-EOS
814
- :gem_name: asciidoctor
815
-
816
- .Require the `{gem_name}` gem
817
- To use {gem_name}, the first thing to do is to import it in your Ruby source file.
818
- EOS
819
- output = convert_string_to_embedded input
820
- assert_xpath '//*[@class="title"]/code[text()="asciidoctor"]', output, 1
821
- end
822
-
823
- test 'sets attribute until it is deleted' do
824
- input = <<-EOS
825
- :foo: bar
826
-
827
- Crossing the {foo}.
828
-
829
- :foo!:
830
-
831
- Belly up to the {foo}.
832
- EOS
833
- output = convert_string_to_embedded input
834
- assert_xpath '//p[text()="Crossing the bar."]', output, 1
835
- assert_xpath '//p[text()="Belly up to the bar."]', output, 0
836
- end
837
-
838
- test 'should allow compat-mode to be set and unset in middle of document' do
839
- input = <<-EOS
840
- :foo: bar
841
-
842
- [[paragraph-a]]
843
- `{foo}`
844
-
845
- :compat-mode!:
846
-
847
- [[paragraph-b]]
848
- `{foo}`
849
-
850
- :compat-mode:
851
-
852
- [[paragraph-c]]
853
- `{foo}`
854
- EOS
855
-
856
- result = convert_string_to_embedded input, :attributes => {'compat-mode' => '@'}
857
- assert_xpath '/*[@id="paragraph-a"]//code[text()="{foo}"]', result, 1
858
- assert_xpath '/*[@id="paragraph-b"]//code[text()="bar"]', result, 1
859
- assert_xpath '/*[@id="paragraph-c"]//code[text()="{foo}"]', result, 1
860
- end
861
-
862
- test 'does not disturb attribute-looking things escaped with backslash' do
863
- html = convert_string(":foo: bar\nThis is a \\{foo} day.")
864
- result = Nokogiri::HTML(html)
865
- assert_equal 'This is a {foo} day.', result.css('p').first.content.strip
866
- end
867
-
868
- test 'does not disturb attribute-looking things escaped with literals' do
869
- html = convert_string(":foo: bar\nThis is a +++{foo}+++ day.")
870
- result = Nokogiri::HTML(html)
871
- assert_equal 'This is a {foo} day.', result.css('p').first.content.strip
872
- end
873
-
874
- test 'does not substitute attributes inside listing blocks' do
875
- input = <<-EOS
876
- :forecast: snow
877
-
878
- ----
879
- puts 'The forecast for today is {forecast}'
880
- ----
881
- EOS
882
- output = convert_string(input)
883
- assert_match(/\{forecast\}/, output)
884
- end
885
-
886
- test 'does not substitute attributes inside literal blocks' do
887
- input = <<-EOS
888
- :foo: bar
889
-
890
- ....
891
- You insert the text {foo} to expand the value
892
- of the attribute named foo in your document.
893
- ....
894
- EOS
895
- output = convert_string(input)
896
- assert_match(/\{foo\}/, output)
897
- end
898
-
899
- test 'does not show docdir and shows relative docfile if safe mode is SERVER or greater' do
900
- input = <<-EOS
901
- * docdir: {docdir}
902
- * docfile: {docfile}
903
- EOS
904
-
905
- docdir = Dir.pwd
906
- docfile = File.join(docdir, 'sample.asciidoc')
907
- output = convert_string_to_embedded input, :safe => Asciidoctor::SafeMode::SERVER, :attributes => {'docdir' => docdir, 'docfile' => docfile}
908
- assert_xpath '//li[1]/p[text()="docdir: "]', output, 1
909
- assert_xpath '//li[2]/p[text()="docfile: sample.asciidoc"]', output, 1
910
- end
911
-
912
- test 'shows absolute docdir and docfile paths if safe mode is less than SERVER' do
913
- input = <<-EOS
914
- * docdir: {docdir}
915
- * docfile: {docfile}
916
- EOS
917
-
918
- docdir = Dir.pwd
919
- docfile = File.join(docdir, 'sample.asciidoc')
920
- output = convert_string_to_embedded input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'docdir' => docdir, 'docfile' => docfile}
921
- assert_xpath %(//li[1]/p[text()="docdir: #{docdir}"]), output, 1
922
- assert_xpath %(//li[2]/p[text()="docfile: #{docfile}"]), output, 1
923
- end
924
-
925
- test 'assigns attribute defined in attribute reference with set prefix and value' do
926
- input = '{set:foo:bar}{foo}'
927
- output = convert_string_to_embedded input
928
- assert_xpath '//p', output, 1
929
- assert_xpath '//p[text()="bar"]', output, 1
930
- end
931
-
932
- test 'assigns attribute defined in attribute reference with set prefix and no value' do
933
- input = "{set:foo}\n{foo}yes"
934
- output = convert_string_to_embedded input
935
- assert_xpath '//p', output, 1
936
- assert_xpath '//p[normalize-space(text())="yes"]', output, 1
937
- end
938
-
939
- test 'assigns attribute defined in attribute reference with set prefix and empty value' do
940
- input = "{set:foo:}\n{foo}yes"
941
- output = convert_string_to_embedded input
942
- assert_xpath '//p', output, 1
943
- assert_xpath '//p[normalize-space(text())="yes"]', output, 1
944
- end
945
-
946
- test 'unassigns attribute defined in attribute reference with set prefix' do
947
- input = <<-EOS
948
- :attribute-missing: drop-line
949
- :foo:
950
-
951
- {set:foo!}
952
- {foo}yes
953
- EOS
954
- output = convert_string_to_embedded input
955
- assert_xpath '//p', output, 1
956
- assert_xpath '//p/child::text()', output, 0
957
- end
958
- end
959
-
960
- context "Intrinsic attributes" do
961
-
962
- test "substitute intrinsics" do
963
- Asciidoctor::INTRINSIC_ATTRIBUTES.each_pair do |key, value|
964
- html = convert_string("Look, a {#{key}} is here")
965
- # can't use Nokogiri because it interprets the HTML entities and we can't match them
966
- assert_match(/Look, a #{Regexp.escape(value)} is here/, html)
967
- end
968
- end
969
-
970
- test "don't escape intrinsic substitutions" do
971
- html = convert_string('happy{nbsp}together')
972
- assert_match(/happy&#160;together/, html)
973
- end
974
-
975
- test "escape special characters" do
976
- html = convert_string('<node>&</node>')
977
- assert_match(/&lt;node&gt;&amp;&lt;\/node&gt;/, html)
978
- end
979
-
980
- test 'creates counter' do
981
- input = <<-EOS
982
- {counter:mycounter}
983
- EOS
984
-
985
- doc = document_from_string input
986
- output = doc.convert
987
- assert_equal 1, doc.attributes['mycounter']
988
- assert_xpath '//p[text()="1"]', output, 1
989
- end
990
-
991
- test 'creates counter silently' do
992
- input = <<-EOS
993
- {counter2:mycounter}
994
- EOS
995
-
996
- doc = document_from_string input
997
- output = doc.convert
998
- assert_equal 1, doc.attributes['mycounter']
999
- assert_xpath '//p[text()="1"]', output, 0
1000
- end
1001
-
1002
- test 'creates counter with numeric seed value' do
1003
- input = <<-EOS
1004
- {counter2:mycounter:10}
1005
- EOS
1006
-
1007
- doc = document_from_string input
1008
- doc.convert
1009
- assert_equal 10, doc.attributes['mycounter']
1010
- end
1011
-
1012
- test 'creates counter with character seed value' do
1013
- input = <<-EOS
1014
- {counter2:mycounter:A}
1015
- EOS
1016
-
1017
- doc = document_from_string input
1018
- doc.convert
1019
- assert_equal 'A', doc.attributes['mycounter']
1020
- end
1021
-
1022
- test 'increments counter with numeric value' do
1023
- input = <<-EOS
1024
- :mycounter: 1
1025
-
1026
- {counter:mycounter}
1027
-
1028
- {mycounter}
1029
- EOS
1030
-
1031
- doc = document_from_string input
1032
- output = doc.convert
1033
- assert_equal 2, doc.attributes['mycounter']
1034
- assert_xpath '//p[text()="2"]', output, 2
1035
- end
1036
-
1037
- test 'increments counter with character value' do
1038
- input = <<-EOS
1039
- :mycounter: @
1040
-
1041
- {counter:mycounter}
1042
-
1043
- {mycounter}
1044
- EOS
1045
-
1046
- doc = document_from_string input
1047
- output = doc.convert
1048
- assert_equal 'A', doc.attributes['mycounter']
1049
- assert_xpath '//p[text()="A"]', output, 2
1050
- end
1051
-
1052
- test 'counter uses 0 as seed value if seed attribute is nil' do
1053
- input = <<-EOS
1054
- :mycounter:
1055
-
1056
- {counter:mycounter}
1057
-
1058
- {mycounter}
1059
- EOS
1060
-
1061
- doc = document_from_string input
1062
- output = doc.convert :header_footer => false
1063
- assert_equal 1, doc.attributes['mycounter']
1064
- assert_xpath '//p[text()="1"]', output, 2
1065
- end
1066
-
1067
- test 'counter value can be reset by attribute entry' do
1068
- input = <<-EOS
1069
- :mycounter:
1070
-
1071
- before: {counter:mycounter} {counter:mycounter} {counter:mycounter}
1072
-
1073
- :mycounter!:
1074
-
1075
- after: {counter:mycounter}
1076
- EOS
1077
-
1078
- doc = document_from_string input
1079
- output = doc.convert :header_footer => false
1080
- assert_equal 1, doc.attributes['mycounter']
1081
- assert_xpath '//p[text()="before: 1 2 3"]', output, 1
1082
- assert_xpath '//p[text()="after: 1"]', output, 1
1083
- end
1084
-
1085
- test 'nested document should use counter from parent document' do
1086
- input = <<-EOS
1087
- .Title for Foo
1088
- image::foo.jpg[]
1089
-
1090
- [cols="2*a"]
1091
- |===
1092
- |
1093
- .Title for Bar
1094
- image::bar.jpg[]
1095
-
1096
- |
1097
- .Title for Baz
1098
- image::baz.jpg[]
1099
- |===
1100
-
1101
- .Title for Qux
1102
- image::qux.jpg[]
1103
- EOS
1104
-
1105
- output = convert_string_to_embedded input
1106
- assert_xpath '//div[@class="title"]', output, 4
1107
- assert_xpath '//div[@class="title"][text() = "Figure 1. Title for Foo"]', output, 1
1108
- assert_xpath '//div[@class="title"][text() = "Figure 2. Title for Bar"]', output, 1
1109
- assert_xpath '//div[@class="title"][text() = "Figure 3. Title for Baz"]', output, 1
1110
- assert_xpath '//div[@class="title"][text() = "Figure 4. Title for Qux"]', output, 1
1111
- end
1112
- end
1113
-
1114
- context 'Block attributes' do
1115
- test 'parses attribute names as name token' do
1116
- input = <<-EOS
1117
- [normal,foo="bar",_foo="_bar",foo1="bar1",foo-foo="bar-bar",foo.foo="bar.bar"]
1118
- content
1119
- EOS
1120
-
1121
- block = block_from_string input
1122
- assert_equal 'bar', block.attr('foo')
1123
- assert_equal '_bar', block.attr('_foo')
1124
- assert_equal 'bar1', block.attr('foo1')
1125
- assert_equal 'bar-bar', block.attr('foo-foo')
1126
- assert_equal 'bar.bar', block.attr('foo.foo')
1127
- end
1128
-
1129
- test 'positional attributes assigned to block' do
1130
- input = <<-EOS
1131
- [quote, author, source]
1132
- ____
1133
- A famous quote.
1134
- ____
1135
- EOS
1136
- doc = document_from_string(input)
1137
- qb = doc.blocks.first
1138
- assert_equal 'quote', qb.style
1139
- assert_equal 'author', qb.attr('attribution')
1140
- assert_equal 'author', qb.attr(:attribution)
1141
- assert_equal 'author', qb.attributes['attribution']
1142
- assert_equal 'source', qb.attributes['citetitle']
1143
- end
1144
-
1145
- test 'normal substitutions are performed on single-quoted positional attribute' do
1146
- input = <<-EOS
1147
- [quote, author, 'http://wikipedia.org[source]']
1148
- ____
1149
- A famous quote.
1150
- ____
1151
- EOS
1152
- doc = document_from_string(input)
1153
- qb = doc.blocks.first
1154
- assert_equal 'quote', qb.style
1155
- assert_equal 'author', qb.attr('attribution')
1156
- assert_equal 'author', qb.attr(:attribution)
1157
- assert_equal 'author', qb.attributes['attribution']
1158
- assert_equal '<a href="http://wikipedia.org">source</a>', qb.attributes['citetitle']
1159
- end
1160
-
1161
- test 'normal substitutions are performed on single-quoted named attribute' do
1162
- input = <<-EOS
1163
- [quote, author, citetitle='http://wikipedia.org[source]']
1164
- ____
1165
- A famous quote.
1166
- ____
1167
- EOS
1168
- doc = document_from_string(input)
1169
- qb = doc.blocks.first
1170
- assert_equal 'quote', qb.style
1171
- assert_equal 'author', qb.attr('attribution')
1172
- assert_equal 'author', qb.attr(:attribution)
1173
- assert_equal 'author', qb.attributes['attribution']
1174
- assert_equal '<a href="http://wikipedia.org">source</a>', qb.attributes['citetitle']
1175
- end
1176
-
1177
- test 'normal substitutions are performed once on single-quoted named title attribute' do
1178
- input = <<-EOS
1179
- [title='*title*']
1180
- content
1181
- EOS
1182
- output = convert_string_to_embedded input
1183
- assert_xpath '//*[@class="title"]/strong[text()="title"]', output, 1
1184
- end
1185
-
1186
- test 'attribute list may not begin with space' do
1187
- input = <<-EOS
1188
- [ quote]
1189
- ____
1190
- A famous quote.
1191
- ____
1192
- EOS
1193
-
1194
- doc = document_from_string input
1195
- b1 = doc.blocks.first
1196
- assert_equal ['[ quote]'], b1.lines
1197
- end
1198
-
1199
- test 'attribute list may begin with comma' do
1200
- input = <<-EOS
1201
- [, author, source]
1202
- ____
1203
- A famous quote.
1204
- ____
1205
- EOS
1206
-
1207
- doc = document_from_string input
1208
- qb = doc.blocks.first
1209
- assert_equal 'quote', qb.style
1210
- assert_equal 'author', qb.attributes['attribution']
1211
- assert_equal 'source', qb.attributes['citetitle']
1212
- end
1213
-
1214
- test 'first attribute in list may be double quoted' do
1215
- input = <<-EOS
1216
- ["quote", "author", "source", role="famous"]
1217
- ____
1218
- A famous quote.
1219
- ____
1220
- EOS
1221
-
1222
- doc = document_from_string input
1223
- qb = doc.blocks.first
1224
- assert_equal 'quote', qb.style
1225
- assert_equal 'author', qb.attributes['attribution']
1226
- assert_equal 'source', qb.attributes['citetitle']
1227
- assert_equal 'famous', qb.attributes['role']
1228
- end
1229
-
1230
- test 'first attribute in list may be single quoted' do
1231
- input = <<-EOS
1232
- ['quote', 'author', 'source', role='famous']
1233
- ____
1234
- A famous quote.
1235
- ____
1236
- EOS
1237
-
1238
- doc = document_from_string input
1239
- qb = doc.blocks.first
1240
- assert_equal 'quote', qb.style
1241
- assert_equal 'author', qb.attributes['attribution']
1242
- assert_equal 'source', qb.attributes['citetitle']
1243
- assert_equal 'famous', qb.attributes['role']
1244
- end
1245
-
1246
- test 'attribute with value None without quotes is ignored' do
1247
- input = <<-EOS
1248
- [id=None]
1249
- paragraph
1250
- EOS
1251
-
1252
- doc = document_from_string input
1253
- para = doc.blocks.first
1254
- refute para.attributes.has_key?('id')
1255
- end
1256
-
1257
- test 'role? returns true if role is assigned' do
1258
- input = <<-EOS
1259
- [role="lead"]
1260
- A paragraph
1261
- EOS
1262
-
1263
- doc = document_from_string input
1264
- p = doc.blocks.first
1265
- assert p.role?
1266
- end
1267
-
1268
- test 'role? can check for exact role name match' do
1269
- input = <<-EOS
1270
- [role="lead"]
1271
- A paragraph
1272
- EOS
1273
-
1274
- doc = document_from_string input
1275
- p = doc.blocks.first
1276
- assert p.role?('lead')
1277
- p2 = doc.blocks.last
1278
- refute p2.role?('final')
1279
- end
1280
-
1281
- test 'has_role? can check for precense of role name' do
1282
- input = <<-EOS
1283
- [role="lead abstract"]
1284
- A paragraph
1285
- EOS
1286
-
1287
- doc = document_from_string input
1288
- p = doc.blocks.first
1289
- refute p.role?('lead')
1290
- assert p.has_role?('lead')
1291
- end
1292
-
1293
- test 'roles returns array of role names' do
1294
- input = <<-EOS
1295
- [role="story lead"]
1296
- A paragraph
1297
- EOS
1298
-
1299
- doc = document_from_string input
1300
- p = doc.blocks.first
1301
- assert_equal ['story', 'lead'], p.roles
1302
- end
1303
-
1304
- test 'roles returns empty array if role attribute is not set' do
1305
- input = <<-EOS
1306
- A paragraph
1307
- EOS
1308
-
1309
- doc = document_from_string input
1310
- p = doc.blocks.first
1311
- assert_equal [], p.roles
1312
- end
1313
-
1314
- test "Attribute substitutions are performed on attribute list before parsing attributes" do
1315
- input = <<-EOS
1316
- :lead: role="lead"
1317
-
1318
- [{lead}]
1319
- A paragraph
1320
- EOS
1321
- doc = document_from_string(input)
1322
- para = doc.blocks.first
1323
- assert_equal 'lead', para.attributes['role']
1324
- end
1325
-
1326
- test 'id, role and options attributes can be specified on block style using shorthand syntax' do
1327
- input = <<-EOS
1328
- [literal#first.lead%step]
1329
- A literal paragraph.
1330
- EOS
1331
- doc = document_from_string(input)
1332
- para = doc.blocks.first
1333
- assert_equal :literal, para.context
1334
- assert_equal 'first', para.attributes['id']
1335
- assert_equal 'lead', para.attributes['role']
1336
- assert_equal 'step', para.attributes['options']
1337
- assert para.attributes.has_key?('step-option')
1338
- end
1339
-
1340
- test 'id, role and options attributes can be specified using shorthand syntax on block style using multiple block attribute lines' do
1341
- input = <<-EOS
1342
- [literal]
1343
- [#first]
1344
- [.lead]
1345
- [%step]
1346
- A literal paragraph.
1347
- EOS
1348
- doc = document_from_string(input)
1349
- para = doc.blocks.first
1350
- assert_equal :literal, para.context
1351
- assert_equal 'first', para.attributes['id']
1352
- assert_equal 'lead', para.attributes['role']
1353
- assert_equal 'step', para.attributes['options']
1354
- assert para.attributes.has_key?('step-option')
1355
- end
1356
-
1357
- test 'multiple roles and options can be specified in block style using shorthand syntax' do
1358
- input = <<-EOS
1359
- [.role1%option1.role2%option2]
1360
- Text
1361
- EOS
1362
-
1363
- doc = document_from_string input
1364
- para = doc.blocks.first
1365
- assert_equal 'role1 role2', para.attributes['role']
1366
- assert_equal 'option1,option2', para.attributes['options']
1367
- assert para.attributes.has_key?('option1-option')
1368
- assert para.attributes.has_key?('option2-option')
1369
- end
1370
-
1371
- test 'options specified using shorthand syntax on block style across multiple lines should be additive' do
1372
- input = <<-EOS
1373
- [%option1]
1374
- [%option2]
1375
- Text
1376
- EOS
1377
-
1378
- doc = document_from_string input
1379
- para = doc.blocks.first
1380
- assert_equal 'option1,option2', para.attributes['options']
1381
- assert para.attributes.has_key?('option1-option')
1382
- assert para.attributes.has_key?('option2-option')
1383
- end
1384
-
1385
- test 'roles specified using shorthand syntax on block style across multiple lines should be additive' do
1386
- input = <<-EOS
1387
- [.role1]
1388
- [.role2.role3]
1389
- Text
1390
- EOS
1391
-
1392
- doc = document_from_string input
1393
- para = doc.blocks.first
1394
- assert_equal 'role1 role2 role3', para.attributes['role']
1395
- end
1396
-
1397
- test 'setting a role using the role attribute replaces any existing roles' do
1398
- input = <<-EOS
1399
- [.role1]
1400
- [role=role2]
1401
- [.role3]
1402
- Text
1403
- EOS
1404
-
1405
- doc = document_from_string input
1406
- para = doc.blocks.first
1407
- assert_equal 'role2 role3', para.attributes['role']
1408
- end
1409
-
1410
- test 'setting a role using the shorthand syntax on block style should not clear the ID' do
1411
- input = <<-EOS
1412
- [#id]
1413
- [.role]
1414
- Text
1415
- EOS
1416
-
1417
- doc = document_from_string input
1418
- para = doc.blocks.first
1419
- assert_equal 'id', para.id
1420
- assert_equal 'role', para.role
1421
- end
1422
-
1423
- test 'a role can be added using add_role when the node has no roles' do
1424
- input = <<-EOS
1425
- A normal paragraph
1426
- EOS
1427
- doc = document_from_string(input)
1428
- para = doc.blocks.first
1429
- res = para.add_role 'role1'
1430
- assert res
1431
- assert_equal 'role1', para.attributes['role']
1432
- assert para.has_role? 'role1'
1433
- end
1434
-
1435
- test 'a role can be added using add_role when the node already has a role' do
1436
- input = <<-EOS
1437
- [.role1]
1438
- A normal paragraph
1439
- EOS
1440
- doc = document_from_string(input)
1441
- para = doc.blocks.first
1442
- res = para.add_role 'role2'
1443
- assert res
1444
- assert_equal 'role1 role2', para.attributes['role']
1445
- assert para.has_role? 'role1'
1446
- assert para.has_role? 'role2'
1447
- end
1448
-
1449
- test 'a role is not added using add_role if the node already has that role' do
1450
- input = <<-EOS
1451
- [.role1]
1452
- A normal paragraph
1453
- EOS
1454
- doc = document_from_string(input)
1455
- para = doc.blocks.first
1456
- res = para.add_role 'role1'
1457
- refute res
1458
- assert_equal 'role1', para.attributes['role']
1459
- assert para.has_role? 'role1'
1460
- end
1461
-
1462
- test 'an existing role can be removed using remove_role' do
1463
- input = <<-EOS
1464
- [.role1.role2]
1465
- A normal paragraph
1466
- EOS
1467
- doc = document_from_string(input)
1468
- para = doc.blocks.first
1469
- res = para.remove_role 'role1'
1470
- assert res
1471
- assert_equal 'role2', para.attributes['role']
1472
- assert para.has_role? 'role2'
1473
- refute para.has_role?('role1')
1474
- end
1475
-
1476
- test 'roles are removed when last role is removed using remove_role' do
1477
- input = <<-EOS
1478
- [.role1]
1479
- A normal paragraph
1480
- EOS
1481
- doc = document_from_string(input)
1482
- para = doc.blocks.first
1483
- res = para.remove_role 'role1'
1484
- assert res
1485
- refute para.role?
1486
- assert_nil para.attributes['role']
1487
- refute para.has_role? 'role1'
1488
- end
1489
-
1490
- test 'roles are not changed when a non-existent role is removed using remove_role' do
1491
- input = <<-EOS
1492
- [.role1]
1493
- A normal paragraph
1494
- EOS
1495
- doc = document_from_string(input)
1496
- para = doc.blocks.first
1497
- res = para.remove_role 'role2'
1498
- refute res
1499
- assert_equal 'role1', para.attributes['role']
1500
- assert para.has_role? 'role1'
1501
- refute para.has_role?('role2')
1502
- end
1503
-
1504
- test 'roles are not changed when using remove_role if the node has no roles' do
1505
- input = <<-EOS
1506
- A normal paragraph
1507
- EOS
1508
- doc = document_from_string(input)
1509
- para = doc.blocks.first
1510
- res = para.remove_role 'role1'
1511
- refute res
1512
- assert_nil para.attributes['role']
1513
- refute para.has_role?('role1')
1514
- end
1515
-
1516
- test 'option can be specified in first position of block style using shorthand syntax' do
1517
- input = <<-EOS
1518
- [%interactive]
1519
- - [x] checked
1520
- EOS
1521
-
1522
- doc = document_from_string input
1523
- list = doc.blocks.first
1524
- assert_equal 'interactive', list.attributes['options']
1525
- assert list.attributes.has_key?('interactive-option')
1526
- end
1527
-
1528
- test 'id and role attributes can be specified on section style using shorthand syntax' do
1529
- input = <<-EOS
1530
- [dedication#dedication.small]
1531
- == Section
1532
- Content.
1533
- EOS
1534
- output = convert_string_to_embedded input
1535
- assert_xpath '/div[@class="sect1 small"]', output, 1
1536
- assert_xpath '/div[@class="sect1 small"]/h2[@id="dedication"]', output, 1
1537
- end
1538
-
1539
- test 'id attribute specified using shorthand syntax should not create a special section' do
1540
- input = <<-EOS
1541
- [#idname]
1542
- == Section
1543
-
1544
- content
1545
- EOS
1546
-
1547
- doc = document_from_string input, :backend => 'docbook45'
1548
- section = doc.blocks[0]
1549
- refute_nil section
1550
- assert_equal :section, section.context
1551
- refute section.special
1552
- output = doc.convert
1553
- assert_css 'section', output, 1
1554
- assert_css 'section#idname', output, 1
1555
- end
1556
-
1557
- test "Block attributes are additive" do
1558
- input = <<-EOS
1559
- [id='foo']
1560
- [role='lead']
1561
- A paragraph.
1562
- EOS
1563
- doc = document_from_string(input)
1564
- para = doc.blocks.first
1565
- assert_equal 'foo', para.id
1566
- assert_equal 'lead', para.attributes['role']
1567
- end
1568
-
1569
- test "Last wins for id attribute" do
1570
- input = <<-EOS
1571
- [[bar]]
1572
- [[foo]]
1573
- == Section
1574
-
1575
- paragraph
1576
-
1577
- [[baz]]
1578
- [id='coolio']
1579
- === Section
1580
- EOS
1581
- doc = document_from_string(input)
1582
- sec = doc.first_section
1583
- assert_equal 'foo', sec.id
1584
- subsec = sec.blocks.last
1585
- assert_equal 'coolio', subsec.id
1586
- end
1587
-
1588
- test "trailing block attributes transfer to the following section" do
1589
- input = <<-EOS
1590
- [[one]]
1591
-
1592
- == Section One
1593
-
1594
- paragraph
1595
-
1596
- [[sub]]
1597
- // try to mess this up!
1598
-
1599
- === Sub-section
1600
-
1601
- paragraph
1602
-
1603
- [role='classy']
1604
-
1605
- ////
1606
- block comment
1607
- ////
1608
-
1609
- == Section Two
1610
-
1611
- content
1612
- EOS
1613
- doc = document_from_string(input)
1614
- section_one = doc.blocks.first
1615
- assert_equal 'one', section_one.id
1616
- subsection = section_one.blocks.last
1617
- assert_equal 'sub', subsection.id
1618
- section_two = doc.blocks.last
1619
- assert_equal 'classy', section_two.attr(:role)
1620
- end
1621
- end
1622
-
1623
- end