asciidoctor 2.0.10 → 2.0.17

Sign up to get free protection for your applications and to get access to all the features.
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.