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
@@ -3,7 +3,24 @@ unless defined? ASCIIDOCTOR_PROJECT_DIR
3
3
  $: << File.dirname(__FILE__); $:.uniq!
4
4
  require 'test_helper'
5
5
  end
6
- require 'asciidoctor/extensions'
6
+
7
+ class ExtensionsInitTest < Minitest::Test
8
+ def test_autoload
9
+ doc = empty_document
10
+ refute doc.extensions?, 'Extensions should not be enabled by default'
11
+
12
+ begin
13
+ # NOTE trigger extensions to autoload
14
+ Asciidoctor::Extensions.groups
15
+ rescue; end
16
+
17
+ doc = empty_document
18
+ assert doc.extensions?, 'Extensions should be enabled after being autoloaded'
19
+
20
+ self.class.remove_tests self.class
21
+ end
22
+ self
23
+ end.new(nil).test_autoload
7
24
 
8
25
  class SamplePreprocessor < Asciidoctor::Extensions::Preprocessor
9
26
  def process doc, reader
@@ -17,8 +34,13 @@ end
17
34
  class SampleDocinfoProcessor < Asciidoctor::Extensions::DocinfoProcessor
18
35
  end
19
36
 
37
+ # NOTE intentionally using the deprecated name
20
38
  class SampleTreeprocessor < Asciidoctor::Extensions::Treeprocessor
39
+ def process document
40
+ nil
41
+ end
21
42
  end
43
+ SampleTreeProcessor = SampleTreeprocessor
22
44
 
23
45
  class SamplePostprocessor < Asciidoctor::Extensions::Postprocessor
24
46
  end
@@ -61,7 +83,7 @@ class BoilerplateTextIncludeProcessor < Asciidoctor::Extensions::IncludeProcesso
61
83
  end
62
84
  end
63
85
 
64
- class ReplaceAuthorTreeprocessor < Asciidoctor::Extensions::Treeprocessor
86
+ class ReplaceAuthorTreeProcessor < Asciidoctor::Extensions::TreeProcessor
65
87
  def process document
66
88
  document.attributes['firstname'] = 'Ghost'
67
89
  document.attributes['author'] = 'Ghost Writer'
@@ -69,7 +91,7 @@ class ReplaceAuthorTreeprocessor < Asciidoctor::Extensions::Treeprocessor
69
91
  end
70
92
  end
71
93
 
72
- class ReplaceTreeTreeprocessor < Asciidoctor::Extensions::Treeprocessor
94
+ class ReplaceTreeTreeProcessor < Asciidoctor::Extensions::TreeProcessor
73
95
  def process document
74
96
  if document.doctitle == 'Original Document'
75
97
  Asciidoctor.load %(== Replacement Document\nReplacement Author\n\ncontent)
@@ -86,9 +108,9 @@ class StripAttributesPostprocessor < Asciidoctor::Extensions::Postprocessor
86
108
  end
87
109
 
88
110
  class UppercaseBlock < Asciidoctor::Extensions::BlockProcessor; use_dsl
89
- match_name :yell
90
- on_contexts :paragraph
91
- parse_content_as :simple
111
+ named :yell
112
+ bound_to :paragraph
113
+ parses_content_as :simple
92
114
  def process parent, reader, attributes
93
115
  create_paragraph parent, reader.lines.map(&:upcase), attributes
94
116
  end
@@ -96,23 +118,43 @@ end
96
118
 
97
119
  class SnippetMacro < Asciidoctor::Extensions::BlockMacroProcessor
98
120
  def process parent, target, attributes
99
- create_pass_block parent, %(<script src="http://example.com/#{target}.js"></script>), {}, :content_model => :raw
121
+ create_pass_block parent, %(<script src="http://example.com/#{target}.js?_mode=#{attributes['mode']}"></script>), {}, :content_model => :raw
100
122
  end
101
123
  end
102
124
 
103
125
  class TemperatureMacro < Asciidoctor::Extensions::InlineMacroProcessor; use_dsl
