asciidoctor 2.0.15 → 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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +38 -2
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +3 -3
  5. data/README-fr.adoc +3 -3
  6. data/README-jp.adoc +3 -3
  7. data/README-zh_CN.adoc +3 -3
  8. data/README.adoc +2 -2
  9. data/asciidoctor.gemspec +1 -8
  10. data/data/locale/attributes-th.adoc +23 -0
  11. data/data/locale/attributes-vi.adoc +23 -0
  12. data/data/stylesheets/asciidoctor-default.css +50 -48
  13. data/lib/asciidoctor.rb +7 -7
  14. data/lib/asciidoctor/abstract_block.rb +4 -4
  15. data/lib/asciidoctor/abstract_node.rb +9 -8
  16. data/lib/asciidoctor/block.rb +6 -6
  17. data/lib/asciidoctor/cli/invoker.rb +0 -1
  18. data/lib/asciidoctor/cli/options.rb +22 -22
  19. data/lib/asciidoctor/convert.rb +1 -0
  20. data/lib/asciidoctor/converter.rb +5 -3
  21. data/lib/asciidoctor/converter/docbook5.rb +20 -22
  22. data/lib/asciidoctor/converter/html5.rb +70 -60
  23. data/lib/asciidoctor/converter/manpage.rb +61 -52
  24. data/lib/asciidoctor/converter/template.rb +11 -12
  25. data/lib/asciidoctor/document.rb +22 -37
  26. data/lib/asciidoctor/extensions.rb +10 -10
  27. data/lib/asciidoctor/list.rb +2 -6
  28. data/lib/asciidoctor/load.rb +10 -9
  29. data/lib/asciidoctor/logging.rb +10 -8
  30. data/lib/asciidoctor/parser.rb +122 -141
  31. data/lib/asciidoctor/path_resolver.rb +3 -3
  32. data/lib/asciidoctor/reader.rb +67 -68
  33. data/lib/asciidoctor/rx.rb +2 -1
  34. data/lib/asciidoctor/substitutors.rb +97 -99
  35. data/lib/asciidoctor/syntax_highlighter.rb +8 -11
  36. data/lib/asciidoctor/syntax_highlighter/coderay.rb +2 -1
  37. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +1 -1
  38. data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -1
  39. data/lib/asciidoctor/syntax_highlighter/rouge.rb +2 -1
  40. data/lib/asciidoctor/table.rb +17 -19
  41. data/lib/asciidoctor/timings.rb +3 -3
  42. data/lib/asciidoctor/version.rb +1 -1
  43. data/man/asciidoctor.1 +8 -9
  44. data/man/asciidoctor.adoc +7 -6
  45. metadata +7 -61
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Asciidoctor
2
3
  class << self
3
4
  # Public: Parse the AsciiDoc source input into a {Document}
@@ -53,7 +54,7 @@ module Asciidoctor
53
54
  end
54
55
 
55
56
  if ::File === input
56
- # File#mtime on JRuby for Windows doesn't honor TZ environment variable; see https://github.com/jruby/jruby/issues/6659
57
+ # File#mtime on JRuby 9.1 for Windows doesn't honor TZ environment variable; see https://github.com/jruby/jruby/issues/6659
57
58
  options[:input_mtime] = RUBY_ENGINE == 'jruby' ? (::Time.at input.mtime.to_i) : input.mtime
58
59
  # NOTE defer setting infile and indir until we get a better sense of their purpose
59
60
  # TODO cli checks if input path can be read and is file, but might want to add check to API too
@@ -84,23 +85,23 @@ module Asciidoctor
84
85
 
85
86
  timings.record :parse if timings
86
87
  doc
87
- rescue => ex
88
+ rescue => e
88
89
  begin
