kramdown 2.4.0 → 2.5.1

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTERS +10 -1
  3. data/VERSION +1 -1
  4. data/bin/kramdown +15 -12
  5. data/lib/kramdown/converter/base.rb +2 -2
  6. data/lib/kramdown/converter/html.rb +22 -14
  7. data/lib/kramdown/converter/kramdown.rb +25 -20
  8. data/lib/kramdown/converter/latex.rb +11 -10
  9. data/lib/kramdown/converter/man.rb +3 -3
  10. data/lib/kramdown/converter/math_engine/mathjax.rb +1 -1
  11. data/lib/kramdown/converter/remove_html_tags.rb +5 -4
  12. data/lib/kramdown/document.rb +1 -1
  13. data/lib/kramdown/element.rb +1 -1
  14. data/lib/kramdown/options.rb +43 -15
  15. data/lib/kramdown/parser/base.rb +6 -0
  16. data/lib/kramdown/parser/html.rb +24 -18
  17. data/lib/kramdown/parser/kramdown/abbreviation.rb +4 -2
  18. data/lib/kramdown/parser/kramdown/codespan.rb +1 -1
  19. data/lib/kramdown/parser/kramdown/emphasis.rb +6 -1
  20. data/lib/kramdown/parser/kramdown/escaped_chars.rb +1 -1
  21. data/lib/kramdown/parser/kramdown/extensions.rb +6 -6
  22. data/lib/kramdown/parser/kramdown/html.rb +26 -23
  23. data/lib/kramdown/parser/kramdown/html_entity.rb +1 -1
  24. data/lib/kramdown/parser/kramdown/link.rb +4 -4
  25. data/lib/kramdown/parser/kramdown/list.rb +19 -18
  26. data/lib/kramdown/parser/kramdown/smart_quotes.rb +1 -1
  27. data/lib/kramdown/parser/kramdown.rb +5 -4
  28. data/lib/kramdown/utils/entities.rb +661 -5
  29. data/lib/kramdown/utils/html.rb +1 -1
  30. data/lib/kramdown/utils/unidecoder.rb +9 -13
  31. data/lib/kramdown/version.rb +1 -1
  32. data/man/man1/kramdown.1 +18 -0
  33. data/test/test_files.rb +8 -0
  34. data/test/testcases/block/04_header/with_header_links.html +7 -0
  35. data/test/testcases/block/04_header/with_header_links.options +2 -0
  36. data/test/testcases/block/04_header/with_header_links.text +8 -0
  37. data/test/testcases/block/04_header/with_line_break.html +1 -0
  38. data/test/testcases/block/04_header/with_line_break.text +1 -0
  39. data/test/testcases/block/08_list/escaping.html +4 -0
  40. data/test/testcases/block/08_list/escaping.text +4 -0
  41. data/test/testcases/block/08_list/nested_compact.kramdown +7 -0
  42. data/test/testcases/block/08_list/nested_compact.text +6 -0
  43. data/test/testcases/block/08_list/special_cases.html +10 -0
  44. data/test/testcases/block/08_list/special_cases.text +9 -0
  45. data/test/testcases/block/09_html/cdata_section.html +10 -0
  46. data/test/testcases/block/09_html/cdata_section.text +10 -0
  47. data/test/testcases/block/09_html/html_to_native/table_simple.html +3 -0
  48. data/test/testcases/block/09_html/html_to_native/table_simple.text +3 -0
  49. data/test/testcases/block/12_extension/options.html +2 -2
  50. data/test/testcases/block/12_extension/options2.html +2 -2
  51. data/test/testcases/block/14_table/table_with_footnote.html +2 -2
  52. data/test/testcases/block/16_toc/toc_with_footnotes.html +2 -2
  53. data/test/testcases/span/02_emphasis/normal.html +6 -1
  54. data/test/testcases/span/02_emphasis/normal.text +5 -0
  55. data/test/testcases/span/04_footnote/backlink_inline.html +10 -10
  56. data/test/testcases/span/04_footnote/backlink_text.html +2 -2
  57. data/test/testcases/span/04_footnote/footnote_link_text.html +12 -0
  58. data/test/testcases/span/04_footnote/footnote_link_text.options +1 -0
  59. data/test/testcases/span/04_footnote/footnote_link_text.text +4 -0
  60. data/test/testcases/span/04_footnote/footnote_nr.html +3 -3
  61. data/test/testcases/span/04_footnote/footnote_prefix.html +3 -3
  62. data/test/testcases/span/04_footnote/inside_footnote.html +6 -6
  63. data/test/testcases/span/04_footnote/markers.html +10 -10
  64. data/test/testcases/span/04_footnote/placement.html +2 -2
  65. data/test/testcases/span/04_footnote/regexp_problem.html +2 -2
  66. data/test/testcases/span/04_footnote/without_backlink.html +2 -2
  67. data/test/testcases/span/abbreviations/abbrev.html +4 -0
  68. data/test/testcases/span/abbreviations/abbrev.text +7 -0
  69. data/test/testcases/span/abbreviations/in_footnote.html +2 -2
  70. metadata +21 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c41b216fbd6f50c68b10864bc3a98040f79641db9af8ced05eb43f7817335ad
