asciidoctor 0.1.3 → 0.1.4

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +387 -0
  3. data/README.adoc +358 -348
  4. data/asciidoctor.gemspec +30 -9
  5. data/bin/asciidoctor +3 -0
  6. data/bin/asciidoctor-safe +3 -0
  7. data/compat/asciidoc.conf +76 -4
  8. data/lib/asciidoctor.rb +174 -79
  9. data/lib/asciidoctor/abstract_block.rb +131 -101
  10. data/lib/asciidoctor/abstract_node.rb +108 -26
  11. data/lib/asciidoctor/attribute_list.rb +1 -1
  12. data/lib/asciidoctor/backends/_stylesheets.rb +204 -62
  13. data/lib/asciidoctor/backends/base_template.rb +11 -22
  14. data/lib/asciidoctor/backends/docbook45.rb +158 -163
  15. data/lib/asciidoctor/backends/docbook5.rb +103 -0
  16. data/lib/asciidoctor/backends/html5.rb +662 -445
  17. data/lib/asciidoctor/block.rb +54 -44
  18. data/lib/asciidoctor/cli/invoker.rb +41 -20
  19. data/lib/asciidoctor/cli/options.rb +66 -20
  20. data/lib/asciidoctor/debug.rb +1 -1
  21. data/lib/asciidoctor/document.rb +265 -100
  22. data/lib/asciidoctor/extensions.rb +443 -0
  23. data/lib/asciidoctor/helpers.rb +38 -6
  24. data/lib/asciidoctor/inline.rb +5 -5
  25. data/lib/asciidoctor/lexer.rb +532 -250
  26. data/lib/asciidoctor/{list_item.rb → list.rb} +33 -13
  27. data/lib/asciidoctor/path_resolver.rb +28 -2
  28. data/lib/asciidoctor/reader.rb +814 -455
  29. data/lib/asciidoctor/renderer.rb +128 -42
  30. data/lib/asciidoctor/section.rb +55 -41
  31. data/lib/asciidoctor/substituters.rb +380 -107
  32. data/lib/asciidoctor/table.rb +40 -30
  33. data/lib/asciidoctor/version.rb +1 -1
  34. data/man/asciidoctor.1 +32 -96
  35. data/man/{asciidoctor.ad → asciidoctor.adoc} +57 -48
  36. data/test/attributes_test.rb +200 -27
  37. data/test/blocks_test.rb +361 -22
  38. data/test/document_test.rb +496 -81
  39. data/test/extensions_test.rb +448 -0
  40. data/test/fixtures/basic-docinfo-footer.html +6 -0
  41. data/test/fixtures/basic-docinfo-footer.xml +8 -0
  42. data/test/fixtures/basic-docinfo.xml +3 -3
  43. data/test/fixtures/basic.asciidoc +1 -0
  44. data/test/fixtures/child-include.adoc +5 -0
  45. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
  46. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
  47. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
  48. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
  49. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
  50. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
  51. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
  52. data/test/fixtures/docinfo-footer.html +1 -0
  53. data/test/fixtures/docinfo-footer.xml +9 -0
  54. data/test/fixtures/docinfo.xml +1 -0
  55. data/test/fixtures/grandchild-include.adoc +3 -0
  56. data/test/fixtures/parent-include-restricted.adoc +5 -0
  57. data/test/fixtures/parent-include.adoc +5 -0
  58. data/test/invoker_test.rb +82 -8
  59. data/test/lexer_test.rb +21 -3
  60. data/test/links_test.rb +34 -2
  61. data/test/lists_test.rb +304 -7
  62. data/test/options_test.rb +19 -3
  63. data/test/paragraphs_test.rb +13 -0
  64. data/test/paths_test.rb +22 -0
  65. data/test/preamble_test.rb +20 -0
  66. data/test/reader_test.rb +1096 -644
  67. data/test/renderer_test.rb +152 -12
  68. data/test/sections_test.rb +417 -76
  69. data/test/substitutions_test.rb +339 -138
  70. data/test/tables_test.rb +109 -4
  71. data/test/test_helper.rb +79 -13
  72. data/test/text_test.rb +111 -11
  73. metadata +54 -18
@@ -22,11 +22,31 @@ context 'Attributes' do
22
22
  assert_equal 'This is the first Ruby implementation of AsciiDoc.', doc.attributes['description']
23
23
  end
24
24
 
25
- test 'deletes an attribute' do
25
+ test 'should delete an attribute that ends with !' do
26
26
  doc = document_from_string(":frog: Tanglefoot\n:frog!:")
27
27
  assert_equal nil, doc.attributes['frog']
28
28
  end
29
29
 
30
+ test 'should delete an attribute that ends with ! set via API' do
31
+ doc = document_from_string(":frog: Tanglefoot", :attributes => {'frog!' => ''})
32
+ assert_equal nil, doc.attributes['frog']
33
+ end
34
+
35
+ test 'should delete an attribute that begins with !' do
36
+ doc = document_from_string(":frog: Tanglefoot\n:!frog:")
37
+ assert_equal nil, doc.attributes['frog']
38
+ end
39
+
40
+ test 'should delete an attribute that begins with ! set via API' do
41
+ doc = document_from_string(":frog: Tanglefoot", :attributes => {'!frog' => ''})
42
+ assert_equal nil, doc.attributes['frog']
43
+ end
44
+
45
+ test 'should delete an attribute set via API to nil value' do
46
+ doc = document_from_string(":frog: Tanglefoot", :attributes => {'frog' => nil})
47
+ assert_equal nil, doc.attributes['frog']
48
+ end
49
+
30
50
  test "doesn't choke when deleting a non-existing attribute" do