89
90
  context = %(asciidoctor: FAILED: #{attrs['docfile'] || '<stdin>'}: Failed to load AsciiDoc document)
90
- if ex.respond_to? :exception
91
+ if e.respond_to? :exception
91
92
  # The original message must be explicitly preserved when wrapping a Ruby exception
92
- wrapped_ex = ex.exception %(#{context} - #{ex.message})
93
+ wrapped_e = e.exception %(#{context} - #{e.message})
93
94
  # JRuby automatically sets backtrace; MRI did not until 2.6
94
- wrapped_ex.set_backtrace ex.backtrace
95
+ wrapped_e.set_backtrace e.backtrace
95
96
  else
96
97
  # Likely a Java exception class
97
- wrapped_ex = ex.class.new context, ex
98
- wrapped_ex.stack_trace = ex.stack_trace
98
+ wrapped_e = e.class.new context, e
99
+ wrapped_e.stack_trace = e.stack_trace
99
100
  end
100
101
  rescue
101
- wrapped_ex = ex
102
+ wrapped_e = e
102
103
  end
103
- raise wrapped_ex
104
+ raise wrapped_e
104
105
  end
105
106
 
106
107
  # Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
@@ -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
@@ -421,9 +421,6 @@ class Parser
421
421
 
422
422
  (intro || section).blocks << new_block
423
423
  attributes.clear
424
- #else
425
- # # don't clear attributes if we don't find a block because they may
426
- # # be trailing attributes that didn't get associated with a block
427
424
  end
428
425
  end
429
426
 
@@ -458,7 +455,7 @@ class Parser
458
455
  # of a section that need to get transfered to the next section
459
456
  # see "trailing block attributes transfer to the following section" in
460
457
  # test/attributes_test.rb for an example
461
- [section != parent ? section : nil, attributes.merge]
458
+ [section == parent ? nil : section, attributes.merge]
462
459
  end
463
460
 
464
461
  # Public: Parse and return the next Block at the Reader's current location
@@ -826,8 +823,8 @@ class Parser
826
823
  if comma_idx > 0
827
824
  language = (language.slice 0, comma_idx).strip
828
825
  attributes['linenums'] = '' if comma_idx < ll - 4
829
- else
830
- attributes['linenums'] = '' if ll > 4
826
+ elsif ll > 4
827
+ attributes['linenums'] = ''
831
828
  end
832
829
  else
833
830
  language = language.lstrip
@@ -908,7 +905,7 @@ class Parser
908
905
  # FIXME title and caption should be assigned when block is constructed (though we need to handle all cases)
909
906
  if attributes['title']
910
907
  block.title = block_title = attributes.delete 'title'
911
- block.assign_caption (attributes.delete 'caption') if CAPTION_ATTRIBUTE_NAMES[block.context]
908
+ block.assign_caption attributes.delete 'caption' if CAPTION_ATTRIBUTE_NAMES[block.context]
912
909
  end
913
910
  # TODO eventually remove the style attribute from the attributes hash
914
911
  #block.style = attributes.delete 'style'
@@ -970,17 +967,12 @@ class Parser
970
967
  # special case for fenced code blocks
971
968
  if Compliance.markdown_syntax && (tip.start_with? '`')
972
969
  if tip_len == 4
973
- if tip == '````'
974
- return
975
- elsif (tip = tip.chop) == '```'
976
- line = tip
977
- line_len = tip_len = 3
978
- else
970
+ if tip == '````' || (tip = tip.chop) != '```'
979
971
  return
980
972
  end
981
- elsif tip == '```'
982
- # keep it
983
- else
973
+ line = tip
974
+ line_len = tip_len = 3
975
+ elsif tip != '```'
984
976
  return
985
977
  end
986
978
  elsif tip_len == 3
@@ -998,9 +990,10 @@ class Parser
998
990
  # if terminator is false, that means the all the lines in the reader should be parsed
999
991
  # NOTE could invoke filter in here, before and after parsing
1000
992
  def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
1001
- if content_model == :skip
993
+ case content_model
994
+ when :skip
1002
995
  skip_processing, parse_as_content_model = true, :simple
1003
- elsif content_model == :raw
996
+ when :raw
1004
997
  skip_processing, parse_as_content_model = false, :simple
1005
998
  else
1006
999
  skip_processing, parse_as_content_model = false, content_model
@@ -1029,14 +1022,15 @@ class Parser
1029
1022
  block_reader = Reader.new reader.read_lines_until(terminator: terminator, skip_processing: skip_processing, context: block_context, cursor: :at_mark), block_cursor
1030
1023
  end
1031
1024
 
1032
- if content_model == :verbatim
1025
+ case content_model
1026
+ when :verbatim
1033
1027
  tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i
1034
1028
  if (indent = attributes['indent'])
1035
1029
  adjust_indentation! lines, indent.to_i, tab_size
1036
1030
  elsif tab_size > 0
1037
1031
  adjust_indentation! lines, -1, tab_size
1038
1032
  end
1039
- elsif content_model == :skip
1033
+ when :skip
1040
1034
  # QUESTION should we still invoke process method if extension is specified?
1041
1035
  return
1042
1036
  end
@@ -1297,7 +1291,8 @@ class Parser
1297
1291
  has_text = true
1298
1292
  list_item = ListItem.new(list_block, (item_text = match[2]))
1299
1293
  list_item.source_location = reader.cursor if list_block.document.sourcemap
1300
- if list_type == :ulist
1294
+ case list_type
1295
+ when :ulist
1301
1296
  list_item.marker = sibling_trait
1302
1297
  if item_text.start_with?('[')
1303
1298
  if style && style == 'bibliography'
@@ -1315,13 +1310,13 @@ class Parser
1315
1310
  list_item.text = item_text.slice(4, item_text.length)
1316
1311
  end
1317
1312
  end
1318
- elsif list_type == :olist
1313
+ when :olist
1319
1314
  sibling_trait, implicit_style = resolve_ordered_list_marker(sibling_trait, (ordinal = list_block.items.size), true, reader)
1320
1315
  list_item.marker = sibling_trait
1321
1316
  if ordinal == 0 && !style
1322
1317
  # using list level makes more sense, but we don't track it
1323
1318
  # basing style on marker level is compliant with AsciiDoc.py
1324
- list_block.style = implicit_style || ((ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s)
1319
+ list_block.style = implicit_style || (ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s
1325
1320
  end
1326
1321
  if item_text.start_with?('[[') && LeadingInlineAnchorRx =~ item_text
1327
1322
  catalog_inline_anchor $1, $2, list_item, reader
@@ -1447,95 +1442,89 @@ class Parser
1447
1442
  # FIXME to be AsciiDoc compliant, we shouldn't break if style in attribute line is "literal" (i.e., [literal])
1448
1443
  elsif dlist && continuation != :active && (BlockAttributeLineRx.match? this_line)
1449
1444
  break
1450
- else
1451
- if continuation == :active && !this_line.empty?
1452
- # literal paragraphs have special considerations (and this is one of
1453
- # two entry points into one)
1454
- # if we don't process it as a whole, then a line in it that looks like a
1455
- # list item will throw off the exit from it
1456
- if LiteralParagraphRx.match? this_line
1457
- reader.unshift_line this_line
1458
- if dlist
1459
- # we may be in an indented list disguised as a literal paragraph
1460
- # so we need to make sure we don't slurp up a legitimate sibling
1461
- 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 }
1462
- else
1463
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1464
- end
1465
- continuation = :inactive
1466
- # let block metadata play out until we find the block
1467
- elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
1468
- 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 }
1469
1456
  else
1470
- if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx].match? this_line }
1471
- within_nested_list = true
1472
- if nested_list_type == :dlist && $3.nil_or_empty?
1473
- # get greedy again
1474
- has_text = false
1475
- end
1476
- end
1477
- buffer << this_line
1478
- continuation = :inactive
1457
+ buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1479
1458
  end
1480
- elsif prev_line && prev_line.empty?
1481
- # advance to the next line of content
1482
- if this_line.empty?
1483
- # stop reading if we reach eof
1484
- break unless (this_line = reader.skip_blank_lines && reader.read_line)
1485
- # stop reading if we hit a sibling list item
1486
- 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
1487
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
1488
1482
 
1489
- if this_line == LIST_CONTINUATION
1490
- 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 })
1491
1492
  buffer << this_line
