reverse_adoc 0.2.3

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/macos.yml +27 -0
  3. data/.github/workflows/ubuntu.yml +27 -0
  4. data/.github/workflows/windows.yml +30 -0
  5. data/.hound.yml +3 -0
  6. data/.rubocop.yml +10 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE.txt +25 -0
  9. data/README.adoc +290 -0
  10. data/Rakefile +14 -0
  11. data/bin/reverse_adoc +67 -0
  12. data/bin/w2a +85 -0
  13. data/lib/reverse_asciidoctor.rb +70 -0
  14. data/lib/reverse_asciidoctor/cleaner.rb +90 -0
  15. data/lib/reverse_asciidoctor/config.rb +53 -0
  16. data/lib/reverse_asciidoctor/converters.rb +33 -0
  17. data/lib/reverse_asciidoctor/converters/a.rb +38 -0
  18. data/lib/reverse_asciidoctor/converters/aside.rb +14 -0
  19. data/lib/reverse_asciidoctor/converters/audio.rb +34 -0
  20. data/lib/reverse_asciidoctor/converters/base.rb +24 -0
  21. data/lib/reverse_asciidoctor/converters/blockquote.rb +18 -0
  22. data/lib/reverse_asciidoctor/converters/br.rb +11 -0
  23. data/lib/reverse_asciidoctor/converters/bypass.rb +77 -0
  24. data/lib/reverse_asciidoctor/converters/code.rb +15 -0
  25. data/lib/reverse_asciidoctor/converters/div.rb +14 -0
  26. data/lib/reverse_asciidoctor/converters/drop.rb +18 -0
  27. data/lib/reverse_asciidoctor/converters/em.rb +18 -0
  28. data/lib/reverse_asciidoctor/converters/figure.rb +21 -0
  29. data/lib/reverse_asciidoctor/converters/h.rb +19 -0
  30. data/lib/reverse_asciidoctor/converters/head.rb +18 -0
  31. data/lib/reverse_asciidoctor/converters/hr.rb +11 -0
  32. data/lib/reverse_asciidoctor/converters/ignore.rb +12 -0
  33. data/lib/reverse_asciidoctor/converters/img.rb +80 -0
  34. data/lib/reverse_asciidoctor/converters/li.rb +24 -0
  35. data/lib/reverse_asciidoctor/converters/mark.rb +12 -0
  36. data/lib/reverse_asciidoctor/converters/math.rb +20 -0
  37. data/lib/reverse_asciidoctor/converters/ol.rb +46 -0
  38. data/lib/reverse_asciidoctor/converters/p.rb +17 -0
  39. data/lib/reverse_asciidoctor/converters/pass_through.rb +9 -0
  40. data/lib/reverse_asciidoctor/converters/pre.rb +38 -0
  41. data/lib/reverse_asciidoctor/converters/q.rb +12 -0
  42. data/lib/reverse_asciidoctor/converters/strong.rb +17 -0
  43. data/lib/reverse_asciidoctor/converters/sub.rb +12 -0
  44. data/lib/reverse_asciidoctor/converters/sup.rb +12 -0
  45. data/lib/reverse_asciidoctor/converters/table.rb +64 -0
  46. data/lib/reverse_asciidoctor/converters/td.rb +67 -0
  47. data/lib/reverse_asciidoctor/converters/text.rb +65 -0
  48. data/lib/reverse_asciidoctor/converters/th.rb +16 -0
  49. data/lib/reverse_asciidoctor/converters/tr.rb +22 -0
  50. data/lib/reverse_asciidoctor/converters/video.rb +36 -0
  51. data/lib/reverse_asciidoctor/errors.rb +10 -0
  52. data/lib/reverse_asciidoctor/version.rb +3 -0
  53. data/reverse_adoc.gemspec +35 -0
  54. data/spec/assets/anchors.html +22 -0
  55. data/spec/assets/basic.html +58 -0
  56. data/spec/assets/code.html +22 -0
  57. data/spec/assets/escapables.html +15 -0
  58. data/spec/assets/from_the_wild.html +23 -0
  59. data/spec/assets/full_example.html +49 -0
  60. data/spec/assets/html_fragment.html +3 -0
  61. data/spec/assets/lists.html +137 -0
  62. data/spec/assets/minimum.html +4 -0
  63. data/spec/assets/paragraphs.html +24 -0
  64. data/spec/assets/quotation.html +12 -0
  65. data/spec/assets/tables.html +99 -0
  66. data/spec/assets/unknown_tags.html +9 -0
  67. data/spec/components/anchors_spec.rb +21 -0
  68. data/spec/components/basic_spec.rb +49 -0
  69. data/spec/components/code_spec.rb +28 -0
  70. data/spec/components/escapables_spec.rb +23 -0
  71. data/spec/components/from_the_wild_spec.rb +17 -0
  72. data/spec/components/html_fragment_spec.rb +11 -0
  73. data/spec/components/lists_spec.rb +86 -0
  74. data/spec/components/paragraphs_spec.rb +15 -0
  75. data/spec/components/quotation_spec.rb +12 -0
  76. data/spec/components/tables_spec.rb +31 -0
  77. data/spec/components/unknown_tags_spec.rb +39 -0
  78. data/spec/lib/reverse_asciidoctor/cleaner_spec.rb +157 -0
  79. data/spec/lib/reverse_asciidoctor/config_spec.rb +26 -0
  80. data/spec/lib/reverse_asciidoctor/converters/aside_spec.rb +12 -0
  81. data/spec/lib/reverse_asciidoctor/converters/audio_spec.rb +18 -0
  82. data/spec/lib/reverse_asciidoctor/converters/blockquote_spec.rb +24 -0
  83. data/spec/lib/reverse_asciidoctor/converters/br_spec.rb +9 -0
  84. data/spec/lib/reverse_asciidoctor/converters/code_spec.rb +18 -0
  85. data/spec/lib/reverse_asciidoctor/converters/div_spec.rb +18 -0
  86. data/spec/lib/reverse_asciidoctor/converters/figure_spec.rb +13 -0
  87. data/spec/lib/reverse_asciidoctor/converters/img_spec.rb +28 -0
  88. data/spec/lib/reverse_asciidoctor/converters/li_spec.rb +13 -0
  89. data/spec/lib/reverse_asciidoctor/converters/mark_spec.rb +10 -0
  90. data/spec/lib/reverse_asciidoctor/converters/p_spec.rb +12 -0
  91. data/spec/lib/reverse_asciidoctor/converters/pre_spec.rb +45 -0
  92. data/spec/lib/reverse_asciidoctor/converters/q_spec.rb +10 -0
  93. data/spec/lib/reverse_asciidoctor/converters/strong_spec.rb +20 -0
  94. data/spec/lib/reverse_asciidoctor/converters/text_spec.rb +62 -0
  95. data/spec/lib/reverse_asciidoctor/converters/video_spec.rb +18 -0
  96. data/spec/lib/reverse_asciidoctor/converters_spec.rb +19 -0
  97. data/spec/lib/reverse_asciidoctor_spec.rb +37 -0
  98. data/spec/spec_helper.rb +21 -0
  99. metadata +299 -0
