asciidoctor 2.0.10 → 2.0.17

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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +294 -30
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +16 -20
  5. data/README-fr.adoc +15 -22
  6. data/README-jp.adoc +15 -26
  7. data/README-zh_CN.adoc +21 -25
  8. data/README.adoc +161 -138
  9. data/asciidoctor.gemspec +6 -13
  10. data/data/locale/attributes-ar.adoc +4 -3
  11. data/data/locale/attributes-be.adoc +23 -0
  12. data/data/locale/attributes-bg.adoc +4 -3
  13. data/data/locale/attributes-ca.adoc +6 -5
  14. data/data/locale/attributes-cs.adoc +4 -3
  15. data/data/locale/attributes-da.adoc +6 -5
  16. data/data/locale/attributes-de.adoc +4 -4
  17. data/data/locale/attributes-en.adoc +4 -4
  18. data/data/locale/attributes-es.adoc +6 -5
  19. data/data/locale/attributes-fa.adoc +4 -3
  20. data/data/locale/attributes-fi.adoc +4 -3
  21. data/data/locale/attributes-fr.adoc +8 -7
  22. data/data/locale/attributes-hu.adoc +4 -3
  23. data/data/locale/attributes-id.adoc +4 -3
  24. data/data/locale/attributes-it.adoc +6 -5
  25. data/data/locale/attributes-ja.adoc +4 -3
  26. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  27. data/data/locale/attributes-nb.adoc +4 -3
  28. data/data/locale/attributes-nl.adoc +6 -5
  29. data/data/locale/attributes-nn.adoc +4 -3
  30. data/data/locale/attributes-pl.adoc +8 -7
  31. data/data/locale/attributes-pt.adoc +6 -5
  32. data/data/locale/attributes-pt_BR.adoc +6 -5
  33. data/data/locale/attributes-ro.adoc +4 -3
  34. data/data/locale/attributes-ru.adoc +6 -5
  35. data/data/locale/attributes-sr.adoc +4 -4
  36. data/data/locale/attributes-sr_Latn.adoc +4 -4
  37. data/data/locale/attributes-sv.adoc +4 -4
  38. data/data/locale/attributes-th.adoc +23 -0
  39. data/data/locale/attributes-tr.adoc +4 -3
  40. data/data/locale/attributes-uk.adoc +6 -5
  41. data/data/locale/attributes-vi.adoc +23 -0
  42. data/data/locale/attributes-zh_CN.adoc +4 -3
  43. data/data/locale/attributes-zh_TW.adoc +4 -3
  44. data/data/reference/syntax.adoc +14 -7
  45. data/data/stylesheets/asciidoctor-default.css +76 -76
  46. data/data/stylesheets/coderay-asciidoctor.css +9 -9
  47. data/lib/asciidoctor/abstract_block.rb +20 -13
  48. data/lib/asciidoctor/abstract_node.rb +23 -12
  49. data/lib/asciidoctor/attribute_list.rb +64 -72
  50. data/lib/asciidoctor/block.rb +6 -6
  51. data/lib/asciidoctor/cli/invoker.rb +3 -2
  52. data/lib/asciidoctor/cli/options.rb +32 -31
  53. data/lib/asciidoctor/convert.rb +168 -162
  54. data/lib/asciidoctor/converter/docbook5.rb +49 -34
  55. data/lib/asciidoctor/converter/html5.rb +180 -139
  56. data/lib/asciidoctor/converter/manpage.rb +118 -90
  57. data/lib/asciidoctor/converter/template.rb +15 -13
  58. data/lib/asciidoctor/converter.rb +19 -16
  59. data/lib/asciidoctor/core_ext/hash/merge.rb +1 -1
  60. data/lib/asciidoctor/document.rb +77 -86
  61. data/lib/asciidoctor/extensions.rb +22 -16
  62. data/lib/asciidoctor/helpers.rb +20 -15
  63. data/lib/asciidoctor/list.rb +2 -6
  64. data/lib/asciidoctor/load.rb +103 -101
  65. data/lib/asciidoctor/logging.rb +10 -8
  66. data/lib/asciidoctor/parser.rb +211 -220
  67. data/lib/asciidoctor/path_resolver.rb +17 -15
  68. data/lib/asciidoctor/reader.rb +87 -79
  69. data/lib/asciidoctor/rx.rb +9 -7
  70. data/lib/asciidoctor/section.rb +7 -0
  71. data/lib/asciidoctor/substitutors.rb +167 -148
  72. data/lib/asciidoctor/syntax_highlighter/coderay.rb +3 -2
  73. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +13 -5
  74. data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
  75. data/lib/asciidoctor/syntax_highlighter/pygments.rb +19 -11
  76. data/lib/asciidoctor/syntax_highlighter/rouge.rb +35 -20
  77. data/lib/asciidoctor/syntax_highlighter.rb +16 -16
  78. data/lib/asciidoctor/table.rb +70 -43
  79. data/lib/asciidoctor/timings.rb +3 -3
  80. data/lib/asciidoctor/version.rb +1 -1
  81. data/lib/asciidoctor.rb +45 -19
  82. data/man/asciidoctor.1 +29 -31
  83. data/man/asciidoctor.adoc +35 -29
  84. metadata +17 -70