31
51
  doc = document_from_string(':frog!:')
32
52
  assert_equal nil, doc.attributes['frog']
@@ -43,12 +63,12 @@ context 'Attributes' do
43
63
  end
44
64
 
45
65
  test "assigns attribute to empty string if substitution fails to resolve attribute" do
46
- doc = document_from_string(":release: Asciidoctor {version}")
66
+ doc = document_from_string ":release: Asciidoctor {version}", :attributes => { 'attribute-missing' => 'drop-line' }
47
67
  assert_equal '', doc.attributes['release']
48
68
  end
49
69
 
50
70
  test "assigns multi-line attribute to empty string if substitution fails to resolve attribute" do
51
- doc = document_from_string(":release: Asciidoctor +\n {version}")
71
+ doc = document_from_string ":release: Asciidoctor +\n {version}", :attributes => { 'attribute-missing' => 'drop-line' }
52
72
  assert_equal '', doc.attributes['release']
53
73
  end
54
74
 
@@ -124,8 +144,16 @@ endif::holygrail[]
124
144
  end
125
145
 
126
146
  test 'attribute lookup is not case sensitive' do
127
- result = render_embedded_string(":He-Man: The most powerful man in the universe\n\n{He-Man}")
128
- assert_xpath '//p[text()="The most powerful man in the universe"]', result, 1
147
+ input = <<-EOS
148
+ :He-Man: The most powerful man in the universe
149
+
150
+ He-Man: {He-Man}
151
+
152
+ She-Ra: {She-Ra}
153
+ EOS
154
+ result = render_embedded_string input, :attributes => {'She-Ra' => 'The Princess of Power'}
155
+ assert_xpath '//p[text()="He-Man: The most powerful man in the universe"]', result, 1
156
+ assert_xpath '//p[text()="She-Ra: The Princess of Power"]', result, 1
129
157
  end
130
158
 
131
159
  test "render properly with single character name" do
@@ -134,7 +162,7 @@ endif::holygrail[]
134
162
  assert_equal 'R is for Ruby!', result.css("p").first.content.strip
135
163
  end
136
164
 
137
- test "convert multi-word names and render" do
165
+ test "collapses spaces in attribute names" do
138
166
  input = <<-EOS
139
167
  Main Header
140
168
  ===========
@@ -146,8 +174,15 @@ Yo, {myfrog}!
146
174
  assert_xpath '(//p)[1][text()="Yo, Tanglefoot!"]', output, 1
147
175
  end
148
176
 
149
- test "ignores lines with bad attributes" do
150
- html = render_string("This is\nblah blah {foobarbaz}\nall there is.")
177
+ test "ignores lines with bad attributes if attribute-missing is drop-line" do
178
+ input = <<-EOS
179
+ :attribute-missing: drop-line
180
+
181
+ This is
182
+ blah blah {foobarbaz}
183
+ all there is.
184
+ EOS
185
+ html = render_embedded_string input
151
186
  result = Nokogiri::HTML(html)
152
187
  assert_no_match(/blah blah/m, result.css("p").first.content.strip)
153
188
  end
@@ -159,14 +194,58 @@ Yo, {myfrog}!
159
194
  assert_xpath '//a[@href="http://google.com"][text() = "Google"]', output, 1
160
195
  end
161
196
 
162
- # See above - AsciiDoc says we're supposed to delete lines with bad
163
- # attribute refs in them. AsciiDoc is strange.
164
- #
165
- # test "Unknowns" do
166
- # html = render_string("Look, a {gobbledygook}")
167
- # result = Nokogiri::HTML(html)
168
- # assert_equal("Look, a {gobbledygook}", result.css("p").first.content.strip)
169
- # end
197
+ test 'should drop line with reference to missing attribute if attribute-missing attribute is drop-line' do
198
+ input = <<-EOS
199
+ :attribute-missing: drop-line
200
+
201
+ Line 1: This line should appear in the output.
202
+ Line 2: Oh no, a {bogus-attribute}! This line should not appear in the output.
203
+ EOS
204
+
205
+ output = render_embedded_string input
206
+ assert_match(/Line 1/, output)
207
+ assert_no_match(/Line 2/, output)
208
+ end
209
+
210
+ test 'should not drop line with reference to missing attribute by default' do
211
+ input = <<-EOS
212
+ Line 1: This line should appear in the output.
213
+ Line 2: A {bogus-attribute}! This time, this line should appear in the output.
214
+ EOS
215
+
216
+ output = render_embedded_string input
217
+ assert_match(/Line 1/, output)
218
+ assert_match(/Line 2/, output)
219
+ assert_match(/\{bogus-attribute\}/, output)
220
+ end
221
+
222
+ test 'should drop line with attribute unassignment by default' do
223
+ input = <<-EOS
224
+ :a:
225
+
226
+ Line 1: This line should appear in the output.
227
+ Line 2: {set:a!}This line should not appear in the output.
228
+ EOS
229
+
230
+ output = render_embedded_string input
231
+ assert_match(/Line 1/, output)
232
+ assert_no_match(/Line 2/, output)
233
+ end
234
+
235
+ test 'should not drop line with attribute unassignment if attribute-undefined is drop' do
236
+ input = <<-EOS
237
+ :attribute-undefined: drop
238
+ :a:
239
+
240
+ Line 1: This line should appear in the output.
241
+ Line 2: {set:a!}This line should not appear in the output.
242
+ EOS
243
+
244
+ output = render_embedded_string input
245
+ assert_match(/Line 1/, output)
246
+ assert_match(/Line 2/, output)
247
+ assert_no_match(/\{set:a!\}/, output)
248
+ end
170
249
 
