kramdown 2.3.2 → 2.5.0

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTERS +11 -2
  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 +23 -15
  7. data/lib/kramdown/converter/kramdown.rb +31 -21
  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 +50 -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 +25 -0
  33. data/test/test_files.rb +11 -0
  34. data/test/testcases/block/03_paragraph/to_kramdown.kramdown +7 -0
  35. data/test/testcases/block/03_paragraph/to_kramdown.text +5 -0
  36. data/test/testcases/block/04_header/with_header_links.html +7 -0
  37. data/test/testcases/block/04_header/with_header_links.options +2 -0
  38. data/test/testcases/block/04_header/with_header_links.text +8 -0
  39. data/test/testcases/block/04_header/with_line_break.html +1 -0
  40. data/test/testcases/block/04_header/with_line_break.text +1 -0
  41. data/test/testcases/block/08_list/escaping.html +4 -0
  42. data/test/testcases/block/08_list/escaping.text +4 -0
  43. data/test/testcases/block/08_list/nested_compact.kramdown +7 -0
  44. data/test/testcases/block/08_list/nested_compact.text +6 -0
  45. data/test/testcases/block/08_list/special_cases.html +10 -0
  46. data/test/testcases/block/08_list/special_cases.text +9 -0
  47. data/test/testcases/block/09_html/cdata_section.html +10 -0
  48. data/test/testcases/block/09_html/cdata_section.text +10 -0
  49. data/test/testcases/block/09_html/html_to_native/table_simple.html +3 -0
  50. data/test/testcases/block/09_html/html_to_native/table_simple.text +3 -0
  51. data/test/testcases/block/12_extension/options.html +2 -2
  52. data/test/testcases/block/12_extension/options2.html +2 -2
  53. data/test/testcases/block/14_table/table_with_footnote.html +2 -2
  54. data/test/testcases/block/16_toc/toc_with_footnotes.html +2 -2
  55. data/test/testcases/span/02_emphasis/normal.html +6 -1
  56. data/test/testcases/span/02_emphasis/normal.text +5 -0
  57. data/test/testcases/span/04_footnote/backlink_inline.html +10 -10
  58. data/test/testcases/span/04_footnote/backlink_text.html +2 -2
  59. data/test/testcases/span/04_footnote/footnote_link_text.html +12 -0
  60. data/test/testcases/span/04_footnote/footnote_link_text.options +1 -0
  61. data/test/testcases/span/04_footnote/footnote_link_text.text +4 -0
  62. data/test/testcases/span/04_footnote/footnote_nr.html +3 -3
  63. data/test/testcases/span/04_footnote/footnote_prefix.html +3 -3
  64. data/test/testcases/span/04_footnote/inside_footnote.html +6 -6
  65. data/test/testcases/span/04_footnote/markers.html +10 -10
  66. data/test/testcases/span/04_footnote/placement.html +2 -2
  67. data/test/testcases/span/04_footnote/regexp_problem.html +2 -2
  68. data/test/testcases/span/04_footnote/without_backlink.html +2 -2
  69. data/test/testcases/span/abbreviations/abbrev.html +4 -0
  70. data/test/testcases/span/abbreviations/abbrev.text +7 -0
  71. data/test/testcases/span/abbreviations/in_footnote.html +2 -2
  72. metadata +23 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f656918e531f3b20c720da64a979ea287aabf5e9b2a9bb18599d968957926e41
4
- data.tar.gz: 3150331b7195b4dd186984a301a174ca0943e85ad11c3aef47b797b9dd46ad58
3
+ metadata.gz: 53bf662f86052a77c6c9867b0c4e6808c9cee58ce1ed2b5e77c74b9d015b8e73
4
+ data.tar.gz: 3f56c0fd6fb00b867ade3ce1df9ddda4380aa01307b37420fbc5a4f1330a8156
5
5
  SHA512:
6
- metadata.gz: d7b0d8a7af60a0c72a6a49b26a05fc8fe3c348458802f489891166711aad985d0240d8b8882432d81ba6a061fd78e5c598ddc6dd6fa5f5de7b1aa57cf5fc9514
7
- data.tar.gz: bec4c4bb4705f28db0bc4b7f3e4f6105e531a8711870edd90f36b0e270a653305bef544116760d3748ef91f112d51e666b468c38cddc116bcdf8c1267fbab1d3
6
+ metadata.gz: 813301a1fe55b9eeb724fec2e482a694e74852d2509cd74e64cbc5f5df5122f77d63b317439c4184b9ebc7651584d5c777d58eb29183e07ab941d453c12a6ed4
7
+ data.tar.gz: 610257c36fc35ac7195114f1a5458d02939116696e799ab257a821a2ab5025ecf94470a4800cd767dfdc0730da0a0ec599276ac2ac745ef64b07d2bc4d20ba9b
data/CONTRIBUTERS CHANGED
@@ -1,6 +1,6 @@
1
1
  Count Name
