metanorma-standoc 1.11.3 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -31
  3. data/.gitignore +23 -0
  4. data/Gemfile +0 -1
  5. data/lib/asciidoctor/standoc/base.rb +2 -145
  6. data/lib/asciidoctor/standoc/blocks.rb +2 -238
  7. data/lib/asciidoctor/standoc/blocks_notes.rb +2 -100
  8. data/lib/asciidoctor/standoc/cleanup.rb +2 -208
  9. data/lib/asciidoctor/standoc/cleanup_amend.rb +2 -53
  10. data/lib/asciidoctor/standoc/cleanup_block.rb +2 -172
  11. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +2 -212
  12. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +2 -108
  13. data/lib/asciidoctor/standoc/cleanup_image.rb +2 -69
  14. data/lib/asciidoctor/standoc/cleanup_inline.rb +2 -189
  15. data/lib/asciidoctor/standoc/cleanup_maths.rb +2 -221
  16. data/lib/asciidoctor/standoc/cleanup_ref.rb +2 -169
  17. data/lib/asciidoctor/standoc/cleanup_ref_dl.rb +2 -103
  18. data/lib/asciidoctor/standoc/cleanup_reqt.rb +2 -110
  19. data/lib/asciidoctor/standoc/cleanup_section.rb +2 -184
  20. data/lib/asciidoctor/standoc/cleanup_section_names.rb +2 -91
  21. data/lib/asciidoctor/standoc/cleanup_symbols.rb +2 -47
  22. data/lib/asciidoctor/standoc/cleanup_table.rb +2 -67
  23. data/lib/asciidoctor/standoc/cleanup_terms.rb +2 -139
  24. data/lib/asciidoctor/standoc/cleanup_terms_designations.rb +2 -192
  25. data/lib/asciidoctor/standoc/cleanup_text.rb +2 -95
  26. data/lib/asciidoctor/standoc/cleanup_toc.rb +3 -0
  27. data/lib/asciidoctor/standoc/cleanup_xref.rb +2 -106
  28. data/lib/asciidoctor/standoc/converter.rb +2 -123
  29. data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +2 -56
  30. data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +2 -102
  31. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +3 -404
  32. data/lib/asciidoctor/standoc/deprecated.rb +5 -0
  33. data/lib/asciidoctor/standoc/front.rb +2 -219
  34. data/lib/asciidoctor/standoc/front_contributor.rb +2 -191
  35. data/lib/asciidoctor/standoc/inline.rb +2 -231
  36. data/lib/asciidoctor/standoc/lists.rb +2 -119
  37. data/lib/asciidoctor/standoc/macros.rb +2 -203
  38. data/lib/asciidoctor/standoc/macros_form.rb +2 -62
  39. data/lib/asciidoctor/standoc/macros_note.rb +2 -44
  40. data/lib/asciidoctor/standoc/macros_plantuml.rb +2 -112
  41. data/lib/asciidoctor/standoc/macros_terms.rb +2 -180
  42. data/lib/asciidoctor/standoc/ref.rb +2 -251
  43. data/lib/asciidoctor/standoc/ref_sect.rb +2 -153
  44. data/lib/asciidoctor/standoc/ref_utility.rb +2 -0
  45. data/lib/asciidoctor/standoc/render.rb +2 -116
  46. data/lib/asciidoctor/standoc/reqt.rb +2 -89
  47. data/lib/asciidoctor/standoc/section.rb +2 -194
  48. data/lib/asciidoctor/standoc/table.rb +2 -84
  49. data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +2 -178
  50. data/lib/asciidoctor/standoc/terms.rb +2 -153
  51. data/lib/asciidoctor/standoc/utils.rb +2 -100
  52. data/lib/asciidoctor/standoc/validate.rb +2 -157
  53. data/lib/asciidoctor/standoc/validate_section.rb +2 -54
  54. data/lib/isodoc/html/htmlstyle.css +44 -29
  55. data/lib/isodoc/html/htmlstyle.scss +17 -12
  56. data/lib/metanorma/standoc/base.rb +163 -0
  57. data/lib/{asciidoctor → metanorma}/standoc/basicdoc.rng +0 -0
  58. data/lib/{asciidoctor → metanorma}/standoc/biblio.rng +2 -2
  59. data/lib/metanorma/standoc/blocks.rb +239 -0
  60. data/lib/metanorma/standoc/blocks_notes.rb +101 -0
  61. data/lib/metanorma/standoc/cleanup.rb +157 -0
  62. data/lib/metanorma/standoc/cleanup_amend.rb +54 -0
  63. data/lib/metanorma/standoc/cleanup_block.rb +173 -0
  64. data/lib/metanorma/standoc/cleanup_boilerplate.rb +213 -0
  65. data/lib/metanorma/standoc/cleanup_footnotes.rb +109 -0
  66. data/lib/metanorma/standoc/cleanup_image.rb +70 -0
  67. data/lib/metanorma/standoc/cleanup_inline.rb +190 -0
  68. data/lib/metanorma/standoc/cleanup_maths.rb +222 -0
  69. data/lib/metanorma/standoc/cleanup_ref.rb +170 -0
  70. data/lib/metanorma/standoc/cleanup_ref_dl.rb +104 -0
  71. data/lib/metanorma/standoc/cleanup_reqt.rb +111 -0
  72. data/lib/metanorma/standoc/cleanup_section.rb +212 -0
  73. data/lib/metanorma/standoc/cleanup_section_names.rb +92 -0
  74. data/lib/metanorma/standoc/cleanup_symbols.rb +48 -0
  75. data/lib/metanorma/standoc/cleanup_table.rb +68 -0
  76. data/lib/metanorma/standoc/cleanup_terms.rb +140 -0
  77. data/lib/metanorma/standoc/cleanup_terms_designations.rb +199 -0
  78. data/lib/metanorma/standoc/cleanup_text.rb +74 -0
  79. data/lib/metanorma/standoc/cleanup_toc.rb +98 -0
  80. data/lib/metanorma/standoc/cleanup_xref.rb +107 -0
  81. data/lib/metanorma/standoc/converter.rb +126 -0
  82. data/lib/metanorma/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
  83. data/lib/metanorma/standoc/datamodel/diagram_preprocessor.rb +103 -0
  84. data/lib/metanorma/standoc/datamodel/plantuml_renderer.rb +409 -0
  85. data/lib/metanorma/standoc/front.rb +224 -0
  86. data/lib/metanorma/standoc/front_contributor.rb +192 -0
  87. data/lib/metanorma/standoc/inline.rb +232 -0
  88. data/lib/{asciidoctor → metanorma}/standoc/isodoc.rng +104 -3
  89. data/lib/metanorma/standoc/lists.rb +120 -0
  90. data/lib/metanorma/standoc/macros.rb +205 -0
  91. data/lib/metanorma/standoc/macros_embed.rb +72 -0
  92. data/lib/metanorma/standoc/macros_form.rb +63 -0
  93. data/lib/metanorma/standoc/macros_note.rb +45 -0
  94. data/lib/metanorma/standoc/macros_plantuml.rb +113 -0
  95. data/lib/metanorma/standoc/macros_terms.rb +194 -0
  96. data/lib/metanorma/standoc/ref.rb +243 -0
  97. data/lib/metanorma/standoc/ref_sect.rb +153 -0
  98. data/lib/{asciidoctor/standoc/ref_date_id.rb → metanorma/standoc/ref_utility.rb} +43 -5
  99. data/lib/metanorma/standoc/render.rb +115 -0
  100. data/lib/metanorma/standoc/reqt.rb +90 -0
  101. data/lib/{asciidoctor → metanorma}/standoc/reqt.rng +0 -0
  102. data/lib/metanorma/standoc/section.rb +209 -0
  103. data/lib/metanorma/standoc/table.rb +85 -0
  104. data/lib/metanorma/standoc/term_lookup_cleanup.rb +179 -0
  105. data/lib/metanorma/standoc/terms.rb +160 -0
  106. data/lib/metanorma/standoc/utils.rb +101 -0
  107. data/lib/metanorma/standoc/validate.rb +158 -0
  108. data/lib/metanorma/standoc/validate_section.rb +55 -0
  109. data/lib/metanorma/standoc/version.rb +1 -1
  110. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/model_representation.adoc.erb +0 -0
  111. data/lib/{asciidoctor → metanorma}/standoc/views/datamodel/plantuml_representation.adoc.erb +0 -0
  112. data/lib/metanorma-standoc.rb +1 -1
  113. data/metanorma-standoc.gemspec +1 -1
  114. data/spec/assets/a1.adoc +8 -0
  115. data/spec/assets/a2.adoc +8 -0
  116. data/spec/assets/a3.adoc +9 -0
  117. data/spec/assets/a4.adoc +4 -0
  118. data/spec/{asciidoctor → metanorma}/base_spec.rb +499 -407
  119. data/spec/{asciidoctor → metanorma}/blank_spec.rb +1 -1
  120. data/spec/{asciidoctor → metanorma}/blocks_spec.rb +1 -1
  121. data/spec/{asciidoctor → metanorma}/cleanup_blocks_spec.rb +1 -1
  122. data/spec/{asciidoctor → metanorma}/cleanup_sections_spec.rb +1 -1
  123. data/spec/{asciidoctor → metanorma}/cleanup_spec.rb +5 -5
  124. data/spec/{asciidoctor → metanorma}/cleanup_terms_spec.rb +227 -119
  125. data/spec/{asciidoctor → metanorma}/datamodel/attributes_table_preprocessor_spec.rb +1 -1
  126. data/spec/{asciidoctor → metanorma}/datamodel/diagram_preprocessor_spec.rb +1 -1
  127. data/spec/{asciidoctor → metanorma}/inline_spec.rb +170 -1
  128. data/spec/{asciidoctor → metanorma}/isobib_cache_spec.rb +1 -1
  129. data/spec/{asciidoctor → metanorma}/lists_spec.rb +1 -1
  130. data/spec/{asciidoctor → metanorma}/macros_json2text_spec.rb +0 -0
  131. data/spec/{asciidoctor → metanorma}/macros_plantuml_spec.rb +3 -3
  132. data/spec/{asciidoctor → metanorma}/macros_spec.rb +97 -6
  133. data/spec/{asciidoctor → metanorma}/macros_yaml2text_spec.rb +0 -0
  134. data/spec/metanorma/refs_dl_spec.rb +863 -0
  135. data/spec/{asciidoctor → metanorma}/refs_spec.rb +522 -15
  136. data/spec/{asciidoctor → metanorma}/section_spec.rb +59 -1
  137. data/spec/{asciidoctor → metanorma}/table_spec.rb +1 -1
  138. data/spec/{asciidoctor → metanorma}/validate_spec.rb +2 -2
  139. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +46 -46
  140. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec1.yml +12 -12
  141. data/spec/vcr_cassettes/hide_refs.yml +599 -0
  142. data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
  143. data/spec/vcr_cassettes/isobib_get_123_1.yml +24 -24
  144. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +35 -35
  145. data/spec/vcr_cassettes/isobib_get_123_2001.yml +13 -13
  146. data/spec/vcr_cassettes/isobib_get_124.yml +10 -10
  147. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +18 -18
  148. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
  149. metadata +88 -32
  150. data/spec/asciidoctor/refs_dl_spec.rb +0 -864