171
250
  test "substitutes inside unordered list items" do
172
251
  html = render_string(":foo: bar\n* snort at the {foo}\n* yawn")
@@ -355,7 +434,13 @@ of the attribute named foo in your document.
355
434
  end
356
435
 
357
436
  test 'unassigns attribute defined in attribute reference with set prefix' do
358
- input = ":foo:\n\n{set:foo!}\n{foo}yes"
437
+ input = <<-EOS
438
+ :attribute-missing: drop-line
439
+ :foo:
440
+
441
+ {set:foo!}
442
+ {foo}yes
443
+ EOS
359
444
  output = render_embedded_string input
360
445
  assert_xpath '//p', output, 1
361
446
  assert_xpath '//p/child::text()', output, 0
@@ -466,8 +551,9 @@ ____
466
551
  EOS
467
552
  doc = document_from_string(input)
468
553
  qb = doc.blocks.first
469
- assert_equal 'quote', qb.attributes['style']
470
- assert_equal 'quote', qb.attr(:style)
554
+ assert_equal 'quote', qb.style
555
+ assert_equal 'author', qb.attr('attribution')
556
+ assert_equal 'author', qb.attr(:attribution)
471
557
  assert_equal 'author', qb.attributes['attribution']
472
558
  assert_equal 'source', qb.attributes['citetitle']
473
559
  end
@@ -481,8 +567,9 @@ ____
481
567
  EOS
482
568
  doc = document_from_string(input)
483
569
  qb = doc.blocks.first
484
- assert_equal 'quote', qb.attributes['style']
485
- assert_equal 'quote', qb.attr(:style)
570
+ assert_equal 'quote', qb.style
571
+ assert_equal 'author', qb.attr('attribution')
572
+ assert_equal 'author', qb.attr(:attribution)
486
573
  assert_equal 'author', qb.attributes['attribution']
487
574
  assert_equal '<a href="http://wikipedia.org">source</a>', qb.attributes['citetitle']
488
575
  end
@@ -497,7 +584,7 @@ ____
497
584
 
498
585
  doc = document_from_string input
499
586
  qb = doc.blocks.first
500
- assert_equal 'quote', qb.attributes['style']
587
+ assert_equal 'quote', qb.style
501
588
  end
502
589
 
503
590
  test 'attribute list may begin with comma' do
@@ -510,7 +597,7 @@ ____
510
597
 
511
598
  doc = document_from_string input
512
599
  qb = doc.blocks.first
513
- assert_equal 'quote', qb.attributes['style']
600
+ assert_equal 'quote', qb.style
514
601
  assert_equal 'author', qb.attributes['attribution']
515
602
  assert_equal 'source', qb.attributes['citetitle']
516
603
  end
@@ -525,7 +612,7 @@ ____
525
612
 
526
613
  doc = document_from_string input
527
614
  qb = doc.blocks.first
528
- assert_equal 'quote', qb.attributes['style']
615
+ assert_equal 'quote', qb.style
529
616
  assert_equal 'author', qb.attributes['attribution']
530
617
  assert_equal 'source', qb.attributes['citetitle']
531
618
  assert_equal 'famous', qb.attributes['role']
@@ -541,12 +628,69 @@ ____
541
628
 
542
629
  doc = document_from_string input
543
630
  qb = doc.blocks.first
544
- assert_equal 'quote', qb.attributes['style']
631
+ assert_equal 'quote', qb.style
545
632
  assert_equal 'author', qb.attributes['attribution']
546
633
  assert_equal 'source', qb.attributes['citetitle']
547
634
  assert_equal 'famous', qb.attributes['role']
548
635
  end
549
636
 
637
+ test 'role? returns true if role is assigned' do
638
+ input = <<-EOS
639
+ [role="lead"]
640
+ A paragraph
641
+ EOS
642
+
643
+ doc = document_from_string input
644
+ p = doc.blocks.first
645
+ assert p.role?
646
+ end
647
+
648
+ test 'role? can check for exact role name match' do
649
+ input = <<-EOS
650
+ [role="lead"]
651
+ A paragraph
652
+ EOS
653
+
654
+ doc = document_from_string input
655
+ p = doc.blocks.first
656
+ assert p.role?('lead')
657
+ p2 = doc.blocks.last
658
+ assert !p2.role?('final')
659
+ end
660
+
661
+ test 'has_role? can check for precense of role name' do
662
+ input = <<-EOS
663
+ [role="lead abstract"]
664
+ A paragraph
665
+ EOS
666
+
667
+ doc = document_from_string input
668
+ p = doc.blocks.first
669
+ assert !p.role?('lead')
670
+ assert p.has_role?('lead')
671
+ end
672
+
673
+ test 'roles returns array of role names' do
674
+ input = <<-EOS
675
+ [role="story lead"]
676
+ A paragraph
677
+ EOS
678
+
679
+ doc = document_from_string input
680
+ p = doc.blocks.first
681
+ assert_equal ['story', 'lead'], p.roles
682
+ end
683
+
684
+ test 'roles returns empty array if role attribute is not set' do
685
+ input = <<-EOS
686
+ A paragraph
687
+ EOS
688
+
689
+ doc = document_from_string input
690
+ p = doc.blocks.first
691
+ assert_equal [], p.roles
692
+ end
693
+
550
694
  test "Attribute substitutions are performed on attribute list before parsing attributes" do