2
2
  ======= ====
3
- 960 Thomas Leitner <t_leitner@gmx.at>
3
+ 986 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>
@@ -11,6 +11,7 @@
11
11
  4 Arne Brasseur <arne@arnebrasseur.net>
12
12
  3 Henning Perl <perl@fast-sicher.de>
13
13
  3 gettalong <t_leitner@gmx.at>
14
+ 3 Carsten Bormann <cabo@tzi.org>
14
15
  3 Brandur <brandur@mutelight.org>
15
16
  3 Ben Armston <ben.armston@googlemail.com>
16
17
  3 Ashwin Maroli <ashmaroli@users.noreply.github.com>
@@ -20,10 +21,11 @@
20
21
  2 Nathanael Jones <nathanael.jones@gmail.com>
21
22
  2 Max Meyer <dev@fedux.org>
22
23
  2 Jo Hund <jhund@clearcove.ca>
23
- 2 Carsten Bormann <cabo@tzi.org>
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.3.2
1
+ 2.5.0
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
@@ -283,7 +294,7 @@ module Kramdown
283
294
  hl_opts = {}
284
295
  result = highlight_code(el.value, lang, :span, hl_opts)
285
296
  if result
286
- add_syntax_highlighter_to_class_attr(attr, hl_opts[:default_lang])
297
+ add_syntax_highlighter_to_class_attr(attr, lang || hl_opts[:default_lang])
287
298
  else
288
299
  result = escape_html(el.value)
289
300
  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
@@ -27,6 +27,8 @@ module Kramdown
27
27
  @footnotes = []
28
28
  @abbrevs = []
29
29
  @stack = []
30
+ @list_indent = @options[:list_indent]
31
+ @list_spacing = ' ' * (@list_indent - 2)
30
32
  end
31
33
 
32
34
  def convert(el, opts = {indent: 0})
@@ -43,7 +45,8 @@ module Kramdown
43
45
  elsif el.block? &&
44
46
  ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
45
47
  (el.type != :html_element || @stack.last.type != :html_element) &&
46
- (el.type != :p || !el.options[:transparent])
48
+ (el.type != :p || !el.options[:transparent]) &&
49
+ !([:ul, :dl, :ol].include?(el.type) && @stack.last.type == :li)
47
50
  res << "\n"
48
51
  end
49
52
  res
@@ -69,24 +72,30 @@ module Kramdown
69
72
  ""
70
73
  end
71
74
 