@@ -198,7 +198,7 @@ class Document < AbstractBlock
198
198
  # Public: Get the document catalog Hash
199
199
  attr_reader :catalog
200
200
 
201
- # Public: Alias catalog property as references for backwards compatiblity
201
+ # Public: Alias catalog property as references for backwards compatibility
202
202
  alias references catalog
203
203
 
204
204
  # Public: Get the Hash of document counters
@@ -259,12 +259,14 @@ class Document < AbstractBlock
259
259
  options[:catalog_assets] = true if parent_doc.options[:catalog_assets]
260
260
  @catalog = parent_doc.catalog.merge footnotes: []
261
261
  # QUESTION should we support setting attribute in parent document from nested document?
262
- # NOTE we must dup or else all the assignments to the overrides clobbers the real attributes
263
- @attribute_overrides = attr_overrides = parent_doc.attributes.merge
264
- parent_doctype = attr_overrides.delete 'doctype'
262
+ @attribute_overrides = attr_overrides = (parent_doc.instance_variable_get :@attribute_overrides).merge parent_doc.attributes
265
263
  attr_overrides.delete 'compat-mode'
264
+ parent_doctype = attr_overrides.delete 'doctype'
265
+ attr_overrides.delete 'notitle'
266
+ attr_overrides.delete 'showtitle'
267
+ # QUESTION if toc is hard unset in parent document, should it be hard unset in nested document?
266
268
  attr_overrides.delete 'toc'
267
- attr_overrides.delete 'toc-placement'
269
+ @attributes['toc-placement'] = (attr_overrides.delete 'toc-placement') || 'auto'
268
270
  attr_overrides.delete 'toc-position'
269
271
  @safe = parent_doc.safe
270
272
  @attributes['compat-mode'] = '' if (@compat_mode = parent_doc.compat_mode)
@@ -284,7 +286,6 @@ class Document < AbstractBlock
284
286
  footnotes: [],
285
287
  links: [],
286
288
  images: [],
287
- #indexterms: [],
288
289
  callouts: Callouts.new,
289
290
  includes: {},
290
291
  }
@@ -309,7 +310,7 @@ class Document < AbstractBlock
309
310
  end
310
311
  attr_overrides[key.downcase] = val
311
312
  end
312
- if (to_file = options[:to_file])
313
+ if ::String === (to_file = options[:to_file])
313
314
  attr_overrides['outfilesuffix'] = Helpers.extname to_file
314
315
  end
315
316
  # safely resolve the safe mode from const, int or string
@@ -326,8 +327,8 @@ class Document < AbstractBlock
326
327
  @sourcemap = options[:sourcemap]
327
328
  @timings = options.delete :timings
328
329
  @path_resolver = PathResolver.new
329
- initialize_extensions = (defined? ::Asciidoctor::Extensions) ? true : nil
330
- @extensions = nil # initialize furthur down if initialize_extensions is true
330
+ initialize_extensions = (defined? ::Asciidoctor::Extensions) || (options.key? :extensions) ? ::Asciidoctor::Extensions : nil
331
+ @extensions = nil # initialize further down if initialize_extensions is true
331
332
  options[:standalone] = options[:header_footer] if (options.key? :header_footer) && !(options.key? :standalone)
332
333
  end
333
334
 
@@ -339,61 +340,46 @@ class Document < AbstractBlock
339
340
  (@options = options).freeze