551
695
  input = <<-EOS
552
696
  :lead: role="lead"
@@ -559,15 +703,44 @@ A paragraph
559
703
  assert_equal 'lead', para.attributes['role']
560
704
  end
561
705
 
562
- test 'id and role attributes can be specified on block style using shorthand syntax' do
706
+ test 'id, role and options attributes can be specified on block style using shorthand syntax' do
563
707
  input = <<-EOS
564
- [normal#first.lead]
708
+ [normal#first.lead%step]
565
709
  A normal paragraph.
566
710
  EOS
567
711
  doc = document_from_string(input)
568
712
  para = doc.blocks.first
569
713
  assert_equal 'first', para.attributes['id']
570
714
  assert_equal 'lead', para.attributes['role']
715
+ assert_equal 'step', para.attributes['options']
716
+ assert para.attributes.has_key?('step-option')
717
+ end
718
+
719
+ test 'multiple roles and options can be specified in block style using shorthand syntax' do
720
+ input = <<-EOS
721
+ [.role1%option1.role2%option2]
722
+ Text
723
+ EOS
724
+
725
+ doc = document_from_string input
726
+ para = doc.blocks.first
727
+ assert_equal 'role1 role2', para.attributes['role']
728
+ assert_equal 'option1,option2', para.attributes['options']
729
+ assert para.attributes.has_key?('option1-option')
730
+ assert para.attributes.has_key?('option2-option')
731
+ end
732
+
733
+ test 'option can be specified in first position of block style using shorthand syntax' do
734
+ input = <<-EOS
735
+ [%interactive]
736
+ - [x] checked
737
+ EOS
738
+
739
+ doc = document_from_string input
740
+ list = doc.blocks.first
741
+ assert_equal 'interactive', list.attributes['options']
742
+ assert list.attributes.has_key?('interactive-option')
743
+ assert list.attributes[1] == '%interactive'
571
744
  end
572
745
 
573
746
  test 'id and role attributes can be specified on section style using shorthand syntax' do
@@ -18,9 +18,9 @@ context "Blocks" do
18
18
 
19
19
  test "page break" do
20
20
  output = render_embedded_string("page 1\n\n<<<\n\npage 2")
21
- assert_xpath '/*[@style="page-break-after: always;"]', output, 1
22
- assert_xpath '/*[@style="page-break-after: always;"]/preceding-sibling::div/p[text()="page 1"]', output, 1
23
- assert_xpath '/*[@style="page-break-after: always;"]/following-sibling::div/p[text()="page 2"]', output, 1
21
+ assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]', output, 1
22
+ assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]/preceding-sibling::div/p[text()="page 1"]', output, 1
23
+ assert_xpath '/*[translate(@style, ";", "")="page-break-after: always"]/following-sibling::div/p[text()="page 2"]', output, 1
24
24
  end
25
25
  end
26
26
 
@@ -115,6 +115,108 @@ block comment
115
115
  output = render_embedded_string input
116
116
  assert !output.strip.empty?, "Line should be emitted => #{input.rstrip}"
117
117
  end
