asciidoctor 1.5.5 → 1.5.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +216 -1
  3. data/CONTRIBUTING.adoc +2 -2
  4. data/Gemfile +20 -1
  5. data/LICENSE.adoc +1 -1
  6. data/README-fr.adoc +4 -3
  7. data/README-jp.adoc +11 -10
  8. data/README-zh_CN.adoc +4 -3
  9. data/README.adoc +17 -202
  10. data/Rakefile +41 -25
  11. data/asciidoctor.gemspec +9 -10
  12. data/data/locale/attributes.adoc +216 -34
  13. data/data/stylesheets/asciidoctor-default.css +23 -16
  14. data/features/step_definitions.rb +15 -19
  15. data/features/xref.feature +584 -20
  16. data/lib/asciidoctor.rb +292 -278
  17. data/lib/asciidoctor/abstract_block.rb +155 -94
  18. data/lib/asciidoctor/abstract_node.rb +108 -94
  19. data/lib/asciidoctor/attribute_list.rb +30 -22
  20. data/lib/asciidoctor/block.rb +7 -7
  21. data/lib/asciidoctor/cli/invoker.rb +47 -34
  22. data/lib/asciidoctor/cli/options.rb +22 -11
  23. data/lib/asciidoctor/converter.rb +3 -3
  24. data/lib/asciidoctor/converter/base.rb +2 -2
  25. data/lib/asciidoctor/converter/composite.rb +1 -1
  26. data/lib/asciidoctor/converter/docbook45.rb +2 -2
  27. data/lib/asciidoctor/converter/docbook5.rb +132 -87
  28. data/lib/asciidoctor/converter/factory.rb +0 -1
  29. data/lib/asciidoctor/converter/html5.rb +116 -98
  30. data/lib/asciidoctor/converter/manpage.rb +51 -52
  31. data/lib/asciidoctor/converter/template.rb +47 -36
  32. data/lib/asciidoctor/core_ext.rb +8 -2
  33. data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
  34. data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
  35. data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
  36. data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
  37. data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
  38. data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
  39. data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
  40. data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
  41. data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
  42. data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
  43. data/lib/asciidoctor/document.rb +216 -213
  44. data/lib/asciidoctor/extensions.rb +318 -185
  45. data/lib/asciidoctor/helpers.rb +35 -35
  46. data/lib/asciidoctor/inline.rb +32 -1
  47. data/lib/asciidoctor/list.rb +22 -6
  48. data/lib/asciidoctor/parser.rb +1008 -1038
  49. data/lib/asciidoctor/path_resolver.rb +46 -50
  50. data/lib/asciidoctor/reader.rb +275 -251
  51. data/lib/asciidoctor/section.rb +86 -58
  52. data/lib/asciidoctor/stylesheets.rb +6 -6
  53. data/lib/asciidoctor/substitutors.rb +567 -649
  54. data/lib/asciidoctor/table.rb +163 -108
  55. data/lib/asciidoctor/version.rb +1 -1
  56. data/man/asciidoctor.1 +18 -16
  57. data/man/asciidoctor.adoc +15 -13
  58. data/test/attributes_test.rb +138 -22
  59. data/test/blocks_test.rb +377 -97
  60. data/test/converter_test.rb +13 -0
  61. data/test/document_test.rb +244 -34
  62. data/test/extensions_test.rb +409 -42
  63. data/test/fixtures/asciidoc_index.txt +521 -0
  64. data/test/fixtures/basic-docinfo-footer.html +6 -0
  65. data/test/fixtures/basic-docinfo-footer.xml +8 -0
  66. data/test/fixtures/basic-docinfo.html +1 -0
  67. data/test/fixtures/basic-docinfo.xml +4 -0
  68. data/test/fixtures/basic.asciidoc +5 -0
  69. data/test/fixtures/chapter-a.adoc +3 -0
  70. data/test/fixtures/child-include.adoc +5 -0
  71. data/test/fixtures/circle.svg +9 -0
  72. data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
  73. data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
  74. data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
  75. data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
  76. data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
  77. data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
  78. data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
  79. data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
  80. data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
  81. data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
  82. data/test/fixtures/docinfo-footer.html +1 -0
  83. data/test/fixtures/docinfo-footer.xml +9 -0
  84. data/test/fixtures/docinfo.html +1 -0
  85. data/test/fixtures/docinfo.xml +3 -0
  86. data/test/fixtures/dot.gif +0 -0
  87. data/test/fixtures/encoding.asciidoc +13 -0
  88. data/test/fixtures/grandchild-include.adoc +3 -0
  89. data/test/fixtures/hello-asciidoctor.pdf +69 -0
  90. data/test/fixtures/include-file.asciidoc +24 -0
  91. data/test/fixtures/include-file.ml +3 -0
  92. data/test/fixtures/include-file.xml +5 -0
  93. data/test/fixtures/master.adoc +5 -0
  94. data/test/fixtures/mismatched-end-tag.adoc +7 -0
  95. data/test/fixtures/parent-include-restricted.adoc +5 -0
  96. data/test/fixtures/parent-include.adoc +5 -0
  97. data/test/fixtures/sample.asciidoc +26 -0
  98. data/test/fixtures/stylesheets/custom.css +3 -0
  99. data/test/fixtures/subs-docinfo.html +2 -0
  100. data/test/fixtures/subs.adoc +7 -0
  101. data/test/fixtures/tagged-class-enclosed.rb +26 -0
  102. data/test/fixtures/tagged-class.rb +23 -0
  103. data/test/fixtures/tip.gif +0 -0
  104. data/test/invoker_test.rb +82 -4
  105. data/test/links_test.rb +312 -37
  106. data/test/lists_test.rb +204 -25
  107. data/test/manpage_test.rb +191 -4
  108. data/test/options_test.rb +18 -1
  109. data/test/paragraphs_test.rb +32 -7
  110. data/test/parser_test.rb +150 -30
  111. data/test/paths_test.rb +47 -13
  112. data/test/preamble_test.rb +1 -1
  113. data/test/reader_test.rb +366 -126
  114. data/test/sections_test.rb +203 -56
  115. data/test/substitutions_test.rb +339 -131
  116. data/test/tables_test.rb +315 -15
  117. data/test/test_helper.rb +400 -0
  118. data/test/text_test.rb +5 -5
  119. metadata +110 -22
