asciidoctor 2.0.12 → 2.0.16

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +142 -22
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +15 -6
  5. data/README-fr.adoc +14 -8
  6. data/README-jp.adoc +15 -6
  7. data/README-zh_CN.adoc +14 -5
  8. data/README.adoc +135 -125
  9. data/asciidoctor.gemspec +4 -11
  10. data/data/locale/attributes-be.adoc +23 -0
  11. data/data/locale/attributes-it.adoc +4 -4
  12. data/data/locale/attributes-nl.adoc +6 -6
  13. data/data/locale/attributes-th.adoc +23 -0
  14. data/data/locale/attributes-vi.adoc +23 -0
  15. data/data/reference/syntax.adoc +14 -7
  16. data/data/stylesheets/asciidoctor-default.css +51 -52
  17. data/lib/asciidoctor.rb +12 -12
  18. data/lib/asciidoctor/abstract_block.rb +4 -4
  19. data/lib/asciidoctor/abstract_node.rb +10 -9
  20. data/lib/asciidoctor/attribute_list.rb +6 -6
  21. data/lib/asciidoctor/block.rb +6 -6
  22. data/lib/asciidoctor/cli/invoker.rb +0 -1
  23. data/lib/asciidoctor/cli/options.rb +27 -26
  24. data/lib/asciidoctor/convert.rb +1 -0
  25. data/lib/asciidoctor/converter.rb +5 -3
  26. data/lib/asciidoctor/converter/docbook5.rb +45 -26
  27. data/lib/asciidoctor/converter/html5.rb +89 -69
  28. data/lib/asciidoctor/converter/manpage.rb +113 -86
  29. data/lib/asciidoctor/converter/template.rb +11 -12
  30. data/lib/asciidoctor/document.rb +44 -51
  31. data/lib/asciidoctor/extensions.rb +10 -12
  32. data/lib/asciidoctor/helpers.rb +3 -6
  33. data/lib/asciidoctor/list.rb +2 -6
  34. data/lib/asciidoctor/load.rb +13 -11
  35. data/lib/asciidoctor/logging.rb +10 -8
  36. data/lib/asciidoctor/parser.rb +135 -150
  37. data/lib/asciidoctor/path_resolver.rb +3 -3
  38. data/lib/asciidoctor/reader.rb +72 -71
  39. data/lib/asciidoctor/rx.rb +4 -3
  40. data/lib/asciidoctor/substitutors.rb +117 -117
  41. data/lib/asciidoctor/syntax_highlighter.rb +8 -11
  42. data/lib/asciidoctor/syntax_highlighter/coderay.rb +2 -1
  43. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +1 -1
  44. data/lib/asciidoctor/syntax_highlighter/pygments.rb +6 -5
  45. data/lib/asciidoctor/syntax_highlighter/rouge.rb +33 -26
  46. data/lib/asciidoctor/table.rb +17 -19
  47. data/lib/asciidoctor/timings.rb +3 -3
  48. data/lib/asciidoctor/version.rb +1 -1
  49. data/man/asciidoctor.1 +10 -11
  50. data/man/asciidoctor.adoc +8 -7
  51. metadata +14 -67
@@ -20,10 +20,10 @@ class Logger < ::Logger
20
20
  end
21
21
 
22
22
  class BasicFormatter < Formatter
23
- SEVERITY_LABELS = { 'WARN' => 'WARNING', 'FATAL' => 'FAILED' }
23
+ SEVERITY_LABEL_SUBSTITUTES = { 'WARN' => 'WARNING', 'FATAL' => 'FAILED' }
24
24
 
25
25
  def call severity, _, progname, msg