118
+
119
+ test 'preprocessor directives should not be processed within comment block within block metadata' do
120
+ input = <<-EOS
121
+ .sample title
122
+ ////
123
+ ifdef::asciidoctor[////]
124
+ ////
125
+ line should be rendered
126
+ EOS
127
+
128
+ output = render_embedded_string input
129
+ assert_xpath '//p[text() = "line should be rendered"]', output, 1
130
+ end
131
+
132
+ test 'preprocessor directives should not be processed within comment block' do
133
+ input = <<-EOS
134
+ dummy line
135
+
136
+ ////
137
+ ifdef::asciidoctor[////]
138
+ ////
139
+
140
+ line should be rendered
141
+ EOS
142
+
143
+ output = render_embedded_string input
144
+ assert_xpath '//p[text() = "line should be rendered"]', output, 1
145
+ end
146
+
147
+ # WARNING if first line of content is a directive, it will get interpretted before we know it's a comment block
148
+ # it happens because we always look a line ahead...not sure what we can do about it
149
+ test 'preprocessor directives should not be processed within comment open block' do
150
+ input = <<-EOS
151
+ [comment]
152
+ --
153
+ first line of comment
154
+ ifdef::asciidoctor[--]
155
+ line should not be rendered
156
+ --
157
+
158
+ EOS
159
+
160
+ output = render_embedded_string input
161
+ assert_xpath '//p', output, 0
162
+ end
163
+
164
+ # WARNING if first line of content is a directive, it will get interpretted before we know it's a comment block
165
+ # it happens because we always look a line ahead...not sure what we can do about it
166
+ test 'preprocessor directives should not be processed within comment paragraph' do
167
+ input = <<-EOS
168
+ [comment]
169
+ first line of content
170
+ ifdef::asciidoctor[////]
171
+
172
+ this line should be rendered
173
+ EOS
174
+
175
+ output = render_embedded_string input
176
+ assert_xpath '//p[text() = "this line should be rendered"]', output, 1
177
+ end
178
+
179
+ test 'comment style on open block should only skip block' do
180
+ input = <<-EOS
181
+ [comment]
182
+ --
183
+ skip
184
+
185
+ this block
186
+ --
187
+
188
+ not this text
189
+ EOS
190
+ result = render_embedded_string input
191
+ assert_xpath '//p', result, 1
192
+ assert_xpath '//p[text()="not this text"]', result, 1
193
+ end
194
+
195
+ test 'comment style on paragraph should only skip paragraph' do
196
+ input = <<-EOS
197
+ [comment]
198
+ skip
199
+ this paragraph
200
+
201
+ not this text
202
+ EOS
203
+ result = render_embedded_string input
204
+ assert_xpath '//p', result, 1
205
+ assert_xpath '//p[text()="not this text"]', result, 1
206
+ end
207
+
208
+ test 'comment style on paragraph should not cause adjacent block to be skipped' do
209
+ input = <<-EOS
210
+ [comment]
211
+ skip
212
+ this paragraph
213
+ [example]
214
+ not this text
215
+ EOS
216
+ result = render_embedded_string input
217
+ assert_xpath '/*[@class="exampleblock"]', result, 1
218
+ assert_xpath '/*[@class="exampleblock"]//*[normalize-space(text())="not this text"]', result, 1
219
+ end
118
220
  end
119
221
 
120
222
  context 'Quote and Verse Blocks' do
@@ -256,7 +358,7 @@ Some more inspiring words.
256
358
  input = <<-EOS
257
359
  > A famous quote.
258
360
  > Some more inspiring words.
259
- > -- Famous Person, Famous Source (1999)
361
+ > -- Famous Person, Famous Source, Volume 1 (1999)
260
362
  EOS
261
363
  output = render_string input
262
364
  assert_css '.quoteblock', output, 1
@@ -266,7 +368,7 @@ Some more inspiring words.
266
368
  assert_css '.quoteblock > .attribution', output, 1
267
369
  assert_css '.quoteblock > .attribution > cite', output, 1
268
370
  assert_css '.quoteblock > .attribution > cite + br', output, 1
269
- assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source (1999)"]', output, 1
371
+ assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source, Volume 1 (1999)"]', output, 1
270
372
  attribution = xmlnodes_at_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
271
373
  author = attribution.children.last
272
374
  assert_equal "#{expand_entity 8212} Famous Person", author.text.strip
@@ -276,7 +378,7 @@ Some more inspiring words.
276
378
  input = <<-EOS
277
379
  "A famous quote.
278
380
  Some more inspiring words."
279
- -- Famous Person, Famous Source (1999)
381
+ -- Famous Person, Famous Source, Volume 1 (1999)
280
382
  EOS
281
383
  output = render_string input
282
384
  assert_css '.quoteblock', output, 1
@@ -285,7 +387,7 @@ Some more inspiring words."
285
387
  assert_css '.quoteblock > .attribution', output, 1
286
388
  assert_css '.quoteblock > .attribution > cite', output, 1
287
389
  assert_css '.quoteblock > .attribution > cite + br', output, 1
288
- assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source (1999)"]', output, 1
390
+ assert_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]/cite[text() = "Famous Source, Volume 1 (1999)"]', output, 1
289
391
  attribution = xmlnodes_at_xpath '//*[@class = "quoteblock"]/*[@class = "attribution"]', output, 1
290
392
  author = attribution.children.last
291
393
  assert_equal "#{expand_entity 8212} Famous Person", author.text.strip
@@ -360,7 +462,31 @@ ____
360
462
  assert_css '.verseblock p', output, 0
361
463
  assert_css '.verseblock .literalblock', output, 0
362
464
  end
363
-
465
+
466
+ test 'verse should only have specialcharacters subs' do
467
+ input = <<-EOS
468
+ [verse]
469
+ ____
470
+ A famous verse
471
+ ____
472
+ EOS
473
+
474
+ verse = block_from_string input
475
+ assert_equal [:specialcharacters], verse.subs
476
+ end
477
+
478
+ test 'should not recognize callouts in a verse' do
479
+ input = <<-EOS
480
+ [verse]
481
+ ____
482
+ La la la <1>
483
+ ____
484
+ <1> Not pointing to a callout
485
+ EOS
486
+
487
+ output = render_embedded_string input
488
+ assert_xpath '//pre[text()="La la la <1>"]', output, 1
489
+ end
364
490
  end
365
491
 
366
492
  context "Example Blocks" do
@@ -564,7 +690,7 @@ EOS
564
690
  if compact
565
691
  assert_equal 2, blank_lines
566
692
  else
567
- assert blank_lines > 2
693
+ assert blank_lines >= 2
568
694
  end
569
695
  }
570
696
  end
@@ -593,7 +719,7 @@ EOS
593
719
  if compact
594
720
  assert_equal 2, blank_lines
595
721
  else
596
- assert blank_lines > 2
722
+ assert blank_lines >= 2
597
723
  end
598
724
  }
