asciidoctor 1.5.3 → 1.5.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +67 -5
  3. data/CONTRIBUTING.adoc +171 -0
  4. data/LICENSE.adoc +1 -1
  5. data/README.adoc +62 -30
  6. data/bin/asciidoctor +3 -3
  7. data/bin/asciidoctor-safe +8 -5
  8. data/lib/asciidoctor.rb +10 -21
  9. data/lib/asciidoctor/abstract_block.rb +29 -11
  10. data/lib/asciidoctor/abstract_node.rb +11 -6
  11. data/lib/asciidoctor/callouts.rb +6 -10
  12. data/lib/asciidoctor/cli/options.rb +2 -2
  13. data/lib/asciidoctor/converter.rb +1 -1
  14. data/lib/asciidoctor/converter/docbook5.rb +46 -23
  15. data/lib/asciidoctor/converter/factory.rb +3 -3
  16. data/lib/asciidoctor/converter/html5.rb +27 -24
  17. data/lib/asciidoctor/converter/manpage.rb +72 -61
  18. data/lib/asciidoctor/converter/template.rb +5 -9
  19. data/lib/asciidoctor/document.rb +18 -18
  20. data/lib/asciidoctor/extensions.rb +5 -5
  21. data/lib/asciidoctor/helpers.rb +2 -2
  22. data/lib/asciidoctor/inline.rb +2 -2
  23. data/lib/asciidoctor/parser.rb +59 -59
  24. data/lib/asciidoctor/path_resolver.rb +23 -15
  25. data/lib/asciidoctor/reader.rb +34 -29
  26. data/lib/asciidoctor/section.rb +6 -8
  27. data/lib/asciidoctor/substitutors.rb +2 -2
  28. data/lib/asciidoctor/table.rb +46 -23
  29. data/lib/asciidoctor/version.rb +1 -1
  30. data/man/asciidoctor.1 +11 -11
  31. data/man/asciidoctor.adoc +2 -2
  32. data/test/attributes_test.rb +21 -37
  33. data/test/blocks_test.rb +41 -14
  34. data/test/converter_test.rb +4 -4
  35. data/test/document_test.rb +61 -8
  36. data/test/extensions_test.rb +2 -2
  37. data/test/invoker_test.rb +3 -3
  38. data/test/links_test.rb +13 -3
  39. data/test/lists_test.rb +114 -114
  40. data/test/manpage_test.rb +203 -0
  41. data/test/paragraphs_test.rb +3 -3
  42. data/test/parser_test.rb +4 -4
  43. data/test/preamble_test.rb +1 -1
  44. data/test/reader_test.rb +149 -109
  45. data/test/sections_test.rb +137 -27
  46. data/test/substitutions_test.rb +24 -16
  47. data/test/tables_test.rb +183 -31
  48. data/test/test_helper.rb +10 -22
  49. metadata +9 -6
  50. data/compat/asciidoc.conf +0 -395
  51. data/compat/font-awesome-3-compat.css +0 -397
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems' if RUBY_VERSION < '1.9'
3
+ require 'rubygems' unless defined? Gem
4
4
 
5
- if File.exist?(asciidoctor_lib_path = File.join(File.dirname(__FILE__), '../lib/asciidoctor'))
6
- require asciidoctor_lib_path
5
+ if File.exist?(asciidoctor = (File.expand_path '../../lib/asciidoctor', __FILE__))
6
+ require asciidoctor
7
7
  else
8
8
  require 'asciidoctor'
9
9
  end
@@ -1,12 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems' if RUBY_VERSION < '1.9'
3
+ require 'rubygems' unless defined? Gem
4
4
 
5
- require File.join File.dirname(__FILE__), '../lib/asciidoctor'
5
+ if File.exist?(asciidoctor = (File.expand_path '../../lib/asciidoctor', __FILE__))
6
+ require asciidoctor
7
+ else
8
+ require 'asciidoctor'
9
+ end
6
10
  require 'asciidoctor/cli'
7
11
 
8
- options = Asciidoctor::Cli::Options.parse! ARGV
9
- options[:safe] = Asciidoctor::SafeMode::SAFE
10
- invoker = Asciidoctor::Cli::Invoker.new options
12
+ invoker = Asciidoctor::Cli::Invoker.new(ARGV + ['-S', 'safe'])
13
+ GC.start
11
14
  invoker.invoke!
