asciidoctor 2.0.18 → 2.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,18 +39,36 @@ class Converter::DocBook5Converter < Converter::Base
39
39
  result << ((node.attr? 'sectnumlevels') ? %(<?asciidoc-numbered maxdepth="#{node.attr 'sectnumlevels'}"?>) : '<?asciidoc-numbered?>') if node.attr? 'sectnums'
40
40
  lang_attribute = (node.attr? 'nolang') ? '' : %( xml:lang="#{node.attr 'lang', 'en'}")
41
41
  if (root_tag_name = node.doctype) == 'manpage'
42
- root_tag_name = 'refentry'
42
+ manpage = true
43
+ root_tag_name = 'article'
43
44
  end
44
45
  root_tag_idx = result.size
45
46
  id = node.id
46
- result << (document_info_tag node) unless node.noheader
47
+ abstract = find_root_abstract node
48
+ result << (document_info_tag node, abstract) unless node.noheader
49
+ if manpage
50
+ result << '<refentry>'
51
+ result << '<refmeta>'
52
+ result << %(<refentrytitle>#{node.apply_reftext_subs node.attr 'mantitle'}</refentrytitle>) if node.attr? 'mantitle'
53
+ result << %(<manvolnum>#{node.attr 'manvolnum'}</manvolnum>) if node.attr? 'manvolnum'
54
+ result << %(<refmiscinfo class="source">#{node.attr 'mansource', '&#160;'}</refmiscinfo>)
55
+ result << %(<refmiscinfo class="manual">#{node.attr 'manmanual', '&#160;'}</refmiscinfo>)
56
+ result << '</refmeta>'
57
+ result << '<refnamediv>'
58
+ result += (node.attr 'mannames').map {|n| %(<refname>#{n}</refname>) } if node.attr? 'mannames'
59
+ result << %(<refpurpose>#{node.attr 'manpurpose'}</refpurpose>) if node.attr? 'manpurpose'
60
+ result << '</refnamediv>'
61
+ end
47
62
  unless (docinfo_content = node.docinfo :header).empty?
48
63
  result << docinfo_content
49
64
  end
50
- result << node.content if node.blocks?
65
+ abstract = extract_abstract node, abstract if abstract
66
+ result << (node.blocks.map {|block| block.convert }.compact.join LF) if node.blocks?
67
+ restore_abstract abstract if abstract
51
68
  unless (docinfo_content = node.docinfo :footer).empty?
52
69
  result << docinfo_content
53
70
  end
71
+ result << '</refentry>' if manpage
54
72
  id, node.id = node.id, nil unless id
55
73
  # defer adding root tag in case document ID is auto-generated on demand
56
74
  result.insert root_tag_idx, %(<#{root_tag_name} xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"#{lang_attribute}#{common_attributes id}>)
@@ -58,7 +76,15 @@ class Converter::DocBook5Converter < Converter::Base
58
76
  result.join LF
59
77
  end
60
78
 
61
- alias convert_embedded content_only
79
+ def convert_embedded node
80
+ # NOTE in DocBook 5, the root abstract must be in the info tag and is thus not part of the body
81
+ if @backend == 'docbook5' && (abstract = find_root_abstract node)
82
+ abstract = extract_abstract node, abstract
83
+ end
84
+ result = node.blocks.map {|block| block.convert }.compact.join LF
85
+ restore_abstract abstract if abstract
86
+ result
87
+ end
62
88
 
63
89
  def convert_section node
64
90
  if node.document.doctype == 'manpage'
@@ -66,7 +92,7 @@ class Converter::DocBook5Converter < Converter::Base
66
92
  else
67
93
  tag_name = node.sectname
68
94
  end
69
- title_el = node.special && (node.option? 'untitled') ? '' : %(<title>#{node.title}</title>\n)
95
+ title_el = node.special && ((node.option? 'notitle') || (node.option? 'untitled')) ? '' : %(<title>#{node.title}</title>\n)
70
96
  %(<#{tag_name}#{common_attributes node.id, node.role, node.reftext}>
71
97
  #{title_el}#{node.content}
72
98
  </#{tag_name}>)
@@ -168,27 +194,11 @@ class Converter::DocBook5Converter < Converter::Base
168
194
  end
169
195
 
170
196
  def convert_image node
171
- # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
172
- # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
173
- if node.attr? 'scaledwidth'
174
- width_attribute = %( width="#{node.attr 'scaledwidth'}")
175
- depth_attribute = ''
176
- scale_attribute = ''
177
- elsif node.attr? 'scale'
178
- # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
179
- #width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
180
- #depth_attribute = (node.attr? 'height') ? %( depth="#{node.attr 'height'}") : ''
181
- scale_attribute = %( scale="#{node.attr 'scale'}")
182
- else
183
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
184
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
185
- scale_attribute = ''
186
- end
187
197
  align_attribute = (node.attr? 'align') ? %( align="#{node.attr 'align'}") : ''
188
198
 
189
199
  mediaobject = %(<mediaobject>
190
200
  <imageobject>
191
- <imagedata fileref="#{node.image_uri(node.attr 'target')}"#{width_attribute}#{depth_attribute}#{scale_attribute}#{align_attribute}/>
201
+ <imagedata fileref="#{node.image_uri node.attr 'target'}"#{image_size_attributes node.attributes}#{align_attribute}/>
192
202
  </imageobject>
193
203
  <textobject><phrase>#{node.alt}</phrase></textobject>
194
204
  </mediaobject>)
@@ -248,10 +258,10 @@ class Converter::DocBook5Converter < Converter::Base
248
258
  def convert_stem node
249
259
  if (idx = node.subs.index :specialcharacters)
250
260
  node.subs.delete_at idx
251
- equation = node.content || ''
261
+ equation = node.content
252
262
  idx > 0 ? (node.subs.insert idx, :specialcharacters) : (node.subs.unshift :specialcharacters)
253
263
  else
254
- equation = node.content || ''
264
+ equation = node.content
255
265
  end
256
266
  if node.style == 'asciimath'
257
267
  # NOTE fop requires jeuclid to process mathml markup
@@ -293,13 +303,17 @@ class Converter::DocBook5Converter < Converter::Base
293
303
  def convert_open node
294
304
  case node.style
295
305
  when 'abstract'
296
- if node.parent == node.document && node.document.doctype == 'book'
297
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
306
+ if (parent = node.parent) == node.document && node.document.doctype == 'book'
307
+ logger.warn 'abstract block cannot be used in a document without a doctitle when doctype is book. Excluding block content.'
298
308
  ''
299
309
  else
300
- %(<abstract>
310
+ result = %(<abstract>
301
311
  #{title_tag node}#{enclose_content node}
302
312
  </abstract>)
313
+ if @backend == 'docbook5' && !(node.option? 'root') && (parent.context == :open ? parent.style == 'partintro' : parent.context == :section && parent.sectname == 'partintro') && node == parent.blocks[0]
314
+ result = %(<info>\n#{result}\n</info>)
315
+ end
316
+ result
303
317
  end
304
318
  when 'partintro'
305
319
  if node.level == 0 && node.parent.context == :section && node.document.doctype == 'book'
@@ -521,11 +535,9 @@ class Converter::DocBook5Converter < Converter::Base
521
535
  end
522
536
 
523
537
  def convert_inline_image node
524
- width_attribute = (node.attr? 'width') ? %( contentwidth="#{node.attr 'width'}") : ''
525
- depth_attribute = (node.attr? 'height') ? %( contentdepth="#{node.attr 'height'}") : ''
526
538
  %(<inlinemediaobject#{common_attributes nil, node.role}>
527
539
  <imageobject>
528
- <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{width_attribute}#{depth_attribute}/>
540
+ <imagedata fileref="#{node.type == 'icon' ? (node.icon_uri node.target) : (node.image_uri node.target)}"#{image_size_attributes node.attributes}/>
529
541
  </imageobject>
530
542
  <textobject><phrase>#{node.alt}</phrase></textobject>
531
543
  </inlinemediaobject>)
@@ -633,6 +645,23 @@ class Converter::DocBook5Converter < Converter::Base
633
645
  end
634
646
  end
635
647
 
648
+ def image_size_attributes attributes
649
+ # NOTE according to the DocBook spec, content area, scaling, and scaling to fit are mutually exclusive
650
+ # See http://tdg.docbook.org/tdg/4.5/imagedata-x.html#d0e79635
651
+ if attributes.key? 'scaledwidth'
652
+ %( width="#{attributes['scaledwidth']}")
653
+ elsif attributes.key? 'scale'
654
+ # QUESTION should we set the viewport using width and depth? (the scaled image would be contained within this box)
655
+ #width_attribute = (attributes.key? 'width') ? %( width="#{attributes['width']}") : ''
656
+ #depth_attribute = (attributes.key? 'height') ? %( depth="#{attributes['height']}") : ''
657
+ %( scale="#{attributes['scale']}")
658
+ else
659
+ width_attribute = (attributes.key? 'width') ? %( contentwidth="#{attributes['width']}") : ''
660
+ depth_attribute = (attributes.key? 'height') ? %( contentdepth="#{attributes['height']}") : ''
661
+ %(#{width_attribute}#{depth_attribute})
662
+ end
663
+ end
664
+
636
665
  def author_tag doc, author
637
666
  result = []
638
667
  result << '<author>'
@@ -646,7 +675,7 @@ class Converter::DocBook5Converter < Converter::Base
646
675
  result.join LF
647
676
  end
648
677
 
649
- def document_info_tag doc
678
+ def document_info_tag doc, abstract
650
679
  result = ['<info>']
651
680
  unless doc.notitle
652
681
  if (title = doc.doctitle partition: true, use_fallback: true).subtitle?
@@ -700,22 +729,35 @@ class Converter::DocBook5Converter < Converter::Base
700
729
  result << docinfo_content
701
730
  end
702
731
  end
732
+ if abstract
733
+ abstract.set_option 'root'
734
+ result << (convert abstract, abstract.node_name)
735
+ abstract.remove_attr 'root-option'
736
+ end
703
737
  result << '</info>'
704
738
 
705
- if doc.doctype == 'manpage'
706
- result << '<refmeta>'
707
- result << %(<refentrytitle>#{doc.attr 'mantitle'}</refentrytitle>) if doc.attr? 'mantitle'
708
- result << %(<manvolnum>#{doc.attr 'manvolnum'}</manvolnum>) if doc.attr? 'manvolnum'
709
- result << %(<refmiscinfo class="source">#{doc.attr 'mansource', '&#160;'}</refmiscinfo>)
710
- result << %(<refmiscinfo class="manual">#{doc.attr 'manmanual', '&#160;'}</refmiscinfo>)
711
- result << '</refmeta>'
712
- result << '<refnamediv>'
713
- result += (doc.attr 'mannames').map {|n| %(<refname>#{n}</refname>) } if doc.attr? 'mannames'
714
- result << %(<refpurpose>#{doc.attr 'manpurpose'}</refpurpose>) if doc.attr? 'manpurpose'
715
- result << '</refnamediv>'
739
+ result.join LF
740
+ end
741
+
742
+ def find_root_abstract doc
743
+ return unless doc.blocks?
744
+ if (first_block = doc.blocks[0]).context == :preamble
745
+ return unless (first_block = first_block.blocks[0])
746
+ elsif first_block.context == :section
747
+ return first_block if first_block.sectname == 'abstract'
748
+ return unless first_block.sectname == 'preface' && (first_block = first_block.blocks[0])
716
749
  end
750
+ return first_block if first_block.style == 'abstract' && first_block.context == :open
751
+ end
717
752
 
718
- result.join LF
753
+ def extract_abstract document, abstract
754
+ parent = abstract.parent
755
+ parent = parent.parent while parent != document && parent.blocks.length == 1
756
+ parent.blocks.delete_at 0
757
+ end
758
+
759
+ def restore_abstract abstract
760
+ abstract.parent.blocks.insert 0, abstract
719
761
  end
720
762
 
721
763
  def get_root_document node
@@ -740,26 +782,18 @@ class Converter::DocBook5Converter < Converter::Base
740
782
 
741
783
  def cover_tag doc, face, use_placeholder = false
742
784
  if (cover_image = doc.attr %(#{face}-cover-image))
743
- width_attr = ''
744
- depth_attr = ''
745
785
  if (cover_image.include? ':') && ImageMacroRx =~ cover_image
746
- attrlist = $2
747
- cover_image = doc.image_uri $1
748
- if attrlist
749
- attrs = (AttributeList.new attrlist).parse ['alt', 'width', 'height']
750
- if attrs.key? 'scaledwidth'
751
- # NOTE scalefit="1" is the default in this case
752
- width_attr = %( width="#{attrs['scaledwidth']}")
753
- else
754
- width_attr = %( contentwidth="#{attrs['width']}") if attrs.key? 'width'
755
- depth_attr = %( contentdepth="#{attrs['height']}") if attrs.key? 'height'
756
- end
757
- end
786
+ target, attrlist = $1, $2
787
+ cover_image = doc.image_uri target
788
+ # NOTE scalefit="1" is the default for a cover image
789
+ size_attrs = image_size_attributes (AttributeList.new attrlist).parse %w(alt width height) if attrlist
790
+ else
791
+ size_attrs = ''
758
792
  end
759
793
  %(<cover role="#{face}">
760
794
  <mediaobject>
761
795
  <imageobject>
762
- <imagedata fileref="#{cover_image}"#{width_attr}#{depth_attr}/>
796
+ <imagedata fileref="#{cover_image}"#{size_attrs}/>
763
797
  </imageobject>
764
798
  </mediaobject>
765
799
  </cover>)
@@ -675,7 +675,7 @@ Your browser does not support the audio tag.
675
675
  title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : ''
676
676
  %(<div#{id_attribute} class="listingblock#{(role = node.role) ? " #{role}" : ''}">
677
677
  #{title_element}<div class="content">
678
- #{syntax_hl ? (syntax_hl.format node, lang, opts) : pre_open + (node.content || '') + pre_close}
678
+ #{syntax_hl ? (syntax_hl.format node, lang, opts) : pre_open + node.content + pre_close}
679
679
  </div>
680
680
  </div>)
681
681
  end
@@ -748,7 +748,7 @@ Your browser does not support the audio tag.
748
748
  def convert_open node
749
749
  if (style = node.style) == 'abstract'
750
750
  if node.parent == node.document && node.document.doctype == 'book'
751
- logger.warn 'abstract block cannot be used in a document without a title when doctype is book. Excluding block content.'
751
+ logger.warn 'abstract block cannot be used in a document without a doctitle when doctype is book. Excluding block content.'
752
752
  ''
753
753
  else
754
754
  id_attr = node.id ? %( id="#{node.id}") : ''
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Asciidoctor
3
- # A built-in {Converter} implementation that generates the man page (troff) format.
3
+ # A built-in {Converter} implementation that generates the man page (groff) format.
4
4
  #
5
5
  # The output of this converter adheres to the man definition as defined by
6
6
  # groff and uses the manpage output of the DocBook toolchain as a foundation.
@@ -28,7 +28,7 @@ class Converter::ManPageConverter < Converter::Base
28
28
  EllipsisCharRefRx = /&#8230;(?:&#8203;)?/
29
29
  WrappedIndentRx = /#{CG_BLANK}*#{LF}#{CG_BLANK}*/
30
30
  XMLMarkupRx = /&#?[a-z\d]+;|</
31
- PCDATAFilterRx = /(&#?[a-z\d]+;|<[^>]+>)|([^&<]+)/
31
+ PCDATAFilterRx = %r((&#?[a-z\d]+;|<#{ESC}\\f\(CR.*?</#{ESC}\\fP>|<[^>]+>)|([^&<]+))
32
32
 
33
33
  def initialize backend, opts = {}
34
34
  @backend = backend
@@ -39,7 +39,7 @@ class Converter::ManPageConverter < Converter::Base
39
39
  unless node.attr? 'mantitle'
40
40
  raise 'asciidoctor: ERROR: doctype must be set to manpage when using manpage backend'
41
41
  end
42
- mantitle = node.attr 'mantitle'
42
+ mantitle = (node.attr 'mantitle').gsub InvalidSectionIdCharsRx, ''
43
43
  manvolnum = node.attr 'manvolnum', '1'
44
44
  manname = node.attr 'manname', mantitle
45
45
  manmanual = node.attr 'manmanual'
@@ -236,7 +236,7 @@ r lw(\n(.lu*75u/100u).'
236
236
  result << (node.title? ? %(.sp
237
237
  .B #{manify node.captioned_title}
238
238
  .br) : '.sp')
239
- result << %([#{node.alt}])
239
+ result << %([#{manify node.alt}])
240
240
  result.join LF
241
241
  end
242
242
 
@@ -432,7 +432,7 @@ allbox tab(:);'
432
432
  when :literal
433
433
  cell_content = %(.nf#{LF}#{manify cell.text, whitespace: :preserve}#{LF}.fi)
434
434
  else
435
- cell_content = manify cell.content.join, whitespace: :normalize
435
+ cell_content = cell.content.map {|p| manify p, whitespace: :normalize }.join %(#{LF}.sp#{LF})
436
436
  end
437
437
  row_text[row_index] << %(#{cell_content}#{LF})
438
438
  else # tsec == :head || tsec == :foot
@@ -476,21 +476,14 @@ allbox tab(:);'
476
476
  end unless rows.empty?
477
477
  end
478
478
 
479
- #row_header.each do |row|
480
- # result << LF
481
- # row.each_with_index do |cell, i|
482
- # result << (cell.join ' ')
483
- # result << ' ' if row.size > i + 1
484
- # end
485
- #end
486
- # FIXME temporary fix to get basic table to display
487
- result << LF
488
- result << ('lt ' * row_header[0].size).chop
489
-
490
- result << %(.#{LF})
491
- row_text.each do |row|
492
- result << row.join
479
+ if node.has_header_option && (header_row_text = row_text[0])
480
+ result << %(#{LF}#{row_header[0].join ' '}.)
481
+ result << %(#{LF}#{header_row_text.join})
482
+ result << '.T&'
483
+ row_text = row_text.slice 1, row_text.length
493
484
  end
485
+ result << %(#{LF}#{row_header[0].map { 'lt' }.join ' '}.#{LF})
486
+ row_text.each {|row| result << row.join }
494
487
  result << %(.TE#{LF}.sp)
495
488
  result.join
496
489
  end
@@ -706,46 +699,44 @@ allbox tab(:);'
706
699
  def manify str, opts = {}
707
700
  case opts.fetch :whitespace, :collapse
708
701
  when :preserve
709
- str = str.gsub TAB, ET
702
+ str = (str.gsub TAB, ET).gsub(/(^)? +/) { $1 ? $& : %(#{ESC_BS}&#{$&}) }
710
703
  when :normalize
711
704
  str = str.gsub WrappedIndentRx, LF
712
705
  else
713
706
  str = str.tr_s WHITESPACE, ' '
714
707
  end
715
- str = str
716
- .gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' } # literal backslash (not a troff escape sequence)
717
- .gsub(EllipsisCharRefRx, '...') # horizontal ellipsis
718
- .gsub(LeadingPeriodRx, '\\\&.') # leading . is used in troff for macro call or other formatting; replace with \&.
719
- .gsub(EscapedMacroRx) do # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
720
- (rest = $3.lstrip).empty? ? %(.#{$1}"#{$2}") : %(.#{$1}"#{$2.rstrip}"#{LF}#{rest})
721
- end
722
- .gsub('-', '\-')
723
- .gsub('&lt;', '<')
724
- .gsub('&gt;', '>')
725
- .gsub('&#43;', '+') # plus sign; alternately could use \c(pl
726
- .gsub('&#160;', '\~') # non-breaking space
727
- .gsub('&#169;', '\(co') # copyright sign
728
- .gsub('&#174;', '\(rg') # registered sign
729
- .gsub('&#8482;', '\(tm') # trademark sign
730
- .gsub('&#176;', '\(de') # degree sign
731
- .gsub('&#8201;', ' ') # thin space
732
- .gsub('&#8211;', '\(en') # en dash
733
- .gsub(EmDashCharRefRx, '\(em') # em dash
734
- .gsub('&#8216;', '\(oq') # left single quotation mark
735
- .gsub('&#8217;', '\(cq') # right single quotation mark
736
- .gsub('&#8220;', '\(lq') # left double quotation mark
737
- .gsub('&#8221;', '\(rq') # right double quotation mark
738
- .gsub('&#8592;', '\(<-') # leftwards arrow
739
- .gsub('&#8594;', '\(->') # rightwards arrow
740
- .gsub('&#8656;', '\(lA') # leftwards double arrow
741
- .gsub('&#8658;', '\(rA') # rightwards double arrow
742
- .gsub('&#8203;', '\:') # zero width space
743
- .gsub('&amp;', '&') # literal ampersand (NOTE must take place after any other replacement that includes &)
744
- .gsub('\'', '\*(Aq') # apostrophe / neutral single quote
745
- .gsub(MockMacroRx, '\1') # mock boundary
746
- .gsub(ESC_BS, '\\') # unescape troff backslash (NOTE update if more escapes are added)
747
- .gsub(ESC_FS, '.') # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
748
- .rstrip # strip trailing space
708
+ str = str.
709
+ gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' }. # literal backslash (not a troff escape sequence)
710
+ gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
711
+ gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
712
+ gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#{$1}"#{$2}") : %(.#{$1}"#{$2.rstrip}"#{LF}#{rest}) }. # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
713
+ gsub('-', '\-').
714
+ gsub('&lt;', '<').
715
+ gsub('&gt;', '>').
716
+ gsub('&#43;', '+'). # plus sign; alternately could use \c(pl
717
+ gsub('&#160;', '\~'). # non-breaking space
718
+ gsub('&#169;', '\(co'). # copyright sign
719
+ gsub('&#174;', '\(rg'). # registered sign
720
+ gsub('&#8482;', '\(tm'). # trademark sign
721
+ gsub('&#176;', '\(de'). # degree sign
722
+ gsub('&#8201;', ' '). # thin space
723
+ gsub('&#8211;', '\(en'). # en dash
724
+ gsub(EmDashCharRefRx, '\(em'). # em dash
725
+ gsub('&#8216;', '\(oq'). # left single quotation mark
726
+ gsub('&#8217;', '\(cq'). # right single quotation mark
727
+ gsub('&#8220;', '\(lq'). # left double quotation mark
728
+ gsub('&#8221;', '\(rq'). # right double quotation mark
729
+ gsub('&#8592;', '\(<-'). # leftwards arrow
730
+ gsub('&#8594;', '\(->'). # rightwards arrow
731
+ gsub('&#8656;', '\(lA'). # leftwards double arrow
732
+ gsub('&#8658;', '\(rA'). # rightwards double arrow
733
+ gsub('&#8203;', '\:'). # zero width space
734
+ gsub('&amp;', '&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
735
+ gsub('\'', '\*(Aq'). # apostrophe / neutral single quote
736
+ gsub(MockMacroRx, '\1'). # mock boundary
737
+ gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
738
+ gsub(ESC_FS, '.'). # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
739
+ rstrip # strip trailing space
749
740
  opts[:append_newline] ? %(#{str}#{LF}) : str
750
741
  end
751
742
 
@@ -29,7 +29,7 @@ class Converter::TemplateConverter < Converter::Base
29
29
  erb: { trim: 0 },
30
30
  # TODO line 466 of haml/compiler.rb sorts the attributes; file an issue to make this configurable
31
31
  # NOTE AsciiDoc syntax expects HTML/XML output to use double quotes around attribute values
32
- haml: { format: :xhtml, attr_wrapper: '"', escape_attrs: false, ugly: true },
32
+ haml: { format: :xhtml, attr_wrapper: '"', escape_html: false, escape_attrs: false, ugly: true },
33
33
  slim: { disable_escape: true, sort_attrs: false, pretty: false },
34
34
  }
35
35
 
@@ -227,6 +227,7 @@ class Converter::TemplateConverter < Converter::Base
227
227
  Helpers.require_library 'haml' unless defined? ::Haml::Engine
228
228
  # NOTE Haml 5 dropped support for pretty printing
229
229
  @engine_options[extsym].delete :ugly if defined? ::Haml::TempleEngine
230
+ @engine_options[extsym][:attr_quote] = @engine_options[extsym].delete :attr_wrapper unless defined? ::Haml::Options
230
231
  @active_engines[extsym] = true
231
232
  end
232
233
  when :erb
@@ -1109,6 +1109,9 @@ module Extensions
1109
1109
  # Public: Checks whether any {BlockProcessor} extensions are registered to
1110
1110
  # handle the specified block name appearing on the specified context.
1111
1111
  #
1112
+ # This method assumes you've called blocks? first to check whether any
1113
+ # block extensions are registered.
1114
+ #
1112
1115
  # Returns the [Extension] proxy object for the BlockProcessor that matches
1113
1116
  # the block name and context or false if no match is found.
1114
1117
  def registered_for_block? name, context
@@ -1124,6 +1127,9 @@ module Extensions
1124
1127
  #
1125
1128
  # name - the String or Symbol (coersed to a Symbol) macro name
1126
1129
  #
1130
+ # This method assumes you've called blocks? first to check whether any
1131
+ # block extensions are registered.
1132
+ #
1127
1133
  # Returns the [Extension] object stored in the registry that proxies the
1128
1134
  # corresponding BlockProcessor or nil if a match is not found.
1129
1135
  def find_block_extension name
@@ -1200,6 +1206,9 @@ module Extensions
1200
1206
  #
1201
1207
  # name - the String or Symbol (coersed to a Symbol) macro name
1202
1208
  #
1209
+ # This method assumes you've called block_macros? first to check whether any
1210
+ # block macro extensions are registered.
1211
+ #
1203
1212
  # Returns the [Extension] proxy object for the BlockMacroProcessor that matches
1204
1213
  # the macro name or false if no match is found.
1205
1214
  #--
@@ -1213,6 +1222,9 @@ module Extensions
1213
1222
  #
1214
1223
  # name - the String or Symbol (coersed to a Symbol) macro name
1215
1224
  #
1225
+ # This method assumes you've called block_macros? first to check whether any
1226
+ # block macro extensions are registered.
1227
+ #
1216
1228
  # Returns the [Extension] object stored in the registry that proxies the
1217
1229
  # corresponding BlockMacroProcessor or nil if a match is not found.
1218
1230
  def find_block_macro_extension name
@@ -1289,6 +1301,9 @@ module Extensions
1289
1301
  #
1290
1302
  # name - the String or Symbol (coersed to a Symbol) macro name
1291
1303
  #
1304
+ # This method assumes you've called inline_macros? first to check whether any
1305
+ # inline macro extensions are registered.
1306
+ #
1292
1307
  # Returns the [Extension] proxy object for the InlineMacroProcessor that matches
1293
1308
  # the macro name or false if no match is found.
1294
1309
  def registered_for_inline_macro? name
@@ -1300,6 +1315,9 @@ module Extensions
1300
1315
  #
1301
1316
  # name - the String or Symbol (coersed to a Symbol) macro name
1302
1317
  #
1318
+ # This method assumes you've called inline_macros? first to check whether any
1319
+ # inline macro extensions are registered.
1320
+ #
1303
1321
  # Returns the [Extension] object stored in the registry that proxies the
1304
1322
  # corresponding InlineMacroProcessor or nil if a match is not found.
1305
1323
  def find_inline_macro_extension name
@@ -1309,6 +1327,9 @@ module Extensions
1309
1327
  # Public: Retrieves the {Extension} proxy objects for all
1310
1328
  # InlineMacroProcessor instances in this registry.
1311
1329
  #
1330
+ # This method assumes you've called inline_macros? first to check whether any
1331
+ # inline macro extensions are registered.
1332
+ #
1312
1333
  # Returns an [Array] of Extension proxy objects.
1313
1334
  def inline_macros
1314
1335
  @inline_macro_extensions.values
@@ -120,8 +120,14 @@ module Helpers
120
120
  # str - the String to check
121
121
  #
122
122
  # returns true if the String is a URI, false if it is not
123
- def uriish? str
124
- (str.include? ':') && (UriSniffRx.match? str)
123
+ if ::RUBY_ENGINE == 'jruby'
124
+ def uriish? str
125
+ (str.include? ':') && !(str.start_with? 'uri:classloader:') && (UriSniffRx.match? str)
126
+ end
127
+ else
128
+ def uriish? str
129
+ (str.include? ':') && (UriSniffRx.match? str)
130
+ end
125
131
  end
126
132
 
127
133
  # Internal: Encode a URI component String for safe inclusion in a URI.
@@ -139,10 +145,13 @@ module Helpers
139
145
  })
140
146
  )
141
147
  end
148
+ elsif (CGI = ::CGI).respond_to? :escapeURIComponent
149
+ def encode_uri_component str
150
+ CGI.escapeURIComponent str
151
+ end
142
152
  else
143
- CGI = ::CGI
144
153
  def encode_uri_component str
145
- CGI.escape str
154
+ (CGI.escape str).gsub '+', '%20'
146
155
  end
147
156
  end
148
157
 
@@ -40,6 +40,7 @@ class MemoryLogger < ::Logger
40
40
  attr_reader :messages
41
41
 
42
42
  def initialize
43
+ super nil
43
44
  self.level = WARN
44
45
  @messages = []
45
46
  end
@@ -67,6 +68,7 @@ class NullLogger < ::Logger
67
68
  attr_reader :max_severity
68
69
 
69
70
  def initialize
71
+ super nil
70
72
  self.level = WARN
71
73
  end
72
74