@@ -0,0 +1,120 @@
1
+ module Metanorma
2
+ module Standoc
3
+ module Lists
4
+ def li(xml_ul, item)
5
+ xml_ul.li do |xml_li|
6
+ if item.blocks?
7
+ xml_li.p(**attr_code(id_attr(item))) { |t| t << item.text }
8
+ xml_li << item.content
9
+ else
10
+ xml_li.p(**attr_code(id_attr(item))) { |p| p << item.text }
11
+ end
12
+ end
13
+ end
14
+
15
+ def ul_li(xml_ul, item)
16
+ xml_ul.li **ul_li_attrs(item) do |xml_li|
17
+ xml_li.p(**attr_code(id_attr(item))) { |t| t << item.text }
18
+ if item.blocks?
19
+ xml_li << item.content
20
+ end
21
+ end
22
+ end
23
+
24
+ def ul_attrs(node)
25
+ attr_code(id_attr(node).merge(keep_attrs(node)))
26
+ end
27
+
28
+ def ul_li_attrs(node)
29
+ c = node.attr?("checked")
30
+ attr_code(
31
+ uncheckedcheckbox: node.attr?("checkbox") ? !c : nil,
32
+ checkedcheckbox: node.attr?("checkbox") ? c : nil,
33
+ )
34
+ end
35
+
36
+ def ulist(node)
37
+ return reference(node) if in_norm_ref? || in_biblio?
38
+
39
+ noko do |xml|
40
+ xml.ul **ul_attrs(node) do |xml_ul|
41
+ node.items.each do |item|
42
+ ul_li(xml_ul, item)
43
+ end
44
+ end
45
+ end.join("\n")
46
+ end
47
+
48
+ def olist_style(style)
49
+ return "alphabet" if style == "loweralpha"
50
+ return "roman" if style == "lowerroman"
51
+ return "roman_upper" if style == "upperroman"
52
+ return "alphabet_upper" if style == "upperalpha"
53
+
54
+ style
55
+ end
56
+
57
+ def ol_attrs(node)
58
+ attr_code(id_attr(node).merge(keep_attrs(node)
59
+ .merge(type: olist_style(node.style))))
60
+ end
61
+
62
+ def olist(node)
63
+ noko do |xml|
64
+ xml.ol **ol_attrs(node) do |xml_ol|
65
+ node.items.each { |item| li(xml_ol, item) }
66
+ end
67
+ end.join("\n")
68
+ end
69
+
70
+ def dt(terms, xml_dl)
71
+ terms.each_with_index do |dt, idx|
72
+ xml_dl.dt { |xml_dt| xml_dt << dt.text }
73
+ if idx < terms.size - 1
74
+ xml_dl.dd
75
+ end
76
+ end
77
+ end
78
+
79
+ def dd(ddefn, xml_dl)
80
+ if ddefn.nil?
81
+ xml_dl.dd
82
+ return
83
+ end
84
+ xml_dl.dd do |xml_dd|
85
+ xml_dd.p { |t| t << ddefn.text } if ddefn.text?
86
+ xml_dd << ddefn.content if ddefn.blocks?
87
+ end
88
+ end
89
+
90
+ def dl_attrs(node)
91
+ attr_code(id_attr(node).merge(keep_attrs(node)
92
+ .merge(
93
+ metadata: node.option?("metadata") ? "true" : nil,
94
+ key: node.option?("key") ? "true" : nil,
95
+ )))
96
+ end
97
+
98
+ def dlist(node)
99
+ noko do |xml|
100
+ xml.dl **dl_attrs(node) do |xml_dl|
101
+ node.items.each do |terms, dd|
102
+ dt(terms, xml_dl)
103
+ dd(dd, xml_dl)
104
+ end
105
+ end
106
+ end.join("\n")
107
+ end
108
+
109
+ def colist(node)
110
+ noko do |xml|
111
+ node.items.each_with_index do |item, i|
112
+ xml.annotation **attr_code(id: i + 1) do |xml_li|
113
+ xml_li.p { |p| p << item.text }
114
+ end
115
+ end
116
+ end.join("\n")
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,205 @@
1
+ require "asciidoctor/extensions"
2
+ require "fileutils"
3
+ require "uuidtools"
4
+ require "yaml"
5
+ require "csv"
6
+ require_relative "./macros_plantuml"
7
+ require_relative "./macros_terms"
8
+ require_relative "./macros_form"
9
+ require_relative "./macros_note"
10
+ require_relative "./macros_embed"
11
+ require_relative "./datamodel/attributes_table_preprocessor"
12
+ require_relative "./datamodel/diagram_preprocessor"
13
+ require "metanorma-plugin-datastruct"
14
+ require "metanorma-plugin-lutaml"
15
+
16
+ module Metanorma
17
+ module Standoc
18
+ class InheritInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
19
+ use_dsl
20
+ named :inherit
21
+ parse_content_as :text
22
+ using_format :short
23
+
24
+ def process(parent, _target, attrs)
25
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
26
+ %{<inherit>#{out}</inherit>}
27
+ end
28
+ end
29
+
30
+ class IndexXrefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
31
+ use_dsl
32
+ named :index
33
+
34
+ def preprocess_attrs(attrs)
35
+ return unless attrs.size > 1 && attrs.size < 5
36
+
37
+ ret = { primary: attrs[1], target: attrs[attrs.size] }
38
+ ret[:secondary] = attrs[2] if attrs.size > 2
39
+ ret[:tertiary] = attrs[3] if attrs.size > 3
40
+ ret
41
+ end
42
+
43
+ def process(_parent, target, attr)
44
+ args = preprocess_attrs(attr) or return
45
+ ret = "<index-xref also='#{target == 'also'}'>"\
46
+ "<primary>#{args[:primary]}</primary>"
47
+ ret += "<secondary>#{args[:secondary]}</secondary>" if args[:secondary]
48
+ ret += "<tertiary>#{args[:tertiary]}</tertiary>" if args[:tertiary]
49
+ ret + "<target>#{args[:target]}</target></index-xref>"
50
+ end
51
+ end
52
+
53
+ class IndexRangeInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
54
+ use_dsl
55
+ named :"index-range"
56
+ parse_content_as :text
57
+
58
+ def process(parent, target, attr)
59
+ text = attr["text"]
60
+ text = "((#{text}))" unless /^\(\(.+\)\)$/.match?(text)
61
+ out = parent.sub_macros(text)
62
+ out.sub(/<index>/, "<index to='#{target}'>")
63
+ end
64
+ end
65
+
66
+ class PseudocodeBlockMacro < Asciidoctor::Extensions::BlockProcessor
67
+ use_dsl
68
+ named :pseudocode
69
+ on_context :example, :sourcecode
70
+
71
+ def init_indent(line)
72
+ /^(?<prefix>[ \t]*)(?<suffix>.*)$/ =~ line
73
+ prefix = prefix.gsub(/\t/, "\u00a0\u00a0\u00a0\u00a0")
74
+ .gsub(/ /, "\u00a0")
75
+ prefix + suffix
76
+ end
77
+
78
+ def supply_br(lines)
79
+ ignore = false
80
+ lines.each_with_index do |l, i|
81
+ /^(--+|====+|\|===|\.\.\.\.+|\*\*\*\*+|\+\+\+\++|````+|____\+)$/
82
+ .match(l) && (ignore = !ignore)
83
+ next if l.empty? || l.match(/ \+$/) || /^\[.*\]$/.match?(l) || ignore
84
+ next if i == lines.size - 1 ||
85
+ i < lines.size - 1 && lines[i + 1].empty?
86
+
87
+ lines[i] += " +"
88
+ end
89
+ lines
90
+ end
91
+
92
+ def process(parent, reader, attrs)
93
+ attrs["role"] = "pseudocode"
94
+ lines = reader.lines.map { |m| init_indent(m) }
95
+ create_block(parent, :example, supply_br(lines),
96
+ attrs, content_model: :compound)
97
+ end
98
+ end
99
+
100
+ class HTML5RubyMacro < Asciidoctor::Extensions::InlineMacroProcessor
101
+ use_dsl
102
+ named :ruby
103
+ parse_content_as :text
104
+ option :pos_attrs, %w(rpbegin rt rpend)
105
+
106
+ # for example, html5ruby:楽聖少女[がくせいしょうじょ]
107
+ def process(_parent, target, attributes)
108
+ rpbegin = "("
109
+ rpend = ")"
110
+ if (attributes.size == 1) && attributes.key?("text")
111
+ rt = attributes["text"]
112
+ elsif (attributes.size == 2) && attributes.key?(1) &&
113
+ attributes.key?("rpbegin")
114
+ rt = attributes[1] || ""
115
+ else
116
+ rpbegin = attributes["rpbegin"]
117
+ rt = attributes["rt"]
118
+ rpend = attributes["rpend"]
119
+ end
120
+
121
+ "<ruby>#{target}<rp>#{rpbegin}</rp><rt>#{rt}</rt>"\
122
+ "<rp>#{rpend}</rp></ruby>"
123
+ end
124
+ end
125
+
126
+ class AutonumberInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
127
+ use_dsl
128
+ named :autonumber
129
+ parse_content_as :text
130
+
131
+ def process(parent, target, attrs)
132
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
133
+ %{<autonumber type=#{target}>#{out}</autonumber>}
134
+ end
135
+ end
136
+
137
+ class VariantInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
138
+ use_dsl
139
+ named :lang
140
+ parse_content_as :text
141
+
142
+ def process(parent, target, attrs)
143
+ /^(?<lang>[^-]*)(-(?<script>.*))?$/ =~ target
144
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
145
+ if script
146
+ %{<variant lang=#{lang} script=#{script}>#{out}</variant>}
147
+ else
148
+ %{<variant lang=#{lang}>#{out}</variant>}
149
+ end
150
+ end
151
+ end
152
+
153
+ class AddMacro < Asciidoctor::Extensions::InlineMacroProcessor
154
+ use_dsl
155
+ named :add
156
+ parse_content_as :text
157
+ using_format :short
158
+
159
+ def process(parent, _target, attrs)
160
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
161
+ %{<add>#{out}</add>}
162
+ end
163
+ end
164
+
165
+ class DelMacro < Asciidoctor::Extensions::InlineMacroProcessor
166
+ use_dsl
167
+ named :del
168
+ parse_content_as :text
169
+ using_format :short
170
+
171
+ def process(parent, _target, attrs)
172
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
173
+ %{<del>#{out}</del>}
174
+ end
175
+ end
176
+
177
+ class ToCInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
178
+ use_dsl
179
+ named :toc
180
+ parse_content_as :text
181
+ using_format :short
182
+
183
+ def process(parent, _target, attrs)
184
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
185
+ content = CSV.parse_line(out).map do |x|
186
+ x.sub!(/^(["'])(.+)\1/, "\\2")
187
+ m = /^(.*?)(:\d+)?$/.match(x)
188
+ %{<toc-xpath depth='#{m[2]&.sub(/:/, '') || 1}'>#{m[1]}</toc-xpath>}
189
+ end.join
190
+ "<toc>#{content}</toc>"
191
+ end
192
+ end
193
+
194
+ class PassInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
195
+ use_dsl
196
+ named :"pass-format"
197
+
198
+ def process(parent, target, attrs)
199
+ format = target || "metanorma"
200
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs[1]).convert
201
+ %{<passthrough formats="#{format}">#{out}</passthrough>}
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,72 @@
1
+ module Metanorma
2
+ module Standoc
3
+ class EmbedIncludeProcessor < Asciidoctor::Extensions::Preprocessor
4
+ def process(doc, reader)
5
+ return reader if reader.eof?
6
+
7
+ lines = reader.readlines
8
+ while !lines.grep(/^embed::/).empty?
9
+ headings = lines.grep(/^== /).map(&:strip)
10
+ lines = lines.map do |line|
11
+ /^embed::/.match?(line) ? embed(line, doc, reader, headings) : line
12
+ end.flatten
13
+ end
14
+ ::Asciidoctor::Reader.new lines
15
+ end
16
+
17
+ def filename(line, doc, reader)
18
+ m = /^embed::([^\[]+)\[/.match(line)
19
+ f = doc.normalize_system_path m[1], reader.dir, nil,
20
+ target_name: "include file"
21
+ File.exist?(f) ? f : nil
22
+ end
23
+
24
+ def readlines_safe(file)
25
+ if file.eof? then []
26
+ else file.readlines
27
+ end
28
+ end
29
+
30
+ def embed(line, doc, reader, headings)
31
+ inc_path = filename(line, doc, reader) or return line
32
+ lines = filter_sections(read(inc_path), headings)
33
+ doc = Asciidoctor::Document.new [], { safe: :safe }
34
+ reader = ::Asciidoctor::PreprocessorReader.new doc, lines
35
+ strip_header(reader.read_lines)
36
+ end
37
+
38
+ def read(inc_path)
39
+ ::File.open inc_path, "r" do |fd|
40
+ readlines_safe(fd).map(&:chomp)
41
+ end
42
+ end
43
+
44
+ def strip_header(lines)
45
+ return lines unless !lines.empty? && lines.first.start_with?("= ")
46
+
47
+ skip = true
48
+ lines.each_with_object([]) do |l, m|
49
+ m << l unless skip
50
+ skip = false if !/\S/.match?(l)
51
+ end
52
+ end
53
+
54
+ def filter_sections(lines, headings)
55
+ skip = false
56
+ lines.each_with_index.with_object([]) do |(l, i), m|
57
+ if headings.include?(l.strip)
58
+ skip = true
59
+ m.unshift while !m.empty? && /^\S/.match?(m[-1])
60
+ elsif skip && /^== |^embed::|^include::/.match?(l)
61
+ skip = false
62
+ j = i
63
+ j -= 1 while j >= 0 && /^\S/.match?(m[j])
64
+ lines[j..i].each { |n| m << n }
65
+ else
66
+ skip or m << l
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,63 @@
1
+ module Metanorma
2
+ module Standoc
3
+ class FormInputMacro < Asciidoctor::Extensions::InlineMacroProcessor
4
+ use_dsl
5
+ named :input
6
+
7
+ def process(_parent, target, attr)
8
+ m = %w(id name value disabled readonly checked maxlength minlength)
9
+ .map { |a| attr[a] ? " #{a}='#{attr[a]}'" : nil }.compact
10
+ %{<input type='#{target}' #{m.join}/>}
11
+ end
12
+ end
13
+
14
+ class FormLabelMacro < Asciidoctor::Extensions::InlineMacroProcessor
15
+ use_dsl
16
+ named :label
17
+ parse_content_as :text
18
+
19
+ def process(parent, target, attr)
20
+ out = Asciidoctor::Inline.new(parent, :quoted, attr["text"]).convert
21
+ %{<label for="#{target}">#{out}</label>}
22
+ end
23
+ end
24
+
25
+ class FormTextareaMacro < Asciidoctor::Extensions::InlineMacroProcessor
26
+ use_dsl
27
+ named :textarea
28
+ using_format :short
29
+
30
+ def process(_parent, _target, attr)
31
+ m = %w(id name rows cols value)
32
+ .map { |a| attr[a] ? " #{a}='#{attr[a]}'" : nil }.compact
33
+ %{<textarea #{m.join}/>}
34
+ end
35
+ end
36
+
37
+ class FormSelectMacro < Asciidoctor::Extensions::InlineMacroProcessor
38
+ use_dsl
39
+ named :select
40
+ using_format :short
41
+
42
+ def process(parent, _target, attr)
43
+ m = %w(id name size disabled multiple value)
44
+ .map { |a| attr[a] ? " #{a}='#{attr[a]}'" : nil }.compact
45
+ out = Asciidoctor::Inline.new(parent, :quoted, attr["text"]).convert
46
+ %{<select #{m.join}>#{out}</select>}
47
+ end
48
+ end
49
+
50
+ class FormOptionMacro < Asciidoctor::Extensions::InlineMacroProcessor
51
+ use_dsl
52
+ named :option
53
+ using_format :short
54
+
55
+ def process(parent, _target, attr)
56
+ m = %w(disabled value)
57
+ .map { |a| attr[a] ? " #{a}='#{attr[a]}'" : nil }.compact
58
+ out = Asciidoctor::Inline.new(parent, :quoted, attr["text"]).convert
59
+ %{<option #{m.join}">#{out}</option>}
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,45 @@
1
+ module Metanorma
2
+ module Standoc
3
+ class ToDoAdmonitionBlock < Asciidoctor::Extensions::BlockProcessor
4
+ use_dsl
5
+ named :TODO
6
+ on_contexts :example, :paragraph
7
+
8
+ def process(parent, reader, attrs)
9
+ attrs["name"] = "todo"
10
+ attrs["caption"] = "TODO"
11
+ create_block(parent, :admonition, reader.lines, attrs,
12
+ content_model: :compound)
13
+ end
14
+ end
15
+
16
+ class ToDoInlineAdmonitionBlock < Asciidoctor::Extensions::Treeprocessor
17
+ def process(document)
18
+ (document.find_by context: :paragraph).each do |para|
19
+ next unless /^TODO: /.match? para.lines[0]
20
+
21
+ parent = para.parent
22
+ para.set_attr("name", "todo")
23
+ para.set_attr("caption", "TODO")
24
+ para.lines[0].sub!(/^TODO: /, "")
25
+ todo = Asciidoctor::Block.new(parent, :admonition, attributes: para.attributes,
26
+ source: para.lines,
27
+ content_model: :compound)
28
+ parent.blocks[parent.blocks.index(para)] = todo
29
+ end
30
+ end
31
+ end
32
+
33
+ class FootnoteBlockInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
34
+ use_dsl
35
+ named :footnoteblock
36
+ parse_content_as :text
37
+ using_format :short
38
+
39
+ def process(parent, _target, attrs)
40
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
41
+ %{<footnoteblock>#{out}</footnoteblock>}
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,113 @@
1
+ module Metanorma
2
+ module Standoc
3
+ class PlantUMLBlockMacroBackend
4
+ # https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
5
+ def self.plantuml_installed?
6
+ cmd = "plantuml"
7
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
8
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
9
+ exts.each do |ext|
10
+ exe = File.join(path, "#{cmd}#{ext}")
11
+ return exe if File.executable?(exe) && !File.directory?(exe)
12
+ end
13
+ end
14
+ raise "PlantUML not installed"
15
+ end
16
+
17
+ def self.run(umlfile, outfile)
18
+ system "plantuml #{umlfile.path}" or (warn $? and return false)
19
+ i = 0
20
+ until !Gem.win_platform? || File.exist?(outfile) || i == 15
21
+ sleep(1)
22
+ i += 1
23
+ end
24
+ File.exist?(outfile)
25
+ end
26
+
27
+ # if no :imagesdir: leave image file in plantuml
28
+ # sleep need for windows because dot works in separate process and
29
+ # plantuml process may finish earlier then dot, as result png file
30
+ # maybe not created yet after plantuml finish
31
+ #
32
+ # # Warning: metanorma/metanorma-standoc#187
33
+ # Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
34
+ # This is why we need to copy and then unlink.
35
+ def self.generate_file(parent, reader)
36
+ localdir = Metanorma::Utils::localdir(parent.document)
37
+ imagesdir = parent.document.attr("imagesdir")
38
+ umlfile, outfile = save_plantuml parent, reader, localdir
39
+ run(umlfile, outfile) or
40
+ raise "No image output from PlantUML (#{umlfile}, #{outfile})!"
41
+ umlfile.unlink
42
+
43
+ path = path_prep(localdir, imagesdir)
44
+ filename = File.basename(outfile.to_s)
45
+ FileUtils.cp(outfile, path) and outfile.unlink
46
+
47
+ imagesdir ? filename : File.join(path, filename)
48
+ end
49
+
50
+ def self.path_prep(localdir, imagesdir)
51
+ path = Pathname.new(localdir) + (imagesdir || "plantuml")
52
+ File.writable?(localdir) or
53
+ raise "Destination path #{path} not writable for PlantUML!"
54
+ path.mkpath
55
+ File.writable?(path) or
56
+ raise "Destination path #{path} not writable for PlantUML!"
57
+ # File.exist?(path) or raise "Destination path #{path} already exists for PlantUML!"
58
+ path
59
+ end
60
+
61
+ def self.save_plantuml(_parent, reader, _localdir)
62
+ src = prep_source(reader)
63
+ /^@startuml (?<fn>[^\n]+)\n/ =~ src
64
+ Tempfile.open(["plantuml", ".pml"], encoding: "utf-8") do |f|
65
+ f.write(src)
66
+ [f, File.join(File.dirname(f.path),
67
+ "#{fn || File.basename(f.path, '.pml')}.png")]
68
+ end
69
+ end
70
+
71
+ def self.prep_source(reader)
72
+ src = reader.source
73
+ reader.lines.first.sub(/\s+$/, "").match /^@startuml($| )/ or
74
+ src = "@startuml\n#{src}\n@enduml\n"
75
+ %r{@enduml\s*$}m.match?(src) or
76
+ raise "@startuml without matching @enduml in PlantUML!"
77
+ src
78
+ end
79
+
80
+ def self.generate_attrs(attrs)
81
+ %w(id align float title role width height alt)
82
+ .inject({}) do |memo, key|
83
+ memo[key] = attrs[key] if attrs.has_key? key
84
+ memo
85
+ end
86
+ end
87
+ end
88
+
89
+ class PlantUMLBlockMacro < Asciidoctor::Extensions::BlockProcessor
90
+ use_dsl
91
+ named :plantuml
92
+ on_context :literal
93
+ parse_content_as :raw
94
+
95
+ def abort(parent, reader, attrs, msg)
96
+ warn msg
97
+ attrs["language"] = "plantuml"
98
+ create_listing_block parent, reader.source,
99
+ (attrs.reject { |k, _v| k == 1 })
100
+ end
101
+
102
+ def process(parent, reader, attrs)
103
+ PlantUMLBlockMacroBackend.plantuml_installed?
104
+ filename = PlantUMLBlockMacroBackend.generate_file(parent, reader)
105
+ through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
106
+ through_attrs["target"] = filename
107
+ create_image_block parent, through_attrs
108
+ rescue StandardError => e
109
+ abort(parent, reader, attrs, e.message)
110
+ end
111
+ end
112
+ end
113
+ end