104
126
  named :degrees
105
- name_attributes 'units'
127
+ resolves_attributes '1:units', 'precision=1'
106
128
  def process parent, target, attributes
107
129
  units = attributes['units'] || (parent.document.attr 'temperature-unit', 'C')
130
+ precision = attributes['precision'].to_i
108
131
  c = target.to_f
109
132
  case units
110
133
  when 'C'
111
- %(#{c} &#176;C)
134
+ %(#{round_with_precision c, precision} &#176;C)
112
135
  when 'F'
113
- %(#{c * 1.8 + 32 } &#176;F)
136
+ %(#{round_with_precision c * 1.8 + 32, precision} &#176;F)
114
137
  else
115
- c
138
+ raise ::ArgumentError, %(Unknown temperature units: #{units})
139
+ end
140
+ end
141
+
142
+ if (::Numeric.instance_method :round).arity == 0
143
+ def round_with_precision value, precision = 0
144
+ if precision == 0
145
+ value.round
146
+ else
147
+ factor = 10 ** precision
148
+ if precision < 0
149
+ (value * factor).round.div factor
150
+ else
151
+ (value * factor).round.fdiv factor
152
+ end
153
+ end
154
+ end
155
+ else
156
+ def round_with_precision value, precision = 0
157
+ value.round precision
116
158
  end
117
159
  end
118
160
  end
@@ -123,8 +165,7 @@ class MetaRobotsDocinfoProcessor < Asciidoctor::Extensions::DocinfoProcessor
123
165
  end
124
166
  end
125
167
 
126
- class MetaAppDocinfoProcessor < Asciidoctor::Extensions::DocinfoProcessor
127
- use_dsl
168
+ class MetaAppDocinfoProcessor < Asciidoctor::Extensions::DocinfoProcessor; use_dsl
128
169
  at_location :head
129
170
 
130
171
  def process document
@@ -197,43 +238,108 @@ context 'Extensions' do
197
238
  end
198
239
  end
199
240
 
241
+ test 'should unregister extension group by symbol name' do
242
+ begin
243
+ Asciidoctor::Extensions.register :sample, SampleExtensionGroup
244
+ refute_nil Asciidoctor::Extensions.groups
245
+ assert_equal 1, Asciidoctor::Extensions.groups.size
246
+ Asciidoctor::Extensions.unregister :sample
247
+ assert_equal 0, Asciidoctor::Extensions.groups.size
248
+ ensure
249
+ Asciidoctor::Extensions.unregister_all
250
+ end
251
+ end
252
+
253
+ test 'should unregister extension group by string name' do
254
+ begin
255
+ Asciidoctor::Extensions.register :sample, SampleExtensionGroup
256
+ refute_nil Asciidoctor::Extensions.groups
257
+ assert_equal 1, Asciidoctor::Extensions.groups.size
258
+ Asciidoctor::Extensions.unregister 'sample'
259
+ assert_equal 0, Asciidoctor::Extensions.groups.size
260
+ ensure
261
+ Asciidoctor::Extensions.unregister_all
262
+ end
263
+ end
264
+
265
+ test 'should unregister multiple extension groups by name' do
266
+ begin
267
+ Asciidoctor::Extensions.register :sample1, SampleExtensionGroup
268
+ Asciidoctor::Extensions.register :sample2, SampleExtensionGroup
269
+ refute_nil Asciidoctor::Extensions.groups
270
+ assert_equal 2, Asciidoctor::Extensions.groups.size
271
+ Asciidoctor::Extensions.unregister :sample1, :sample2
272
+ assert_equal 0, Asciidoctor::Extensions.groups.size
273
+ ensure
274
+ Asciidoctor::Extensions.unregister_all
275
+ end
276
+ end
277
+
200
278
  test 'should get class for top-level class name' do
201
- clazz = Asciidoctor::Extensions.class_for_name('Asciidoctor')
279
+ clazz = Asciidoctor::Extensions.class_for_name 'String'
202
280
  refute_nil clazz
203
- assert_equal Asciidoctor, clazz
281
+ assert_equal String, clazz
204
282
  end
205
283
 
206
284
  test 'should get class for class name in module' do
207
- clazz = Asciidoctor::Extensions.class_for_name('Asciidoctor::Extensions')
285
+ clazz = Asciidoctor::Extensions.class_for_name 'Asciidoctor::Document'
208
286
  refute_nil clazz
209
- assert_equal Asciidoctor::Extensions, clazz
287
+ assert_equal Asciidoctor::Document, clazz
210
288
  end
211
289
 
212
290
  test 'should get class for class name resolved from root' do
213
- clazz = Asciidoctor::Extensions.class_for_name('::Asciidoctor::Extensions')
291
+ clazz = Asciidoctor::Extensions.class_for_name '::Asciidoctor::Document'
214
292
  refute_nil clazz
215
- assert_equal Asciidoctor::Extensions, clazz
293
+ assert_equal Asciidoctor::Document, clazz
216
294
  end
217
295
 
218
296
  test 'should raise exception if cannot find class for name' do
219
297
  begin
220
- Asciidoctor::Extensions.class_for_name('InvalidModule::InvalidClass')
298
+ Asciidoctor::Extensions.class_for_name 'InvalidModule::InvalidClass'
221
299
  flunk 'Expecting RuntimeError to be raised'
222
- rescue RuntimeError => e
300
+ rescue NameError => e
223
301
  assert_equal 'Could not resolve class for name: InvalidModule::InvalidClass', e.message
224
302
  end
225
303
  end
226
304
 
305
+ test 'should raise exception if name resolves to module' do
306
+ begin
307
+ Asciidoctor::Extensions.class_for_name 'Asciidoctor::Extensions'
308
+ flunk 'Expecting RuntimeError to be raised'
309
+ rescue NameError => e
310
+ assert_equal 'Could not resolve class for name: Asciidoctor::Extensions', e.message
311
+ end
312
+ end
313
+
227
314
  test 'should resolve class if class is given' do
228
- clazz = Asciidoctor::Extensions.resolve_class(Asciidoctor::Extensions)
315
+ clazz = Asciidoctor::Extensions.resolve_class Asciidoctor::Document
229
316
  refute_nil clazz
230
- assert_equal Asciidoctor::Extensions, clazz
317
+ assert_equal Asciidoctor::Document, clazz
231
318
  end
232
319
 
233
320
  test 'should resolve class if class from string' do
234
- clazz = Asciidoctor::Extensions.resolve_class('Asciidoctor::Extensions')
321
+ clazz = Asciidoctor::Extensions.resolve_class 'Asciidoctor::Document'
235
322
  refute_nil clazz
236
- assert_equal Asciidoctor::Extensions, clazz
323
+ assert_equal Asciidoctor::Document, clazz
324
+ end
325
+
326
+ test 'should allow standalone registry to be created but not registered' do
327
+ registry = Asciidoctor::Extensions.create 'sample' do
328
+ block do
329
+ named :whisper
330
+ bound_to :paragraph
331
+ parses_content_as :simple
332
+ def process parent, reader, attributes
333
+ create_paragraph parent, reader.lines.map(&:downcase), attributes
334
+ end
335
+ end
336
+ end
337
+
338
+ assert_instance_of Asciidoctor::Extensions::Registry, registry
339
+ refute_nil registry.groups
340
+ assert_equal 1, registry.groups.size
341
+ assert_equal 'sample', registry.groups.keys.first
342
+ assert_equal 0, Asciidoctor::Extensions.groups.size
237
343
  end
238
344
  end
239
345
 
@@ -318,7 +424,8 @@ context 'Extensions' do
318
424
  assert extensions.first.process_method.is_a? ::Method
319
425
  end
320
426
 
321
- test 'should instantiate treeprocessors' do
427
+ # NOTE intentionally using the legacy names
428
+ test 'should instantiate tree processors' do
322
429
  registry = Asciidoctor::Extensions::Registry.new
323
430
  registry.treeprocessor SampleTreeprocessor
324
431
  registry.activate Asciidoctor::Document.new
@@ -397,6 +504,30 @@ context 'Extensions' do
397
504
  end
398
505
 
399
506
  context 'Integration' do
507
+ test 'can provide extension registry as option' do
508
+ registry = Asciidoctor::Extensions.create do
509
+ tree_processor SampleTreeProcessor
510
+ end
511
+
512
+ doc = document_from_string %(= Document Title\n\ncontent), :extension_registry => registry
513
+ refute_nil doc.extensions
514
+ assert_equal 1, doc.extensions.groups.size
515
+ assert doc.extensions.tree_processors?
516
+ assert_equal 1, doc.extensions.tree_processors.size
517
+ assert_equal 0, Asciidoctor::Extensions.groups.size
518
+ end
519
+
520
+ test 'can provide extensions proc as option' do
521
+ doc = document_from_string %(= Document Title\n\ncontent), :extensions => proc {
522
+ tree_processor SampleTreeProcessor
523
+ }
524
+ refute_nil doc.extensions
525
+ assert_equal 1, doc.extensions.groups.size
526
+ assert doc.extensions.tree_processors?
527
+ assert_equal 1, doc.extensions.tree_processors.size
528
+ assert_equal 0, Asciidoctor::Extensions.groups.size
529
+ end
530
+
400
531
  test 'should invoke preprocessors before parsing document' do
401
532
  input = <<-EOS
402
533
  junk line
@@ -457,13 +588,17 @@ last line
457
588
  # Safe Mode is not required here
458
589
  document = empty_document :base_dir => File.expand_path(File.dirname(__FILE__))
459
590
  document.extensions.include_processor do
591
+ handles? do |target|
592
+ target == 'include-file.asciidoc'
593
+ end
594
+
460
595
  process do |doc, reader, target, attributes|
461
596
  # demonstrate that push_include normalizes endlines
462
597
  content = ["include target:: #{target}\n", "\n", "middle line\n"]
463
598
  reader.push_include content, target, target, 1, attributes
464
599
  end
465
600
  end
466
- reader = Asciidoctor::PreprocessorReader.new document, input
601
+ reader = Asciidoctor::PreprocessorReader.new document, input, nil, :normalize => true
467
602
  lines = []
468
603
  lines << reader.read_line
469
604
  lines << reader.read_line
@@ -473,12 +608,12 @@ last line
473
608
  while reader.has_more_lines?
474
609
  lines << reader.read_line
475
610
  end
476
- source = lines * ::Asciidoctor::EOL
611
+ source = lines * ::Asciidoctor::LF
477
612
  assert_match(/^include target:: include-file.asciidoc$/, source)
478
613
  assert_match(/^middle line$/, source)
479
614
  end
480
615
 
481
- test 'should invoke treeprocessors after parsing document' do
616
+ test 'should invoke tree processors after parsing document' do
482
617
  input = <<-EOS
483
618
  = Document Title
484
619
  Doc Writer
@@ -488,7 +623,7 @@ content
488
623
 
489
624
  begin
490
625
  Asciidoctor::Extensions.register do
491
- treeprocessor ReplaceAuthorTreeprocessor
626
+ tree_processor ReplaceAuthorTreeProcessor
492
627
  end
493
628
 
494
629
  doc = document_from_string input
@@ -498,7 +633,7 @@ content
498
633
  end
499
634
  end
500
635
 
501
- test 'should allow treeprocessor to replace tree' do
636
+ test 'should allow tree processor to replace tree' do
502
637
  input = <<-EOS
503
638
  = Original Document
504
639
  Doc Writer
@@ -508,7 +643,7 @@ content
508
643
 
509
644
  begin
510
645
  Asciidoctor::Extensions.register do
511
- treeprocessor ReplaceTreeTreeprocessor
646
+ tree_processor ReplaceTreeTreeProcessor
512
647
  end
513
648
 
514
649
  doc = document_from_string input
@@ -518,6 +653,37 @@ content
518
653
  end
519
654
  end
520
655
 
656
+ test 'should honor block title assigned in tree processor' do
657
+ input = <<-EOS
658
+ = Document Title
659
+ :!example-caption:
660
+
661
+ .Old block title
662
+ ====
663
+ example block content
664
+ ====
665
+ EOS
666
+
667
+ old_title = nil
668
+ begin
669
+ Asciidoctor::Extensions.register do
670
+ tree_processor do
671
+ process do |doc|
672
+ ex = (doc.find_by :context => :example)[0]
673
+ old_title = ex.title
674
+ ex.title = 'New block title'
675
+ end
676
+ end
677
+ end
678
+
679
+ doc = document_from_string input
680
+ assert_equal 'Old block title', old_title
681
+ assert_equal 'New block title', (doc.find_by :context => :example)[0].title
682
+ ensure
683
+ Asciidoctor::Extensions.unregister_all
684
+ end
685
+ end
686
+
521
687
  test 'should invoke postprocessors after rendering document' do
522
688
  input = <<-EOS
523
689
  * one
@@ -556,9 +722,36 @@ Hi there!
556
722
  end
557
723
  end
558
724
 
725
+ test 'should pass cloaked context in attributes passed to process method of custom block' do
726
+ input = <<-EOS
727
+ [custom]
728
+ ****
729
+ sidebar
730
+ ****
731
+ EOS
732
+
733
+ cloaked_context = nil
734
+ begin
735
+ Asciidoctor::Extensions.register do
736
+ block :custom do
737
+ on_context :sidebar
738
+ process do |doc, reader, attrs|
739
+ cloaked_context = attrs['cloaked-context']
740
+ nil
741
+ end
742
+ end
743
+ end
744
+
745
+ render_embedded_string input
746
+ assert_equal :sidebar, cloaked_context
747
+ ensure
748
+ Asciidoctor::Extensions.unregister_all
749
+ end
750
+ end
751
+
559
752
  test 'should invoke processor for custom block macro' do
560
753
  input = <<-EOS
561
- snippet::12345[]
754
+ snippet::12345[mode=edit]
562
755
  EOS
563
756
 
564
757
  begin
@@ -567,7 +760,33 @@ snippet::12345[]
567
760
  end
568
761
 
569
762
  output = render_embedded_string input
570
- assert output.include?('<script src="http://example.com/12345.js"></script>')
763
+ assert output.include?('<script src="http://example.com/12345.js?_mode=edit"></script>')
764
+ ensure
765
+ Asciidoctor::Extensions.unregister_all
766
+ end
767
+ end
768
+
769
+ test 'should match short form of block macro' do
770
+ input = <<-EOS
771
+ custom_toc::[]
772
+ EOS
773
+
774
+ resolved_target = nil
775
+
776
+ begin
777
+ Asciidoctor::Extensions.register do
778
+ block_macro do
779
+ named :custom_toc
780
+ process do |parent, target, attrs|
781
+ resolved_target = target
782
+ create_pass_block parent, '<!-- custom toc goes here -->', {}, :content_model => :raw
783
+ end
784
+ end
785
+ end
786
+
787
+ output = render_embedded_string input
788
+ assert_equal '<!-- custom toc goes here -->', output
789
+ assert_equal '', resolved_target
571
790
  ensure
572
791
  Asciidoctor::Extensions.unregister_all
573
792
  end
@@ -576,14 +795,14 @@ snippet::12345[]
576
795
  test 'should invoke processor for custom inline macro' do
577
796
  begin
578
797
  Asciidoctor::Extensions.register do
579
- inline_macro TemperatureMacro, :degrees
798
+ inline_macro TemperatureMacro, :deg
580
799
  end
581
800
 
582
- output = render_embedded_string 'Room temperature is degrees:25[C].', :attributes => {'temperature-unit' => 'F'}
583
- assert output.include?('Room temperature is 25.0 &#176;C.')
801
+ output = render_embedded_string 'Room temperature is deg:25[C,precision=0].', :attributes => { 'temperature-unit' => 'F' }
802
+ assert output.include?('Room temperature is 25 &#176;C.')
584
803
 
585
- output = render_embedded_string 'Room temperature is degrees:25[].', :attributes => {'temperature-unit' => 'F'}
586
- assert output.include?('Room temperature is 77.0 &#176;F.')
804
+ output = render_embedded_string 'Normal body temperature is deg:37[].', :attributes => { 'temperature-unit' => 'F' }
805
+ assert output.include?('Normal body temperature is 98.6 &#176;F.')
587
806
  ensure
588
807
  Asciidoctor::Extensions.unregister_all
589
808
  end
@@ -594,7 +813,8 @@ snippet::12345[]
594
813
  Asciidoctor::Extensions.register do
595
814
  inline_macro do
596
815
  named :label
597
- using_format :short
816
+ with_format :short
817
+ resolves_attributes false
598
818
  process do |parent, target|
599
819
  %(<label>#{target}</label>)
600
820
  end
@@ -608,13 +828,114 @@ snippet::12345[]
608
828
  end
609
829
  end
610
830
 
831
+ test 'should assign captures correctly for inline macros' do
832
+ begin
833
+ Asciidoctor::Extensions.register do
834
+ inline_macro do
835
+ named :short_attributes
836
+ with_format :short
837
+ resolves_attributes '1:name'
838
+ process do |parent, target, attrs|
839
+ %(target=#{target.inspect}, attributes=#{attrs.sort_by {|k, _| k.to_s }.inspect})
840
+ end
841
+ end
842
+
843
+ inline_macro do
844
+ named :short_text
845
+ with_format :short
846
+ resolves_attributes false
847
+ process do |parent, target, attrs|
848
+ %(target=#{target.inspect}, attributes=#{attrs.sort_by {|k, _| k.to_s }.inspect})
849
+ end
850
+ end
851
+
852
+ inline_macro do
853
+ named :full_attributes
854
+ resolves_attributes '1:name' => nil
855
+ process do |parent, target, attrs|
856
+ %(target=#{target.inspect}, attributes=#{attrs.sort_by {|k, _| k.to_s }.inspect})
857
+ end
858
+ end
859
+
860
+ inline_macro do
861
+ named :full_text
862
+ resolves_attributes false
863
+ process do |parent, target, attrs|
864
+ %(target=#{target.inspect}, attributes=#{attrs.sort_by {|k, _| k.to_s }.inspect})
865
+ end
866
+ end
867
+
868
+ inline_macro do
869
+ named :@short_match
870
+ matching %r/@(\w+)/
871
+ resolves_attributes false
872
+ process do |parent, target, attrs|
873
+ %(target=#{target.inspect}, attributes=#{attrs.sort_by {|k, _| k.to_s }.inspect})
874
+ end
875
+ end
876
+ end
877
+
878
+ input = <<-EOS
879
+ [subs=normal]
880
+ ++++
881
+ short_attributes:[]
882
+ short_attributes:[value,key=val]
883
+ short_text:[]
884
+ short_text:[[text\\]]
885
+ full_attributes:target[]
886
+ full_attributes:target[value,key=val]
887
+ full_text:target[]
888
+ full_text:target[[text\\]]
889
+ @target
890
+ ++++
891
+ EOS
892
+ expected = <<-EOS.chomp
893
+ target="", attributes=[]
894
+ target="value,key=val", attributes=[[1, "value"], ["key", "val"], ["name", "value"]]
895
+ target="", attributes=[["text", ""]]
896
+ target="[text]", attributes=[["text", "[text]"]]
897
+ target="target", attributes=[]
898
+ target="target", attributes=[[1, "value"], ["key", "val"], ["name", "value"]]
899
+ target="target", attributes=[["text", ""]]
900
+ target="target", attributes=[["text", "[text]"]]
901
+ target="target", attributes=[]
902
+ EOS
903
+ output = render_embedded_string input
904
+ assert_equal expected, output
905
+ ensure
906
+ Asciidoctor::Extensions.unregister_all
907
+ end
908
+ end
909
+
910
+ test 'should invoke convert on return value if value is an inline node' do
911
+ begin
912
+ Asciidoctor::Extensions.register do
913
+ inline_macro do
914
+ named :mention
915
+ resolves_attributes false
916
+ process do |parent, target, attrs|
917
+ if (text = attrs['text']).empty?
918
+ text = %(@#{target})
919
+ end
920
+ create_anchor parent, text, :type => :link, :target => %(https://github.com/#{target})
921
+ end
922
+ end
923
+ end
924
+
925
+ output = render_embedded_string 'mention:mojavelinux[Dan]'
926
+ assert output.include?('<a href="https://github.com/mojavelinux">Dan</a>')
927
+ ensure
928
+ Asciidoctor::Extensions.unregister_all
929
+ end
930
+ end
931
+
611
932
  test 'should not carry over attributes if block processor returns nil' do
612
933
  begin
613
934
  Asciidoctor::Extensions.register do
614
935
  block do
615
936
  named :skip
616
937
  on_context :paragraph
617
- parse_content_as :raw
938
+ parses_content_as :raw
618
939
  process do |parent, reader, attrs|
619
940
  nil
620
941
  end
@@ -643,7 +964,7 @@ rendered
643
964
  block do
644
965
  named :foo
645
966
  on_context :paragraph
646
- parse_content_as :raw
967
+ parses_content_as :raw
647
968
  process do |parent, reader, attrs|
648
969
  original_attrs = attrs.dup
649
970
  attrs.delete('title')
@@ -703,6 +1024,52 @@ content
703
1024
  end
704
1025
  end
705
1026
 
1027
+ test 'create_section should set up all section properties' do
1028
+ begin
1029
+ sect = nil
1030
+ Asciidoctor::Extensions.register do
1031
+ block_macro do
1032
+ named :sect
1033
+ process do |parent, target, attrs|
1034
+ opts = (level = attrs.delete 'level') ? { :level => level.to_i } : {}
1035
+ attrs['id'] = false if attrs['id'] == 'false'
1036
+ sect = create_section parent, 'Section Title', attrs, opts
1037
+ nil
1038
+ end
1039
+ end
1040
+ end
1041
+
1042
+ input_tpl = <<-EOS
1043
+ = Document Title
1044
+ :doctype: book
1045
+ :sectnums:
1046
+
1047
+ sect::[%s]
1048
+ EOS
1049
+
1050
+ {
1051
+ '' => ['chapter', 1, false, true, '_section_title'],
1052
+ 'level=0' => ['part', 0, false, false, '_section_title'],
1053
+ 'level=0,style=appendix' => ['appendix', 1, true, true, '_section_title'],
1054
+ 'style=appendix' => ['appendix', 1, true, true, '_section_title'],
1055
+ 'style=glossary' => ['glossary', 1, true, false, '_section_title'],
1056
+ 'style=abstract' => ['chapter', 1, false, true, '_section_title'],
1057
+ 'id=section-title' => ['chapter', 1, false, true, 'section-title'],
1058
+ 'id=false' => ['chapter', 1, false, true, nil]
1059
+ }.each do |attrlist, (expect_sectname, expect_level, expect_special, expect_numbered, expect_id)|
1060
+ input = input_tpl % attrlist
1061
+ document_from_string input, :safe => :server
1062
+ assert_equal expect_sectname, sect.sectname
1063
+ assert_equal expect_level, sect.level
1064
+ assert_equal expect_special, sect.special
1065
+ assert_equal expect_numbered, sect.numbered
1066
+ assert_equal expect_id, sect.id
1067
+ end
1068
+ ensure
1069
+ Asciidoctor::Extensions.unregister_all
1070
+ end
1071
+ end
1072
+
706
1073
  test 'should add docinfo to document' do
707
1074
  input = <<-EOS
708
1075
  = Document Title