26
- %(#{progname}: #{SEVERITY_LABELS[severity] || severity}: #{::String === msg ? msg : msg.inspect}#{LF})
26
+ %(#{progname}: #{SEVERITY_LABEL_SUBSTITUTES[severity] || severity}: #{::String === msg ? msg : msg.inspect}#{LF})
27
27
  end
28
28
  end
29
29
 
@@ -35,7 +35,7 @@ class Logger < ::Logger
35
35
  end
36
36
 
37
37
  class MemoryLogger < ::Logger
38
- SEVERITY_LABELS = {}.tap {|accum| (Severity.constants false).each {|c| accum[Severity.const_get c, false] = c } }
38
+ SEVERITY_SYMBOL_BY_VALUE = (Severity.constants false).map {|c| [(Severity.const_get c), c] }.to_h
39
39
 
40
40
  attr_reader :messages
41
41
 
@@ -45,8 +45,8 @@ class MemoryLogger < ::Logger
45
45
  end
46
46
 
47
47
  def add severity, message = nil, progname = nil
48
- message = block_given? ? yield : progname unless message
49
- @messages << { severity: SEVERITY_LABELS[severity || UNKNOWN], message: message }
48
+ message ||= block_given? ? yield : progname
49
+ @messages << { severity: SEVERITY_SYMBOL_BY_VALUE[severity || UNKNOWN], message: message }
50
50
  true
51
51
  end
52
52
 
@@ -59,7 +59,7 @@ class MemoryLogger < ::Logger
59
59
  end
60
60
 
61
61
  def max_severity
62
- empty? ? nil : @messages.map {|m| Severity.const_get m[:severity], false }.max
62
+ empty? ? nil : @messages.map {|m| Severity.const_get m[:severity] }.max
63
63
  end
64
64
  end
65
65
 
@@ -89,6 +89,7 @@ module LoggerManager
89
89
  @logger ||= (@logger_class.new pipe)
90
90
  end
91
91
 
92
+ # Returns the specified Logger
92
93
  def logger= new_logger
93
94
  @logger = new_logger || (@logger_class.new $stderr)
94
95
  end
@@ -110,9 +111,10 @@ module Logging
110
111
  # into - The Class that includes the {Logging} module
111
112
  #
112
113
  # Returns nothing
113
- private_class_method def self.included into
114
+ def self.included into
114
115
  into.extend Logging
115
- end || :included
116
+ end
117
+ private_class_method :included # use separate declaration for Ruby 2.0.x
116
118
 
117
119
  def logger
118
120
  LoggerManager.logger
@@ -119,7 +119,7 @@ class Parser
119
119
  # returns the Hash of orphan block attributes captured above the header
120
120
  def self.parse_document_header(reader, document)
121
121
  # capture lines of block-level metadata and plow away comment lines that precede first block
122
- block_attrs = parse_block_metadata_lines reader, document
122
+ block_attrs = reader.skip_blank_lines ? (parse_block_metadata_lines reader, document) : {}
123
123
  doc_attrs = document.attributes
124
124
 
125
125
  # special case, block title is not allowed above document title,
@@ -144,7 +144,10 @@ class Parser
144
144
  l0_section_title = nil
145
145
  else
146
146
  document.title = l0_section_title
147
- doc_attrs['doctitle'] = doctitle_attr_val = document.apply_header_subs l0_section_title
147
+ if (doc_attrs['doctitle'] = doctitle_attr_val = document.sub_specialchars l0_section_title).include? ATTR_REF_HEAD
148
+ # QUESTION should we defer substituting attributes until the end of the header? or should we substitute again if necessary?
149
+ doc_attrs['doctitle'] = doctitle_attr_val = document.sub_attributes doctitle_attr_val, attribute_missing: 'skip'
150
+ end
148
151
  end
149
152
  document.header.source_location = source_location if source_location
150
153
  # default to compat-mode if document has setext doctitle
@@ -215,9 +218,6 @@ class Parser
215
218
  name_section = initialize_section reader, document, {}
216
219
  name_section_buffer = (reader.read_lines_until break_on_blank_lines: true, skip_line_comments: true).map {|l| l.lstrip }.join ' '
217
220
  if ManpageNamePurposeRx =~ name_section_buffer
218
- doc_attrs['manname-title'] ||= name_section.title
219
- doc_attrs['manname-id'] = name_section.id if name_section.id
220
- doc_attrs['manpurpose'] = $2
221
221
  if (manname = $1).include? ATTR_REF_HEAD
222
222
  manname = document.sub_attributes manname
223
223
  end
@@ -226,8 +226,14 @@ class Parser
226
226
  else
227
227
  mannames = [manname]
228
228
  end
229
+ if (manpurpose = $2).include? ATTR_REF_HEAD
230
+ manpurpose = document.sub_attributes manpurpose
231
+ end
232
+ doc_attrs['manname-title'] ||= name_section.title
233
+ doc_attrs['manname-id'] = name_section.id if name_section.id
229
234
  doc_attrs['manname'] = manname
230
235
  doc_attrs['mannames'] = mannames
236
+ doc_attrs['manpurpose'] = manpurpose
231
237
  if document.backend == 'manpage'
232
238
  doc_attrs['docname'] = manname
233
239
  doc_attrs['outfilesuffix'] = %(.#{manvolnum})
@@ -327,7 +333,7 @@ class Parser
327
333
  if current_level == 0
328
334
  part = book
329
335
  elsif current_level == 1 && section.special
330
- # NOTE technically preface and abstract sections are only permitted in the book doctype
336
+ # NOTE technically preface sections are only permitted in the book doctype
331
337
  unless (sectname = section.sectname) == 'appendix' || sectname == 'preface' || sectname == 'abstract'
332
338
  expected_next_level = nil
333
339
  end
@@ -415,9 +421,6 @@ class Parser
415
421
 
416
422
  (intro || section).blocks << new_block
417
423
  attributes.clear
418
- #else
419
- # # don't clear attributes if we don't find a block because they may
420
- # # be trailing attributes that didn't get associated with a block
421
424
  end
422
425
  end
423
426
 
@@ -452,7 +455,7 @@ class Parser
452
455
  # of a section that need to get transfered to the next section
453
456
  # see "trailing block attributes transfer to the following section" in
454
457
  # test/attributes_test.rb for an example
455
- [section != parent ? section : nil, attributes.merge]
458
+ [section == parent ? nil : section, attributes.merge]
456
459
  end
457
460
 
458
461
  # Public: Parse and return the next Block at the Reader's current location
@@ -820,8 +823,8 @@ class Parser
820
823
  if comma_idx > 0
821
824
  language = (language.slice 0, comma_idx).strip
822
825
  attributes['linenums'] = '' if comma_idx < ll - 4
823
- else
824
- attributes['linenums'] = '' if ll > 4
826
+ elsif ll > 4
827
+ attributes['linenums'] = ''
825
828
  end
826
829
  else
827
830
  language = language.lstrip
@@ -902,9 +905,7 @@ class Parser
902
905
  # FIXME title and caption should be assigned when block is constructed (though we need to handle all cases)
903
906
  if attributes['title']
904
907
  block.title = block_title = attributes.delete 'title'
905
- if (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[block.context]) && document.attributes[caption_attr_name]
906
- block.assign_caption (attributes.delete 'caption')
907
- end
908
+ block.assign_caption attributes.delete 'caption' if CAPTION_ATTRIBUTE_NAMES[block.context]
908
909
  end
909
910
  # TODO eventually remove the style attribute from the attributes hash
910
911
  #block.style = attributes.delete 'style'
@@ -966,17 +967,12 @@ class Parser
966
967
  # special case for fenced code blocks
967
968
  if Compliance.markdown_syntax && (tip.start_with? '`')
968
969
  if tip_len == 4
969
- if tip == '````'
970
- return
971
- elsif (tip = tip.chop) == '```'
972
- line = tip
973
- line_len = tip_len = 3
974
- else
970
+ if tip == '````' || (tip = tip.chop) != '```'
975
971
  return
976
972
  end
977
- elsif tip == '```'
978
- # keep it
979
- else
973
+ line = tip
974
+ line_len = tip_len = 3
975
+ elsif tip != '```'
980
976
  return
981
977
  end
982
978
  elsif tip_len == 3
@@ -994,9 +990,10 @@ class Parser
994
990
  # if terminator is false, that means the all the lines in the reader should be parsed
995
991
  # NOTE could invoke filter in here, before and after parsing
996
992
  def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
997
- if content_model == :skip
993
+ case content_model
994
+ when :skip
998
995
  skip_processing, parse_as_content_model = true, :simple
999
- elsif content_model == :raw
996
+ when :raw
1000
997
  skip_processing, parse_as_content_model = false, :simple
1001
998
  else
1002
999
  skip_processing, parse_as_content_model = false, content_model
@@ -1025,14 +1022,15 @@ class Parser
1025
1022
  block_reader = Reader.new reader.read_lines_until(terminator: terminator, skip_processing: skip_processing, context: block_context, cursor: :at_mark), block_cursor
1026
1023
  end
1027
1024
 
1028
- if content_model == :verbatim
1025
+ case content_model
1026
+ when :verbatim
1029
1027
  tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i
1030
1028
  if (indent = attributes['indent'])
1031
1029
  adjust_indentation! lines, indent.to_i, tab_size
1032
1030
  elsif tab_size > 0
1033
1031
  adjust_indentation! lines, -1, tab_size
1034
1032
  end
1035
- elsif content_model == :skip
1033
+ when :skip
1036
1034
  # QUESTION should we still invoke process method if extension is specified?
1037
1035
  return
1038
1036
  end
@@ -1293,7 +1291,8 @@ class Parser
1293
1291
  has_text = true
1294
1292
  list_item = ListItem.new(list_block, (item_text = match[2]))
1295
1293
  list_item.source_location = reader.cursor if list_block.document.sourcemap
1296
- if list_type == :ulist
1294
+ case list_type
1295
+ when :ulist
1297
1296
  list_item.marker = sibling_trait
1298
1297
  if item_text.start_with?('[')
1299
1298
  if style && style == 'bibliography'
@@ -1311,13 +1310,13 @@ class Parser
1311
1310
  list_item.text = item_text.slice(4, item_text.length)
1312
1311
  end
1313
1312
  end
1314
- elsif list_type == :olist
1313
+ when :olist
1315
1314
  sibling_trait, implicit_style = resolve_ordered_list_marker(sibling_trait, (ordinal = list_block.items.size), true, reader)
1316
1315
  list_item.marker = sibling_trait
1317
1316
  if ordinal == 0 && !style
1318
1317
  # using list level makes more sense, but we don't track it
1319
- # basing style on marker level is compliant with AsciiDoc Python
1320
- list_block.style = implicit_style || ((ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s)
1318
+ # basing style on marker level is compliant with AsciiDoc.py
1319
+ list_block.style = implicit_style || (ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s
1321
1320
  end
1322
1321
  if item_text.start_with?('[[') && LeadingInlineAnchorRx =~ item_text
1323
1322
  catalog_inline_anchor $1, $2, list_item, reader
@@ -1443,95 +1442,89 @@ class Parser
1443
1442
  # FIXME to be AsciiDoc compliant, we shouldn't break if style in attribute line is "literal" (i.e., [literal])
1444
1443
  elsif dlist && continuation != :active && (BlockAttributeLineRx.match? this_line)
1445
1444
  break
1446
- else
1447
- if continuation == :active && !this_line.empty?
1448
- # literal paragraphs have special considerations (and this is one of
1449
- # two entry points into one)
1450
- # if we don't process it as a whole, then a line in it that looks like a
1451
- # list item will throw off the exit from it
1452
- if LiteralParagraphRx.match? this_line
1453
- reader.unshift_line this_line
1454
- if dlist
1455
- # we may be in an indented list disguised as a literal paragraph
1456
- # so we need to make sure we don't slurp up a legitimate sibling
1457
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
1458
- else
1459
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1460
- end
1461
- continuation = :inactive
1462
- # let block metadata play out until we find the block
1463
- elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
1464
- buffer << this_line
1445
+ elsif continuation == :active && !this_line.empty?
1446
+ # literal paragraphs have special considerations (and this is one of
1447
+ # two entry points into one)
1448
+ # if we don't process it as a whole, then a line in it that looks like a
1449
+ # list item will throw off the exit from it
1450
+ if LiteralParagraphRx.match? this_line
1451
+ reader.unshift_line this_line
1452
+ if dlist
1453
+ # we may be in an indented list disguised as a literal paragraph
1454
+ # so we need to make sure we don't slurp up a legitimate sibling
1455
+ buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
1465
1456
  else
1466
- if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx].match? this_line }
1467
- within_nested_list = true
1468
- if nested_list_type == :dlist && $3.nil_or_empty?
1469
- # get greedy again
1470
- has_text = false
1471
- end
1472
- end
1473
- buffer << this_line
1474
- continuation = :inactive
1457
+ buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1475
1458
  end
1476
- elsif prev_line && prev_line.empty?
1477
- # advance to the next line of content
1478
- if this_line.empty?
1479
- # stop reading if we reach eof
1480
- break unless (this_line = reader.skip_blank_lines && reader.read_line)
1481
- # stop reading if we hit a sibling list item
1482
- break if is_sibling_list_item? this_line, list_type, sibling_trait
1459
+ continuation = :inactive
1460
+ # let block metadata play out until we find the block
1461
+ elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
1462
+ buffer << this_line
1463
+ else
1464
+ if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx].match? this_line })
1465
+ within_nested_list = true
1466
+ if nested_list_type == :dlist && $3.nil_or_empty?
1467
+ # get greedy again
1468
+ has_text = false
1469
+ end
1483
1470
  end
