asciidoctor 0.0.9 → 0.1.0

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 (42) hide show
  1. data/README.asciidoc +163 -41
  2. data/Rakefile +3 -1
  3. data/asciidoctor.gemspec +13 -5
  4. data/bin/asciidoctor +6 -3
  5. data/bin/asciidoctor-safe +13 -0
  6. data/lib/asciidoctor.rb +237 -26
  7. data/lib/asciidoctor/abstract_node.rb +27 -17
  8. data/lib/asciidoctor/attribute_list.rb +6 -0
  9. data/lib/asciidoctor/backends/base_template.rb +3 -4
  10. data/lib/asciidoctor/backends/docbook45.rb +114 -55
  11. data/lib/asciidoctor/backends/html5.rb +173 -104
  12. data/lib/asciidoctor/cli/invoker.rb +105 -0
  13. data/lib/asciidoctor/cli/options.rb +146 -0
  14. data/lib/asciidoctor/document.rb +135 -35
  15. data/lib/asciidoctor/lexer.rb +86 -33
  16. data/lib/asciidoctor/list_item.rb +2 -2
  17. data/lib/asciidoctor/reader.rb +6 -7
  18. data/lib/asciidoctor/section.rb +17 -5
  19. data/lib/asciidoctor/substituters.rb +216 -97
  20. data/lib/asciidoctor/table.rb +9 -2
  21. data/lib/asciidoctor/version.rb +1 -1
  22. data/man/asciidoctor.1 +212 -0
  23. data/man/asciidoctor.ad +156 -0
  24. data/test/attributes_test.rb +108 -5
  25. data/test/blocks_test.rb +102 -15
  26. data/test/document_test.rb +214 -3
  27. data/test/fixtures/encoding.asciidoc +4 -0
  28. data/test/fixtures/sample.asciidoc +26 -0
  29. data/test/invoker_test.rb +254 -0
  30. data/test/lexer_test.rb +53 -0
  31. data/test/links_test.rb +30 -0
  32. data/test/lists_test.rb +648 -9
  33. data/test/options_test.rb +68 -0
  34. data/test/paragraphs_test.rb +65 -1
  35. data/test/reader_test.rb +18 -4
  36. data/test/{headers_test.rb → sections_test.rb} +237 -0
  37. data/test/substitutions_test.rb +247 -5
  38. data/test/tables_test.rb +22 -4
  39. data/test/test_helper.rb +47 -3
  40. data/test/text_test.rb +20 -4
  41. metadata +34 -6
  42. data/noof.rb +0 -16
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'pathname'
2
3
 
3
4
  context "Blocks" do
4
5
  context "Rulers" do
@@ -113,6 +114,73 @@ How crazy is that?
113
114
  output = render_string input
114
115
  assert_xpath '//*[@class="exampleblock"]//p', output, 2
115
116
  end
117
+
118
+ test "assigns sequential numbered caption to example block with title" do
119
+ input = <<-EOS
120
+ .Writing Docs with AsciiDoc
121
+ ====
122
+ Here's how you write AsciiDoc.
123
+
124
+ You just write.
125
+ ====
126
+
127
+ .Writing Docs with DocBook
128
+ ====
129
+ Here's how you write DocBook.
130
+
131
+ You futz with XML.
132
+ ====
133
+ EOS
134
+
135
+ doc = document_from_string input
136
+ output = doc.render
137
+ assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Example 1. Writing Docs with AsciiDoc"]', output, 1
138
+ assert_xpath '(//*[@class="exampleblock"])[2]/*[@class="title"][text()="Example 2. Writing Docs with DocBook"]', output, 1
139
+ assert_equal 2, doc.attributes['example-number']
140
+ end
141
+
142
+ test "assigns sequential character caption to example block with title" do
143
+ input = <<-EOS
144
+ :example-number: @
145
+
146
+ .Writing Docs with AsciiDoc
147
+ ====
148
+ Here's how you write AsciiDoc.
149
+
150
+ You just write.
151
+ ====
152
+
153
+ .Writing Docs with DocBook
154
+ ====
155
+ Here's how you write DocBook.
156
+
157
+ You futz with XML.
158
+ ====
159
+ EOS
160
+
161
+ doc = document_from_string input
162
+ output = doc.render
163
+ assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Example A. Writing Docs with AsciiDoc"]', output, 1
164
+ assert_xpath '(//*[@class="exampleblock"])[2]/*[@class="title"][text()="Example B. Writing Docs with DocBook"]', output, 1
165
+ assert_equal 'B', doc.attributes['example-number']
166
+ end
167
+
168
+ test "explicit caption is used if provided" do
169
+ input = <<-EOS
170
+ [caption="Look! "]
171
+ .Writing Docs with AsciiDoc
172
+ ====
173
+ Here's how you write AsciiDoc.
174
+
175
+ You just write.
176
+ ====
177
+ EOS
178
+
179
+ doc = document_from_string input
180
+ output = doc.render
181
+ assert_xpath '(//*[@class="exampleblock"])[1]/*[@class="title"][text()="Look! Writing Docs with AsciiDoc"]', output, 1
182
+ assert !doc.attributes.has_key?('example-number')
183
+ end
116
184
  end