4
- data.tar.gz: ef3adb19cbfbe4586bf0ef4f14362ca843a7fe3331ff6dc990c270ff65cff000
3
+ metadata.gz: c6af2d8cc1534df385fd1f15fac4804896f9ccb75bdadc3ea8bda14176eb66d3
4
+ data.tar.gz: 82b5c04482a0de4d5414418682d30d14cc6c958f2fc4197231a83611d266e566
5
5
  SHA512:
6
- metadata.gz: 483e269f858aadd6bf8e7bf2f49ec90ddfdcd9628aec17822eb7eefcfc21897eb19d258a84b6291611a38a5958a79013c2c656d35f7740b116923bd8624a2329
7
- data.tar.gz: 5ffeef35cdfb994411414d62bd8b5fcf09fcea7d926069896248148575b88b4abbfdc1e5aab6da8dbe6f97c3e0a4921b391802e391ea3c76a646be7f64fbbbda
6
+ metadata.gz: 99afe4aee5580b8fe7a71360037f0ac895e5b5f2229af46e30f07f29c5cd5424fd78ca8336ca5c128b8c7a968669efc5ac5723efa4a91392c2d51b4716599123
7
+ data.tar.gz: 8997ded392dd07a7606255fb4c80048a5b3048bb8b0346ba32f0aadea0be2c13be9d4b4d9a734e16401f01e8164790de8ba0f350b1ae5bcd107bfd871074d56b
data/CONTRIBUTERS CHANGED
@@ -1,6 +1,6 @@
1
1
  Count Name
2
2
  ======= ====
3
- 964 Thomas Leitner <t_leitner@gmx.at>
3
+ 988 Thomas Leitner <t_leitner@gmx.at>
4
4
  18 Ashwin Maroli <ashmaroli@gmail.com>
5
5
  7 Christian Cornelssen <ccorn@1tein.de>
6
6
  6 Gioele Barabucci <gioele@svario.it>
@@ -21,9 +21,11 @@
21
21
  2 Nathanael Jones <nathanael.jones@gmail.com>
22
22
  2 Max Meyer <dev@fedux.org>
23
23
  2 Jo Hund <jhund@clearcove.ca>
24
+ 2 Bryce Willey <Bryce.Steven.Willey@gmail.com>
24
25
  2 Bran <m.versum@gmail.com>
25
26
  1 winniehell <git@winniehell.de>
26
27
  1 William <suttonwilliamd@gmail.com>
28
+ 1 Virgil Ierubino <30758921+Convincible@users.noreply.github.com>
27
29
  1 Uwe Kubosch <donv@users.noreply.github.com>
28
30
  1 utenmiki <utenmiki@gmail.com>
29
31
  1 Trevor Wennblom <trevor@well.com>
@@ -45,6 +47,8 @@
45
47
  1 scherr <maximilianscherr@gmail.com>
46
48
  1 Postmodern <postmodern.mod3@gmail.com>
47
49
  1 Pete Michaud <michaudp@gmail.com>
50
+ 1 Paul McMahon <paul@tokyodev.com>
51
+ 1 Paul <2528280+psfrolov@users.noreply.github.com>
48
52
  1 Noah Doersing <doersino@gmail.com>
49
53
  1 myqlarson <myqlarson@gmail.com>