1471
+ buffer << this_line
1472
+ continuation = :inactive
1473
+ end
1474
+ elsif prev_line && prev_line.empty?
1475
+ # advance to the next line of content
1476
+ if this_line.empty?
1477
+ # stop reading if we reach eof
1478
+ break unless (this_line = reader.skip_blank_lines && reader.read_line)
1479
+ # stop reading if we hit a sibling list item
1480
+ break if is_sibling_list_item? this_line, list_type, sibling_trait
1481
+ end
1484
1482
 
1485
- if this_line == LIST_CONTINUATION
1486
- detached_continuation = buffer.size
1483
+ if this_line == LIST_CONTINUATION
1484
+ detached_continuation = buffer.size
1485
+ buffer << this_line
1486
+ elsif has_text # has_text only relevant for dlist, which is more greedy until it has text for an item; has_text is always true for all other lists
1487
+ # in this block, we have to see whether we stay in the list
1488
+ # TODO any way to combine this with the check after skipping blank lines?
1489
+ if is_sibling_list_item?(this_line, list_type, sibling_trait)
1490
+ break
1491
+ elsif (nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line })
1487
1492
  buffer << this_line
1488
- else
1489
- # has_text is only relevant for dlist, which is more greedy until it has text for an item
1490
- # for all other lists, has_text is always true
1491
- # in this block, we have to see whether we stay in the list
1492
- if has_text
1493
- # TODO any way to combine this with the check after skipping blank lines?
1494
- if is_sibling_list_item?(this_line, list_type, sibling_trait)
1495
- break
1496
- elsif nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line }
1497
- buffer << this_line
1498
- within_nested_list = true
1499
- if nested_list_type == :dlist && $3.nil_or_empty?
1500
- # get greedy again
1501
- has_text = false
1502
- end
1503
- # slurp up any literal paragraph offset by blank lines
1504
- # NOTE we have to check for indented list items first
1505
- elsif LiteralParagraphRx.match? this_line
1506
- reader.unshift_line this_line
1507
- if dlist
1508
- # we may be in an indented list disguised as a literal paragraph
1509
- # so we need to make sure we don't slurp up a legitimate sibling
1510
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
1511
- else
1512
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1513
- end
1514
- else
1515
- break
1516
- end
1517
- else # only dlist in need of item text, so slurp it up!
1518
- # pop the blank line so it's not interpretted as a list continuation
1519
- buffer.pop unless within_nested_list
1520
- buffer << this_line
1521
- has_text = true
1522
- end
1523
- end
1524
- else
1525
- has_text = true unless this_line.empty?
1526
- if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
1527
1493
  within_nested_list = true