599
725
  end
@@ -622,7 +748,7 @@ EOS
622
748
  if compact
623
749
  assert_equal 2, blank_lines
624
750
  else
625
- assert blank_lines > 2
751
+ assert blank_lines >= 2
626
752
  end
627
753
  }
628
754
  end
@@ -714,6 +840,31 @@ end
714
840
  assert_equal expected.chomp, result
715
841
  end
716
842
 
843
+ test 'literal block should honor nowrap option' do
844
+ input = <<-EOS
845
+ [options="nowrap"]
846
+ ----
847
+ Do not wrap me if I get too long.
848
+ ----
849
+ EOS
850
+
851
+ output = render_embedded_string input
852
+ assert_css 'pre.nowrap', output, 1
853
+ end
854
+
855
+ test 'literal block should set nowrap class if prewrap document attribute is disabled' do
856
+ input = <<-EOS
857
+ :prewrap!:
858
+
859
+ ----
860
+ Do not wrap me if I get too long.
861
+ ----
862
+ EOS
863
+
864
+ output = render_embedded_string input
865
+ assert_css 'pre.nowrap', output, 1
866
+ end
867
+
717
868
  test 'literal block should honor explicit subs list' do
718
869
  input = <<-EOS
719
870
  [subs="verbatim,quotes"]
@@ -722,9 +873,24 @@ Map<String, String> *attributes*; //<1>
722
873
  ----
723
874
  EOS
724
875
 
725
- output = render_embedded_string input
876
+ block = block_from_string input
877
+ assert_equal [:specialcharacters,:callouts,:quotes], block.subs
878
+ output = block.render
726
879
  assert output.include?('Map&lt;String, String&gt; <strong>attributes</strong>;')
727
- assert output.include?('1')
880
+ assert_xpath '//pre/b[text()="(1)"]', output, 1
881
+ end
882
+
883
+ test 'should be able to disable callouts for literal block' do
884
+ input = <<-EOS
885
+ [subs="specialcharacters"]
886
+ ----
887
+ No callout here <1>
888
+ ----
889
+ EOS
890
+ block = block_from_string input
891
+ assert_equal [:specialcharacters], block.subs
892
+ output = block.render
893
+ assert_xpath '//pre/b[text()="(1)"]', output, 0
728
894
  end
729
895
 
730
896
  test 'listing block should honor explicit subs list' do
@@ -758,7 +924,7 @@ AssertionError
758
924
 
759
925
  output2 = render_embedded_string input2
760
926
  # FIXME JRuby is adding extra trailing endlines in the second document,
761
- # so rstrip is necessary
927
+ # for now, rstrip is necessary
762
928
  assert_equal output.rstrip, output2.rstrip
763
929
  end
764
930
 
@@ -858,8 +1024,8 @@ This is a passthrough block.
858
1024
 
859
1025
  block = block_from_string input
860
1026
  assert !block.nil?
861
- assert_equal 1, block.buffer.size
862
- assert_equal 'This is a passthrough block.', block.buffer.first
1027
+ assert_equal 1, block.lines.size
1028
+ assert_equal 'This is a passthrough block.', block.source
863
1029
  end
864
1030
 
865
1031
  test 'performs passthrough subs on a passthrough block' do
@@ -918,7 +1084,7 @@ section paragraph
918
1084
  output, errors = nil
919
1085
  redirect_streams do |stdout, stderr|
920
1086
  output = render_string input
921
- errors = stdout.string
1087
+ errors = stderr.string
922
1088
  end
923
1089
  assert_xpath '//*[@id="header"]/*', output, 0
924
1090
  assert_xpath '//*[@id="preamble"]/*', output, 0
@@ -1063,8 +1229,32 @@ image::images/tiger.png[Tiger]
1063
1229
  assert !doc.attributes.has_key?('figure-number')
1064
1230
  end
1065
1231
 
1066
- test 'drops line if image target is missing attribute reference' do
1232
+ test 'keeps line unprocessed if image target is missing attribute reference and attribute-missing is skip' do
1067
1233
  input = <<-EOS
1234
+ :attribute-missing: skip
1235
+
1236
+ image::{bogus}[]
1237
+ EOS
1238
+
1239
+ output = render_embedded_string input
1240
+ assert output.include?('image::{bogus}[]')
1241
+ end
1242
+
1243
+ test 'drops line if image target is missing attribute reference and attribute-missing is drop' do
1244
+ input = <<-EOS
1245
+ :attribute-missing: drop
1246
+
1247
+ image::{bogus}[]
1248
+ EOS
1249
+
1250
+ output = render_embedded_string input
1251
+ assert output.strip.empty?
1252
+ end
1253
+
1254
+ test 'drops line if image target is missing attribute reference and attribute-missing is drop-line' do
1255
+ input = <<-EOS
1256
+ :attribute-missing: drop-line
1257
+
1068
1258
  image::{bogus}[]
1069
1259
  EOS
1070
1260
 
@@ -1072,8 +1262,10 @@ image::{bogus}[]
1072
1262
  assert output.strip.empty?
1073
1263
  end
1074
1264
 