50
54
  1 milo.simpson <milo.simpson@bazaarvoice.com>
@@ -59,9 +63,11 @@
59
63
  1 Kir Kolyshkin <kolyshkin@gmail.com>
60
64
  1 Jun Aruga <jaruga@redhat.com>
61
65
  1 Jonathan Hooper <jonathan.hooper@gsa.gov>
66
+ 1 John Haugeland <stonecypher@gmail.com>
62
67
  1 John Croisant <jacius@gmail.com>
63
68
  1 Joe Fiorini <joe@faithfulgeek.org>
64
69
  1 Jens Kraemer <jk@jkraemer.net>
70
+ 1 Jay Stramel <js@ionactual.com>
65
71
  1 Hirofumi Wakasugi <baenej@gmail.com>
66
72
  1 Hector Correa <hector@hectorcorrea.com>
67
73
  1 Florian Klampfer <f.klampfer@gmail.com>
@@ -72,13 +78,16 @@
72
78
  1 Daniel Bair <daniel@danielbair.com>
73
79
  1 Damien Pollet <damien.pollet@gmail.com>
74
80
  1 Christopher Jefferson <caj21@st-andrews.ac.uk>
81
+ 1 Christian Boos <christian.boos@bct-technology.com>
75
82
  1 Cédric Boutillier <cedric.boutillier@gmail.com>
76
83
  1 Bob Lail <lail@squareup.com>
84
+ 1 Ashesh Kumar Singh <user501254@gmail.com>
77
85
  1 Ashe Connor <ashe@kivikakk.ee>
78
86
  1 aschmitz <29508+aschmitz@users.noreply.github.com>
79
87
  1 Antoine Cotten <hello@acotten.com>
80
88
  1 Andrew <andrew.dale.wylie@gmail.com>
81
89
  1 Alpha Chen <alpha.chen@gmail.com>
82
90
  1 Alex Tomlins <alex.tomlins@digital.cabinet-office.gov.uk>
91
+ 1 Alex Taylor <alex@alextaylor.ca>
83
92
  1 Alexey Vasiliev <le0pard@users.noreply.github.com>
84
93
  1 284km <k.furuhashi10@gmail.com>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.4.0
1
+ 2.5.1
data/bin/kramdown CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- coding: utf-8 -*-
2
+ # -*- coding: utf-8; frozen_string_literal: true -*-
3
3
  #
4
4
  #--
5
5
  # Copyright (C) 2009-2019 Thomas Leitner <t_leitner@gmx.at>
@@ -36,7 +36,7 @@ def add_kramdown_options(opts, parsed_options, banner: [], ignore: [])
36
36
  opts.on("--#{no} ARG", type) {|v| parsed_options[n] = Kramdown::Options.parse(n, v) }
37
37
  end
38
38
 
39
- definition.desc.split(/\n/).each do |line|
39
+ definition.desc.split("\n").each do |line|
40
40
  opts.separator opts.summary_indent + ' ' * 6 + line
41
41
  end
42
42
  opts.separator ''
@@ -78,14 +78,12 @@ OptionParser.new do |opts|
78
78
  "prefix) separated", "by commas (e.g. parser-gfm,syntax-coderay)",
79
79
  "Note: Use this option before other options!") do |exts|
80
80
  exts.each do |ext|
81
- begin
82
- require "kramdown-#{ext}"
83
- new_options = add_kramdown_options(opts, options, banner: ["#{ext} options:"],
84
- ignore: defined_options)
85
- defined_options.concat(new_options)
86
- rescue LoadError
87
- $stderr.puts "Couldn't load extension #{ext}, ignoring"
88
- end
81
+ require "kramdown-#{ext}"
82
+ new_options = add_kramdown_options(opts, options, banner: ["#{ext} options:"],
83
+ ignore: defined_options)
84
+ defined_options.concat(new_options)
85
+ rescue LoadError
86
+ $stderr.puts "Couldn't load extension #{ext}, ignoring"
89
87
  end
90
88
  end
91
89
  opts.separator ""
@@ -101,7 +99,7 @@ OptionParser.new do |opts|
101
99
  exit
102
100
  end
103
101
  opts.on("-h", "--help", "Show the help") do
