asciidoctor 2.0.12 → 2.0.16

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