@@ -10,7 +10,7 @@ module Asciidoctor
10
10
  TAB = %(\t)
11
11
  WHITESPACE = %(#{LF}#{TAB} )
12
12
  ET = ' ' * 8
13
- ESC = %(\u001b) # troff leader marker
13
+ ESC = %(\u001b) # troff leader marker
14
14
  ESC_BS = %(#{ESC}\\) # escaped backslash (indicates troff formatting sequence)
15
15
  ESC_FS = %(#{ESC}.) # escaped full stop (indicates troff macro)
16
16
 
@@ -60,6 +60,7 @@ module Asciidoctor
60
60
  gsub('\'', '\(aq'). # apostrophe-quote
61
61
  gsub(MockBoundaryRx, ''). # mock boundary
62
62
  gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
63
+ gsub(ESC_FS, '.'). # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
63
64
  rstrip # strip trailing space
64
65
  opts[:append_newline] ? %(#{str}#{LF}) : str
65
66
  end
@@ -159,13 +160,10 @@ Author(s).
159
160
  end
160
161
 
161
162
  def section node
162
- slevel = node.level
163
- # QUESTION should the check for slevel be done in section?
164
- slevel = 1 if slevel == 0 && node.special
165
163
  result = []
166
- if slevel > 1
164
+ if node.level > 1
167
165
  macro = 'SS'
168
- # QUESTION why captioned title? why not for slevel == 1?
166
+ # QUESTION why captioned title? why not when level == 1?
169
167
  stitle = node.captioned_title
170
168
  else
171
169
  macro = 'SH'
@@ -187,7 +185,7 @@ Author(s).
187
185
  .nr an-break-flag 1
188
186
  .br
189
187
  .ps +1
190
- .B #{node.caption}#{node.title? ? "\\fP #{manify node.title}" : nil}
188
+ .B #{node.attr 'textlabel'}#{node.title? ? "\\fP: #{manify node.title}" : nil}
191
189
  .ps -1
192
190
  .br
193
191
  #{resolve_content node}
@@ -196,7 +194,7 @@ Author(s).
196
194
  result * LF
197
195
  end
198
196
 
199
- alias :audio :skip_with_warning
197
+ alias audio skip_with_warning
200
198
 
201
199
  def colist node
202
200
  result = []
@@ -207,10 +205,12 @@ Author(s).
207
205
  tab(:);
208
206
  r lw(\n(.lu*75u/100u).'
209
207
 
210
- node.items.each_with_index do |item, index|
211
- result << %(\\fB(#{index + 1})\\fP\\h'-2n':T{
212
- #{manify item.text}
213
- T})
208
+ num = 0
209
+ node.items.each do |item|
210
+ result << %(\\fB(#{num += 1})\\fP\\h'-2n':T{)
211
+ result << (manify item.text)
212
+ result << item.content if item.blocks?
213
+ result << 'T}'
214
214
  end
215
215
  result << '.TE'
216
216
  result * LF
@@ -226,11 +226,11 @@ T})
226
226
  case node.style
227
227
  when 'qanda'
228
228
  result << %(.sp
229
- #{counter}. #{manify([*terms].map {|dt| dt.text }.join ' ')}
229
+ #{counter}. #{manify([*terms].map {|dt| dt.text } * ' ')}
230
230
  .RS 4)
231
231
  else
232
232
  result << %(.sp
233
- #{manify([*terms].map {|dt| dt.text }.join ', ')}
233
+ #{manify([*terms].map {|dt| dt.text } * ', ')}
234
234
  .RS 4)
235
235
  end
236
236
  if dd
@@ -257,7 +257,7 @@ T})
257
257
  %(.SS "#{manify node.title}")
258
258
  end
259
259
 
260
- alias :image :skip_with_warning
260
+ alias image skip_with_warning
261
261
 
262
262
  def listing node
263
263
  result = []
@@ -328,7 +328,7 @@ T})
328
328
  end
329
329
 
330
330
  # TODO use Page Control https://www.gnu.org/software/groff/manual/html_node/Page-Control.html#Page-Control
331
- alias :page_break :skip
331
+ alias page_break skip
332
332
 
333
333
  def paragraph node
334
334
  if node.title?
@@ -342,7 +342,7 @@ T})
342
342
  end
