asciidoctor 2.0.15 → 2.0.16

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