72
- ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'|])|^[ ]{0,3}(:)/
75
+ ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]{"'|])|^ {0,3}(:)/
73
76
 
74
77
  def convert_text(el, opts)
75
- if opts[:raw_text]
78
+ if opts[:raw_text] || (@stack.last.type == :html_element && @stack.last.options[:content_model] == :raw)
76
79
  el.value
77
80
  else
78
- el.value.gsub(/\A\n/) do
81
+ result = el.value.gsub(/\A\n/) do
79
82
  opts[:prev] && opts[:prev].type == :br ? '' : "\n"
80
- end.gsub(/\s+/, ' ').gsub(ESCAPED_CHAR_RE) { "\\#{$1 || $2}" }
83
+ end
84
+ result.gsub!(/\s+/, ' ') unless el.options[:cdata]
85
+ result.gsub!(ESCAPED_CHAR_RE) do
86
+ $1 || !opts[:prev] || opts[:prev].type == :br ? "\\#{$1 || $2}" : $&
87
+ end
88
+ result
81
89
  end
82
90
  end
83
91
 
84
92
  def convert_p(el, opts)
85
93
  w = @options[:line_width] - opts[:indent].to_s.to_i
86
94
  first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
87
- first&.gsub!(/^(?:(#|>)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\." }
95
+ first&.gsub!(/^(?:(#|>)|(\d+)\.(\s)|([+-]\s))/) { $1 || $4 ? "\\#{$1 || $4}" : "#{$2}\\.#{$3}" }
88
96
  second&.gsub!(/^([=-]+\s*?)$/, "\\\1")
89
97
  res = [first, second, *rest].compact.join("\n") + "\n"
98
+ res.gsub!(/^ {0,3}:/, "\\:")
90
99
  if el.children.length == 1 && el.children.first.type == :math
91
100
  res = "\\#{res}"
92
101
  elsif res.start_with?('\$$') && res.end_with?("\\$$\n")
@@ -96,15 +105,16 @@ module Kramdown
96
105
  end
97
106
 
98
107
  def convert_codeblock(el, _opts)
99
- 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"
100
109
  end
101
110
 
102
111
  def convert_blockquote(el, opts)
103
112
  opts[:indent] += 2
104
- 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"
105
114
  end
106
115
 
107
116
  def convert_header(el, opts)
117
+ opts[:in_header] = true
108
118
  res = +''
109
119
  res << "#{'#' * output_header_level(el.options[:level])} #{inner(el, opts)}"
110
120
  res[-1, 1] = "\\#" if res[-1] == '#'
@@ -124,7 +134,7 @@ module Kramdown
124
134
 
125
135
  def convert_li(el, opts)
126
136
  sym, width = if @stack.last.type == :ul
127
- [+'* ', el.children.first && el.children.first.type == :codeblock ? 4 : 2]
137
+ ['* ' + @list_spacing, el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent]
128
138
  else
129
139
  ["#{opts[:index] + 1}.".ljust(4), 4]
130
140
  end
@@ -135,13 +145,13 @@ module Kramdown
135
145
  opts[:indent] += width
136
146
  text = inner(el, opts)
137
147
  newlines = text.scan(/\n*\Z/).first
138
- first, *last = text.split(/\n/)
148
+ first, *last = text.split("\n")
139
149
  last = last.map {|l| " " * width + l }.join("\n")
140
150
  text = (first.nil? ? "\n" : first + (last.empty? ? "" : "\n") + last + newlines)
141
151
  if el.children.first && el.children.first.type == :p && !el.children.first.options[:transparent]
142
152
  res = +"#{sym}#{text}"
143
153
  res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
144
- (@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)
145
155
  res
146
156
  elsif el.children.first && el.children.first.type == :codeblock
147
157
  "#{sym}\n #{text}"
@@ -151,7 +161,7 @@ module Kramdown
151
161
  end
152
162
 
153
163
  def convert_dd(el, opts)
154
- sym, width = +": ", (el.children.first && el.children.first.type == :codeblock ? 4 : 2)
164
+ sym, width = ": " + @list_spacing, (el.children.first && el.children.first.type == :codeblock ? 4 : @list_indent)
155
165
  if (ial = ial_for_element(el))
156
166
  sym << ial << " "
157
167
  end
@@ -159,7 +169,7 @@ module Kramdown
159
169
  opts[:indent] += width
160
170
  text = inner(el, opts)
161
171
  newlines = text.scan(/\n*\Z/).first
162
- first, *last = text.split(/\n/)
172
+ first, *last = text.split("\n")
163
173
  last = last.map {|l| " " * width + l }.join("\n")
164
174
  text = first.to_s + (last.empty? ? "" : "\n") + last + newlines
165
175
  text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
@@ -182,7 +192,7 @@ module Kramdown
182
192
  result << inner(el, opts) << "\n"
183
193
  end
184
194
 
185
- HTML_TAGS_WITH_BODY = ['div', 'script', 'iframe', 'textarea', 'th', 'td']
195
+ HTML_TAGS_WITH_BODY = %w[div script iframe textarea th td]
186
196
 
187
197
  HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze
188
198
  private_constant :HTML_ELEMENT_TYPES
@@ -238,7 +248,7 @@ module Kramdown
238
248
 
239
249
  def convert_thead(el, opts)
240
250
  rows = inner(el, opts)
241
- if opts[:alignment].all? {|a| a == :default }
251
+ if opts[:alignment].all?(:default)
242
252
  "#{rows}|#{'-' * 10}\n"
243
253
  else
244
254
  "#{rows}| " + opts[:alignment].map do |a|
@@ -279,8 +289,8 @@ module Kramdown
279
289
  end
280
290
  end
281
291
 
282
- def convert_br(_el, _opts)
283
- " \n"
292
+ def convert_br(_el, opts)
293
+ opts[:in_header] ? "<br />" : " \n"
284
294
  end
285
295
 
286
296
  def convert_a(el, opts)
@@ -362,7 +372,7 @@ module Kramdown
362
372
  end
363
373
 
364
374
  def convert_smart_quote(el, _opts)
365
- el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
375
+ el.value.to_s.match?(/[rl]dquo/) ? "\"" : "'"
366
376
  end
367
377
 
368
378
  def convert_math(el, _opts)
@@ -395,7 +405,7 @@ module Kramdown
395
405
  res = +''
396
406
  @footnotes.each do |name, data|
397
407
  res << "[^#{name}]:\n"
398
- 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"
399
409
  end
400
410
  res
401
411
  end
@@ -417,14 +427,14 @@ module Kramdown
417
427
  next if el.type == :header && k == 'id' && !v.strip.empty?
418
428
  if v.nil?
419
429
  ''
420
- elsif k == 'class' && !v.empty? && !v.index(/[\.#]/)
430
+ elsif k == 'class' && !v.empty? && !v.index(/[.#]/)
421
431
  " " + v.split(/\s+/).map {|w| ".#{w}" }.join(" ")
422
432
  elsif k == 'id' && !v.strip.empty?
423
433
  " ##{v}"
424
434
  else
425
435
  " #{k}=\"#{v}\""
426
436
  end
427
- end.compact.join('')
437
+ end.compact.join
428
438
  res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
429
439
  el.options.dig(:ial, :refs)&.include?('toc')
430
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}" \