343
343
  end
344
344
 
345
- alias :preamble :content
345
+ alias preamble content
346
346
 
347
347
  def quote node
348
348
  result = []
@@ -373,7 +373,7 @@ T})
373
373
  result * LF
374
374
  end
375
375
 
376
- alias :sidebar :skip_with_warning
376
+ alias sidebar skip_with_warning
377
377
 
378
378
  def stem node
379
379
  title_element = node.title? ? %(.sp
@@ -402,15 +402,16 @@ T})
402
402
  .nr an-no-space-flag 1
403
403
  .nr an-break-flag 1
404
404
  .br
405
- .B #{manify node.captioned_title})
405
+ .B #{manify node.captioned_title}
406
+ )
406
407
  end
407
408
  result << '.TS
408
409
  allbox tab(:);'
409
410
  row_header = []
410
411
  row_text = []
411
412
  row_index = 0
412
- [:head, :body, :foot].each do |tsec|
413
- node.rows[tsec].each do |row|
413
+ node.rows.by_section.each do |tsec, rows|
414
+ rows.each do |row|
414
415
  row_header[row_index] ||= []
415
416
  row_text[row_index] ||= []
416
417
  # result << LF
@@ -430,19 +431,17 @@ allbox tab(:);'
430
431
  row_text[row_index] << %(T{#{LF}.sp#{LF}T}:)
431
432
  end
432
433
  row_text[row_index] << %(T{#{LF}.sp#{LF})
433
- cell_halign = (cell.attr 'halign', 'left')[0..0]
434
+ cell_halign = (cell.attr 'halign', 'left').chr
434
435
  if tsec == :head
435
- if row_header[row_index].empty? ||
436
- row_header[row_index][cell_index].empty?
436
+ if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
437
437
  row_header[row_index][cell_index] << %(#{cell_halign}tB)
438
438
  else
439
439
  row_header[row_index][cell_index + 1] ||= []
440
440
  row_header[row_index][cell_index + 1] << %(#{cell_halign}tB)
441
441
  end
442
- row_text[row_index] << %(#{cell.text}#{LF})
442
+ row_text[row_index] << %(#{manify cell.text}#{LF})
443
443
  elsif tsec == :body
444
- if row_header[row_index].empty? ||
445
- row_header[row_index][cell_index].empty?
444
+ if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
446
445
  row_header[row_index][cell_index] << %(#{cell_halign}t)
447
446
  else
448
447
  row_header[row_index][cell_index + 1] ||= []
@@ -451,26 +450,26 @@ allbox tab(:);'
451
450
  case cell.style
452
451
  when :asciidoc
453
452
  cell_content = cell.content
454
- when :verse, :literal
455
- cell_content = cell.text
453
+ when :literal
454
+ cell_content = %(.nf#{LF}#{manify cell.text}#{LF}.fi)
455
+ when :verse
456
+ cell_content = %(.nf#{LF}#{manify cell.text}#{LF}.fi)
456
457
  else
457
- cell_content = cell.content.join
458
+ cell_content = manify cell.content.join
458
459
  end
459
460
  row_text[row_index] << %(#{cell_content}#{LF})
460
461
  elsif tsec == :foot
461
- if row_header[row_index].empty? ||
462
- row_header[row_index][cell_index].empty?
462
+ if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
463
463
  row_header[row_index][cell_index] << %(#{cell_halign}tB)
464
464
  else
465
465
  row_header[row_index][cell_index + 1] ||= []
466
466
  row_header[row_index][cell_index + 1] << %(#{cell_halign}tB)
467
467
  end
468
- row_text[row_index] << %(#{cell.text}#{LF})
468
+ row_text[row_index] << %(#{manify cell.text}#{LF})
469
469
  end
470
470
  if cell.colspan && cell.colspan > 1
471
471
  (cell.colspan - 1).times do |i|
472
- if row_header[row_index].empty? ||
473
- row_header[row_index][cell_index].empty?
472
+ if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
474
473
  row_header[row_index][cell_index + i] << 'st'
475
474
  else
476
475
  row_header[row_index][cell_index + 1 + i] ||= []
@@ -481,8 +480,7 @@ allbox tab(:);'
481
480
  if cell.rowspan && cell.rowspan > 1
482
481
  (cell.rowspan - 1).times do |i|
483
482
  row_header[row_index + 1 + i] ||= []
484
- if row_header[row_index + 1 + i].empty? ||
485
- row_header[row_index + 1 + i][cell_index].empty?
483
+ if row_header[row_index + 1 + i].empty? || row_header[row_index + 1 + i][cell_index].empty?
486
484
  row_header[row_index + 1 + i][cell_index] ||= []
487
485
  row_header[row_index + 1 + i][cell_index] << '^t'
488
486
  else
@@ -498,19 +496,19 @@ allbox tab(:);'
498
496
  end
499
497
  end
500
498
  row_index += 1
501
- end
499
+ end unless rows.empty?
502
500
  end
503
501
 
504
502
  #row_header.each do |row|
505
503
  # result << LF
506
504
  # row.each_with_index do |cell, i|
507
- # result << (cell.join ' ')
505
+ # result << (cell * ' ')
508
506
  # result << ' ' if row.size > i + 1
509
507
  # end
510
508
  #end
511
509
  # FIXME temporary fix to get basic table to display
512
510
  result << LF
513
- result << row_header.first.map {|r| 'lt'}.join(' ')
511
+ result << row_header[0].map { 'lt' } * ' '
514
512
 
515
513
  result << %(.#{LF})
516
514
  row_text.each do |row|
@@ -526,7 +524,7 @@ allbox tab(:);'
526
524
  \l\'\n(.lu*25u/100u\(ap\''
527
525
  end
528
526
 
529
- alias :toc :skip
527
+ alias toc skip
530
528
 
531
529
  def ulist node
532
530
  result = []
@@ -578,8 +576,12 @@ allbox tab(:);'
578
576
  def video node
579
577
  start_param = (node.attr? 'start', nil, false) ? %(&start=#{node.attr 'start'}) : nil
580
578
  end_param = (node.attr? 'end', nil, false) ? %(&end=#{node.attr 'end'}) : nil
581
- %(.sp
582
- #{manify node.captioned_title} (video) <#{node.media_uri(node.attr 'target')}#{start_param}#{end_param}>)
579
+ result = []
580
+ result << %(.sp
581
+ .B #{manify node.title}
582
+ .br) if node.title?
583
+ result << %(<#{node.media_uri(node.attr 'target')}#{start_param}#{end_param}> (video))
584
+ result * LF
583
585
  end
584
586
 
585
587
  def inline_anchor node
@@ -600,9 +602,9 @@ allbox tab(:);'
600
602
  %(#{ESC_BS}c#{LF}#{ESC_FS}#{macro} "#{target}" "#{text}" )
601
603
  when :xref
602
604
  refid = (node.attr 'refid') || target
603
- node.text || (node.document.references[:ids][refid] || %([#{refid}]))
605
+ node.text || (node.document.catalog[:ids][refid] || %([#{refid}]))
604
606
  when :ref, :bibref
605
- # These are anchor points, which shouldn't be visual
607
+ # These are anchor points, which shouldn't be visible
606
608
  ''
607
609
  else
608
610
  warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect})
@@ -610,8 +612,7 @@ allbox tab(:);'
610
612
  end
611
613
 
612
614
  def inline_break node
613
- %(#{node.text}
614
- .br)
615
+ %(#{node.text}#{LF}#{ESC_FS}br)
615
616
  end
616
617
 
617
618
  def inline_button node
@@ -632,9 +633,7 @@ allbox tab(:);'
632
633
  end
633
634
 
634
635
  def inline_image node
635
- # NOTE alt should always be set
636
- alt_text = (node.attr? 'alt') ? (node.attr 'alt') : node.target
637
- (node.attr? 'link') ? %([#{alt_text}] <#{node.attr 'link'}>) : %([#{alt_text}])
636
+ (node.attr? 'link') ? %([#{node.alt}] <#{node.attr 'link'}>) : %([#{node.alt}])
638
637
  end
639
638
 
640
639
  def inline_indexterm node
@@ -645,7 +644,7 @@ allbox tab(:);'
645
644
  if (keys = node.attr 'keys').size == 1
646
645
  keys[0]
647
646
  else
648
- keys.join %(#{ESC_BS}0+#{ESC_BS}0)
647
+ keys * %(#{ESC_BS}0+#{ESC_BS}0)
649
648
  end
650
649
  end
651
650
 
@@ -653,7 +652,7 @@ allbox tab(:);'
653
652
  caret = %[#{ESC_BS}0#{ESC_BS}(fc#{ESC_BS}0]
654
653
  menu = node.attr 'menu'
655
654
  if !(submenus = node.attr 'submenus').empty?
656
- submenu_path = submenus.map {|item| %(#{ESC_BS}fI#{item}#{ESC_BS}fP) }.join caret
655
+ submenu_path = submenus.map {|item| %(#{ESC_BS}fI#{item}#{ESC_BS}fP) } * caret
657
656
  %(#{ESC_BS}fI#{menu}#{ESC_BS}fP#{caret}#{submenu_path}#{caret}#{ESC_BS}fI#{node.attr 'menuitem'}#{ESC_BS}fP)
658
657
  elsif (menuitem = node.attr 'menuitem')
659
658
  %(#{ESC_BS}fI#{menu}#{caret}#{menuitem}#{ESC_BS}fP)
@@ -5,9 +5,9 @@ module Asciidoctor
5
5
  # {AbstractNode} objects from a parsed AsciiDoc document tree to the backend
6
6
  # format.
7
7
  #
8
- # The converter scans the provided directories for template files that are
8
+ # The converter scans the specified directories for template files that are
9
9
  # supported by Tilt. If an engine name (e.g., "slim") is specified in the
10
- # options Hash passed to the constructor, the scan is limited to template
10
+ # options Hash passed to the constructor, the scan is restricted to template
11
11
  # files that have a matching extension (e.g., ".slim"). The scanner trims any
12
12
  # extensions from the basename of the file and uses the resulting name as the
13
13
  # key under which to store the template. When the {Converter#convert} method
@@ -15,20 +15,21 @@ module Asciidoctor
15
15
  # table and use it to convert the node.
16
16
  #
17
17
  # For example, the template file "path/to/templates/paragraph.html.slim" will
18
- # be registered as the "paragraph" transform. The template would then be used
19
- # to convert a paragraph {Block} object from the parsed AsciiDoc tree to an
20
- # HTML backend format (e.g., "html5").
18
+ # be registered as the "paragraph" transform. The template is then used to
19
+ # convert a paragraph {Block} object from the parsed AsciiDoc tree to an HTML
20
+ # backend format (e.g., "html5").
21
21
  #
22
22
  # As an optimization, scan results and templates are cached for the lifetime
23
23
  # of the Ruby process. If the {https://rubygems.org/gems/thread_safe
24
24
  # thread_safe} gem is installed, these caches are guaranteed to be thread
25
- # safe. If this gem is not present, they are not and a warning is issued.
25
+ # safe. If this gem is not present, there is no such guarantee and a warning
26
+ # will be issued.
26
27
  class Converter::TemplateConverter < Converter::Base
27
28
  DEFAULT_ENGINE_OPTIONS = {
28
29
  :erb => { :trim => '<' },
29
30
  # TODO line 466 of haml/compiler.rb sorts the attributes; file an issue to make this configurable
30
31
  # NOTE AsciiDoc syntax expects HTML/XML output to use double quotes around attribute values
31
- :haml => { :format => :xhtml, :attr_wrapper => '"', :ugly => true, :escape_attrs => false },
32
+ :haml => { :format => :xhtml, :attr_wrapper => '"', :escape_attrs => false, :ugly => true },
32
33
  :slim => { :disable_escape => true, :sort_attrs => false, :pretty => false }
33
34
  }
34
35
 
@@ -58,6 +59,7 @@ module Asciidoctor
58
59
  @template_dirs = template_dirs
59
60
  @eruby = opts[:eruby]
60
61
  @safe = opts[:safe]
62
+ @active_engines = {}
61
63
  @engine = opts[:template_engine]
62
64
  @engine_options = DEFAULT_ENGINE_OPTIONS.inject({}) do |accum, (engine, default_opts)|
63
65
  accum[engine] = default_opts.dup
@@ -67,6 +69,7 @@ module Asciidoctor
67
69
  @engine_options[:haml][:format] = :html5
68
70
  @engine_options[:slim][:format] = :html
69
71
  end
72
+ @engine_options[:slim][:include_dirs] = template_dirs.reverse.map {|dir| ::File.expand_path dir }
70
73
  if (overrides = opts[:template_engine_options])
71
74
  overrides.each do |engine, override_opts|
72
75
  (@engine_options[engine] ||= {}).update override_opts
@@ -208,7 +211,7 @@ module Asciidoctor
208
211
  #
209
212
  # Returns a [Hash] of Tilt template objects keyed by template name.
210
213
  def templates
211
- @templates.dup.freeze
214
+ @templates.dup
212
215
  end
213
216
 
214
217
  # Public: Registers a Tilt template with this converter.
@@ -231,45 +234,53 @@ module Asciidoctor
231
234
  #
232
235
  # Returns the scan result as a [Hash]
233
236
  def scan_dir template_dir, pattern, template_cache = nil
234
- result = {}
235
- eruby_loaded = nil
237
+ result, helpers = {}, nil
236
238
  # Grab the files in the top level of the directory (do not recurse)
237
239
  ::Dir.glob(pattern).select {|match| ::File.file? match }.each do |file|
238
- if (basename = ::File.basename file) == 'helpers.rb' || (path_segments = basename.split '.').size < 2
240
+ if (basename = ::File.basename file) == 'helpers.rb'
241
+ helpers = file
242
+ next
243
+ elsif (path_segments = basename.split '.').size < 2
239
244
  next
240
245
  end
241
- # TODO we could derive the basebackend from the minor extension of the template file
242
- #name, *rest, ext_name = *path_segments # this form only works in Ruby >= 1.9
243
- name = path_segments[0]
244
- if name == 'block_ruler'
246
+ if (name = path_segments[0]) == 'block_ruler'
245
247
  name = 'thematic_break'
246
248
  elsif name.start_with? 'block_'
247
- name = name[6..-1]
248
- end
249
-
250
- template_class = ::Tilt
251
- extra_engine_options = {}
252
- case (ext_name = path_segments[-1])
253
- when 'slim'
254
- # slim doesn't get loaded by Tilt, so we have to load it explicitly
255
- Helpers.require_library 'slim' unless defined? ::Slim
256
- # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document
257
- (@engine_options[:slim][:asciidoc] ||= {})[:safe] ||= @safe if @safe && ::Slim::VERSION >= '3.0'
258
- # load include plugin when using Slim >= 2.1
259
- require 'slim/include' unless (defined? ::Slim::Include) || ::Slim::VERSION < '2.1'
260
- when 'erb'
261
- template_class, extra_engine_options = (eruby_loaded ||= load_eruby(@eruby))
262
- when 'rb'
263
- next
264
- else
265
- next unless ::Tilt.registered? ext_name
249
+ name = name.slice 6, name.length
266
250
  end
267
251
  unless template_cache && (template = template_cache[file])
268
- template = template_class.new file, 1, (@engine_options[ext_name.to_sym] || {}).merge(extra_engine_options)
252
+ template_class, extra_engine_options, extsym = ::Tilt, {}, path_segments[-1].to_sym
253
+ case extsym
254
+ when :slim
255
+ unless @active_engines[extsym]
256
+ # NOTE slim doesn't get automatically loaded by Tilt
257
+ Helpers.require_library 'slim' unless defined? ::Slim
258
+ # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document
259
+ # NOTE safe mode won't get updated if using template cache and changing safe mode
260
+ (@engine_options[extsym][:asciidoc] ||= {})[:safe] ||= @safe if @safe && ::Slim::VERSION >= '3.0'
261
+ # load include plugin when using Slim >= 2.1
262
+ require 'slim/include' unless (defined? ::Slim::Include) || ::Slim::VERSION < '2.1'
263
+ @active_engines[extsym] = true
264
+ end
265
+ when :haml
266
+ unless @active_engines[extsym]
267
+ Helpers.require_library 'haml' unless defined? ::Haml
268
+ # NOTE Haml 5 dropped support for pretty printing
269
+ @engine_options[extsym].delete :ugly if defined? ::Haml::TempleEngine
270
+ @active_engines[extsym] = true
271
+ end
272
+ when :erb
273
+ template_class, extra_engine_options = (@active_engines[extsym] ||= (load_eruby @eruby))
274
+ when :rb
275
+ next
276
+ else
277
+ next unless ::Tilt.registered? extsym.to_s
278
+ end
279
+ template = template_class.new file, 1, (@engine_options[extsym] ||= {}).merge(extra_engine_options)
269
280
  end
270
281
  result[name] = template
271
282
  end
272
- if ::File.file?(helpers = (::File.join template_dir, 'helpers.rb'))
283
+ if helpers || ::File.file?(helpers = (::File.join template_dir, 'helpers.rb'))
273
284
  require helpers
274
285
  end
275
286
  result
@@ -1,8 +1,14 @@
1
1
  require 'asciidoctor/core_ext/nil_or_empty'
2
+ require 'asciidoctor/core_ext/regexp/is_match'
2
3
  if RUBY_MIN_VERSION_1_9
3
- require 'asciidoctor/core_ext/string/limit'
4
+ require 'asciidoctor/core_ext/string/limit_bytesize'
5
+ require 'asciidoctor/core_ext/1.8.7/io/write' if RUBY_ENGINE == 'opal'
4
6
  elsif RUBY_ENGINE != 'opal'
7
+ require 'asciidoctor/core_ext/1.8.7/hash/key'
8
+ require 'asciidoctor/core_ext/1.8.7/io/binread'
9
+ require 'asciidoctor/core_ext/1.8.7/io/write'
5
10
  require 'asciidoctor/core_ext/1.8.7/string/chr'
6
- require 'asciidoctor/core_ext/1.8.7/string/limit'
11
+ require 'asciidoctor/core_ext/1.8.7/string/limit_bytesize'
12
+ require 'asciidoctor/core_ext/1.8.7/symbol/empty'
7
13
  require 'asciidoctor/core_ext/1.8.7/symbol/length'
8
14
  end