1528
1494
  if nested_list_type == :dlist && $3.nil_or_empty?
1529
1495
  # get greedy again
1530
1496
  has_text = false
1531
1497
  end
1498
+ # slurp up any literal paragraph offset by blank lines
1499
+ # NOTE we have to check for indented list items first
1500
+ elsif LiteralParagraphRx.match? this_line
1501
+ reader.unshift_line this_line
1502
+ if dlist
1503
+ # we may be in an indented list disguised as a literal paragraph
1504
+ # so we need to make sure we don't slurp up a legitimate sibling
1505
+ buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
1506
+ else
1507
+ buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1508
+ end
1509
+ else
1510
+ break
1532
1511
  end
1512
+ else # only dlist in need of item text, so slurp it up!
1513
+ # pop the blank line so it's not interpretted as a list continuation
1514
+ buffer.pop unless within_nested_list
1533
1515
  buffer << this_line
1516
+ has_text = true
1517
+ end
1518
+ else
1519
+ has_text = true unless this_line.empty?
1520
+ if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line })
1521
+ within_nested_list = true
1522
+ if nested_list_type == :dlist && $3.nil_or_empty?
1523
+ # get greedy again
1524
+ has_text = false
1525
+ end
1534
1526
  end
1527
+ buffer << this_line
1535
1528
  end