104
- puts opts.summarize('', 5, 72)
102
+ puts opts.summarize(+'', 5, 72)
105
103
  exit
106
104
  end
107
105
 
@@ -111,7 +109,12 @@ end.parse!
111
109
 
112
110
  begin
113
111
  if config_file && File.exist?(config_file)
114
- config_file_options = YAML.safe_load(File.read(config_file), [Symbol])
112
+ config_file_options =
113
+ if YAML.method(:safe_load).parameters.include?(%i[key permitted_classes])
114
+ YAML.safe_load(File.read(config_file), permitted_classes: [Symbol])
115
+ else # compatibility with Psych < 3.1.0
116
+ YAML.safe_load(File.read(config_file), [Symbol])
117
+ end
115
118
  case config_file_options
116
119
  when nil # empty configuration file except perhaps YAML header and comments
117
120
  # Nothing to do
@@ -137,7 +137,7 @@ module Kramdown
137
137
 
138
138
  # Return the template specified by +template+.
139
139
  def self.get_template(template) # :nodoc:
140
- format_ext = '.' + ::Kramdown::Utils.snake_case(self.name.split(/::/).last)
140
+ format_ext = '.' + ::Kramdown::Utils.snake_case(name.split("::").last)
141
141
  shipped = File.join(::Kramdown.data_dir, template + format_ext)
142
142
  if File.exist?(template)
143
143
  File.read(template)
@@ -146,7 +146,7 @@ module Kramdown
146
146
  elsif File.exist?(shipped)
147
147
  File.read(shipped)
148
148
  elsif template.start_with?('string://')
149
- template.sub(/\Astring:\/\//, '')
149
+ template.delete_prefix("string://")
150
150
  else
151
151
  raise "The specified template file #{template} does not exist"
152
152
  end
@@ -100,8 +100,12 @@ module Kramdown
100
100
  figure_attr = el.attr.dup
101
101
  image_attr = el.children.first.attr.dup
102
102
 
103
- figure_attr['class'] = image_attr.delete('class') if image_attr.key?('class') and not figure_attr.key?('class')
104
- figure_attr['id'] = image_attr.delete('id') if image_attr.key?('id') and not figure_attr.key?('id')
103
+ if image_attr.key?('class') && !figure_attr.key?('class')
104
+ figure_attr['class'] = image_attr.delete('class')
105
+ end
106
+ if image_attr.key?('id') && !figure_attr.key?('id')
107
+ figure_attr['id'] = image_attr.delete('id')
108
+ end
105
109
 
106
110
  body = "#{' ' * (indent + @indent)}<img#{html_attributes(image_attr)} />\n" \
107
111
  "#{' ' * (indent + @indent)}<figcaption>#{image_attr['alt']}</figcaption>\n"
@@ -128,7 +132,7 @@ module Kramdown
128
132
  when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>"
129
133
  when " " then "<span class=\"ws-space#{suffix}\">&#8901;</span>"
130
134
  end
131
- end.join('')
135
+ end.join
132
136
  end
133
137
  end
134
138
  code_attr = {}
@@ -147,6 +151,13 @@ module Kramdown
147
151
  if @options[:auto_ids] && !attr['id']
148
152
  attr['id'] = generate_id(el.options[:raw_text])
149
153
  end
154
+
155
+ if @options[:header_links] && attr['id'].to_s.length > 0
156
+ link = Element.new(:a, nil, nil)
157
+ link.attr['href'] = "##{attr['id']}"
158
+ el.children.unshift(link)
159
+ end
160
+
150
161
  @toc << [el.options[:level], attr['id'], el.children] if attr['id'] && in_toc?(el)
151
162
  level = output_header_level(el.options[:level])
152
163
  format_as_block_html("h#{level}", attr, inner(el, indent), indent)
@@ -179,7 +190,7 @@ module Kramdown
179
190
  output = ' ' * indent << "<#{el.type}" << html_attributes(el.attr) << ">"
180
191
  res = inner(el, indent)
181
192
  if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent])
182
- output << res << (res =~ /\n\Z/ ? ' ' * indent : '')
193
+ output << res << (res.match?(/\n\Z/) ? ' ' * indent : '')
183
194
  else
184
195
  output << "\n" << res << ' ' * indent
185
196
  end