340
341
 
341
342
  attrs = @attributes
342
- #attrs['encoding'] = 'UTF-8'
343
- attrs['sectids'] = ''
344
- attrs['toc-placement'] = 'auto'
343
+ unless parent_doc
344
+ attrs['attribute-undefined'] = Compliance.attribute_undefined
345
+ attrs['attribute-missing'] = Compliance.attribute_missing
346
+ attrs.update DEFAULT_ATTRIBUTES
347
+ # TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc,
348
+ # load attributes from data/locale/attributes-<lang>.adoc
349
+ end
350
+
345
351
  if standalone
346
- attrs['copycss'] = ''
347
352
  # sync embedded attribute with :standalone option value
348
353
  attr_overrides['embedded'] = nil
354
+ attrs['copycss'] = ''
355
+ attrs['iconfont-remote'] = ''
356
+ attrs['stylesheet'] = ''
357
+ attrs['webfonts'] = ''
349
358
  else
350
- attrs['notitle'] = ''
351
359
  # sync embedded attribute with :standalone option value
352
360
  attr_overrides['embedded'] = ''
361
+ if (attr_overrides.key? 'showtitle') && (attr_overrides.keys & %w(notitle showtitle))[-1] == 'showtitle'
362
+ attr_overrides['notitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['showtitle']]
363
+ elsif attr_overrides.key? 'notitle'
364
+ attr_overrides['showtitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['notitle']]
365
+ else
366
+ attrs['notitle'] = ''
367
+ end
353
368
  end
354
- attrs['stylesheet'] = ''
355
- attrs['webfonts'] = ''
356
- attrs['prewrap'] = ''
357
- attrs['attribute-undefined'] = Compliance.attribute_undefined
358
- attrs['attribute-missing'] = Compliance.attribute_missing
359
- attrs['iconfont-remote'] = ''
360
-
361
- # language strings
362
- # TODO load these based on language settings
363
- attrs['caution-caption'] = 'Caution'
364
- attrs['important-caption'] = 'Important'
365
- attrs['note-caption'] = 'Note'
366
- attrs['tip-caption'] = 'Tip'
367
- attrs['warning-caption'] = 'Warning'
368
- attrs['example-caption'] = 'Example'
369
- attrs['figure-caption'] = 'Figure'
370
- #attrs['listing-caption'] = 'Listing'
371
- attrs['table-caption'] = 'Table'
372
- attrs['toc-title'] = 'Table of Contents'
373
- #attrs['preface-title'] = 'Preface'
374
- attrs['section-refsig'] = 'Section'
375
- attrs['part-refsig'] = 'Part'
376
- attrs['chapter-refsig'] = 'Chapter'
377
- attrs['appendix-caption'] = attrs['appendix-refsig'] = 'Appendix'
378
- attrs['untitled-label'] = 'Untitled'
379
- attrs['version-label'] = 'Version'
380
- attrs['last-update-label'] = 'Last updated'
381
369
 
382
370
  attr_overrides['asciidoctor'] = ''
383
371
  attr_overrides['asciidoctor-version'] = ::Asciidoctor::VERSION
384
372
 
385
373
  attr_overrides['safe-mode-name'] = (safe_mode_name = SafeMode.name_for_value @safe)
386
- attr_overrides["safe-mode-#{safe_mode_name}"] = ''
374
+ attr_overrides[%(safe-mode-#{safe_mode_name})] = ''
387
375
  attr_overrides['safe-mode-level'] = @safe
388
376
 
389
- # the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc Python
377
+ # the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc.py
390
378
  attr_overrides['max-include-depth'] ||= 64
391
379
 
392
380
  # the only way to set the allow-uri-read attribute is via the API; disabled by default
393
381
  attr_overrides['allow-uri-read'] ||= nil
394
382
 
395
- attr_overrides['user-home'] = USER_HOME
396
-
397
383
  # remap legacy attribute names
398
384
  attr_overrides['sectnums'] = attr_overrides.delete 'numbered' if attr_overrides.key? 'numbered'
399
385
  attr_overrides['hardbreaks-option'] = attr_overrides.delete 'hardbreaks' if attr_overrides.key? 'hardbreaks'
@@ -412,11 +398,11 @@ class Document < AbstractBlock
412
398
 
413
399
  # allow common attributes backend and doctype to be set using options hash, coerce values to string
414
400
  if (backend_val = options[:backend])
415
- attr_overrides['backend'] = %(#{backend_val})
401
+ attr_overrides['backend'] = backend_val.to_s
416
402
  end
417
403
 
418
404
  if (doctype_val = options[:doctype])
419
- attr_overrides['doctype'] = %(#{doctype_val})
405
+ attr_overrides['doctype'] = doctype_val.to_s
420
406
  end
421
407
 
422
408
  if @safe >= SafeMode::SERVER
@@ -429,7 +415,7 @@ class Document < AbstractBlock
429
415
  attr_overrides['docfile'] = attr_overrides['docfile'][(attr_overrides['docdir'].length + 1)..-1]
430
416
  end
431
417
  attr_overrides['docdir'] = ''
432
- attr_overrides['user-home'] = '.'
418
+ attr_overrides['user-home'] ||= '.'
433
419
  if @safe >= SafeMode::SECURE
434
420
  attr_overrides['max-attribute-value-size'] = 4096 unless attr_overrides.key? 'max-attribute-value-size'
435
421
  # assign linkcss (preventing css embedding) unless explicitly disabled from the commandline or API
@@ -438,6 +424,8 @@ class Document < AbstractBlock
438
424
  # restrict document from enabling icons
439
425
  attr_overrides['icons'] ||= nil
440
426
  end
427
+ else
428
+ attr_overrides['user-home'] ||= USER_HOME
441
429
  end
442
430
 
443
431
  # the only way to set the max-attribute-value-size attribute is via the API; disabled by default
@@ -505,10 +493,10 @@ class Document < AbstractBlock
505
493
  ::AsciidoctorJ::Extensions::ExtensionRegistry === ext_registry)
506
494
  @extensions = ext_registry.activate self
507
495
  end
508
- elsif ::Proc === (ext_block = options[:extensions])
496
+ elsif (ext_block = options[:extensions]).nil?
497
+ @extensions = Extensions::Registry.new.activate self unless Extensions.groups.empty?
498
+ elsif ::Proc === ext_block
509
499
  @extensions = Extensions.create(&ext_block).activate self
510
- elsif !Extensions.groups.empty?
511
- @extensions = Extensions::Registry.new.activate self
512
500
  end
513
501
  end
514
502
 
@@ -577,13 +565,15 @@ class Document < AbstractBlock
577
565
  # returns the next number in the sequence for the specified counter
578
566
  def counter name, seed = nil
579
567
  return @parent_document.counter name, seed if @parent_document
580
- if (attr_seed = !(attr_val = @attributes[name]).nil_or_empty?) && (@counters.key? name)
581
- @attributes[name] = @counters[name] = Helpers.nextval attr_val
568
+ if ((locked = attribute_locked? name) && (curr_val = @counters[name])) || !(curr_val = @attributes[name]).nil_or_empty?
569
+ next_val = @counters[name] = Helpers.nextval curr_val
582
570
  elsif seed
583
- @attributes[name] = @counters[name] = seed == seed.to_i.to_s ? seed.to_i : seed
571
+ next_val = @counters[name] = seed == seed.to_i.to_s ? seed.to_i : seed
584
572
  else
585
- @attributes[name] = @counters[name] = Helpers.nextval attr_seed ? attr_val : 0
573
+ next_val = @counters[name] = 1
586
574
  end
575
+ @attributes[name] = next_val unless locked
576
+ next_val
587
577
  end
588
578
 
589
579
  # Public: Increment the specified counter and store it in the block's attributes
@@ -625,15 +615,29 @@ class Document < AbstractBlock
625
615
  # @reftexts is set eagerly to prevent nested lazy init
626
616
  (@reftexts = {}).tap {|accum| @catalog[:refs].each {|id, ref| accum[ref.xreftext] ||= id } }[text]
627
617
  else
628
- # @reftexts is set eagerly to prevent nested lazy init
629
618
  resolved_id = nil
630
- # NOTE short-circuit early since we're throwing away this table
631
- (@reftexts = {}).tap {|accum| @catalog[:refs].each {|id, ref| (xreftext = ref.xreftext) == text ? (break (resolved_id = id)) : (accum[xreftext] ||= id) } }
619
+ # @reftexts is set eagerly to prevent nested lazy init
620
+ @reftexts = accum = {}
621
+ @catalog[:refs].each do |id, ref|
622
+ # NOTE short-circuit early since we're throwing away this table anyway
623
+ if (xreftext = ref.xreftext) == text
624
+ resolved_id = id
625
+ break
626
+ end
627
+ accum[xreftext] ||= id
628
+ end
632
629
  @reftexts = nil
633
630
  resolved_id
634
631
  end
635
632
  end
636
633
 
634
+ # Public: Check whether this Document has any child Section objects.
635
+ #
636
+ # Returns A [Boolean] to indicate whether this Document has child Section objects
637
+ def sections?
638
+ @next_section_index > 0
639
+ end
640
+
637
641
  def footnotes?
638
642
  @catalog[:footnotes].empty? ? false : true
639
643
  end
@@ -686,7 +690,7 @@ class Document < AbstractBlock
686
690
  #
687
691
  # title - the String title to assign as the title of the document header
688
692
  #
689
- # Returns the new [String] title assigned to the document header
693
+ # Returns the specified [String] title
690
694
  def title= title
691
695
  unless (sect = @header)
692
696
  (sect = (@header = Section.new self, 0)).sectname = 'header'
@@ -772,7 +776,7 @@ class Document < AbstractBlock
772
776
  end
773
777
 
774
778
  def notitle
775
- !@attributes.key?('showtitle') && @attributes.key?('notitle')
779
+ @attributes.key? 'notitle'
776
780
  end
777
781
 
778
782
  def noheader
@@ -968,8 +972,14 @@ class Document < AbstractBlock
968
972
 
969
973
  # Public: Write the output to the specified file
970
974
  #
971
- # If the converter responds to :write, delegate the work of writing the file
972
- # to that method. Otherwise, write the output the specified file.
975
+ # If the converter responds to :write, delegate the work of writing the output
976
+ # to that method. Otherwise, write the output to the specified file. In the
977
+ # latter case, this method ensures the output has a trailing newline if the
978
+ # target responds to write and the output is not empty.
979
+ #
980
+ # output - The output to write. Unless the converter responds to write, this
981
+ # object is expected to be a String.
982
+ # target - The file to write, either a File object or a String path.
973
983
  #
974
984
  # Returns nothing
975
985
  def write output, target
@@ -995,25 +1005,6 @@ class Document < AbstractBlock
995
1005
  nil
996
1006
  end
997
1007
 
998
- =begin
999
- def convert_to target, opts = {}
1000
- start = ::Time.now.to_f if (monitor = opts[:monitor])
1001
- output = (r = converter opts).convert
1002
- monitor[:convert] = ::Time.now.to_f - start if monitor
1003
-
1004
- unless target.respond_to? :write
1005
- @attributes['outfile'] = target = ::File.expand_path target
1006
- @attributes['outdir'] = ::File.dirname target
1007
- end
1008
-
1009
- start = ::Time.now.to_f if monitor
1010
- r.write output, target
1011
- monitor[:write] = ::Time.now.to_f - start if monitor
1012
-
1013
- output
1014
- end
1015
- =end
1016
-
1017
1008
  def content
1018
1009
  # NOTE per AsciiDoc-spec, remove the title before converting the body
1019
1010
  @attributes.delete('title')
@@ -1035,7 +1026,7 @@ class Document < AbstractBlock
1035
1026
  def docinfo location = :head, suffix = nil
1036
1027
  if safe < SafeMode::SECURE
1037
1028
  qualifier = %(-#{location}) unless location == :head
1038
- suffix = @outfilesuffix unless suffix
1029
+ suffix ||= @outfilesuffix
1039
1030
 
1040
1031
  if (docinfo = @attributes['docinfo']).nil_or_empty?
1041
1032
  if @attributes.key? 'docinfo2'
@@ -1092,7 +1083,7 @@ class Document < AbstractBlock
1092
1083
  end
1093
1084
 
1094
1085
  def to_s
1095
- %(#<#{self.class}@#{object_id} {doctype: #{doctype.inspect}, doctitle: #{(@header != nil ? @header.title : nil).inspect}, blocks: #{@blocks.size}}>)
1086
+ %(#<#{self.class}@#{object_id} {doctype: #{doctype.inspect}, doctitle: #{(@header && @header.title).inspect}, blocks: #{@blocks.size}}>)
1096
1087
  end
1097
1088
 
1098
1089
  private
@@ -1221,8 +1212,8 @@ class Document < AbstractBlock
1221
1212
  end
1222
1213
  end
1223
1214
 
1224
- if (@compat_mode = attrs.key? 'compat-mode')
1225
- attrs['source-language'] = attrs['language'] if attrs.key? 'language'
1215
+ if (@compat_mode = attrs.key? 'compat-mode') && (attrs.key? 'language')
1216
+ attrs['source-language'] = attrs['language']
1226
1217
  end
1227
1218
 
1228
1219
  unless @parent_document
@@ -1395,7 +1386,7 @@ class Document < AbstractBlock
1395
1386
  attrs[%(basebackend-#{current_basebackend}-doctype-#{new_doctype})] = '' if current_basebackend
1396
1387
  end
1397
1388
  attrs[%(doctype-#{new_doctype})] = ''
1398
- return @doctype = attrs['doctype'] = new_doctype
1389
+ @doctype = attrs['doctype'] = new_doctype
1399
1390
  end
1400
1391
  end
1401
1392
  end
@@ -134,14 +134,14 @@ module Extensions
134
134
  if opts.fetch :numbered, (style == 'appendix')
135
135
  sect.numbered = true
136
136
  elsif !(opts.key? :numbered) && (doc.attr? 'sectnums', 'all')
137
- sect.numbered = book && level == 1 ? :chapter : true
137
+ sect.numbered = (book && level == 1 ? :chapter : true)
138
138
  end
139
139
  elsif level > 0
140
140
  if opts.fetch :numbered, (doc.attr? 'sectnums')
141
141
  sect.numbered = sect.special ? parent.numbered && true : true
142
142
  end
143
- else
144
- sect.numbered = true if opts.fetch :numbered, (book && (doc.attr? 'partnums'))
143
+ elsif opts.fetch :numbered, (book && (doc.attr? 'partnums'))
144
+ sect.numbered = true
145
145
  end
146
146
  if (id = attrs['id']) == false
147
147
  attrs.delete 'id'
@@ -229,7 +229,7 @@ module Extensions
229
229
  def parse_attributes block, attrlist, opts = {}
230
230
  return {} if attrlist ? attrlist.empty? : true
231
231
  attrlist = block.sub_attributes attrlist if opts[:sub_attributes] && (attrlist.include? ATTR_REF_HEAD)
232
- (AttributeList.new attrlist).parse (opts[:positional_attributes] || [])
232
+ (AttributeList.new attrlist).parse opts[:positional_attributes] || []
233
233
  end
234
234
 
235
235
  # TODO fill out remaining methods
@@ -425,7 +425,7 @@ module Extensions
425
425
  # TIP: Postprocessors can also be used to relocate assets needed by the published
426
426
  # document.
427
427
  #
428
- # Postprocessor implementations must Postprocessor.
428
+ # Postprocessor implementations must extend Postprocessor.
429
429
  class Postprocessor < Processor
430
430
  def process document, output
431
431
  raise ::NotImplementedError, %(#{Postprocessor} subclass #{self.class} must implement the ##{__method__} method)
@@ -511,6 +511,10 @@ module Extensions
511
511
  # registered to handle this name and, if found, invokes its {Processor#process}
512
512
  # method to build a corresponding node in the document tree.
513
513
  #
514
+ # If the process method returns an instance of Block, the content model of that
515
+ # Block is :compound, and the Block contains at least one line, the parser will
516
+ # parse those lines into blocks an assigned them to the returned block.
517
+ #
514
518
  # AsciiDoc example:
515
519
  #
516
520
  # [shout]
@@ -594,6 +598,10 @@ module Extensions
594
598
  # Public: BlockMacroProcessors are used to handle block macros that have a
595
599
  # custom name.
596
600
  #
601
+ # If the process method returns an instance of Block, the content model of that
602
+ # Block is :compound, and the Block contains at least one line, the parser will
603
+ # parse those lines into blocks an assigned them to the returned block.
604
+ #
597
605
  # BlockMacroProcessor implementations must extend BlockMacroProcessor.
598
606
  class BlockMacroProcessor < MacroProcessor
599
607
  def name
@@ -610,7 +618,7 @@ module Extensions
610
618
  #--
611
619
  # TODO break this out into different pattern types
612
620
  # for example, FullInlineMacro, ShortInlineMacro (no target) and other patterns
613
- # FIXME for inline passthrough, we need to have some way to specify the text as a passthrough
621
+ # FIXME for inline macro, we need to have some way to specify the text as a passthrough
614
622
  class InlineMacroProcessor < MacroProcessor
615
623
  @@rx_cache = {}
616
624
 
@@ -666,7 +674,7 @@ module Extensions
666
674
 
667
675
  # Public: A specialization of the Extension proxy that additionally stores a
668
676
  # reference to the {Processor#process} method. By storing this reference, its
669
- # possible to accomodate both concrete extension implementations and Procs.
677
+ # possible to accommodate both concrete extension implementations and Procs.
670
678
  class ProcessorExtension < Extension
671
679
  attr_reader :process_method
672
680
 
@@ -954,7 +962,7 @@ module Extensions
954
962
  end
955
963
 
956
964
  # Public: Registers an {DocinfoProcessor} with the extension registry to
957
- # add additionnal docinfo to the document.
965
+ # add additional docinfo to the document.
958
966
  #
959
967
  # The DocinfoProcessor may be one of four types:
960
968
  #
@@ -1021,8 +1029,6 @@ module Extensions
1021
1029
  else
1022
1030
  @docinfo_processor_extensions
1023
1031
  end
1024
- else
1025
- nil
1026
1032
  end
1027
1033
  end
1028
1034
 
@@ -1201,7 +1207,7 @@ module Extensions
1201
1207
  # name - the String or Symbol (coersed to a Symbol) macro name
1202
1208
  #
1203
1209
  # Returns the [Extension] object stored in the registry that proxies the
1204
- # cooresponding BlockMacroProcessor or nil if a match is not found.
1210
+ # corresponding BlockMacroProcessor or nil if a match is not found.
1205
1211
  def find_block_macro_extension name
1206
1212
  @block_macro_extensions[name.to_sym]
1207
1213
  end
@@ -1288,7 +1294,7 @@ module Extensions
1288
1294
  # name - the String or Symbol (coersed to a Symbol) macro name
1289
1295
  #
1290
1296
  # Returns the [Extension] object stored in the registry that proxies the
1291
- # cooresponding InlineMacroProcessor or nil if a match is not found.
1297
+ # corresponding InlineMacroProcessor or nil if a match is not found.
1292
1298
  def find_inline_macro_extension name
1293
1299
  @inline_macro_extensions[name.to_sym]
1294
1300
  end
@@ -1330,7 +1336,7 @@ module Extensions
1330
1336
  kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
1331
1337
  kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, [])
1332
1338
  # style 1: specified as block
1333
- extension = if block_given?
1339
+ if block_given?
1334
1340
  config = resolve_args args, 1
1335
1341
  (processor = kind_class.new config).singleton_class.enable_dsl
1336
1342
  if block.arity == 0
@@ -1342,7 +1348,7 @@ module Extensions
1342
1348
  raise ::ArgumentError, %(No block specified to process #{kind_name} extension at #{block.source_location})
1343
1349
  end
1344
1350
  processor.freeze
1345
- ProcessorExtension.new kind, processor
1351
+ extension = ProcessorExtension.new kind, processor
1346
1352
  else
1347
1353
  processor, config = resolve_args args, 2
1348
1354
  # style 2: specified as Class or String class name
@@ -1352,12 +1358,12 @@ module Extensions
1352
1358
  end
1353
1359
  processor_instance = processor_class.new config
1354
1360
  processor_instance.freeze
1355
- ProcessorExtension.new kind, processor_instance
1361
+ extension = ProcessorExtension.new kind, processor_instance
1356
1362
  # style 3: specified as instance
1357
1363
  elsif kind_class === processor || (kind_java_class && kind_java_class === processor)
1358
1364
  processor.update_config config
1359
1365
  processor.freeze
1360
- ProcessorExtension.new kind, processor
1366
+ extension = ProcessorExtension.new kind, processor
1361
1367
  else
1362
1368
  raise ::ArgumentError, %(Invalid arguments specified for registering #{kind_name} extension: #{args})
1363
1369
  end
@@ -56,25 +56,27 @@ module Helpers
56
56
  # If a BOM is found at the beginning of the data, a best attempt is made to
57
57
  # encode it to UTF-8 from the specified source encoding.
58
58
  #
59
- # data - the source data Array to prepare (no nil entries allowed)
59
+ # data - the source data Array to prepare (no nil entries allowed)
60
+ # trim_end - whether to trim whitespace from the end of each line;
61
+ # (true cleans all whitespace; false only removes trailing newline) (default: true)
60
62
  #
61
63
  # returns a String Array of prepared lines
62
- def prepare_source_array data
64
+ def prepare_source_array data, trim_end = true
63
65
  return [] if data.empty?
64
66
  if (leading_2_bytes = (leading_bytes = (first = data[0]).unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
65
67
  data[0] = first.byteslice 2, first.bytesize
66
68
  # NOTE you can't split a UTF-16LE string using .lines when encoding is UTF-8; doing so will cause this line to fail
67
- return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).rstrip }
69
+ return trim_end ? data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).rstrip } : data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).chomp }
68
70
  elsif leading_2_bytes == BOM_BYTES_UTF_16BE
69
71
  data[0] = first.byteslice 2, first.bytesize
70
- return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).rstrip }
72
+ return trim_end ? data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).rstrip } : data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).chomp }
71
73
  elsif leading_bytes == BOM_BYTES_UTF_8
72
74
  data[0] = first.byteslice 3, first.bytesize
73
75
  end
74
76
  if first.encoding == UTF_8
75
- data.map {|line| line.rstrip }
77
+ trim_end ? data.map {|line| line.rstrip } : data.map {|line| line.chomp }
76
78
  else
77
- data.map {|line| (line.encode UTF_8).rstrip }
79
+ trim_end ? data.map {|line| (line.encode UTF_8).rstrip } : data.map {|line| (line.encode UTF_8).chomp }
78
80
  end
79
81
  end
80
82
 
@@ -86,10 +88,12 @@ module Helpers
86
88
  # If a BOM is found at the beginning of the data, a best attempt is made to
87
89
  # encode it to UTF-8 from the specified source encoding.
88
90
  #
89
- # data - the source data String to prepare
91
+ # data - the source data String to prepare
92
+ # trim_end - whether to trim whitespace from the end of each line;
93
+ # (true cleans all whitespace; false only removes trailing newline) (default: true)
90
94
  #
91
95
  # returns a String Array of prepared lines
92
- def prepare_source_string data
96
+ def prepare_source_string data, trim_end = true
93
97
  return [] if data.nil_or_empty?
94
98
  if (leading_2_bytes = (leading_bytes = data.unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
95
99
  data = (data.byteslice 2, data.bytesize).encode UTF_8, ::Encoding::UTF_16LE
@@ -101,7 +105,11 @@ module Helpers
101
105
  elsif data.encoding != UTF_8
102
106
  data = data.encode UTF_8
103
107
  end
104
- [].tap {|lines| data.each_line {|line| lines << line.rstrip } }
108
+ if trim_end
109
+ [].tap {|lines| data.each_line {|line| lines << line.rstrip } }
110
+ else
111
+ [].tap {|lines| data.each_line {|line| lines << line.chomp } }
112
+ end
105
113
  end
106
114
 
107
115
  # Internal: Efficiently checks whether the specified String resembles a URI
@@ -266,13 +274,10 @@ module Helpers
266
274
  def nextval current
267
275
  if ::Integer === current
268
276
  current + 1
277
+ elsif (intval = current.to_i).to_s == current.to_s
278
+ intval + 1
269
279
  else
270
- intval = current.to_i
271
- if intval.to_s != current.to_s
272
- (current[0].ord + 1).chr
273
- else
274
- intval + 1
275
- end
280
+ current.succ
276
281
  end
277
282
  end
278
283
 
@@ -80,12 +80,8 @@ class ListItem < AbstractBlock
80
80
  @text && (apply_subs @text, @subs)
81
81
  end
82
82
 
83
- # Public: Set the String text.
84
- #
85
- # Returns the new String text assigned to this ListItem
86
- def text= val
87
- @text = val
88
- end
83
+ # Public: Set the String text assigned to this ListItem
84
+ attr_writer :text
89
85
 
90
86
  # Check whether this list item has simple content (no nested blocks aside from a single outline list).
91
87
  # Primarily relevant for outline lists.