12
15
  exit invoker.code
@@ -105,12 +105,10 @@ module Asciidoctor
105
105
 
106
106
  # Defines a new compliance key and assigns an initial value.
107
107
  def self.define key, value
108
- if key == :keys || (self.respond_to? key)
109
- raise ::ArgumentError, %(illegal key name: #{key})
110
- end
111
108
  instance_variable_set %(@#{key}), value
112
109
  class << self; self; end.send :attr_accessor, key
113
110
  @keys << key
111
+ nil
114
112
  end
115
113
 
116
114
  # AsciiDoc terminates paragraphs adjacent to
@@ -190,7 +188,7 @@ module Asciidoctor
190
188
 
191
189
  # Flag to indicate whether encoding can be coerced to UTF-8
192
190
  # _All_ input data must be force encoded to UTF-8 if Encoding.default_external is *not* UTF-8
193
- # Addresses failures performing string operations that are reported as "invalid byte sequence in US-ASCII"
191
+ # Addresses failures performing string operations that are reported as "invalid byte sequence in US-ASCII"
194
192
  # Ruby 1.8 doesn't seem to experience this problem (perhaps because it isn't validating the encodings)
195
193
  COERCE_ENCODING = !::RUBY_ENGINE_OPAL && ::RUBY_MIN_VERSION_1_9
196
194
 
@@ -424,7 +422,7 @@ module Asciidoctor
424
422
  #
425
423
  # Examples
426
424
  #
427
- # = asciidoctor ( 1 )
425
+ # = asciidoctor ( 1 )
428
426
  #
429
427
  ManpageTitleVolnumRx = /^(.*)\((.*)\)$/
430
428
 
@@ -710,7 +708,7 @@ module Asciidoctor
710
708
  #
711
709
  # NOTE negative match for comment line is intentional since that isn't handled when looking for next list item
712
710
  # QUESTION should we check for line comment in regex or when scanning the lines?
713
- #
711
+ #
714
712
  DefinitionListRx = /^(?!\/\/)#{CG_BLANK}*(.*?)(:{2,4}|;;)(?:#{CG_BLANK}+(.*))?$/
715
713
 
716
714
  # Matches a sibling definition list item (which does not include the keyed type).
@@ -732,7 +730,7 @@ module Asciidoctor
732
730
  CalloutListRx = /^<?(\d+)>#{CG_BLANK}+(.*)/
733
731
 
734
732
  # Matches a callout reference inside literal text.
735
- #
733
+ #
736
734
  # Examples
737
735
  # <1> (optionally prefixed by //, #, -- or ;; line comment chars)
738
736
  # <1> <2> (multiple callouts on one line)
@@ -780,7 +778,7 @@ module Asciidoctor
780
778
  # Matches the general block macro pattern.
781
779
  #
782
780
  # Examples
783
- #
781
+ #
784
782
  # gist::123456[]
785
783
  #
786
784
  #--
@@ -887,7 +885,7 @@ module Asciidoctor
887
885
  # Matches an implicit link and some of the link inline macro.
888
886
  #
889
887
  # Examples
890
- #
888
+ #
891
889
  # http://github.com
892
890
  # http://github.com[GitHub]
893
891
  #
@@ -1015,15 +1013,7 @@ module Asciidoctor
1015
1013
  # one,two
1016
1014
  # three;four
1017
1015
  #
1018
- DataDelimiterRx = /,|;/
1019
-
1020
- # Matches one or more consecutive digits on a single line.
1021
- #
1022
- # Examples
1023
- #
1024
- # 29
1025
- #
1026
- DigitsRx = /^\d+$/
1016
+ DataDelimiterRx = /,|;/
1027
1017
 
1028
1018
  # Matches a single-line of text enclosed in double quotes, capturing the quote char and text.
1029
1019
  #
@@ -1055,7 +1045,7 @@ module Asciidoctor
1055
1045
  # Matches a space escaped by a backslash.
1056
1046
  #
1057
1047
  # Examples
1058
- #
1048
+ #
1059
1049
  # one\ two\ three
1060
1050
  #
1061
1051
  EscapedSpaceRx = /\\(#{CG_BLANK})/
@@ -1295,9 +1285,8 @@ module Asciidoctor
1295
1285
  elsif ::String === attrs
1296
1286
  # convert non-escaped spaces into null character, so we split on the
1297
1287
  # correct spaces chars, and restore escaped spaces
1298
- capture_1 = ::RUBY_ENGINE_OPAL ? '$1' : '\1'
1288
+ capture_1 = '\1'
1299
1289
  attrs = attrs.gsub(SpaceDelimiterRx, %(#{capture_1}#{NULL})).gsub(EscapedSpaceRx, capture_1)
1300
-
1301
1290
  attrs.split(NULL).inject({}) do |accum, entry|
1302
1291
  k, v = entry.split '=', 2
1303
1292
  accum[k] = v || ''
@@ -167,11 +167,12 @@ class AbstractBlock < AbstractNode
167
167
  # block.blocks.size
168
168
  # # => 2
169
169
  #
170
- # Returns nothing.
170
+ # Returns The parent Block
171
171
  def << block
172
172
  # parent assignment pending refactor
173
173
  #block.parent = self
174
174
  @blocks << block
175
+ self
175
176
  end
176
177
 
177
178
  # NOTE append alias required for adapting to a Java API
@@ -182,16 +183,20 @@ class AbstractBlock < AbstractNode
182
183
  # Only applies to Document and Section instances
183
184
  #
184
185
  # Examples
185
- #
186
- # section = Section.new(parent)
187
- # section << Block.new(section, :paragraph, :source => 'paragraph 1')
188
- # section << Section.new(parent)
189
- # section << Block.new(section, :paragraph, :source => 'paragraph 2')
190
- # section.blocks?
186
+ #
187
+ # doc << (sect1 = Section.new doc, 1, false)
188
+ # sect1.title = 'Section 1'
189
+ # para1 = Block.new sect1, :paragraph, :source => 'Paragraph 1'
190
+ # para2 = Block.new sect1, :paragraph, :source => 'Paragraph 2'
191
+ # sect1 << para1 << para2
192
+ # sect1 << (sect1_1 = Section.new sect1, 2, false)
193
+ # sect1_1.title = 'Section 1.1'
194
+ # sect1_1 << (Block.new sect1_1, :paragraph, :source => 'Paragraph 3')
195
+ # sect1.blocks?
191
196
  # # => true
192
- # section.blocks.size
197
+ # sect1.blocks.size
193
198
  # # => 3
194
- # section.sections.size
199
+ # sect1.sections.size
195
200
  # # => 1
196
201
  #
197
202
  # Returns an [Array] of Section objects
@@ -199,6 +204,15 @@ class AbstractBlock < AbstractNode
199
204
  @blocks.select {|block| block.context == :section }
200
205
  end
201
206
 
207
+ # Public: Check whether this block has any child Section objects.
208
+ #
209
+ # Only applies to Document and Section instances
210
+ #
211
+ # Returns A [Boolean] to indicate whether this block has child Section objects
212
+ def sections?
213
+ @next_section_index > 0
214
+ end
215
+
202
216
  # stage the Enumerable mixin until we're sure we've got it right
203
217
  =begin
204
218
  include ::Enumerable
@@ -238,7 +252,7 @@ class AbstractBlock < AbstractNode
238
252
  #
239
253
  # Examples
240
254
  #
241
- # doc.find_by context: :section
255
+ # doc.find_by context: :section
242
256
  # #=> Asciidoctor::Section@14459860 { level: 0, title: "Hello, AsciiDoc!", blocks: 0 }
243
257
  # #=> Asciidoctor::Section@14505460 { level: 1, title: "First Section", blocks: 1 }
244
258
  #
@@ -281,7 +295,8 @@ class AbstractBlock < AbstractNode
281
295
  if @context == :dlist
282
296
  if any_context || context_selector != :section # optimization
283
297
  @blocks.flatten.each do |li|
284
- result.concat(li.find_by selector, &block)
298
+ # NOTE the list item of a dlist can be nil, so we have to check
299
+ result.concat(li.find_by selector, &block) if li
285
300
  end
286
301
  end
287
302
  elsif
@@ -375,6 +390,9 @@ class AbstractBlock < AbstractNode
375
390
  # Walk the descendents of the current Document or Section
376
391
  # and reassign the section 0-based index value to each Section
377
392
  # as it appears in document order.
393
+ #
394
+ # IMPORTANT You must invoke this method on a node after removing
395
+ # child sections or else the internal counters will be off.
378
396
  #
379
397
  # Returns nothing
380
398
  def reindex_sections
@@ -264,11 +264,16 @@ class AbstractNode
264
264
  # name - The String name of the icon
265
265
  #
266
266
  # Returns A String reference or data URI for an icon image
267
- def icon_uri(name)
267
+ def icon_uri name
268
268
  if attr? 'icon'
269
- image_uri(attr('icon'), nil)
269
+ # QUESTION should we add extension if resolved value is an absolute URI?
270
+ if ::File.extname(uri = (image_uri attr('icon'), 'iconsdir')).empty?
271
+ %(#{uri}.#{@document.attr 'icontype', 'png'})
272
+ else
273
+ uri
274
+ end
270
275
  else
271
- image_uri(%(#{name}.#{@document.attr('icontype', 'png')}), 'iconsdir')
276
+ image_uri %(#{name}.#{@document.attr 'icontype', 'png'}), 'iconsdir'
272
277
  end
273
278
  end
274
279
 
@@ -366,7 +371,7 @@ class AbstractNode
366
371
  # NOTE base64 is autoloaded by reference to ::Base64
367
372
  %(data:#{mimetype};base64,#{::Base64.encode64(bindata).delete EOL})
368
373
  end
369
-
374
+
370
375
  # Public: Read the image data from the specified URI and generate a data URI
371
376
  #
372
377
  # The image data is read from the URI and converted to Base64. A data URI is
@@ -392,7 +397,7 @@ class AbstractNode
392
397
  begin
393
398
  mimetype = nil
394
399
  bindata = open(image_uri, 'rb') {|file|
395
- mimetype = file.content_type
400
+ mimetype = file.content_type
396
401
  file.read
397
402
  }
398
403
  # NOTE base64 is autoloaded by reference to ::Base64
@@ -484,7 +489,7 @@ class AbstractNode
484
489
  # start - the String start (i.e, parent) path (optional, default: nil)
485
490
  # preserve_uri_target - a Boolean indicating whether target should be preserved if contains a URI (default: true)
486
491
  #
487
- # Returns the resolved [String] path
492
+ # Returns the resolved [String] path
488
493
  def normalize_web_path(target, start = nil, preserve_uri_target = true)
489
494
  if preserve_uri_target && (Helpers.uriish? target)
490
495
  target
@@ -27,10 +27,9 @@ class Callouts
27
27
  # # => "CO2-1"
28
28
  #
29
29
  # Returns The unique String id of this callout
30
- def register(li_ordinal)
31
- current_list << {:ordinal => li_ordinal.to_i, :id => (id = generate_next_callout_id)}
30
+ def register li_ordinal
31
+ current_list << { :ordinal => li_ordinal.to_i, :id => (id = generate_next_callout_id) }
32
32
  @co_index += 1
33
-
34
33
  id
35
34
  end
36
35
 
@@ -50,7 +49,6 @@ class Callouts
50
49
  end
51
50
 
52
51
  @co_index += 1
53
-
54
52
  id
55
53
  end
56
54
 
@@ -60,7 +58,7 @@ class Callouts
60
58
  # retrieve the callouts
61
59
  #
62
60
  # Returns A space-separated String of callout ids associated with the specified list item
63
- def callout_ids(li_ordinal)
61
+ def callout_ids li_ordinal
64
62
  current_list.map {|element| element[:ordinal] == li_ordinal ? %(#{element[:id]} ) : nil }.join.chop
65
63
  end
66
64
 
@@ -82,7 +80,6 @@ class Callouts
82
80
  end
83
81
 
84
82
  @co_index = 1
85
-
86
83
  nil
87
84
  end
88
85
 
@@ -93,7 +90,6 @@ class Callouts
93
90
  def rewind
94
91
  @list_index = 1
95
92
  @co_index = 1
96
-
97
93
  nil
98
94
  end
99
95
 
@@ -101,7 +97,7 @@ class Callouts
101
97
  #
102
98
  # Returns A unique String id for this callout
103
99
  def generate_next_callout_id
104
- generate_callout_id(@list_index, @co_index)
100
+ generate_callout_id @list_index, @co_index
105
101
  end
106
102
 
107
103
  # Internal: Generate a unique id for the callout at the specified position
@@ -110,8 +106,8 @@ class Callouts
110
106
  # co_index - The 1-based Integer index of the callout since the end of the last callout list
111
107
  #
112
108
  # Returns A unique String id for a callout
113
- def generate_callout_id(list_index, co_index)
114
- "CO#{list_index}-#{co_index}"
109
+ def generate_callout_id list_index, co_index
110
+ %(CO#{list_index}-#{co_index})
115
111
  end
116
112
  end
117
113
  end
@@ -136,12 +136,12 @@ Example: asciidoctor -b html5 source.asciidoc
136
136
  opts.on_tail('-V', '--version', 'display the version and runtime environment (or -v if no other flags or arguments)') do
137
137
  return print_version $stdout
138
138
  end
139
-
139
+
140
140
  end
141
141
 
142
142
  infiles = []
143
143
  opts_parser.parse! args
144
-
144
+
145
145
  if args.empty?
146
146
  if self[:verbose] == 2
147
147
  return print_version $stdout
@@ -136,7 +136,7 @@ module Asciidoctor
136
136
  converter.extend Config
137
137
  end
138
138
  end
139
-
139
+
140
140
  include Config
141
141
  include BackendInfo
142
142
 
@@ -43,10 +43,13 @@ module Asciidoctor
43
43
 
44
44
  def section node
45
45
  doctype = node.document.doctype
46
- tag_name = if node.special
47
- node.level <= 1 ? node.sectname : 'section'
46
+ if node.special
47
+ if (tag_name = node.sectname).start_with? 'sect'
48
+ # a normal child section of a special section
49
+ tag_name = 'section'
50
+ end
48
51
  else
49
- doctype == 'book' && node.level <= 1 ? (node.level == 0 ? 'part' : 'chapter') : 'section'
52
+ tag_name = doctype == 'book' && node.level <= 1 ? (node.level == 0 ? 'part' : 'chapter') : 'section'
50
53
  end
51
54
  if doctype == 'manpage'
52
55
  if tag_name == 'section'
@@ -103,7 +106,12 @@ module Asciidoctor
103
106
  :term => 'glossterm',
104
107
  :item => 'glossdef'
105
108
  }
106
- }).default = DLIST_TAGS['labeled']
109
+ }).default = { # default value == DLIST['labeled'], expanded for Opal
110
+ :list => 'variablelist',
111
+ :entry => 'varlistentry',
112
+ :term => 'term',
113
+ :item => 'listitem'
114
+ }
107
115
 
108
116
  def dlist node
109
117
  result = []
@@ -252,15 +260,18 @@ module Asciidoctor
252
260
  end
253
261
  equation = node.content
254
262
  node.subs.insert idx, :specialcharacters if idx
255
- if node.style == 'latexmath'
256
- equation_data = %(<alt><![CDATA[#{equation}]]></alt>
257
- <mediaobject><textobject><phrase></phrase></textobject></mediaobject>)
258
- elsif node.style == 'asciimath' && ((defined? ::AsciiMath) || (!(defined? @asciimath_loaded) ?
259
- (@asciimath_loaded = Helpers.require_library 'asciimath', true, :warn) : @asciimath_loaded))
260
- equation_data = ::AsciiMath.parse(equation).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'
263
+ if node.style == 'asciimath'
264
+ if ((defined? ::AsciiMath) || ((defined? @asciimath_available) ? @asciimath_available :
265
+ (@asciimath_available = Helpers.require_library 'asciimath', true, :warn)))
266
+ # NOTE fop requires jeuclid to process raw mathml
267
+ equation_data = (::AsciiMath.parse equation).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'
268
+ else
269
+ equation_data = %(<mathphrase><![CDATA[#{equation}]]></mathphrase>)
270
+ end
261
271
  else
262
- # Unsupported math style, so output raw expression in text object
263
- equation_data = %(<mediaobject><textobject><phrase><![CDATA[#{equation}]]></phrase></textobject></mediaobject>)
272
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
273
+ equation_data = %(<alt><![CDATA[#{equation}]]></alt>
274
+ <mathphrase><![CDATA[#{equation}]]></mathphrase>)
264
275
  end
265
276
  if node.title?
266
277
  %(<equation#{common_attributes node.id, node.role, node.reftext}>
@@ -268,6 +279,7 @@ module Asciidoctor
268
279
  #{equation_data}
269
280
  </equation>)
270
281
  else
282
+ # WARNING dblatex displays the <informalequation> element inline instead of block as documented (except w/ mathml)
271
283
  %(<informalequation#{common_attributes node.id, node.role, node.reftext}>
272
284
  #{equation_data}
273
285
  </informalequation>)
@@ -383,14 +395,17 @@ module Asciidoctor
383
395
  result << '<?dbfo keep-together="auto"?>'
384
396
  end
385
397
  result << %(<title>#{node.title}</title>) if tag_name == 'table'
386
- if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
398
+ col_width_key = if (width = (node.attr? 'width') ? (node.attr 'width') : nil)
387
399
  TABLE_PI_NAMES.each do |pi_name|
388
400
  result << %(<?#{pi_name} table-width="#{width}"?>)
389
401
  end
402
+ 'colabswidth'
403
+ else
404
+ 'colpcwidth'
390
405
  end
391
406
  result << %(<tgroup cols="#{node.attr 'colcount'}">)
392
407
  node.columns.each do |col|
393
- result << %(<colspec colname="col_#{col.attr 'colnumber'}" colwidth="#{col.attr(width ? 'colabswidth' : 'colpcwidth')}*"/>)
408
+ result << %(<colspec colname="col_#{col.attr 'colnumber'}" colwidth="#{col.attr col_width_key}*"/>)
394
409
  end
395
410
  TABLE_SECTIONS.select {|tblsec| !node.rows[tblsec].empty? }.each do |tblsec|
396
411
  has_body = true if tblsec == :body
@@ -498,13 +513,13 @@ module Asciidoctor
498
513
  when :xref
499
514
  if (path = node.attributes['path'])
500
515
  # QUESTION should we use refid as fallback text instead? (like the html5 backend?)
501
- %(<link xlink:href="#{node.target}">#{node.text || path}</link>)
516
+ %(<link xl:href="#{node.target}">#{node.text || path}</link>)
502
517
  else
503
518
  linkend = node.attributes['fragment'] || node.target
504
519
  (text = node.text) ? %(<link linkend="#{linkend}">#{text}</link>) : %(<xref linkend="#{linkend}"/>)
505
520
  end
506
521
  when :link
507
- %(<link xlink:href="#{node.target}">#{node.text}</link>)
522
+ %(<link xl:href="#{node.target}">#{node.text}</link>)
508
523
  when :bibref
509
524
  target = node.target
510
525
  %(<anchor#{common_attributes target, nil, "[#{target}]"}/>[#{target}])
@@ -599,11 +614,17 @@ module Asciidoctor
599
614
  }).default = [nil, nil, true]
600
615
 
601
616
  def inline_quoted node
602
- if (type = node.type) == :latexmath
603
- %(<inlineequation>
604
- <alt><![CDATA[#{node.text}]]></alt>
605
- <inlinemediaobject><textobject><phrase><![CDATA[#{node.text}]]></phrase></textobject></inlinemediaobject>
606
- </inlineequation>)
617
+ if (type = node.type) == :asciimath
618
+ if ((defined? ::AsciiMath) || ((defined? @asciimath_available) ? @asciimath_available :
619
+ (@asciimath_available = Helpers.require_library 'asciimath', true, :warn)))
620
+ # NOTE fop requires jeuclid to process raw mathml
621
+ %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>)
622
+ else
623
+ %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
624
+ end
625
+ elsif type == :latexmath
626
+ # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
627
+ %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
607
628
  else
608
629
  open, close, supports_phrase = QUOTE_TAGS[type]
609
630
  text = node.text
@@ -656,7 +677,9 @@ module Asciidoctor
656
677
  result = []
657
678
  result << %(<#{info_tag_prefix}info>)
658
679
  result << document_title_tags(doc.doctitle :partition => true, :use_fallback => true) unless doc.notitle
659
- result << %(<date>#{(doc.attr? 'revdate') ? (doc.attr 'revdate') : (doc.attr 'docdate')}</date>)
680
+ if (date = (doc.attr? 'revdate') ? (doc.attr 'revdate') : ((doc.attr? 'reproducible') ? nil : (doc.attr 'docdate')))
681
+ result << %(<date>#{date}</date>)
682
+ end
660
683
  if doc.has_header?
661
684
  if doc.attr? 'author'
662
685
  if (authorcount = (doc.attr 'authorcount').to_i) < 2
@@ -702,7 +725,7 @@ module Asciidoctor
702
725
  end
703
726
 
704
727
  def document_ns_attributes doc
705
- ' xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0"'
728
+ ' xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0"'
706
729
  end
707
730
 
708
731
  def lang_attribute_name