1075
- test 'dropped image does not break processing of following section' do
1265
+ test 'dropped image does not break processing of following section and attribute-missing is drop-line' do
1076
1266
  input = <<-EOS
1267
+ :attribute-missing: drop-line
1268
+
1077
1269
  image::{bogus}[]
1078
1270
 
1079
1271
  == Section Title
@@ -1217,6 +1409,30 @@ video::http://example.org/videos/cats-vs-dogs.avi[]
1217
1409
  assert_css 'video', output, 1
1218
1410
  assert_css 'video[src="http://example.org/videos/cats-vs-dogs.avi"]', output, 1
1219
1411
  end
1412
+
1413
+ test 'video macro should output custom HTML with iframe for vimeo service' do
1414
+ input = <<-EOS
1415
+ video::67480300[vimeo, 400, 300, start=60, options=autoplay]
1416
+ EOS
1417
+ output = render_embedded_string input
1418
+ assert_css 'video', output, 0
1419
+ assert_css 'iframe', output, 1
1420
+ assert_css 'iframe[src="//player.vimeo.com/video/67480300#at=60?autoplay=1"]', output, 1
1421
+ assert_css 'iframe[width="400"]', output, 1
1422
+ assert_css 'iframe[height="300"]', output, 1
1423
+ end
1424
+
1425
+ test 'video macro should output custom HTML with iframe for youtube service' do
1426
+ input = <<-EOS
1427
+ video::rPQoq7ThGAU[youtube, 640, 360, start=60, options=autoplay]
1428
+ EOS
1429
+ output = render_embedded_string input
1430
+ assert_css 'video', output, 0
1431
+ assert_css 'iframe', output, 1
1432
+ assert_css 'iframe[src="//www.youtube.com/embed/rPQoq7ThGAU?rel=0&start=60&autoplay=1"]', output, 1
1433
+ assert_css 'iframe[width="640"]', output, 1
1434
+ assert_css 'iframe[height="360"]', output, 1
1435
+ end
1220
1436
 
1221
1437
  test 'should detect and render audio macro' do
1222
1438
  input = <<-EOS
@@ -1336,7 +1552,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
1336
1552
  assert_xpath '//*[@class="admonitionblock tip"]//*[@class="icon"]/img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Tip"]', output, 1
1337
1553
  end
1338
1554
 
1339
- test 'can use font-based icons' do
1555
+ test 'should import Font Awesome and use font-based icons when value of icons attribute is font' do
1340
1556
  input = <<-EOS
1341
1557
  :icons: font
1342
1558
 
@@ -1345,6 +1561,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
1345
1561
  EOS
1346
1562
 
1347
1563
  output = render_string input, :safe => Asciidoctor::SafeMode::SERVER
1564
+ assert_css 'html > head > link[rel="stylesheet"][href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/3.2.1/css/font-awesome.min.css"]', output, 1
1348
1565
  assert_xpath '//*[@class="admonitionblock tip"]//*[@class="icon"]/i[@class="icon-tip"]', output, 1
1349
1566
  end
1350
1567
  end
@@ -1408,6 +1625,21 @@ puts "Hello, World!"
1408
1625
  assert_css '.listingblock pre code', output, 1
1409
1626
  assert_css '.listingblock pre code:not([class])', output, 1
1410
1627
  end
1628
+
1629
+ test 'should not recognize fenced code blocks with more than three delimiters' do
1630
+ input = <<-EOS
1631
+ ````ruby
1632
+ puts "Hello, World!"
1633
+ ````
1634
+
1635
+ ~~~~ javascript
1636
+ alert("Hello, World!")
1637
+ ~~~~
1638
+ EOS
1639
+
1640
+ output = render_embedded_string input
1641
+ assert_css '.listingblock', output, 0
1642
+ end
1411
1643
 
1412
1644
  test 'should support fenced code blocks with languages' do
1413
1645
  input = <<-EOS
@@ -1426,6 +1658,23 @@ alert("Hello, World!")
1426
1658
  assert_css '.listingblock pre code.javascript', output, 1
1427
1659
  end
1428
1660
 
1661
+ test 'should support fenced code blocks with languages and numbering' do
1662
+ input = <<-EOS
1663
+ ```ruby,numbered
1664
+ puts "Hello, World!"
1665
+ ```
1666
+
1667
+ ~~~ javascript, numbered
1668
+ alert("Hello, World!")
1669
+ ~~~
1670
+ EOS
1671
+
1672
+ output = render_embedded_string input
1673
+ assert_css '.listingblock', output, 2
1674
+ assert_css '.listingblock pre code.ruby', output, 1
1675
+ assert_css '.listingblock pre code.javascript', output, 1
1676
+ end
1677
+
1429
1678
  test 'should highlight source if source-highlighter attribute is coderay' do
1430
1679
  input = <<-EOS
1431
1680
  :source-highlighter: coderay
@@ -1437,11 +1686,80 @@ require 'coderay'
1437
1686
  html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table)
1438
1687
  ----
1439
1688
  EOS
1440
- output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
1689
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :linkcss_default => true
1441
1690
  assert_xpath '//pre[@class="CodeRay"]/code[@class="ruby language-ruby"]//span[@class = "constant"][text() = "CodeRay"]', output, 1