117
185
 
118
186
  context "Preformatted Blocks" do
@@ -216,6 +284,22 @@ EOS
216
284
  end
217
285
  }
218
286
  end
287
+
288
+ test 'should process block with CRLF endlines' do
289
+ input = <<-EOS
290
+ [source]\r
291
+ ----\r
292
+ source line 1\r
293
+ source line 2\r
294
+ ----\r
295
+ EOS
296
+
297
+ output = render_embedded_string input
298
+ assert_no_match(/\[source\]/, output)
299
+ assert_xpath '/*[@class="listingblock"]//pre', output, 1
300
+ assert_xpath '/*[@class="listingblock"]//pre/code', output, 1
301
+ assert_xpath %(/*[@class="listingblock"]//pre/code[text()="source line 1\nsource line 2"]), output, 1
302
+ end
219
303
  end
220
304
 
221
305
  context "Open Blocks" do
@@ -355,9 +439,11 @@ image::images/tiger.png[Tiger, link='http://en.wikipedia.org/wiki/Tiger']
355
439
  image::images/tiger.png[Tiger]
356
440
  EOS
357
441
 
358
- output = render_string input
442
+ doc = document_from_string input
443
+ output = doc.render
359
444
  assert_xpath '//*[@class="imageblock"]//img[@src="images/tiger.png"][@alt="Tiger"]', output, 1
360
- assert_xpath '//*[@class="imageblock"]/*[@class="title"][text() = "The AsciiDoc Tiger"]', output, 1
445
+ assert_xpath '//*[@class="imageblock"]/*[@class="title"][text() = "Figure 1. The AsciiDoc Tiger"]', output, 1
446
+ assert_equal 1, doc.attributes['figure-number']
361
447
  end
362
448
 
363
449
  test 'can resolve image relative to imagesdir' do
@@ -410,7 +496,7 @@ image::dot.gif[Dot]
410
496
  You can use icons for admonitions by setting the 'icons' attribute.
411
497
  EOS
412
498
 
413
- output = render_string input
499
+ output = render_string input, :safe => Asciidoctor::SafeMode::SERVER
414
500
  assert_xpath '//*[@class="admonitionblock"]//*[@class="icon"]/img[@src="images/icons/tip.png"][@alt="Tip"]', output, 1
415
501
  end
416
502
 
@@ -423,7 +509,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
423
509
  You can use icons for admonitions by setting the 'icons' attribute.
424
510
  EOS
425
511
 
426
- output = render_string input
512
+ output = render_string input, :safe => Asciidoctor::SafeMode::SERVER
427
513
  assert_xpath '//*[@class="admonitionblock"]//*[@class="icon"]/img[@src="icons/tip.png"][@alt="Tip"]', output, 1
428
514
  end
429
515
 
@@ -431,7 +517,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
431
517
  input = <<-EOS
432
518
  :icons:
433
519
  :iconsdir: fixtures
434
- :iconstype: gif
520
+ :icontype: gif
435
521
  :data-uri:
436
522
 
437
523
  [TIP]
@@ -442,18 +528,18 @@ You can use icons for admonitions by setting the 'icons' attribute.
442
528
  assert_xpath '//*[@class="admonitionblock"]//*[@class="icon"]/img[@src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="][@alt="Tip"]', output, 1
443
529
  end
444
530
 
445
- test 'does not embed base64-encoded data uri of icon when safe mode level is at least SECURE' do
531
+ test 'does not embed base64-encoded data uri of icon when safe mode level is SECURE or greater' do
446
532
  input = <<-EOS
447
533
  :icons:
448
534
  :iconsdir: fixtures
449
- :iconstype: gif
535
+ :icontype: gif
450
536
  :data-uri:
451
537
 
452
538
  [TIP]
453
539
  You can use icons for admonitions by setting the 'icons' attribute.
454
540
  EOS
455
541
 
456
- output = render_string input
542
+ output = render_string input, :attributes => {'icons' => ''}
457
543
  assert_xpath '//*[@class="admonitionblock"]//*[@class="icon"]/img[@src="fixtures/tip.gif"][@alt="Tip"]', output, 1
458
544
  end
459
545
 
@@ -461,7 +547,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
461
547
  input = <<-EOS
462
548
  :icons:
463
549
  :iconsdir: ../fixtures
464
- :iconstype: gif
550
+ :icontype: gif
465
551
  :data-uri:
466
552
 
467
553
  [TIP]
@@ -479,13 +565,13 @@ You can use icons for admonitions by setting the 'icons' attribute.
479
565
  input = <<-EOS
480
566
  image::asciidoctor.png[Asciidoctor]
481
567
  EOS
482
- basedir = File.dirname(__FILE__)
568
+ basedir = File.expand_path File.dirname(__FILE__)
483
569
  block = block_from_string input, :attributes => {'docdir' => basedir}
484
570
  doc = block.document
485
571
  assert doc.safe >= Asciidoctor::SafeMode::SAFE
486
572
 
487
573
  assert_equal File.join(basedir, 'images'), block.normalize_asset_path('images')
488
- assert_equal File.join(basedir, 'etc/images'), block.normalize_asset_path('/etc/images')
574
+ assert_equal File.join(basedir, 'etc/images'), block.normalize_asset_path("#{disk_root}etc/images")
489
575
  assert_equal File.join(basedir, 'images'), block.normalize_asset_path('../../images')
490
576
  end
491
577
 
@@ -493,13 +579,14 @@ image::asciidoctor.png[Asciidoctor]
493
579
  input = <<-EOS
494
580
  image::asciidoctor.png[Asciidoctor]
495
581
  EOS
496
- basedir = File.dirname(__FILE__)
582
+ basedir = File.expand_path File.dirname(__FILE__)
497
583
  block = block_from_string input, :safe => Asciidoctor::SafeMode::UNSAFE, :attributes => {'docdir' => basedir}
498
584
  doc = block.document
499
585
  assert doc.safe == Asciidoctor::SafeMode::UNSAFE
500
586
 
501
587
  assert_equal File.join(basedir, 'images'), block.normalize_asset_path('images')
502
- assert_equal '/etc/images', block.normalize_asset_path('/etc/images')
588
+ absolute_path = "#{disk_root}etc/images"
589
+ assert_equal absolute_path, block.normalize_asset_path(absolute_path)
503
590
  assert_equal File.expand_path(File.join(basedir, '../../images')), block.normalize_asset_path('../../images')
504
591
  end
505
592
 
@@ -556,11 +643,11 @@ html = CodeRay.scan("puts 'Hello, world!'", :ruby).div(:line_numbers => :table)
556
643
  assert_match(/hljs.initHighlightingOnLoad/, output)
557
644
  end
558
645
 
559
- test 'document cannot turn on source highlighting if safe mode is at least SECURE' do
646
+ test 'document cannot turn on source highlighting if safe mode is at least SERVER' do
560
647
  input = <<-EOS
561
648
  :source-highlighter: coderay
562
649
  EOS
563
- doc = document_from_string input
650
+ doc = document_from_string input, :safe => Asciidoctor::SafeMode::SERVER
564
651
  assert doc.attributes['source-highlighter'].nil?
565
652
  end
566
653
  end
@@ -34,6 +34,180 @@ context 'Document' do
34
34
  end
35
35
  end
36
36
 
37
+ context 'Load APIs' do
38
+ test 'should load input file' do
39
+ sample_input_path = fixture_path('sample.asciidoc')
40
+ doc = Asciidoctor.load(File.new(sample_input_path), :safe => Asciidoctor::SafeMode::SAFE)
41
+ assert_equal 'Document Title', doc.doctitle
42
+ assert_equal File.expand_path(sample_input_path), doc.attr('docfile')
43
+ assert_equal File.expand_path(File.dirname(sample_input_path)), doc.attr('docdir')
44
+ end
45
+
46
+ test 'should load input file from filename' do
47
+ sample_input_path = fixture_path('sample.asciidoc')
48
+ doc = Asciidoctor.load_file(sample_input_path, :safe => Asciidoctor::SafeMode::SAFE)
49
+ assert_equal 'Document Title', doc.doctitle
50
+ assert_equal File.expand_path(sample_input_path), doc.attr('docfile')
51
+ assert_equal File.expand_path(File.dirname(sample_input_path)), doc.attr('docdir')
52
+ end
53
+
54
+ test 'should load input IO' do
55
+ input = StringIO.new(<<-EOS)
56
+ Document Title
57
+ ==============
58
+
59
+ preamble
60
+ EOS
61
+ doc = Asciidoctor.load(input, :safe => Asciidoctor::SafeMode::SAFE)
62
+ assert_equal 'Document Title', doc.doctitle
63
+ assert !doc.attr?('docfile')
64
+ assert_equal doc.base_dir, doc.attr('docdir')
65
+ end
66
+
67
+ test 'should load input string' do
68
+ input = <<-EOS
69
+ Document Title
70
+ ==============
71
+
72
+ preamble
73
+ EOS
74
+ doc = Asciidoctor.load(input, :safe => Asciidoctor::SafeMode::SAFE)
75
+ assert_equal 'Document Title', doc.doctitle
76
+ assert !doc.attr?('docfile')
77
+ assert_equal doc.base_dir, doc.attr('docdir')
78
+ end
79
+
80
+ test 'should load input string array' do
81
+ input = <<-EOS
82
+ Document Title
83
+ ==============
84
+
85
+ preamble
86
+ EOS
87
+ doc = Asciidoctor.load(input.lines.entries, :safe => Asciidoctor::SafeMode::SAFE)
88
+ assert_equal 'Document Title', doc.doctitle
89
+ assert !doc.attr?('docfile')
90
+ assert_equal doc.base_dir, doc.attr('docdir')
91
+ end
92
+ end
93
+
94
+ context 'Render APIs' do
95
+ test 'should render document to string' do
96
+ sample_input_path = fixture_path('sample.asciidoc')
97
+ output = Asciidoctor.render_file(sample_input_path, :header_footer => true)
98
+ assert !output.empty?
99
+ assert_xpath '/html', output, 1
100
+ assert_xpath '/html/head', output, 1
101
+ assert_xpath '/html/body', output, 1
102
+ assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
103
+ assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
104
+ end
105
+
106
+ test 'should render document in place' do
107
+ sample_input_path = fixture_path('sample.asciidoc')
108
+ sample_output_path = fixture_path('sample.html')
109
+ begin
110
+ Asciidoctor.render_file(sample_input_path, :in_place => true)
111
+ assert File.exist?(sample_output_path)
112
+ output = File.read(sample_output_path)
113
+ assert !output.empty?
114
+ assert_xpath '/html', output, 1
115
+ assert_xpath '/html/head', output, 1
116
+ assert_xpath '/html/body', output, 1
117
+ assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
118
+ assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
119
+ ensure
120
+ FileUtils::rm(sample_output_path)
121
+ end
122
+ end
123
+
124
+ test 'should render document to file' do
125
+ sample_input_path = fixture_path('sample.asciidoc')
126
+ sample_output_path = fixture_path('result.html')
127
+ begin
128
+ Asciidoctor.render_file(sample_input_path, :to_file => sample_output_path)
129
+ assert File.exist?(sample_output_path)
130
+ output = File.read(sample_output_path)
131
+ assert !output.empty?
132
+ assert_xpath '/html', output, 1
133
+ assert_xpath '/html/head', output, 1
134
+ assert_xpath '/html/body', output, 1
135
+ assert_xpath '/html/head/title[text() = "Document Title"]', output, 1
136
+ assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
137
+ ensure
138
+ FileUtils::rm(sample_output_path)
139
+ end
140
+ end
141
+
142
+ test 'in_place option must not be used with to_file option' do
143
+ sample_input_path = fixture_path('sample.asciidoc')
144
+ sample_output_path = fixture_path('result.html')
145
+ assert_raise ArgumentError do
146
+ begin
147
+ Asciidoctor.render_file(sample_input_path, :to_file => sample_output_path, :in_place => true)
148
+ ensure
149
+ FileUtils::rm(sample_output_path) if File.exists? sample_output_path
150
+ end
151
+ end
152
+ end
153
+
154
+ test 'in_place option must not be used with to_dir option' do
155
+ sample_input_path = fixture_path('sample.asciidoc')
156
+ sample_output_path = fixture_path('result.html')
157
+ assert_raise ArgumentError do
158
+ begin
159
+ Asciidoctor.render_file(sample_input_path, :to_dir => '', :in_place => true)
160
+ ensure
161
+ FileUtils::rm(sample_output_path) if File.exists? sample_output_path
162
+ end
163
+ end
164
+ end
165
+
166
+ test 'output should be relative to to_dir option' do
167
+ sample_input_path = fixture_path('sample.asciidoc')
168
+ output_dir = File.join(File.dirname(sample_input_path), 'test_output')
169
+ Dir.mkdir output_dir if !File.exists? output_dir
170
+ sample_output_path = File.join(output_dir, 'sample.html')
171
+ begin
172
+ Asciidoctor.render_file(sample_input_path, :to_dir => output_dir)
173
+ assert File.exists? sample_output_path
174
+ ensure
175
+ FileUtils::rm(sample_output_path) if File.exists? sample_output_path
176
+ FileUtils::rmdir output_dir
177
+ end
178
+ end
179
+
180
+ test 'missing directories should be created if specified' do
181
+ sample_input_path = fixture_path('sample.asciidoc')
182
+ output_dir = File.join(File.join(File.dirname(sample_input_path), 'test_output'), 'subdir')
183
+ sample_output_path = File.join(output_dir, 'sample.html')
184
+ begin
185
+ Asciidoctor.render_file(sample_input_path, :to_dir => output_dir, :mkdirs => true)
186
+ assert File.exists? sample_output_path
187
+ ensure
188
+ FileUtils::rm(sample_output_path) if File.exists? sample_output_path
189
+ FileUtils::rmdir output_dir
190
+ FileUtils::rmdir File.dirname(output_dir)
191
+ end
192
+ end
193
+
194
+ test 'to_file should be relative to to_dir when both given' do
195
+ sample_input_path = fixture_path('sample.asciidoc')
196
+ base_dir = File.dirname(sample_input_path)
197
+ sample_rel_output_path = File.join('test_output', 'result.html')
198
+ output_dir = File.dirname(File.join(base_dir, sample_rel_output_path))
199
+ Dir.mkdir output_dir if !File.exists? output_dir
200
+ sample_output_path = File.join(base_dir, sample_rel_output_path)
201
+ begin
202
+ Asciidoctor.render_file(sample_input_path, :to_dir => base_dir, :to_file => sample_rel_output_path)
203
+ assert File.exists? sample_output_path
204
+ ensure
205
+ FileUtils::rm(sample_output_path) if File.exists? sample_output_path
206
+ FileUtils::rmdir output_dir
207
+ end
208
+ end
209
+ end
210
+
37
211
  context 'Renderer' do
38
212
  test 'built-in HTML5 views are registered by default' do
39
213
  doc = document_from_string ''
@@ -45,7 +219,7 @@ context 'Document' do
45
219
  assert !renderer.nil?
46
220
  views = renderer.views
47
221
  assert !views.nil?
48
- assert_equal 26, views.size
222
+ assert_equal 29, views.size
49
223
  assert views.has_key? 'document'
50
224
  assert views['document'].is_a?(Asciidoctor::HTML5::DocumentTemplate)
51
225
  assert_equal 'ERB', views['document'].eruby.to_s
@@ -61,14 +235,14 @@ context 'Document' do
61
235
  assert !renderer.nil?
62
236
  views = renderer.views
63
237
  assert !views.nil?
64
- assert_equal 26, views.size
238
+ assert_equal 29, views.size
65
239
  assert views.has_key? 'document'
66
240
  assert views['document'].is_a?(Asciidoctor::DocBook45::DocumentTemplate)
67
241
  assert_equal 'ERB', views['document'].eruby.to_s
68
242
  end
69
243
 
70
244
  test 'can set erubis as eRuby implementation' do
71
- doc = Asciidoctor::Document.new [], :eruby => 'erubis'
245
+ doc = Asciidoctor::Document.new [], :eruby => 'erubis', :header_footer => true
72
246
  assert $LOADED_FEATURES.detect {|p| p == 'erubis.rb' || p.end_with?('/erubis.rb') }.nil?
73
247
  renderer = doc.renderer
74
248
  assert $LOADED_FEATURES.detect {|p| p == 'erubis.rb' || p.end_with?('/erubis.rb') }
@@ -106,6 +280,23 @@ preamble
106
280
  assert_equal 'Title', doc.first_section.title
107
281
  end
108
282
 
283
+ test 'should recognize document title when preceded by blank lines' do
284
+ input = <<-EOS
285
+ :doctype: book
286
+
287
+ = Title
288
+
289
+ preamble
290
+
291
+ == Section 1
292
+
293
+ text
294
+ EOS
295
+ output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
296
+ assert_css '#header h1', output, 1
297
+ assert_css '#content h1', output, 0
298
+ end
299
+
109
300
  test 'test_empty_document' do
110
301
  doc = document_from_string('')
111
302
  assert doc.blocks.empty?
@@ -147,6 +338,26 @@ more info...
147
338
  assert_xpath '/*[@id="footer"]', result, 0
148
339
  assert_xpath '/*[@id="preamble"]', result, 1
149
340
  end
341
+
342
+ test 'renders footnotes in footer' do
343
+ input = <<-EOS
344
+ A footnote footnote:[An example footnote.];
345
+ a second footnote with a reference ID footnoteref:[note2,Second footnote.];
346
+ finally a reference to the second footnote footnoteref:[note2].
347
+ EOS
348
+
349
+ output = render_string input
350
+ assert_css '#footnotes', output, 1
351
+ assert_css '#footnotes .footnote', output, 2
352
+ assert_css '#footnotes .footnote#_footnote_1', output, 1
353
+ assert_xpath '//div[@id="footnotes"]/div[@id="_footnote_1"]/a[@href="#_footnoteref_1"][text()="1"]', output, 1
354
+ text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnote_1"]/text()', output, 1
355
+ assert_equal '. An example footnote.', text.text.strip
356
+ assert_css '#footnotes .footnote#_footnote_2', output, 1
357
+ assert_xpath '//div[@id="footnotes"]/div[@id="_footnote_2"]/a[@href="#_footnoteref_2"][text()="2"]', output, 1
358
+ text = xmlnodes_at_xpath '//div[@id="footnotes"]/div[@id="_footnote_2"]/text()', output, 1
359
+ assert_equal '. Second footnote.', text.text.strip
360
+ end
150
361
  end
151
362
 
152
363
  context 'Backends and Doctypes' do