@@ -0,0 +1,20 @@
1
+ # Unless run with ReverseAsciidoctor.config.mathml2asciimath,
2
+ # this is cheating: we're injecting MathML into Asciidoctor, but
3
+ # Asciidoctor only understands AsciiMath or LaTeX
4
+
5
+ require "mathml2asciimath"
6
+
7
+ module ReverseAsciidoctor
8
+ module Converters
9
+ class Math < Base
10
+ def convert(node, state = {})
11
+ stem = node.to_s.gsub(/\n/, " ")
12
+ stem = MathML2AsciiMath.m2a(stem) if ReverseAsciidoctor.config.mathml2asciimath
13
+ stem = stem.gsub(/\[/, "\\[").gsub(/\]/, "\\]").gsub(/\(\(([^\)]+)\)\)/, "(\\1)") unless stem.nil?
14
+ " stem:[" << stem << "] "
15
+ end
16
+ end
17
+
18
+ register :math, Math.new
19
+ end
20
+ end
@@ -0,0 +1,46 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Ol < Base
4
+ def convert(node, state = {})
5
+ id = node['id']
6
+ anchor = id ? "[[#{id}]]\n" : ""
7
+ ol_count = state.fetch(:ol_count, 0) + 1
8
+ attrs = ol_attrs(node)
9
+ "\n#{anchor}#{attrs}" << treat_children(node, state.merge(ol_count: ol_count))
10
+ end
11
+
12
+ def number_style(node)
13
+ style = case node["style"]
14
+ when "1" then "arabic"
15
+ when "A" then "upperalpha"
16
+ when "a" then "loweralpha"
17
+ when "I" then "upperroman"
18
+ when "i" then "lowerroman"
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ def ol_attrs(node)
25
+ style = number_style(node)
26
+ reversed = "%reversed" if node["reversed"]
27
+ start = "start=#{node['start']}" if node["start"]
28
+ type = "type=#{node['type']}" if node["type"]
29
+ attrs = []
30
+ attrs << style if style
31
+ attrs << reversed if reversed
32
+ attrs << start if start
33
+ attrs << type if type
34
+ if attrs.empty?
35
+ ""
36
+ else
37
+ "[#{attrs.join(',')}]\n"
38
+ end
39
+ end
40
+ end
41
+
42
+ register :ol, Ol.new
43
+ register :ul, Ol.new
44
+ register :dir, Ol.new
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class P < Base
4
+ def convert(node, state = {})
5
+ id = node['id']
6
+ anchor = id ? "[[#{id}]]\n" : ""
7
+ if state[:tdsinglepara]
8
+ "#{anchor}" << treat_children(node, state).strip
9
+ else
10
+ "\n\n#{anchor}" << treat_children(node, state).strip << "\n\n"
11
+ end
12
+ end
13
+ end
14
+
15
+ register :p, P.new
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class PassThrough < Base
4
+ def convert(node, state = {})
5
+ node.to_s
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Pre < Base
4
+ def convert(node, state = {})
5
+ id = node['id']
6
+ anchor = id ? "[[#{id}]]\n" : ""
7
+ lang = language(node)
8
+ content = treat_children(node, state)
9
+ if lang
10
+ "\n\n#{anchor}[source,#{lang}]\n----\n" << content.lines.to_a.join("") << "\n----\n\n"
11
+ else
12
+ "\n\n#{anchor}....\n" << content.lines.to_a.join("") << "\n....\n\n"
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def treat(node, state)
19
+ node.to_s
20
+ end
21
+
22
+ def language(node)
23
+ lang = language_from_highlight_class(node)
24
+ lang || language_from_confluence_class(node)
25
+ end
26
+
27
+ def language_from_highlight_class(node)
28
+ node.parent['class'].to_s[/highlight-([a-zA-Z0-9]+)/, 1]
29
+ end
30
+
31
+ def language_from_confluence_class(node)
32
+ node['class'].to_s[/brush:\s?(:?.*);/, 1]
33
+ end
34
+ end
35
+
36
+ register :pre, Pre.new
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Q < Base
4
+ def convert(node, state = {})
5
+ content = treat_children(node, state)
6
+ "#{content[/^\s*/]}\"#{content.strip}\"#{content[/\s*$/]}"
7
+ end
8
+ end
9
+
10
+ register :q, Q.new
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Strong < Base
4
+ def convert(node, state = {})
5
+ content = treat_children(node, state.merge(already_strong: true))
6
+ if content.strip.empty? || state[:already_strong]
7
+ content
8
+ else
9
+ "#{content[/^\s*/]}*#{content.strip}*#{content[/\s*$/]}"
10
+ end
11
+ end
12
+ end
13
+
14
+ register :strong, Strong.new
15
+ register :b, Strong.new
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Sub < Base
4
+ def convert(node, state = {})
5
+ content = treat_children(node, state)
6
+ "#{content[/^\s*/]}~#{content.strip}~#{content[/\s*$/]}"
7
+ end
8
+ end
9
+
10
+ register :sub, Sub.new
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Sup < Base
4
+ def convert(node, state = {})
5
+ content = treat_children(node, state)
6
+ "#{content[/^\s*/]}^#{content.strip}^#{content[/\s*$/]}"
7
+ end
8
+ end
9
+
10
+ register :sup, Sup.new
11
+ end
12
+ end
@@ -0,0 +1,64 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Table < Base
4
+ def convert(node, state = {})
5
+ id = node['id']
6
+ anchor = id ? "[[#{id}]]\n" : ""
7
+ title = extract_title(node)
8
+ title = ".#{title}\n" unless title.empty?
9
+ attrs = style(node)
10
+ "\n\n#{anchor}#{attrs}#{title}|===\n" << treat_children(node, state) << "\n|===\n"
11
+ end
12
+
13
+ def extract_title(node)
14
+ title = node.at("./caption")
15
+ return "" if title.nil?
16
+ treat_children(title, {})
17
+ end
18
+
19
+ def frame(node)
20
+ case node["frame"]
21
+ when "void"
22
+ "frame=none"
23
+ when "hsides"
24
+ "frame=topbot"
25
+ when "vsides"
26
+ "frame=sides"
27
+ when "box", "border"
28
+ "frame=all"
29
+ else
30
+ nil
31
+ end
32
+ end
33
+
34
+ def rules(node)
35
+ case node["rules"]
36
+ when "all"
37
+ "rules=all"
38
+ when "rows"
39
+ "rules=rows"
40
+ when "cols"
41
+ "rules=cols"
42
+ when "none"
43
+ "rules=none"
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def style(node)
50
+ width = "width=#{node['width']}" if node['width']
51
+ attrs = []
52
+ frame_attr = frame(node)
53
+ rules_attr = rules(node)
54
+ attrs << width if width
55
+ attrs << frame_attr if frame_attr
56
+ attrs << rules_attr if rules_attr
57
+ return "" if attrs.empty?
58
+ "[#{attrs.join(',')}]\n"
59
+ end
60
+ end
61
+
62
+ register :table, Table.new
63
+ end
64
+ end
@@ -0,0 +1,67 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Td < Base
4
+ def convert(node, state = {})
5
+ id = node['id']
6
+ anchor = id ? "[[#{id}]]" : ""
7
+ colrowattr = colrow(node['colspan'], node['rowspan'])
8
+ alignattr = alignstyle(node)
9
+ style = cellstyle(node)
10
+ singlepara = node.elements.size == 1 && node.elements.first.name == "p"
11
+ state[:tdsinglepara] = singlepara if singlepara
12
+ adoccell = node.at(".//ul | .//ol | .//pre | .//blockquote | .//br | .//hr") ||
13
+ node.at(".//p") && !singlepara
14
+ style = "a" if adoccell
15
+ delim = adoccell ? "\n" : " "
16
+ content = treat_children(node, state)
17
+ "#{colrowattr}#{alignattr}#{style}| #{anchor}#{content}#{delim}"
18
+ end
19
+
20
+ def cellstyle(node)
21
+ ""
22
+ end
23
+
24
+ def colrow(colspan, rowspan)
25
+ if colspan && rowspan
26
+ "#{colspan}.#{rowspan}+"
27
+ elsif colspan
28
+ "#{colspan}+"
29
+ elsif rowspan
30
+ ".#{rowspan}+"
31
+ else
32
+ ""
33
+ end
34
+ end
35
+
36
+ def alignstyle(node)
37
+ align = node["align"]
38
+ valign = node["valign"]
39
+ a = case align
40
+ when "left" then "<"
41
+ when "center" then "^"
42
+ when "right" then ">"
43
+ else
44
+ ""
45
+ end
46
+ v = case valign
47
+ when "top" then "<"
48
+ when "middle" then "^"
49
+ when "bottom" then ">"
50
+ else
51
+ ""
52
+ end
53
+ if align && valign
54
+ "#{a}.#{v}"
55
+ elsif align
56
+ a
57
+ elsif valign
58
+ ".#{v}"
59
+ else
60
+ ""
61
+ end
62
+ end
63
+ end
64
+
65
+ register :td, Td.new
66
+ end
67
+ end
@@ -0,0 +1,65 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Text < Base
4
+ def convert(node, state = {})
5
+ if node.text.strip.empty?
6
+ treat_empty(node, state)
7
+ else
8
+ treat_text(node)
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def treat_empty(node, state)
15
+ parent = node.parent.name.to_sym
16
+ if [:ol, :ul].include?(parent) # Otherwise the identation is broken
17
+ ''
18
+ elsif state[:tdsinglepara]
19
+ ''
20
+ elsif node.text == ' ' # Regular whitespace text node
21
+ ' '
22
+ else
23
+ ''
24
+ end
25
+ end
26
+
27
+ def treat_text(node)
28
+ text = node.text
29
+ text = preserve_nbsp(text)
30
+ text = remove_border_newlines(text)
31
+ text = remove_inner_newlines(text)
32
+ text = escape_keychars(text)
33
+
34
+ text = preserve_keychars_within_backticks(text)
35
+ text = preserve_tags(text)
36
+
37
+ text
38
+ end
39
+
40
+ def preserve_nbsp(text)
41
+ text.gsub(/\u00A0/, "&nbsp;")
42
+ end
43
+
44
+ def preserve_tags(text)
45
+ text.gsub(/[<>]/, '>' => '\>', '<' => '\<')
46
+ end
47
+
48
+ def remove_border_newlines(text)
49
+ text.gsub(/\A\n+/, '').gsub(/\n+\z/, '')
50
+ end
51
+
52
+ def remove_inner_newlines(text)
53
+ text.tr("\n\t", ' ').squeeze(' ')
54
+ end
55
+
56
+ def preserve_keychars_within_backticks(text)
57
+ text.gsub(/`.*?`/) do |match|
58
+ match.gsub('\_', '_').gsub('\*', '*')
59
+ end
60
+ end
61
+ end
62
+
63
+ register :text, Text.new
64
+ end
65
+ end
@@ -0,0 +1,16 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Th < Td
4
+ def cellstyle(node)
5
+ if node.parent.previous_element.nil?
6
+ # this is the header row
7
+ ""
8
+ else
9
+ "h"
10
+ end
11
+ end
12
+ end
13
+
14
+ register :th, Th.new
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Tr < Base
4
+ def convert(node, state = {})
5
+ content = treat_children(node, state).rstrip
6
+ result = "#{content}\n"
7
+ table_header_row?(node) ? result + underline_for(node) : result
8
+ end
9
+
10
+ def table_header_row?(node)
11
+ # node.element_children.all? {|child| child.name.to_sym == :th}
12
+ node.previous_element.nil?
13
+ end
14
+
15
+ def underline_for(node)
16
+ "\n"
17
+ end
18
+ end
19
+
20
+ register :tr, Tr.new
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ module ReverseAsciidoctor
2
+ module Converters
3
+ class Video < Base
4
+ def convert(node, state = {})
5
+ autoplay = node['autoplay']
6
+ loop_attr = node['loop']
7
+ controls = node['controls']
8
+ src = node['src']
9
+ id = node['id']
10
+ anchor = id ? "[[#{id}]]\n" : ""
11
+ title = extract_title(node)
12
+ title = ".#{title}\n" unless title.empty?
13
+ [anchor, title, "video::", src, "[", options(node), "]"].join("")
14
+ end
15
+
16
+ def options(node)
17
+ autoplay = node['autoplay']
18
+ loop_attr = node['loop']
19
+ controls = node['controls']
20
+ width = node['width']
21
+ ret = ""
22
+ if autoplay || loop_attr || controls
23
+ out = []
24
+ out << "autoplay" if autoplay
25
+ out << "loop" if loop_attr
26
+ out << "controls" if controls
27
+ out << "width=#{width}" if width
28
+ ret = %{options="#{out.join(',')}"}
29
+ end
30
+ ret
31
+ end
32
+ end
33
+
34
+ register :video, Video.new
35
+ end
36
+ end