1442
1691
  assert_match(/\.CodeRay \{/, output)
1443
1692
  end
1444
1693
 
1694
+ test 'should replace callout marks but not highlight them if source-highlighter attribute is coderay' do
1695
+ input = <<-EOS
1696
+ :source-highlighter: coderay
1697
+
1698
+ [source, ruby]
1699
+ ----
1700
+ require 'coderay' # <1>
1701
+
1702
+ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table) # <2>
1703
+ puts html # <3> <4>
1704
+ exit 0 # <5><6>
1705
+ ----
1706
+ <1> Load library
1707
+ <2> Highlight source
1708
+ <3> Print to stdout
1709
+ <4> Redirect to a file to capture output
1710
+ <5> Exit program
1711
+ <6> Reports success
1712
+ EOS
1713
+ output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE
1714
+ assert_match(/<span class="content">coderay<\/span>.* <b>\(1\)<\/b>$/, output)
1715
+ assert_match(/<span class="content">puts 'Hello, world!'<\/span>.* <b>\(2\)<\/b>$/, output)
1716
+ assert_match(/puts html * <b>\(3\)<\/b> <b>\(4\)<\/b>$/, output)
1717
+ assert_match(/exit.* <b>\(5\)<\/b> <b>\(6\)<\/b><\/code>/, output)
1718
+ end
1719
+
1720
+ test 'should restore callout marks to correct lines if source highlighter is coderay and table line numbering is enabled' do
1721
+ input = <<-EOS
1722
+ :source-highlighter: coderay
1723
+ :coderay-linenums-mode: table
1724
+
1725
+ [source, ruby, numbered]
1726
+ ----
1727
+ require 'coderay' # <1>
1728
+
1729
+ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table) # <2>
1730
+ puts html # <3> <4>
1731
+ exit 0 # <5><6>
1732
+ ----
1733
+ <1> Load library
1734
+ <2> Highlight source
1735
+ <3> Print to stdout
1736
+ <4> Redirect to a file to capture output
1737
+ <5> Exit program
1738
+ <6> Reports success
1739
+ EOS
1740
+ output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SAFE
1741
+ assert_match(/<span class="content">coderay<\/span>.* <b>\(1\)<\/b>$/, output)
1742
+ assert_match(/<span class="content">puts 'Hello, world!'<\/span>.* <b>\(2\)<\/b>$/, output)
1743
+ assert_match(/puts html * <b>\(3\)<\/b> <b>\(4\)<\/b>$/, output)
1744
+ assert_match(/exit.* <b>\(5\)<\/b> <b>\(6\)<\/b><\/pre>/, output)
1745
+ end
1746
+
1747
+ test 'should link to CodeRay stylesheet if source-highlighter is coderay and linkcss is set' do
1748
+ input = <<-EOS
1749
+ :source-highlighter: coderay
1750
+
1751
+ [source, ruby]
1752
+ ----
1753
+ require 'coderay'
1754
+
1755
+ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table)
1756
+ ----
1757
+ EOS
1758
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :attributes => {'linkcss' => ''}
1759
+ assert_xpath '//pre[@class="CodeRay"]/code[@class="ruby language-ruby"]//span[@class = "constant"][text() = "CodeRay"]', output, 1
1760
+ assert_css 'link[rel="stylesheet"][href="./asciidoctor-coderay.css"]', output, 1
1761
+ end
1762
+
1445
1763
  test 'should highlight source inline if source-highlighter attribute is coderay and coderay-css is style' do
1446
1764
  input = <<-EOS
1447
1765
  :source-highlighter: coderay
@@ -1454,7 +1772,7 @@ require 'coderay'
1454
1772
  html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table)
1455
1773
  ----
1456
1774
  EOS
1457
- output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
1775
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE, :linkcss_default => true
1458
1776
  assert_xpath '//pre[@class="CodeRay"]/code[@class="ruby language-ruby"]//span[@style = "color:#036;font-weight:bold"][text() = "CodeRay"]', output, 1
1459
1777
  assert_no_match(/\.CodeRay \{/, output)
1460
1778
  end
@@ -1476,6 +1794,27 @@ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table)
1476
1794
  assert_match(/hljs.initHighlightingOnLoad/, output)
1477
1795
  end
1478
1796
 
1797
+ test 'should set lang attribute on pre when source-highlighter is html-pipeline' do
1798
+ input = <<-EOS
1799
+ [source,ruby]
1800
+ ----
1801
+ filters = [
1802
+ HTML::Pipeline::AsciiDocFilter,
1803
+ HTML::Pipeline::SanitizationFilter,
1804
+ HTML::Pipeline::SyntaxHighlightFilter
1805
+ ]
1806
+
1807
+ puts HTML::Pipeline.new(filters, {}).call(input)[:output]
1808
+ ----
1809
+ EOS
1810
+
1811
+ output = render_string input, :attributes => {'source-highlighter' => 'html-pipeline'}
1812
+ assert_css 'pre[lang="ruby"]', output, 1
1813
+ assert_css 'pre[lang="ruby"] > code', output, 1
1814
+ assert_css 'pre[class]', output, 0
1815
+ assert_css 'code[class]', output, 0
1816
+ end
1817
+
1479
1818
  test 'document cannot turn on source highlighting if safe mode is at least SERVER' do
1480
1819
  input = <<-EOS
1481
1820
  :source-highlighter: coderay