1492
- else
1493
- # has_text is only relevant for dlist, which is more greedy until it has text for an item
1494
- # for all other lists, has_text is always true
1495
- # in this block, we have to see whether we stay in the list
1496
- if has_text
1497
- # TODO any way to combine this with the check after skipping blank lines?
1498
- if is_sibling_list_item?(this_line, list_type, sibling_trait)
1499
- break
1500
- elsif nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line }
1501
- buffer << this_line
1502
- within_nested_list = true
1503
- if nested_list_type == :dlist && $3.nil_or_empty?
1504
- # get greedy again
1505
- has_text = false
1506
- end
1507
- # slurp up any literal paragraph offset by blank lines
1508
- # NOTE we have to check for indented list items first
1509
- elsif LiteralParagraphRx.match? this_line
1510
- reader.unshift_line this_line
1511
- if dlist
1512
- # we may be in an indented list disguised as a literal paragraph
1513
- # so we need to make sure we don't slurp up a legitimate sibling
1514
- 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 }
1515
- else
1516
- buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
1517
- end
1518
- else
1519
- break
1520
- end
1521
- else # only dlist in need of item text, so slurp it up!
1522
- # pop the blank line so it's not interpretted as a list continuation
1523
- buffer.pop unless within_nested_list
1524
- buffer << this_line
1525
- has_text = true
1526
- end
1527
- end
1528
- else
1529
- has_text = true unless this_line.empty?
1530
- if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
1531
1493
  within_nested_list = true