1536
1529
  this_line = nil
1537
1530
  end
@@ -1572,12 +1565,6 @@ class Parser
1572
1565
  sect_style = attributes[1]
1573
1566
  sect_id, sect_reftext, sect_title, sect_level, sect_atx = parse_section_title reader, document, attributes['id']
1574
1567
 
1575
- if sect_reftext
1576
- attributes['reftext'] = sect_reftext
1577
- else
1578
- sect_reftext = attributes['reftext']
1579
- end
1580
-
1581
1568
  if sect_style
1582
1569
  if book && sect_style == 'abstract'
1583
1570
  sect_name, sect_level = 'chapter', 1
@@ -1596,6 +1583,7 @@ class Parser
1596
1583
  sect_name = 'section'
1597
1584
  end
1598
1585
 
1586
+ attributes['reftext'] = sect_reftext if sect_reftext
1599
1587
  section = Section.new parent, sect_level
1600
1588
  section.id, section.title, section.sectname, section.source_location = sect_id, sect_title, sect_name, source_location
1601
1589
  if sect_special
@@ -1603,7 +1591,7 @@ class Parser
1603
1591
  if sect_numbered
1604
1592
  section.numbered = true
1605
1593
  elsif document.attributes['sectnums'] == 'all'
1606
- section.numbered = book && sect_level == 1 ? :chapter : true
1594
+ section.numbered = (book && sect_level == 1 ? :chapter : true)
1607
1595
  end
