metanorma-standoc 2.8.11 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6a03a5dfead99850405d6b949a0103367ff0c280aa22d55e9c637eb34d1fe2c
4
- data.tar.gz: '06098dc9ad34cc0fdbd3df1ccaeedd51ef3b79e89a645e0ccb66979f582f82bf'
3
+ metadata.gz: 629fbf02985b771b385ed63f1ebcfecbd7f5031d1f476b5a5902e1b930b15a77
4
+ data.tar.gz: d89624a478853541b6cb07fe76b126f0e3e78001ac43ab63907d67481a3b05cf
5
5
  SHA512:
6
- metadata.gz: a35bd65e87ae978c0e34694b94365d364a528168e8aad39aa2733f6e900a14f219a85a38a275f9c24d00001fd0e19b5931a24578063dd1d45d1016066d744677
7
- data.tar.gz: 9e8e5215b27ba6b2e11fe50d0a544084afb32aa7d74fabde539844ff38797bd3217c48b8f980e97cfdd93f446bb4ef44e9cd80e610081996d45941cfc10f2357
6
+ metadata.gz: 6aa6a1c220c69aae4eb245b2d744d03356a30ed89bfe94c8c316415934041899fa0a68e2b86fe4b026ac294cede284f4d4ff1977eecb4272914ceb4ab2b7f87f
7
+ data.tar.gz: 26f1f58f773930cdf01d08c9c09aaa4e0f2e31392746cfb199cfb629299ec4500a9dd4e62bc999b9a5b65bea8ee568076431b82de79d323dfe654b891ffafc7f
data/.rubocop.yml CHANGED
@@ -7,4 +7,4 @@ inherit_from:
7
7
  # ...
8
8
 
9
9
  AllCops:
10
- TargetRubyVersion: 2.5
10
+ TargetRubyVersion: 3.4
@@ -2,19 +2,15 @@ module Metanorma
2
2
  module Standoc
3
3
  module Cleanup
4
4
  def external_terms_boilerplate(sources)
5
- @i18n.l10n(
6
- @i18n.external_terms_boilerplate.gsub(/%(?=\p{P}|\p{Z}|$)/,
7
- sources || "???"),
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.l10n(
14
- @i18n.internal_external_terms_boilerplate.gsub(/%(?=\p{P}|\p{Z}|$)/,
15
- sources || "??"),
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
- if ref.at("./note[@type = 'boilerplate']")
46
- unwrap_boilerplate_clauses(ref, ".")
47
- else
48
- refs = ref.elements.select do |e|
49
- %w(references bibitem).include? e.name
50
- end
51
- pref = refs.empty? ? @i18n.norm_empty_pref : @i18n.norm_with_refs_pref
52
- ref.at("./title").next = "<p>#{pref}</p>"
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 = "//sections/terms | " \
57
- "//sections/clause[descendant::terms]".freeze
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[.//terms]")
104
- !f || !root and return f || root
105
- f.at("./following::terms") and return root
106
- f.at("./preceding-sibling::clause") and return root
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("./clause[@type = 'boilerplate'] | " \
112
- "./note[@type = 'boilerplate']") and return
113
- term_defs_boilerplate(sect.at("./title"),
114
- xmldoc.xpath(".//termdocsource"),
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) and norm_ref_preface(f)
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+)?$}.freeze
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[.//terms]#{SYMnoABBR}",
87
+ replace_title(xml, "//terms#{SYMnoABBR} | //clause[@type = 'terms']#{SYMnoABBR}",
88
88
  @i18n&.termsdefsymbols, true)
89
- replace_title(xml, "//terms#{ABBRnoSYM} | //clause[.//terms]#{ABBRnoSYM}",
89
+ replace_title(xml, "//terms#{ABBRnoSYM} | //clause[@type = 'terms']#{ABBRnoSYM}",
90
90
  @i18n&.termsdefabbrev, true)
91
- replace_title(xml, "//terms#{SYMABBR} | //clause[.//terms]#{SYMABBR}",
91
+ replace_title(xml, "//terms#{SYMABBR} | //clause[@type = 'terms']#{SYMABBR}",
92
92
  @i18n&.termsdefsymbolsabbrev, true)
93
- replace_title(xml, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
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[.//terms][not(.//definitions)]",
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 { |t| t.name = "clause" }
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
- return unless @index_terms
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
- return unless term
139
-
140
+ term or return
140
141
  idx = term.children.dup
141
142
  fieldofappl.empty? or idx << ", &#x3c;#{fieldofappl}&#x3e;"
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 StdLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
139
+ class SpanInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
198
140
  use_dsl
199
- named :"std-link"
141
+ named :span
200
142
  parse_content_as :text
201
- using_format :short
202
143
 
203
- def process(parent, _target, attrs)
204
- t = attrs["text"]
205
- t = if /,/.match?(t)
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 SpanInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
150
+ class NumberInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
151
+ include ::Metanorma::Standoc::Utils
152
+
216
153
  use_dsl
217
- named :span
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
- %{<span class="#{target}">#{out}</span>}
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(&block)
21
- Metanorma::Utils::noko(@script, &block)
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|
@@ -19,6 +19,6 @@ module Metanorma
19
19
  end
20
20
 
21
21
  module Standoc
22
- VERSION = "2.8.11".freeze
22
+ VERSION = "2.9.0".freeze
23
23
  end
24
24
  end
@@ -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(">= 2.7.0")
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.6.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.18.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.8.11
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-06-17 00:00:00.000000000 Z
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.6.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.6.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.18.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.18.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: 2.7.0
571
+ version: 3.1.0
571
572
  required_rubygems_version: !ruby/object:Gem::Requirement
572
573
  requirements:
573
574
  - - ">="