metanorma-standoc 2.8.11 → 2.9.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/lib/metanorma/standoc/cleanup_boilerplate.rb +67 -31
- data/lib/metanorma/standoc/cleanup_maths.rb +24 -1
- data/lib/metanorma/standoc/cleanup_section_names.rb +5 -5
- data/lib/metanorma/standoc/cleanup_terms.rb +6 -5
- data/lib/metanorma/standoc/converter.rb +1 -0
- data/lib/metanorma/standoc/init.rb +13 -2
- data/lib/metanorma/standoc/macros.rb +1 -0
- data/lib/metanorma/standoc/macros_inline.rb +38 -75
- data/lib/metanorma/standoc/macros_link.rb +81 -0
- data/lib/metanorma/standoc/utils.rb +22 -2
- data/lib/metanorma/standoc/validate_table.rb +7 -0
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +3 -3
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 629fbf02985b771b385ed63f1ebcfecbd7f5031d1f476b5a5902e1b930b15a77
|
4
|
+
data.tar.gz: d89624a478853541b6cb07fe76b126f0e3e78001ac43ab63907d67481a3b05cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6aa6a1c220c69aae4eb245b2d744d03356a30ed89bfe94c8c316415934041899fa0a68e2b86fe4b026ac294cede284f4d4ff1977eecb4272914ceb4ab2b7f87f
|
7
|
+
data.tar.gz: 26f1f58f773930cdf01d08c9c09aaa4e0f2e31392746cfb199cfb629299ec4500a9dd4e62bc999b9a5b65bea8ee568076431b82de79d323dfe654b891ffafc7f
|
data/.rubocop.yml
CHANGED
@@ -2,19 +2,15 @@ module Metanorma
|
|
2
2
|
module Standoc
|
3
3
|
module Cleanup
|
4
4
|
def external_terms_boilerplate(sources)
|
5
|
-
@i18n.
|
6
|
-
|
7
|
-
|
8
|
-
@lang, @script, @locale
|
9
|
-
)
|
5
|
+
e = @i18n.external_terms_boilerplate
|
6
|
+
@i18n.l10n(e.gsub(/%(?=\p{P}|\p{Z}|$)/, sources || "???"),
|
7
|
+
@lang, @script, @locale)
|
10
8
|
end
|
11
9
|
|
12
10
|
def internal_external_terms_boilerplate(sources)
|
13
|
-
@i18n.
|
14
|
-
|
15
|
-
|
16
|
-
@lang, @script
|
17
|
-
)
|
11
|
+
e = @i18n.internal_external_terms_boilerplate
|
12
|
+
@i18n.l10n(e.gsub(/%(?=\p{P}|\p{Z}|$)/, sources || "??"),
|
13
|
+
@lang, @script)
|
18
14
|
end
|
19
15
|
|
20
16
|
def term_defs_boilerplate(div, source, term, _preface, isodoc)
|
@@ -26,8 +22,7 @@ module Metanorma
|
|
26
22
|
end
|
27
23
|
a = if source.empty? && term.nil? then @i18n.no_terms_boilerplate
|
28
24
|
else term_defs_boilerplate_cont(source, term, isodoc)
|
29
|
-
end
|
30
|
-
a and div.next = a
|
25
|
+
end and div.next = a
|
31
26
|
end
|
32
27
|
|
33
28
|
def term_defs_boilerplate_cont(src, term, isodoc)
|
@@ -42,19 +37,42 @@ module Metanorma
|
|
42
37
|
end
|
43
38
|
|
44
39
|
def norm_ref_preface(ref)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
40
|
+
ins = norm_ref_boilerplate_insert_location(ref)
|
41
|
+
ins2 = norm_ref_process_boilerplate_note(ref)
|
42
|
+
ins2 == :populated and return
|
43
|
+
ins2 == :missing or ins = ins2
|
44
|
+
refs = ref.elements.select do |e|
|
45
|
+
%w(references bibitem).include? e.name
|
46
|
+
end
|
47
|
+
pref = refs.empty? ? @i18n.norm_empty_pref : @i18n.norm_with_refs_pref
|
48
|
+
ins.next = "<p>#{pref}</p>"
|
49
|
+
end
|
50
|
+
|
51
|
+
def norm_ref_process_boilerplate_note(ref)
|
52
|
+
ins2 = ref.at("./note[@type = 'boilerplate']") or return :missing
|
53
|
+
if ins2 && ins2.text.strip.downcase == "(default)"
|
54
|
+
ins2.children = " "
|
55
|
+
ins2.children.first
|
56
|
+
else :populated
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def norm_ref_boilerplate_insert_location(ref)
|
61
|
+
while (n = ref.parent) && %w(clause references).include?(n&.name)
|
62
|
+
n.elements.detect do |e|
|
63
|
+
!%(title references).include?(e.name) &&
|
64
|
+
!e.at("./self::clause[@type = 'boilerplate']") &&
|
65
|
+
!e.at("./self::clause[.//references][not(.//clause[not(.//bibitem)])]")
|
66
|
+
end and break
|
67
|
+
ref = n
|
53
68
|
end
|
69
|
+
ref.at("./title")
|
54
70
|
end
|
55
71
|
|
56
|
-
TERM_CLAUSE =
|
57
|
-
|
72
|
+
TERM_CLAUSE =
|
73
|
+
"//sections//terms[not(.//ancestor::clause[@type = 'terms'])] | " \
|
74
|
+
"//sections/clause[descendant::terms][@type = 'terms'] | " \
|
75
|
+
"//sections/clause[not(@type = 'terms')]//terms".freeze
|
58
76
|
|
59
77
|
NORM_REF =
|
60
78
|
"//bibliography/references[@normative = 'true'][not(@hidden)] | " \
|
@@ -100,18 +118,33 @@ module Metanorma
|
|
100
118
|
|
101
119
|
def termdef_boilerplate_insert_location(xmldoc)
|
102
120
|
f = xmldoc.at(self.class::TERM_CLAUSE)
|
103
|
-
root = xmldoc.at("//sections/terms | //sections/clause[
|
104
|
-
|
105
|
-
|
106
|
-
f
|
121
|
+
root = xmldoc.at("//sections/terms | //sections/clause[@type = 'terms']")
|
122
|
+
if f && root && f["id"] != root["id"]
|
123
|
+
f = termdef_boilerplate_climb_up(f, root)
|
124
|
+
elsif !f && root then f = root
|
125
|
+
end
|
107
126
|
f
|
108
127
|
end
|
109
128
|
|
129
|
+
def termdef_boilerplate_climb_up(clause, container)
|
130
|
+
container.at(".//*[@id = '#{clause['id']}']") or return clause
|
131
|
+
while (n = clause.parent)
|
132
|
+
n.at(".//definitions") and break
|
133
|
+
clause = n
|
134
|
+
n["id"] == container["id"] and break
|
135
|
+
end
|
136
|
+
clause
|
137
|
+
end
|
138
|
+
|
110
139
|
def termdef_boilerplate_insert1(sect, xmldoc, isodoc)
|
111
|
-
sect.at("./
|
112
|
-
|
113
|
-
|
114
|
-
|
140
|
+
ins = sect.at("./title")
|
141
|
+
if (ins2 = sect.at("./clause[@type = 'boilerplate'] | " \
|
142
|
+
"./note[@type = 'boilerplate']"))
|
143
|
+
ins2.text.strip.downcase == "(default)" or return
|
144
|
+
ins2.children = " "
|
145
|
+
ins = ins2.children.first
|
146
|
+
end
|
147
|
+
term_defs_boilerplate(ins, xmldoc.xpath(".//termdocsource"),
|
115
148
|
sect.at(".//term"), sect.at(".//p"), isodoc)
|
116
149
|
end
|
117
150
|
|
@@ -120,7 +153,10 @@ module Metanorma
|
|
120
153
|
termdef_boilerplate_cleanup(xmldoc)
|
121
154
|
termdef_boilerplate_insert(xmldoc, isodoc)
|
122
155
|
unwrap_boilerplate_clauses(xmldoc, self.class::TERM_CLAUSE)
|
123
|
-
f = xmldoc.at(self.class::NORM_REF)
|
156
|
+
if f = xmldoc.at(self.class::NORM_REF)
|
157
|
+
norm_ref_preface(f)
|
158
|
+
unwrap_boilerplate_clauses(f, ".")
|
159
|
+
end
|
124
160
|
initial_boilerplate(xmldoc, isodoc)
|
125
161
|
end
|
126
162
|
|
@@ -27,7 +27,7 @@ module Metanorma
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# https://medium.com/@rickwang_wxc/in-ruby-given-a-string-detect-if-it-is-valid-numeric-c58275eace60
|
30
|
-
NUMERIC_REGEX = %r{^((\+|-)?\d*\.?\d+)([eE](\+|-){1}\d+)?$}
|
30
|
+
NUMERIC_REGEX = %r{^((\+|-)?\d*\.?\d+)([eE](\+|-){1}\d+)?$}
|
31
31
|
|
32
32
|
MATHML_NS = "http://www.w3.org/1998/Math/MathML".freeze
|
33
33
|
|
@@ -204,6 +204,28 @@ module Metanorma
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
+
def mathml_mn_format(math)
|
208
|
+
math.xpath(".//m:mn", "m" => MATHML_NS).each do |m|
|
209
|
+
profile = mathml_mn_profile(m)
|
210
|
+
attr = profile.each_with_object([]) do |(k, v), acc|
|
211
|
+
v == "nil" and next
|
212
|
+
acc << "#{k}='#{v}'"
|
213
|
+
end.join(",")
|
214
|
+
attr.empty? or m["data-metanorma-numberformat"] = attr
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def mathml_mn_profile(mnum)
|
219
|
+
fmt = @numberfmt_default&.dup || {}
|
220
|
+
fmt1 = {}
|
221
|
+
fmt2 = kv_parse(mnum["data-metanorma-numberformat"] || "")
|
222
|
+
if fmt2["profile"]
|
223
|
+
fmt1 = @numberfmt_prof[fmt2["profile"]] || {}
|
224
|
+
fmt2.delete("profile")
|
225
|
+
end
|
226
|
+
fmt.merge(fmt1).merge(fmt2)
|
227
|
+
end
|
228
|
+
|
207
229
|
def mathml_cleanup(xmldoc)
|
208
230
|
unitsml = Asciimath2UnitsML::Conv.new(asciimath2unitsml_options)
|
209
231
|
xmldoc.xpath("//stem[@type = 'MathML'][not(@validate = 'false')]")
|
@@ -214,6 +236,7 @@ module Metanorma
|
|
214
236
|
unitsml.MathML2UnitsML(x)
|
215
237
|
mathml_mathvariant(x)
|
216
238
|
mathml_italicise(x)
|
239
|
+
mathml_mn_format(x)
|
217
240
|
end
|
218
241
|
mathml_unitsML(xmldoc)
|
219
242
|
end
|
@@ -84,15 +84,15 @@ module Metanorma
|
|
84
84
|
|
85
85
|
def section_names_terms1_cleanup(xml)
|
86
86
|
auto_name_terms(xml) or return
|
87
|
-
replace_title(xml, "//terms#{SYMnoABBR} | //clause[
|
87
|
+
replace_title(xml, "//terms#{SYMnoABBR} | //clause[@type = 'terms']#{SYMnoABBR}",
|
88
88
|
@i18n&.termsdefsymbols, true)
|
89
|
-
replace_title(xml, "//terms#{ABBRnoSYM} | //clause[
|
89
|
+
replace_title(xml, "//terms#{ABBRnoSYM} | //clause[@type = 'terms']#{ABBRnoSYM}",
|
90
90
|
@i18n&.termsdefabbrev, true)
|
91
|
-
replace_title(xml, "//terms#{SYMABBR} | //clause[
|
91
|
+
replace_title(xml, "//terms#{SYMABBR} | //clause[@type = 'terms']#{SYMABBR}",
|
92
92
|
@i18n&.termsdefsymbolsabbrev, true)
|
93
|
-
replace_title(xml, "//terms#{NO_SYMABBR} | //clause[
|
93
|
+
replace_title(xml, "//terms#{NO_SYMABBR} | //clause[@type = 'terms']#{NO_SYMABBR}",
|
94
94
|
@i18n&.termsdefsymbolsabbrev, true)
|
95
|
-
replace_title(xml, "//terms[not(.//definitions)] | //clause[
|
95
|
+
replace_title(xml, "//terms[not(.//definitions)] | //clause[@type = 'terms'][not(.//definitions)]",
|
96
96
|
@i18n&.termsdef, true)
|
97
97
|
end
|
98
98
|
|
@@ -74,7 +74,10 @@ module Metanorma
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def term_children_cleanup(xmldoc)
|
77
|
-
xmldoc.xpath("//terms[terms][not(term)]").each
|
77
|
+
xmldoc.xpath("//terms[terms][not(term)]").each do |t|
|
78
|
+
t.name = "clause"
|
79
|
+
t["type"] = "terms"
|
80
|
+
end
|
78
81
|
xmldoc.xpath("//term").each do |t|
|
79
82
|
%w(termnote termexample termsource term).each do |w|
|
80
83
|
t.xpath("./#{w}").each { |n| t << n.remove }
|
@@ -122,8 +125,7 @@ module Metanorma
|
|
122
125
|
end
|
123
126
|
|
124
127
|
def term_index_cleanup(xmldoc)
|
125
|
-
|
126
|
-
|
128
|
+
@index_terms or return
|
127
129
|
xmldoc.xpath("//preferred").each do |p|
|
128
130
|
index_cleanup1(p.at("./expression/name | ./letter-symbol/name"),
|
129
131
|
p.xpath("./field-of-application | ./usage-info")
|
@@ -135,8 +137,7 @@ module Metanorma
|
|
135
137
|
end
|
136
138
|
|
137
139
|
def index_cleanup1(term, fieldofappl)
|
138
|
-
|
139
|
-
|
140
|
+
term or return
|
140
141
|
idx = term.children.dup
|
141
142
|
fieldofappl.empty? or idx << ", <#{fieldofappl}>"
|
142
143
|
term << "<index><primary>#{idx.to_xml}</primary></index>"
|
@@ -67,6 +67,7 @@ module Metanorma
|
|
67
67
|
inline_macro Metanorma::Standoc::ToCInlineMacro
|
68
68
|
inline_macro Metanorma::Standoc::PassInlineMacro
|
69
69
|
inline_macro Metanorma::Standoc::StdLinkInlineMacro
|
70
|
+
inline_macro Metanorma::Standoc::NumberInlineMacro
|
70
71
|
block Metanorma::Standoc::ToDoAdmonitionBlock
|
71
72
|
block Metanorma::Standoc::EditorAdmonitionBlock
|
72
73
|
treeprocessor Metanorma::Standoc::EditorInlineAdmonitionBlock
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative "utils"
|
2
|
+
|
1
3
|
module Metanorma
|
2
4
|
module Standoc
|
3
5
|
module Base
|
@@ -10,6 +12,7 @@ module Metanorma
|
|
10
12
|
init_output(node) # feeds init_biblio
|
11
13
|
init_i18n(node)
|
12
14
|
init_biblio(node)
|
15
|
+
init_math(node)
|
13
16
|
@metadata_attrs = metadata_attrs(node)
|
14
17
|
end
|
15
18
|
|
@@ -42,8 +45,6 @@ module Metanorma
|
|
42
45
|
def init_processing(node)
|
43
46
|
@novalid = node.attr("novalid")
|
44
47
|
@smartquotes = node.attr("smartquotes") != "false"
|
45
|
-
@keepasciimath = node.attr("mn-keep-asciimath") &&
|
46
|
-
node.attr("mn-keep-asciimath") != "false"
|
47
48
|
@sourcecode_markup_start = node.attr("sourcecode-markup-start") || "{{{"
|
48
49
|
@sourcecode_markup_end = node.attr("sourcecode-markup-end") || "}}}"
|
49
50
|
@datauriimage = node.attr("data-uri-image") != "false"
|
@@ -108,6 +109,16 @@ module Metanorma
|
|
108
109
|
::Metanorma::Standoc::LocalBiblio.new(node, @localdir, self)
|
109
110
|
end
|
110
111
|
|
112
|
+
def init_math(node)
|
113
|
+
@keepasciimath = node.attr("mn-keep-asciimath") &&
|
114
|
+
node.attr("mn-keep-asciimath") != "false"
|
115
|
+
@numberfmt_default = kv_parse(node.attr("number-presentation"))
|
116
|
+
@numberfmt_prof = node.attributes.each_with_object({}) do |(k, v), m|
|
117
|
+
p = /^number-presentation-profile-(.*)$/.match(k) or next
|
118
|
+
m[p[1]] = kv_parse(v)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
111
122
|
def requirements_processor
|
112
123
|
Metanorma::Requirements
|
113
124
|
end
|
@@ -7,6 +7,7 @@ require_relative "macros_terms"
|
|
7
7
|
require_relative "macros_form"
|
8
8
|
require_relative "macros_note"
|
9
9
|
require_relative "macros_embed"
|
10
|
+
require_relative "macros_link"
|
10
11
|
require_relative "datamodel/attributes_table_preprocessor"
|
11
12
|
require_relative "datamodel/diagram_preprocessor"
|
12
13
|
require "metanorma-plugin-datastruct"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative "utils"
|
2
|
+
|
1
3
|
module Metanorma
|
2
4
|
module Standoc
|
3
5
|
class InheritInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
@@ -12,49 +14,6 @@ module Metanorma
|
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
|
-
class IndexXrefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
16
|
-
use_dsl
|
17
|
-
named :index
|
18
|
-
|
19
|
-
def preprocess_attrs(attrs)
|
20
|
-
ret = { primary: attrs[1], target: attrs[attrs.size] }
|
21
|
-
ret[:secondary] = attrs[2] if attrs.size > 2
|
22
|
-
ret[:tertiary] = attrs[3] if attrs.size > 3
|
23
|
-
ret
|
24
|
-
end
|
25
|
-
|
26
|
-
def validate(parent, target, attrs)
|
27
|
-
attrs.size > 1 && attrs.size < 5 and return true
|
28
|
-
e = "invalid index \"#{target}\" cross-reference: wrong number of " \
|
29
|
-
"attributes in `index:#{target}[#{attrs.values.join(',')}]`"
|
30
|
-
parent.converter.log.add("Crossreferences", parent, e, severity: 0)
|
31
|
-
false
|
32
|
-
end
|
33
|
-
|
34
|
-
def process(parent, target, attr)
|
35
|
-
validate(parent, target, attr) or return
|
36
|
-
args = preprocess_attrs(attr)
|
37
|
-
ret = "<index-xref also='#{target == 'also'}'>" \
|
38
|
-
"<primary>#{args[:primary]}</primary>"
|
39
|
-
ret += "<secondary>#{args[:secondary]}</secondary>" if args[:secondary]
|
40
|
-
ret += "<tertiary>#{args[:tertiary]}</tertiary>" if args[:tertiary]
|
41
|
-
ret + "<target>#{args[:target]}</target></index-xref>"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class IndexRangeInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
46
|
-
use_dsl
|
47
|
-
named :"index-range"
|
48
|
-
parse_content_as :text
|
49
|
-
|
50
|
-
def process(parent, target, attr)
|
51
|
-
text = attr["text"]
|
52
|
-
text = "((#{text}))" unless /^\(\(.+\)\)$/.match?(text)
|
53
|
-
out = parent.sub_macros(text)
|
54
|
-
out.sub("<index>", "<index to='#{target}'>")
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
17
|
class HTML5RubyMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
59
18
|
use_dsl
|
60
19
|
named :ruby
|
@@ -151,23 +110,6 @@ module Metanorma
|
|
151
110
|
end
|
152
111
|
end
|
153
112
|
|
154
|
-
class ToCInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
155
|
-
use_dsl
|
156
|
-
named :toc
|
157
|
-
parse_content_as :text
|
158
|
-
using_format :short
|
159
|
-
|
160
|
-
def process(parent, _target, attrs)
|
161
|
-
out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
|
162
|
-
content = CSV.parse_line(out).map do |x|
|
163
|
-
x.sub!(/^(["'])(.+)\1/, "\\2")
|
164
|
-
m = /^(.*?)(:\d+)?$/.match(x)
|
165
|
-
%{<toc-xpath depth='#{m[2]&.sub(':', '') || 1}'>#{m[1]}</toc-xpath>}
|
166
|
-
end.join
|
167
|
-
"<toc>#{content}</toc>"
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
113
|
# inject ZWNJ to prevent Asciidoctor from attempting regex substitutions
|
172
114
|
class PassInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
173
115
|
use_dsl
|
@@ -194,32 +136,53 @@ module Metanorma
|
|
194
136
|
end
|
195
137
|
end
|
196
138
|
|
197
|
-
class
|
139
|
+
class SpanInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
198
140
|
use_dsl
|
199
|
-
named :
|
141
|
+
named :span
|
200
142
|
parse_content_as :text
|
201
|
-
using_format :short
|
202
143
|
|
203
|
-
def process(parent,
|
204
|
-
|
205
|
-
|
206
|
-
t.sub(/,/, "%")
|
207
|
-
else
|
208
|
-
"#{t}%"
|
209
|
-
end
|
210
|
-
create_anchor(parent, "hidden=#{t}",
|
211
|
-
type: :xref, target: "_#{UUIDTools::UUID.random_create}")
|
144
|
+
def process(parent, target, attrs)
|
145
|
+
out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
|
146
|
+
%{<span class="#{target}">#{out}</span>}
|
212
147
|
end
|
213
148
|
end
|
214
149
|
|
215
|
-
class
|
150
|
+
class NumberInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
151
|
+
include ::Metanorma::Standoc::Utils
|
152
|
+
|
216
153
|
use_dsl
|
217
|
-
named :
|
154
|
+
named :number
|
218
155
|
parse_content_as :text
|
219
156
|
|
157
|
+
MATHML_NS = "http://www.w3.org/1998/Math/MathML".freeze
|
158
|
+
|
159
|
+
def unquote(str)
|
160
|
+
str.sub(/^(["'])(.+)\1$/, "\\2")
|
161
|
+
end
|
162
|
+
|
163
|
+
def format(attrs)
|
164
|
+
# a="," => "a=,"
|
165
|
+
quoted_csv_split(attrs || "", ",").map do |x|
|
166
|
+
m = /^(.+?)=(.+)?$/.match(x) or next
|
167
|
+
"#{m[1]}='#{m[2]}'"
|
168
|
+
end.join(",")
|
169
|
+
end
|
170
|
+
|
171
|
+
def number(text)
|
172
|
+
n = BigDecimal(text)
|
173
|
+
trailing_zeroes = 0
|
174
|
+
m = /\.[1-9]*(0+)/.match(text) and trailing_zeroes += m[1].size
|
175
|
+
n.to_s("E").sub("e", "0" * trailing_zeroes + "e")
|
176
|
+
end
|
177
|
+
|
220
178
|
def process(parent, target, attrs)
|
221
179
|
out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
|
222
|
-
|
180
|
+
fmt = format(out)
|
181
|
+
fmt.empty? and fmt = "notation='basic'"
|
182
|
+
fmt = %( data-metanorma-numberformat="#{fmt}")
|
183
|
+
<<~OUTPUT
|
184
|
+
<stem type="MathML"><math xmlns='#{MATHML_NS}'><mn#{fmt}>#{number(target)}</mn></math></stem>
|
185
|
+
OUTPUT
|
223
186
|
end
|
224
187
|
end
|
225
188
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Metanorma
|
2
|
+
module Standoc
|
3
|
+
class IndexXrefInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
4
|
+
use_dsl
|
5
|
+
named :index
|
6
|
+
|
7
|
+
def preprocess_attrs(attrs)
|
8
|
+
ret = { primary: attrs[1], target: attrs[attrs.size] }
|
9
|
+
ret[:secondary] = attrs[2] if attrs.size > 2
|
10
|
+
ret[:tertiary] = attrs[3] if attrs.size > 3
|
11
|
+
ret
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate(parent, target, attrs)
|
15
|
+
attrs.size > 1 && attrs.size < 5 and return true
|
16
|
+
e = "invalid index \"#{target}\" cross-reference: wrong number of " \
|
17
|
+
"attributes in `index:#{target}[#{attrs.values.join(',')}]`"
|
18
|
+
parent.converter.log.add("Crossreferences", parent, e, severity: 0)
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def process(parent, target, attr)
|
23
|
+
validate(parent, target, attr) or return
|
24
|
+
args = preprocess_attrs(attr)
|
25
|
+
ret = "<index-xref also='#{target == 'also'}'>" \
|
26
|
+
"<primary>#{args[:primary]}</primary>"
|
27
|
+
ret += "<secondary>#{args[:secondary]}</secondary>" if args[:secondary]
|
28
|
+
ret += "<tertiary>#{args[:tertiary]}</tertiary>" if args[:tertiary]
|
29
|
+
ret + "<target>#{args[:target]}</target></index-xref>"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class IndexRangeInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
34
|
+
use_dsl
|
35
|
+
named :"index-range"
|
36
|
+
parse_content_as :text
|
37
|
+
|
38
|
+
def process(parent, target, attr)
|
39
|
+
text = attr["text"]
|
40
|
+
text = "((#{text}))" unless /^\(\(.+\)\)$/.match?(text)
|
41
|
+
out = parent.sub_macros(text)
|
42
|
+
out.sub("<index>", "<index to='#{target}'>")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ToCInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
47
|
+
use_dsl
|
48
|
+
named :toc
|
49
|
+
parse_content_as :text
|
50
|
+
using_format :short
|
51
|
+
|
52
|
+
def process(parent, _target, attrs)
|
53
|
+
out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
|
54
|
+
content = CSV.parse_line(out).map do |x|
|
55
|
+
x.sub!(/^(["'])(.+)\1/, "\\2")
|
56
|
+
m = /^(.*?)(:\d+)?$/.match(x)
|
57
|
+
%{<toc-xpath depth='#{m[2]&.sub(':', '') || 1}'>#{m[1]}</toc-xpath>}
|
58
|
+
end.join
|
59
|
+
"<toc>#{content}</toc>"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class StdLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
64
|
+
use_dsl
|
65
|
+
named :"std-link"
|
66
|
+
parse_content_as :text
|
67
|
+
using_format :short
|
68
|
+
|
69
|
+
def process(parent, _target, attrs)
|
70
|
+
t = attrs["text"]
|
71
|
+
t = if /,/.match?(t)
|
72
|
+
t.sub(/,/, "%")
|
73
|
+
else
|
74
|
+
"#{t}%"
|
75
|
+
end
|
76
|
+
create_anchor(parent, "hidden=#{t}",
|
77
|
+
type: :xref, target: "_#{UUIDTools::UUID.random_create}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -17,8 +17,8 @@ module Metanorma
|
|
17
17
|
nil
|
18
18
|
end
|
19
19
|
|
20
|
-
def noko(&
|
21
|
-
Metanorma::Utils::noko(@script, &
|
20
|
+
def noko(&)
|
21
|
+
Metanorma::Utils::noko(@script, &)
|
22
22
|
end
|
23
23
|
|
24
24
|
def attr_code(attributes)
|
@@ -30,6 +30,26 @@ module Metanorma
|
|
30
30
|
.map { |x| @c.encode(x, :basic, :hexadecimal) }
|
31
31
|
end
|
32
32
|
|
33
|
+
def quoted_csv_split(text, delim = ",", eql = "=")
|
34
|
+
# quoted strings: key="va,lue",
|
35
|
+
c = HTMLEntities.new
|
36
|
+
text = c.decode(text).gsub(/([a-zA-Z_]+)#{eql}(["'])(.+?)\2/,
|
37
|
+
%("\\1#{eql}\\3"))
|
38
|
+
Metanorma::Utils::csv_split(text, delim)
|
39
|
+
.map do |x|
|
40
|
+
c.encode(x.sub(/^(["'])(.+)\1$/, "\\2"), :basic, :hexadecimal)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def kv_parse(text, delim = ",", eql = "=")
|
45
|
+
text or return {}
|
46
|
+
c = HTMLEntities.new
|
47
|
+
quoted_csv_split(text, delim).each_with_object({}) do |k, m|
|
48
|
+
x = k.split(eql, 2)
|
49
|
+
m[x[0]] = c.decode(x[1])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
33
53
|
def wrap_in_para(node, out)
|
34
54
|
Metanorma::Utils::wrap_in_para(node, out)
|
35
55
|
end
|
@@ -2,6 +2,7 @@ module Metanorma
|
|
2
2
|
module Standoc
|
3
3
|
module Validate
|
4
4
|
def table_validate(doc)
|
5
|
+
empty_table_validate(doc)
|
5
6
|
doc.xpath("//table[colgroup]").each do |t|
|
6
7
|
maxrowcols_validate(t, t.xpath("./colgroup/col").size)
|
7
8
|
end
|
@@ -13,6 +14,12 @@ module Metanorma
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
17
|
+
def empty_table_validate(doc)
|
18
|
+
doc.xpath("//table[not(.//tr)]").each do |t|
|
19
|
+
@log.add("Table", t, "Empty table", severity: 0)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
16
23
|
def max_td_count(table)
|
17
24
|
max = 0
|
18
25
|
table.xpath("./tr").each do |tr|
|
data/metanorma-standoc.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
f.match(%r{^(test|spec|features|bin|.github)/}) \
|
27
27
|
|| f.match(%r{Rakefile|bin/rspec})
|
28
28
|
end
|
29
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
29
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
|
30
30
|
|
31
31
|
spec.add_dependency "addressable", "~> 2.8.0"
|
32
32
|
spec.add_dependency "asciidoctor", "~> 2.0.0"
|
@@ -36,13 +36,13 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_dependency "metanorma", ">= 1.6.0"
|
37
37
|
spec.add_dependency "metanorma-plugin-datastruct", "~> 0.3.0"
|
38
38
|
spec.add_dependency "metanorma-plugin-glossarist", "~> 0.2.0"
|
39
|
-
spec.add_dependency "metanorma-plugin-lutaml", "~> 0.
|
39
|
+
spec.add_dependency "metanorma-plugin-lutaml", "~> 0.7.0"
|
40
40
|
spec.add_dependency "ruby-jing"
|
41
41
|
# relaton-cli not just relaton, to avoid circular reference in metanorma
|
42
42
|
spec.add_dependency "asciimath2unitsml", "~> 0.4.0"
|
43
43
|
spec.add_dependency "concurrent-ruby"
|
44
44
|
spec.add_dependency "pngcheck"
|
45
|
-
spec.add_dependency "relaton-cli", "~> 1.
|
45
|
+
spec.add_dependency "relaton-cli", "~> 1.19.0"
|
46
46
|
spec.add_dependency "relaton-iev", "~> 1.2.0"
|
47
47
|
spec.add_dependency "unicode2latex", "~> 0.0.1"
|
48
48
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metanorma-standoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 0.7.0
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
138
|
+
version: 0.7.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: ruby-jing
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,14 +198,14 @@ dependencies:
|
|
198
198
|
requirements:
|
199
199
|
- - "~>"
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 1.
|
201
|
+
version: 1.19.0
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
206
|
- - "~>"
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 1.
|
208
|
+
version: 1.19.0
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: relaton-iev
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -528,6 +528,7 @@ files:
|
|
528
528
|
- lib/metanorma/standoc/macros_embed.rb
|
529
529
|
- lib/metanorma/standoc/macros_form.rb
|
530
530
|
- lib/metanorma/standoc/macros_inline.rb
|
531
|
+
- lib/metanorma/standoc/macros_link.rb
|
531
532
|
- lib/metanorma/standoc/macros_note.rb
|
532
533
|
- lib/metanorma/standoc/macros_plantuml.rb
|
533
534
|
- lib/metanorma/standoc/macros_terms.rb
|
@@ -567,7 +568,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
567
568
|
requirements:
|
568
569
|
- - ">="
|
569
570
|
- !ruby/object:Gem::Version
|
570
|
-
version:
|
571
|
+
version: 3.1.0
|
571
572
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
572
573
|
requirements:
|
573
574
|
- - ">="
|