1532
1494
  if nested_list_type == :dlist && $3.nil_or_empty?
1533
1495
  # get greedy again
1534
1496
  has_text = false
1535
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
1536
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
1537
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
1538
1526
  end
1527
+ buffer << this_line
1539
1528
  end
1540
1529
  this_line = nil
1541
1530
  end
@@ -1576,12 +1565,6 @@ class Parser
1576
1565
  sect_style = attributes[1]
1577
1566
  sect_id, sect_reftext, sect_title, sect_level, sect_atx = parse_section_title reader, document, attributes['id']
1578
1567
 
1579
- if sect_reftext
1580
- attributes['reftext'] = sect_reftext
1581
- else
1582
- sect_reftext = attributes['reftext']
1583
- end
1584
-
1585
1568
  if sect_style
1586
1569
  if book && sect_style == 'abstract'
1587
1570
  sect_name, sect_level = 'chapter', 1
@@ -1600,6 +1583,7 @@ class Parser
1600
1583
  sect_name = 'section'
1601
1584
  end
1602
1585
 
1586
+ attributes['reftext'] = sect_reftext if sect_reftext
1603
1587
  section = Section.new parent, sect_level
1604
1588
  section.id, section.title, section.sectname, section.source_location = sect_id, sect_title, sect_name, source_location
1605
1589
  if sect_special
@@ -1607,7 +1591,7 @@ class Parser
1607
1591
  if sect_numbered
1608
1592
  section.numbered = true
1609
1593
  elsif document.attributes['sectnums'] == 'all'
1610
- section.numbered = book && sect_level == 1 ? :chapter : true
1594
+ section.numbered = (book && sect_level == 1 ? :chapter : true)
1611
1595
  end
1612
1596
  elsif document.attributes['sectnums'] && sect_level > 0
1613
1597
  # NOTE a special section here is guaranteed to be nested in another section
@@ -1619,7 +1603,7 @@ class Parser
1619
1603
  # generate an ID if one was not embedded or specified as anchor above section title
1620
1604
  if (id = section.id || (section.id = (document.attributes.key? 'sectids') ? (generated_id = Section.generate_id section.title, document) : nil))
1621
1605
  # convert title to resolve attributes while in scope
1622
- section.title if sect_title.include? ATTR_REF_HEAD unless generated_id
1606
+ section.title unless generated_id || !(sect_title.include? ATTR_REF_HEAD)
1623
1607
  unless document.register :refs, [id, section]
1624
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))
1625
1609
  end
@@ -1638,9 +1622,8 @@ class Parser
1638
1622
  #
1639
1623
  # Returns the Integer section level if the Reader is positioned at a section title or nil otherwise
1640
1624
  def self.is_next_line_section?(reader, attributes)
1641
- if (style = attributes[1]) && (style == 'discrete' || style == 'float')
1642
- return
1643
- elsif Compliance.underline_style_section_titles
1625
+ return if (style = attributes[1]) && (style == 'discrete' || style == 'float')
1626
+ if Compliance.underline_style_section_titles
1644
1627
  next_lines = reader.peek_lines 2, style && style == 'comment'
1645
1628
  is_section_title?(next_lines[0] || '', next_lines[1])
1646
1629
  else
@@ -1881,13 +1864,12 @@ class Parser
1881
1864
  if explicit
1882
1865
  # rebuild implicit author names to reparse
1883
1866
  authors.each_with_index do |author, idx|