@@ -303,9 +314,10 @@ module Kramdown
303
314
  @footnotes << [name, el.value, number, 0]
304
315
  @footnotes_by_name[name] = @footnotes.last
305
316
  end
306
- "<sup id=\"fnref:#{name}#{repeat}\" role=\"doc-noteref\">" \
307
- "<a href=\"#fn:#{name}\" class=\"footnote\" rel=\"footnote\">" \
308
- "#{number}</a></sup>"
317
+ formatted_link_text = sprintf(@options[:footnote_link_text], number)
318
+ "<sup id=\"fnref:#{name}#{repeat}\">" \
319
+ "<a href=\"#fn:#{name}\" class=\"footnote\" rel=\"footnote\" role=\"doc-noteref\">" \
320
+ "#{formatted_link_text}</a></sup>"
309
321
  end
310
322
 
311
323
  def convert_raw(el, _indent)
@@ -340,7 +352,7 @@ module Kramdown
340
352
  if (result = @options[:typographic_symbols][el.value])
341
353
  escape_html(result, :text)
342
354
  else
343
- TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join('')
355
+ TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e) }.join
344
356
  end
345
357
  end
346
358
 
@@ -378,11 +390,7 @@ module Kramdown
378
390
  end
379
391
  if @toc_code
380
392
  toc_tree = generate_toc_tree(@toc, @toc_code[0], @toc_code[1] || {})
381
- text = if !toc_tree.children.empty?
382
- convert(toc_tree, 0)
383
- else
384
- ''
385
- end
393
+ text = toc_tree.children.empty? ? '' : convert(toc_tree, 0)
386
394
  result.sub!(/#{@toc_code.last}/, text.gsub(/\\/, "\\\\\\\\"))
387
395
  end
388
396
  result
@@ -492,7 +500,7 @@ module Kramdown
492
500
  backlink_text = escape_html(@options[:footnote_backlink], :text)
493
501
  while i < @footnotes.length
494
502
  name, data, _, repeat = *@footnotes[i]
495
- li = Element.new(:li, nil, 'id' => "fn:#{name}", 'role' => 'doc-endnote')
503
+ li = Element.new(:li, nil, 'id' => "fn:#{name}")
496
504
  li.children = Marshal.load(Marshal.dump(data.children))
497
505
 
498
506
  para = nil
@@ -45,7 +45,8 @@ module Kramdown
45
45
  elsif el.block? &&
46
46
  ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
47
47
  (el.type != :html_element || @stack.last.type != :html_element) &&
48
- (el.type != :p || !el.options[:transparent])
48
+ (el.type != :p || !el.options[:transparent]) &&
49
+ !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li)
49
50
  res << "\n"
50
51
  end
51
52
  res
@@ -71,27 +72,30 @@ module Kramdown
71
72
  ""
72
73
  end
73
74
 
74
- ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'|])|^[ ]{0,3}(:)/
75
+ ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/
75
76
 
76
77
  def convert_text(el, opts)
77
- if opts[:raw_text]
78
+ if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw)
78
79
  el.value
79
80
  else
80
- el.value.gsub(/\A\n/) do
81
+ result = el.value.gsub(/\A\n/) do
81
82
  opts[:prev] && opts[:prev].type == :br ? '' : "\n"
82
- end.gsub(/\s+/, ' ').gsub(ESCAPED_CHAR_RE) do
83
+ end
84
+ result.gsub!(/\s+/, ' ') unless el.options[:cdata]
85
+ result.gsub!(ESCAPED_CHAR_RE) do
83
86
  $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $&
84
87
  end
88
+ result
85
89
  end
86
90
  end
87
91
 
88
92
  def convert_p(el, opts)
89
93
  w = @options[:line_width] - opts[:indent].to_s.to_i
90
94
  first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