1608
1596
  elsif document.attributes['sectnums'] && sect_level > 0
1609
1597
  # NOTE a special section here is guaranteed to be nested in another section
@@ -1615,7 +1603,7 @@ class Parser
1615
1603
  # generate an ID if one was not embedded or specified as anchor above section title
1616
1604
  if (id = section.id || (section.id = (document.attributes.key? 'sectids') ? (generated_id = Section.generate_id section.title, document) : nil))
1617
1605
  # convert title to resolve attributes while in scope
1618
- section.title if sect_title.include? ATTR_REF_HEAD unless generated_id
1606
+ section.title unless generated_id || !(sect_title.include? ATTR_REF_HEAD)
1619
1607
  unless document.register :refs, [id, section]
1620
1608
  logger.warn message_with_context %(id assigned to section already in use: #{id}), source_location: (reader.cursor_at_line reader.lineno - (sect_atx ? 1 : 2))
1621
1609
  end
@@ -1634,9 +1622,8 @@ class Parser
1634
1622
  #
1635
1623
  # Returns the Integer section level if the Reader is positioned at a section title or nil otherwise
1636
1624
  def self.is_next_line_section?(reader, attributes)
1637
- if (style = attributes[1]) && (style == 'discrete' || style == 'float')
1638
- return
1639
- elsif Compliance.underline_style_section_titles
1625
+ return if (style = attributes[1]) && (style == 'discrete' || style == 'float')
1626
+ if Compliance.underline_style_section_titles
1640
1627
  next_lines = reader.peek_lines 2, style && style == 'comment'
1641
1628
  is_section_title?(next_lines[0] || '', next_lines[1])
1642
1629
  else
@@ -1877,13 +1864,12 @@ class Parser
1877
1864
  if explicit
1878
1865
  # rebuild implicit author names to reparse
1879
1866
  authors.each_with_index do |author, idx|
1880
- unless author
1881
- authors[idx] = [
1882
- author_metadata[%(firstname_#{name_idx = idx + 1})],
1883
- author_metadata[%(middlename_#{name_idx})],
1884
- author_metadata[%(lastname_#{name_idx})]
1885
- ].compact.map {|it| it.tr ' ', '_' }.join ' '
1886
- end
1867
+ next if author
1868
+ authors[idx] = [
1869
+ author_metadata[%(firstname_#{name_idx = idx + 1})],
1870
+ author_metadata[%(middlename_#{name_idx})],
1871
+ author_metadata[%(lastname_#{name_idx})]
1872
+ ].compact.map {|it| it.tr ' ', '_' }.join ' '
1887
1873
  end if sparse
1888
1874
  # process as names only
1889
1875
  author_metadata = process_authors authors, true, false
@@ -2066,6 +2052,7 @@ class Parser
2066
2052
  return true
2067
2053
  end
2068
2054
  end
2055
+ nil
2069
2056
  end
2070
2057
 
2071
2058
  # Process consecutive attribute entry lines, ignoring adjacent line comments and comment blocks.
@@ -2170,9 +2157,10 @@ class Parser
2170
2157
  #
2171
2158
  # Returns the String 0-index marker for this list item
2172
2159
  def self.resolve_list_marker(list_type, marker, ordinal = 0, validate = false, reader = nil)
2173
- if list_type == :ulist
2160
+ case list_type
2161
+ when :ulist
2174
2162
  marker
2175
- elsif list_type == :olist
2163
+ when :olist
2176
2164
  resolve_ordered_list_marker(marker, ordinal, validate, reader)[0]
2177
2165
  else # :colist
2178
2166
  '<1>'
@@ -2475,7 +2463,7 @@ class Parser
2475
2463
 
2476
2464
  if pos == :start
2477
2465
  if line.include? delimiter
2478
- spec_part, delimiter, rest = line.partition delimiter
2466
+ spec_part, _, rest = line.partition delimiter
2479
2467
  if (m = CellSpecStartRx.match spec_part)
2480
2468
  return [{}, rest] if m[0].empty?
2481
2469
  else
@@ -2484,14 +2472,12 @@ class Parser
2484
2472
  else
2485
2473
  return [nil, line]
2486
2474
  end
2487
- else # pos == :end
2488
- if (m = CellSpecEndRx.match line)
2489
- # NOTE return the line stripped of trailing whitespace if no cellspec is found in this case
2490
- return [{}, line.rstrip] if m[0].lstrip.empty?
2491
- rest = m.pre_match
2492
- else
2493
- return [{}, line]
2494
- end
2475
+ elsif (m = CellSpecEndRx.match line) # when pos == :end
2476
+ # NOTE return the line stripped of trailing whitespace if no cellspec is found in this case
2477
+ return [{}, line.rstrip] if m[0].lstrip.empty?
2478
+ rest = m.pre_match
2479
+ else
2480
+ return [{}, line]
2495
2481
  end
2496
2482
 
2497
2483
  spec = {}
@@ -2499,10 +2485,11 @@ class Parser
2499
2485
  colspec, rowspec = m[1].split '.'
2500
2486
  colspec = colspec.nil_or_empty? ? 1 : colspec.to_i
2501
2487
  rowspec = rowspec.nil_or_empty? ? 1 : rowspec.to_i
2502
- if m[2] == '+'
2488
+ case m[2]
2489
+ when '+'
2503
2490
  spec['colspan'] = colspec unless colspec == 1
2504
2491
  spec['rowspan'] = rowspec unless rowspec == 1
2505
- elsif m[2] == '*'
2492
+ when '*'
2506
2493
  spec['repeatcol'] = colspec unless colspec == 1
2507
2494
  end
2508
2495
  end
@@ -2527,7 +2514,7 @@ class Parser
2527
2514
  # Public: Parse the first positional attribute and assign named attributes
2528
2515
  #
2529
2516
  # Parse the first positional attribute to extract the style, role and id
2530
- # parts, assign the values to their cooresponding attribute keys and return
2517
+ # parts, assign the values to their corresponding attribute keys and return
2531
2518
  # the parsed style from the first positional attribute.
2532
2519
  #
2533
2520
  # attributes - The Hash of attributes to process and update
@@ -2567,7 +2554,7 @@ class Parser
2567
2554
  accum = ''
2568
2555
  name = :option
2569
2556
  else
2570
- accum = accum + c
2557
+ accum += c
2571
2558
  end
2572
2559
  end
2573
2560
 
@@ -2658,9 +2645,9 @@ class Parser
2658
2645
  if tab_size > 0 && lines.any? {|line| line.include? TAB }
2659
2646
  full_tab_space = ' ' * tab_size
2660
2647
  lines.map! do |line|
2661
- if line.empty?
2648
+ if line.empty? || (tab_idx = line.index TAB).nil?
2662
2649
  line
2663
- elsif (tab_idx = line.index TAB)
2650
+ else
2664
2651
  if tab_idx == 0
2665
2652
  leading_tabs = 0
2666
2653
  line.each_byte do |b|
@@ -2678,22 +2665,20 @@ class Parser
2678
2665
  if c == TAB
2679
2666
  # calculate how many spaces this tab represents, then replace tab with spaces
2680
2667
  if (offset = idx + spaces_added) % tab_size == 0
2681
- spaces_added += (tab_size - 1)
2682
- result = result + full_tab_space
2668
+ spaces_added += tab_size - 1
2669
+ result += full_tab_space
2683
2670
  else
2684
2671
  unless (spaces = tab_size - offset % tab_size) == 1
2685
- spaces_added += (spaces - 1)
2672
+ spaces_added += spaces - 1
2686
2673
  end
2687
- result = result + (' ' * spaces)
2674
+ result += ' ' * spaces
2688
2675
  end
2689
2676
  else
2690
- result = result + c
2677
+ result += c
2691
2678
  end
2692
2679
  idx += 1
2693
2680
  end
2694
2681
  result
2695
- else
2696
- line
2697
2682
  end
2698
2683
  end
2699
2684
  end