1884
- unless author
1885
- authors[idx] = [
1886
- author_metadata[%(firstname_#{name_idx = idx + 1})],
1887
- author_metadata[%(middlename_#{name_idx})],
1888
- author_metadata[%(lastname_#{name_idx})]
1889
- ].compact.map {|it| it.tr ' ', '_' }.join ' '
1890
- 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 ' '
1891
1873
  end if sparse
1892
1874
  # process as names only
1893
1875
  author_metadata = process_authors authors, true, false
@@ -2070,6 +2052,7 @@ class Parser
2070
2052
  return true
2071
2053
  end
2072
2054
  end
2055
+ nil
2073
2056
  end
2074
2057
 
2075
2058
  # Process consecutive attribute entry lines, ignoring adjacent line comments and comment blocks.
@@ -2174,9 +2157,10 @@ class Parser
2174
2157
  #
2175
2158
  # Returns the String 0-index marker for this list item
2176
2159
  def self.resolve_list_marker(list_type, marker, ordinal = 0, validate = false, reader = nil)
2177
- if list_type == :ulist
2160
+ case list_type
2161
+ when :ulist
2178
2162
  marker
2179
- elsif list_type == :olist
2163
+ when :olist
2180
2164
  resolve_ordered_list_marker(marker, ordinal, validate, reader)[0]
2181
2165
  else # :colist
2182
2166
  '<1>'
@@ -2479,7 +2463,7 @@ class Parser
2479
2463
 
2480
2464
  if pos == :start
2481
2465
  if line.include? delimiter
2482
- spec_part, delimiter, rest = line.partition delimiter
2466
+ spec_part, _, rest = line.partition delimiter
2483
2467
  if (m = CellSpecStartRx.match spec_part)
2484
2468
  return [{}, rest] if m[0].empty?
2485
2469
  else
@@ -2488,14 +2472,12 @@ class Parser
2488
2472
  else
2489
2473
  return [nil, line]
2490
2474
  end
2491
- else # pos == :end
2492
- if (m = CellSpecEndRx.match line)
2493
- # NOTE return the line stripped of trailing whitespace if no cellspec is found in this case
2494
- return [{}, line.rstrip] if m[0].lstrip.empty?
2495
- rest = m.pre_match
2496
- else
2497
- return [{}, line]
2498
- 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]
2499
2481
  end
2500
2482
 
2501
2483
  spec = {}
@@ -2503,10 +2485,11 @@ class Parser
2503
2485
  colspec, rowspec = m[1].split '.'
2504
2486
  colspec = colspec.nil_or_empty? ? 1 : colspec.to_i
2505
2487
  rowspec = rowspec.nil_or_empty? ? 1 : rowspec.to_i
2506
- if m[2] == '+'
2488
+ case m[2]
2489
+ when '+'
2507
2490
  spec['colspan'] = colspec unless colspec == 1
2508
2491
  spec['rowspan'] = rowspec unless rowspec == 1
2509
- elsif m[2] == '*'
2492
+ when '*'
2510
2493
  spec['repeatcol'] = colspec unless colspec == 1
2511
2494
  end
2512
2495
  end
@@ -2531,7 +2514,7 @@ class Parser
2531
2514
  # Public: Parse the first positional attribute and assign named attributes
2532
2515
  #
2533
2516
  # Parse the first positional attribute to extract the style, role and id
2534
- # parts, assign the values to their cooresponding attribute keys and return
2517
+ # parts, assign the values to their corresponding attribute keys and return
2535
2518
  # the parsed style from the first positional attribute.
2536
2519
  #
2537
2520
  # attributes - The Hash of attributes to process and update
@@ -2571,7 +2554,7 @@ class Parser
2571
2554
  accum = ''
2572
2555
  name = :option
2573
2556
  else
2574
- accum = accum + c
2557
+ accum += c
2575
2558
  end
2576
2559
  end
2577
2560
 
@@ -2662,9 +2645,9 @@ class Parser
2662
2645
  if tab_size > 0 && lines.any? {|line| line.include? TAB }
2663
2646
  full_tab_space = ' ' * tab_size
2664
2647
  lines.map! do |line|
2665
- if line.empty?
2648
+ if line.empty? || (tab_idx = line.index TAB).nil?
2666
2649
  line
2667
- elsif (tab_idx = line.index TAB)
2650
+ else
2668
2651
  if tab_idx == 0
2669
2652
  leading_tabs = 0
2670
2653
  line.each_byte do |b|
@@ -2682,22 +2665,20 @@ class Parser
2682
2665
  if c == TAB
2683
2666
  # calculate how many spaces this tab represents, then replace tab with spaces
2684
2667
  if (offset = idx + spaces_added) % tab_size == 0
2685
- spaces_added += (tab_size - 1)
2686
- result = result + full_tab_space
2668
+ spaces_added += tab_size - 1
2669
+ result += full_tab_space
2687
2670
  else
2688
2671
  unless (spaces = tab_size - offset % tab_size) == 1
2689
- spaces_added += (spaces - 1)
2672
+ spaces_added += spaces - 1
2690
2673
  end
2691
- result = result + (' ' * spaces)
2674
+ result += ' ' * spaces
2692
2675
  end
2693
2676
  else
2694
- result = result + c
2677
+ result += c
2695
2678
  end
2696
2679
  idx += 1
2697
2680
  end
2698
2681
  result
2699
- else
2700
- line
2701
2682
  end
2702
2683
  end
2703
2684
  end