91
- first&.gsub!(/^(?:(#|>)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\." }
95
+ first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" }
92
96
  second&.gsub!(/^([=-]+\s*?)$/, "\\\1")
93
97
  res = [first, second, *rest].compact.join("\n") + "\n"
94
- res.gsub!(/^[ ]{0,3}:/, "\\:")
98
+ res.gsub!(/^ {0,3}:/, "\\:")
95
99
  if el.children.length == 1 && el.children.first.type == :math
96
100
  res = "\\#{res}"
97
101
  elsif res.start_with?('\$$') && res.end_with?("\\$$\n")
@@ -101,15 +105,16 @@ module Kramdown
101
105
  end
102
106
 
103
107
  def convert_codeblock(el, _opts)
104
- el.value.split(/\n/).map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n"
108
+ el.value.split("\n").map {|l| l.empty? ? " " : " #{l}" }.join("\n") + "\n"
105
109
  end
106
110
 
107
111
  def convert_blockquote(el, opts)
108
112
  opts[:indent] += 2
109
- inner(el, opts).chomp.split(/\n/).map {|l| "> #{l}" }.join("\n") << "\n"
113
+ inner(el, opts).chomp.split("\n").map {|l| "> #{l}" }.join("\n") << "\n"
110
114
  end
111
115
 
112
116
  def convert_header(el, opts)
117
+ opts[:in_header] = true
113
118
  res = +''
114
119
  res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}"
115
120
  res[-1, 1] = "\\#" if res[-1] == '#'
@@ -140,13 +145,13 @@ module Kramdown
140
145
  opts[:indent] += width
141
146
  text = inner(el, opts)
142
147
  newlines = text.scan(/\n*\Z/).first
143
- first, *last = text.split(/\n/)
148
+ first, *last = text.split("\n")
144
149
  last = last.map {|l| " " * width + l }.join("\n")
145
150
  text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines)
146
151
  if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent]
147
152
  res = +"#{sym}#{text}"
148
153
  res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
149
- (@stack.last.children.any? {|c| c.children.first.type != :p } || @stack.last.children.size == 1)
154
+ (@stack.last.children.any? {|c| !c.children.first || c.children.first.type != :p } || @stack.last.children.size == 1)
150
155
  res
151
156
  elsif el.children.first && el.children.first.type == :codeblock
152
157
  "#{sym}\n #{text}"
@@ -164,7 +169,7 @@ module Kramdown
164
169
  opts[:indent] += width
165
170
  text = inner(el, opts)
166
171
  newlines = text.scan(/\n*\Z/).first
167
- first, *last = text.split(/\n/)
172
+ first, *last = text.split("\n")
168
173
  last = last.map {|l| " " * width + l }.join("\n")
169
174
  text = first.to_s + (last.empty? ? "" : "\n") + last + newlines
170
175
  text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
@@ -187,7 +192,7 @@ module Kramdown
187
192
  result << inner(el, opts) << "\n"
188
193
  end
189
194
 
190
- HTML_TAGS_WITH_BODY = ['div', 'script', 'iframe', 'textarea', 'th', 'td']
195
+ HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td]
191
196
 
192
197
  HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze
193
198
  private_constant :HTML_ELEMENT_TYPES
@@ -243,7 +248,7 @@ module Kramdown
243
248
 
244
249
  def convert_thead(el, opts)
245
250
  rows = inner(el, opts)
246
- if opts[:alignment].all? {|a| a == :default }
251
+ if opts[:alignment].all?(:default)
247
252
  "#{rows}|#{'-' * 10}\n"
248
253
  else
249
254
  "#{rows}| " + opts[:alignment].map do |a|
@@ -284,8 +289,8 @@ module Kramdown
284
289
  end
285
290
  end
286
291
 
287
- def convert_br(_el, _opts)
288
- " \n"
292
+ def convert_br(_el, opts)
293
+ opts[:in_header] ? "<br />" : " \n"
289
294
  end
290
295
 
291
296
  def convert_a(el, opts)
@@ -367,7 +372,7 @@ module Kramdown
367
372
  end
368
373
 
369
374
  def convert_smart_quote(el, _opts)
370
- el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
375
+ el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'"
371
376
  end
372
377
 
373
378
  def convert_math(el, _opts)
@@ -400,7 +405,7 @@ module Kramdown
400
405
  res = +''
401
406
  @footnotes.each do |name, data|
402
407
  res << "[^#{name}]:\n"
403
- res << inner(data).chomp.split(/\n/).map {|l| " #{l}" }.join("\n") + "\n\n"
408
+ res << inner(data).chomp.split("\n").map {|l| " #{l}" }.join("\n") + "\n\n"
404
409
  end
405
410
  res
406
411
  end
@@ -422,14 +427,14 @@ module Kramdown
422
427
  next if el.type == :header && k == 'id' && !v.strip.empty?
423
428
  if v.nil?
424
429
  ''
425
- elsif k == 'class' && !v.empty? && !v.index(/[\.#]/)
430
+ elsif k == 'class' && !v.empty? && !v.index(/[.#]/)
426
431
  " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ")
427
432
  elsif k == 'id' && !v.strip.empty?
428
433
  " ##{v}"
429
434
  else
430
435
  " #{k}=\"#{v}\""
431
436
  end
432
- end.compact.join('')
437
+ end.compact.join
433
438
  res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
434
439
  el.options.dig(:ial, :refs)&.include?('toc')
435
440
  res = "footnotes" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
@@ -59,7 +59,7 @@ module Kramdown
59
59
  end
60
60
 
61
61
  def convert_blank(_el, opts)
62
- opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
62
+ opts[:result].match?(/\n\n\Z|\A\Z/) ? "" : "\n"
63
63
  end
64
64
 
65
65
  def convert_text(el, _opts)
@@ -153,9 +153,10 @@ module Kramdown
153
153
  end
154
154
 
155
155
  def convert_html_element(el, opts)
156
- if el.value == 'i' || el.value == 'em'
156
+ case el.value
157
+ when 'i', 'em'
157
158
  "\\emph{#{inner(el, opts)}}"
158
- elsif el.value == 'b' || el.value == 'strong'
159
+ when 'b', 'strong'
159
160
  "\\textbf{#{inner(el, opts)}}"
160
161
  else
161
162
  warning("Can't convert HTML element")
@@ -164,7 +165,7 @@ module Kramdown
164
165
  end
165
166
 
166
167
  def convert_xml_comment(el, _opts)
167
- el.value.split(/\n/).map {|l| "% #{l}" }.join("\n") + "\n"
168
+ el.value.split("\n").map {|l| "% #{l}" }.join("\n") + "\n"
168
169
  end
169
170
 
170
171
  def convert_xml_pi(_el, _opts)
@@ -203,7 +204,7 @@ module Kramdown
203
204
  end
204
205
 
205
206
  def convert_comment(el, _opts)
206
- el.value.split(/\n/).map {|l| "% #{l}" }.join("\n") << "\n"
207
+ el.value.split("\n").map {|l| "% #{l}" }.join("\n") << "\n"
207
208
  end
208
209
 
209
210
  def convert_br(_el, opts)
@@ -224,7 +225,7 @@ module Kramdown
224
225
 
225
226
  def convert_img(el, _opts)
226
227
  line = el.options[:location]
227
- if el.attr['src'] =~ /^(https?|ftps?):\/\//
228
+ if el.attr['src'].match?(/^(https?|ftps?):\/\//)
228
229
  warning("Cannot include non-local image#{line ? " (line #{line})" : ''}")
229
230
  ''
230
231
  elsif !el.attr['src'].empty?
@@ -556,7 +557,7 @@ module Kramdown
556
557
  def convert_math(el, _opts)
557
558
  @data[:packages] += %w[amssymb amsmath amsthm amsfonts]
558
559
  if el.options[:category] == :block
559
- if el.value =~ /\A\s*\\begin\{/
560
+ if el.value.match?(/\A\s*\\begin\{/)
560
561
  el.value
561
562
  else
562
563
  latex_environment('displaymath', el, el.value)
@@ -573,7 +574,7 @@ module Kramdown
573
574
 
574
575
  # Normalize the abbreviation key so that it only contains allowed ASCII character
575
576
  def normalize_abbreviation_key(key)
576
- key.gsub(/\W/) {|m| m.unpack('H*').first }
577
+ key.gsub(/\W/) {|m| m.unpack1('H*') }
577
578
  end
578
579
 
579
580
  # Wrap the +text+ inside a LaTeX environment of type +type+. The element +el+ is passed on to
@@ -597,7 +598,7 @@ module Kramdown
597
598
 
598
599
  # Return a LaTeX comment containing all attributes as 'key="value"' pairs.
599
600
  def attribute_list(el)
600
- attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join('')
601
+ attrs = el.attr.map {|k, v| v.nil? ? '' : " #{k}=\"#{v}\"" }.compact.sort.join
601
602
  attrs = " % #{attrs}" unless attrs.empty?
602
603
  attrs
603
604
  end
@@ -611,7 +612,7 @@ module Kramdown
611
612
  ">" => "\\textgreater{}",
612
613
  "[" => "{[}",
613
614
  "]" => "{]}",
614
- }.merge(Hash[*("{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten)]) # :nodoc:
615
+ }.merge(Hash[*"{}$%&_#".each_char.map {|c| [c, "\\#{c}"] }.flatten]) # :nodoc:
615
616
  ESCAPE_RE = Regexp.union(*ESCAPE_MAP.collect {|k, _v| k }) # :nodoc:
616
617
 
617
618
  # Escape the special LaTeX characters in the string +str+.
@@ -17,7 +17,7 @@ module Kramdown
17
17
  # man-pages(7) for information regarding the output.
18
18
  class Man < Base
19
19
 
20
- def convert(el, opts = {indent: 0, result: +''}) #:nodoc:
20
+ def convert(el, opts = {indent: 0, result: +''}) # :nodoc:
21
21
  send("convert_#{el.type}", el, opts)
22
22
  end
23
23
 
@@ -139,7 +139,7 @@ module Kramdown
139
139
  def convert_table(el, opts)
140
140
  opts[:alignment] = el.options[:alignment].map {|a| TABLE_CELL_ALIGNMENT[a] }
141
141
  table_options = ["box"]
142
- table_options << "center" if el.attr['class'] =~ /\bcenter\b/
142
+ table_options << "center" if el.attr['class']&.match?(/\bcenter\b/)
143
143
  opts[:result] << macro("TS") << "#{table_options.join(' ')} ;\n"
144
144
  inner(el, opts)
145
145
  opts[:result] << macro("TE") << macro("sp")
@@ -171,7 +171,7 @@ module Kramdown
171
171
  result = opts[:result]
172
172
  opts[:result] = +''
173
173
  inner(el, opts)
174
- if opts[:result] =~ /\n/
174
+ if opts[:result].include?("\n")
175
175
  warning("Table cells using links are not supported")
176
176
  result << "\t"
177
177
  else
@@ -17,7 +17,7 @@ module Kramdown::Converter::MathEngine
17
17
 
18
18
  def self.call(converter, el, opts)
19
19
  value = converter.escape_html(el.value)
20
- result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)"
20
+ result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)"
21
21
  if el.attr.empty?
22
22
  result
23
23
  elsif el.options[:category] == :block
@@ -35,12 +35,13 @@ module Kramdown
35
35
  children = el.children.dup
36
36
  index = 0
37
37
  while index < children.length
38
- if [:xml_pi].include?(children[index].type) ||
39
- (children[index].type == :html_element && %w[style script].include?(children[index].value))
38
+ if children[index].type == :xml_pi ||
39
+ (children[index].type == :html_element && (children[index].value == 'style' ||
40
+ children[index].value == 'script'))
40
41
  children[index..index] = []
41
42
  elsif children[index].type == :html_element &&
42
- ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) ||
43
- (@options[:remove_span_html_tags] && children[index].options[:category] == :span))
43
+ ((@options[:remove_block_html_tags] && children[index].options[:category] == :block) ||
44
+ (@options[:remove_span_html_tags] && children[index].options[:category] == :span))
44
45
  children[index..index] = children[index].children
45
46
  else
46
47
  convert(children[index])
@@ -121,7 +121,7 @@ module Kramdown
121
121
  end
122
122
  end
123
123
 
124
- def inspect #:nodoc:
124
+ def inspect # :nodoc:
125
125
  "<KD:Document: options=#{@options.inspect} root=#{@root.inspect} warnings=#{@warnings.inspect}>"
126
126
  end
127
127
 
@@ -508,7 +508,7 @@ module Kramdown
508
508
  @options ||= {}
509
509
  end
510
510
 
511
- def inspect #:nodoc:
511
+ def inspect # :nodoc:
512
512
  "<kd:#{@type}" \
513
513
  "#{value.nil? ? '' : ' value=' + value.inspect}" \
514
514
  "#{attr.empty? ? '' : ' attr=' + attr.inspect}" \