metanorma-standoc 1.8.3 → 1.8.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +11 -41
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +6 -2
  5. data/lib/asciidoctor/standoc/base.rb +3 -1
  6. data/lib/asciidoctor/standoc/biblio.rng +4 -6
  7. data/lib/asciidoctor/standoc/blocks.rb +26 -12
  8. data/lib/asciidoctor/standoc/cleanup.rb +2 -2
  9. data/lib/asciidoctor/standoc/cleanup_block.rb +49 -12
  10. data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +3 -3
  11. data/lib/asciidoctor/standoc/cleanup_maths.rb +37 -0
  12. data/lib/asciidoctor/standoc/cleanup_ref.rb +4 -13
  13. data/lib/asciidoctor/standoc/cleanup_section.rb +5 -0
  14. data/lib/asciidoctor/standoc/cleanup_terms.rb +2 -2
  15. data/lib/asciidoctor/standoc/inline.rb +7 -15
  16. data/lib/asciidoctor/standoc/isodoc.rng +42 -2
  17. data/lib/asciidoctor/standoc/ref_sect.rb +12 -12
  18. data/lib/asciidoctor/standoc/section.rb +9 -0
  19. data/lib/asciidoctor/standoc/utils.rb +0 -24
  20. data/lib/asciidoctor/standoc/validate.rb +16 -1
  21. data/lib/metanorma/standoc/version.rb +1 -1
  22. data/metanorma-standoc.gemspec +5 -5
  23. data/spec/asciidoctor/base_spec.rb +4 -0
  24. data/spec/asciidoctor/cleanup_sections_spec.rb +14 -14
  25. data/spec/asciidoctor/cleanup_spec.rb +169 -35
  26. data/spec/asciidoctor/inline_spec.rb +2 -0
  27. data/spec/asciidoctor/refs_spec.rb +154 -26
  28. data/spec/asciidoctor/section_spec.rb +17 -0
  29. data/spec/asciidoctor/validate_spec.rb +20 -0
  30. data/spec/assets/html-override.css +1 -0
  31. data/spec/assets/word-override.css +1 -0
  32. data/spec/spec_helper.rb +8 -0
  33. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +62 -62
  34. data/spec/vcr_cassettes/isobib_get_123.yml +15 -15
  35. data/spec/vcr_cassettes/isobib_get_123_1.yml +30 -30
  36. data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +42 -42
  37. data/spec/vcr_cassettes/isobib_get_123_2001.yml +15 -15
  38. data/spec/vcr_cassettes/isobib_get_124.yml +16 -16
  39. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +22 -22
  40. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +59 -57
  41. metadata +21 -22
  42. data/.rubocop.ribose.yml +0 -66
  43. data/.rubocop.tb.yml +0 -650
  44. data/spec/asciidoctor/macros_lutaml_spec.rb +0 -80
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a0e8bdc48a2fa268df4c2d2342787a3c1312eb349c0a8a37306c2674c4440e
4
- data.tar.gz: e063188d68034654d5edf0d45b51b22b7018371dfeef1b252576b6d3d8fe57b9
3
+ metadata.gz: 4c6a59c6f6a5cfd1b0f6515cf768e060cf846f239b2336a6db7bfb8fef1b75ec
4
+ data.tar.gz: f88ef657e463750bdad1f01389f8fc9f30fb881ec4f517010a58ca8676c74e04
5
5
  SHA512:
6
- metadata.gz: fd3fe9734d21153f7955dbd3b3eeade50bee97403a6bc53c18ef97cb72345970c7951f9d96b51916f4ce7a89ff56d6c8e6d9cf5b6d67482ed598c2c6ae8090e8
7
- data.tar.gz: dbc628d7b0df786191086a908b0f849bb9f75dc23881030748313ed78350d9722675371483232bc52ebd38404ec1da79ee1e985484ae648212479a0b66ac346d
6
+ metadata.gz: 21a8546de21b8a31a98dc6b2a48a7afed919e847c4e25d54094b60e9ac5fe6489a42b7b0a99b42577f505232b5d2cbd8099c27a3a811db092cb305dfeeb396fe
7
+ data.tar.gz: 7bbe4985fcf8e3ffe2190552d16d3ece90cd462c4f5ab841241821ea527a00242cd1b17622f07cd6e9900b4875cbefbf0e84d21f7aae0a39ad7be571392ab007
@@ -16,17 +16,17 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.6', '2.5', '2.4' ]
19
+ ruby: [ '2.7', '2.6', '2.5', '2.4' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
22
  include:
23
- - ruby: '2.7'
23
+ - ruby: '3.0'
24
24
  os: 'ubuntu-latest'
25
25
  experimental: true
26
- - ruby: '2.7'
26
+ - ruby: '3.0'
27
27
  os: 'windows-latest'
28
28
  experimental: true
29
- - ruby: '2.7'
29
+ - ruby: '3.0'
30
30
  os: 'macos-latest'
31
31
  experimental: true
32
32
  steps:
@@ -35,49 +35,19 @@ jobs:
35
35
  - uses: ruby/setup-ruby@v1
36
36
  with:
37
37
  ruby-version: ${{ matrix.ruby }}
38
+ bundler-cache: true
38
39
 
39
- - if: matrix.os == 'macos-latest'
40
- run: brew install autoconf automake libtool
41
-
42
- - uses: actions/cache@v2
43
- with:
44
- path: vendor/bundle
45
- key: bundle-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}
46
- restore-keys: bundle-${{ matrix.os }}-${{ matrix.ruby }}
47
-
48
- - run: bundle config set path 'vendor/bundle'
49
-
50
- - run: bundle install --jobs 4 --retry 3
51
-
52
- - name: install plantuml ubuntu
53
- if: matrix.os == 'ubuntu-latest'
54
- uses: nick-invision/retry@v1
55
- with:
56
- polling_interval_seconds: 5
57
- timeout_minutes: 5
58
- max_attempts: 3
59
- command: >
60
- sudo apt-get update -y && sudo bash -c
61
- "curl -L https://github.com/metanorma/plantuml-install/raw/master/ubuntu.sh | bash"
62
-
63
- - if: matrix.os == 'macos-latest'
64
- run: brew install plantuml
65
-
66
- - if: matrix.os == 'windows-latest'
67
- run: cinst -y plantuml
40
+ - uses: metanorma/metanorma-build-scripts/plantuml-setup-action@master
68
41
 
69
42
  - run: bundle exec rake
70
43
 
71
44
  tests-passed:
72
45
  needs: rake
73
46
  runs-on: ubuntu-latest
74
- continue-on-error: true
75
47
  steps:
76
- - name: Trigger tests passed event
77
- uses: Sibz/github-status-action@v1
48
+ - uses: peter-evans/repository-dispatch@v1
78
49
  with:
79
- authToken: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
80
- context: 'tests-passed-successfully'
81
- description: 'Tests passed successfully'
82
- state: 'success'
83
- sha: ${{ github.event.pull_request.head.sha || github.sha }}
50
+ token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
51
+ repository: ${{ github.repository }}
52
+ event-type: notify
53
+ client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
data/.gitignore CHANGED
@@ -10,3 +10,5 @@ spec/examples/rice.html
10
10
  spec/examples/rice.xml
11
11
  spec/examples/rice_files/
12
12
  Gemfile.lock
13
+
14
+ .rubocop-https--*
data/.rubocop.yml CHANGED
@@ -1,10 +1,14 @@
1
1
  # This project follows the Ribose OSS style guide.
2
2
  # https://github.com/riboseinc/oss-guides
3
3
  # All project-specific additions and overrides should be specified in this file.
4
-
5
4
  inherit_from:
6
5
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
6
+
7
+ # local repo-specific modifications
8
+
7
9
  AllCops:
8
- TargetRubyVersion: 2.6
10
+ DisplayCopNames: false
11
+ StyleGuideCopsOnly: false
12
+ TargetRubyVersion: 2.4
9
13
  Rails:
10
14
  Enabled: true
@@ -43,6 +43,7 @@ module Asciidoctor
43
43
  i18nyaml: node.attr("i18nyaml"),
44
44
  scope: node.attr("scope"),
45
45
  htmlstylesheet: node.attr("htmlstylesheet"),
46
+ htmlstylesheet_override: node.attr("htmlstylesheet-override"),
46
47
  htmlcoverpage: node.attr("htmlcoverpage"),
47
48
  htmlintropage: node.attr("htmlintropage"),
48
49
  scripts: node.attr("scripts"),
@@ -67,6 +68,7 @@ module Asciidoctor
67
68
  i18nyaml: node.attr("i18nyaml"),
68
69
  scope: node.attr("scope"),
69
70
  wordstylesheet: node.attr("wordstylesheet"),
71
+ wordstylesheet_override: node.attr("wordstylesheet-override"),
70
72
  standardstylesheet: node.attr("standardstylesheet"),
71
73
  header: node.attr("header"),
72
74
  wordcoverpage: node.attr("wordcoverpage"),
@@ -139,7 +141,7 @@ module Asciidoctor
139
141
 
140
142
  def document(node)
141
143
  init(node)
142
- ret = makexml(node).to_xml(indent: 2)
144
+ ret = makexml(node).to_xml(encoding: "US-ASCII", indent: 2)
143
145
  outputs(node, ret) unless node.attr("nodoc") || !node.attr("docfile")
144
146
  clean_exit
145
147
  ret
@@ -124,7 +124,7 @@
124
124
  <value>application/tei+xml</value>
125
125
  <value>text/x-asciidoc</value>
126
126
  <value>text/markdown</value>
127
- <value>application/x-isodoc+xml</value>
127
+ <value>application/x-metanorma+xml</value>
128
128
  <text/>
129
129
  </choice>
130
130
  </attribute>
@@ -452,6 +452,7 @@
452
452
  <attribute name="type">
453
453
  <choice>
454
454
  <value>isni</value>
455
+ <value>orcid</value>
455
456
  <value>uri</value>
456
457
  </choice>
457
458
  </attribute>
@@ -461,10 +462,7 @@
461
462
  <define name="org-identifier">
462
463
  <element name="identifier">
463
464
  <attribute name="type">
464
- <choice>
465
- <value>orcid</value>
466
- <value>uri</value>
467
- </choice>
465
+ <data type="string" datatypeLibrary=""/>
468
466
  </attribute>
469
467
  <text/>
470
468
  </element>
@@ -1106,7 +1104,7 @@
1106
1104
  <value>complementOf</value>
1107
1105
  <value>obsoletes</value>
1108
1106
  <value>obsoletedBy</value>
1109
- <value>cited</value>
1107
+ <value>cites</value>
1110
1108
  <value>isCitedIn</value>
1111
1109
  </choice>
1112
1110
  </define>
@@ -45,8 +45,9 @@ module Asciidoctor
45
45
  noko do |xml|
46
46
  xml.figure **literal_attrs(node) do |f|
47
47
  figure_title(node, f)
48
- f.pre node.lines.join("\n"), **attr_code(id: Metanorma::Utils::anchor_or_uuid,
49
- alt: node.attr("alt"))
48
+ f.pre node.lines.join("\n"),
49
+ **attr_code(id: Metanorma::Utils::anchor_or_uuid,
50
+ alt: node.attr("alt"))
50
51
  end
51
52
  end
52
53
  end
@@ -78,9 +79,19 @@ module Asciidoctor
78
79
  example_proper(node)
79
80
  end
80
81
 
82
+ def svgmap_attrs(node)
83
+ attr_code( { id: node.id,
84
+ unnumbered: node.option?("unnumbered") ? "true" : nil,
85
+ number: node.attr("number"),
86
+ subsequence: node.attr("subsequence") }.
87
+ merge(keep_attrs(node)))
88
+ end
89
+
81
90
  def svgmap_example(node)
82
91
  noko do |xml|
83
- xml.svgmap **attr_code(example_attrs(node).merge(src: node.attr("src"), alt: node.attr("alt"))) do |ex|
92
+ xml.svgmap **attr_code(svgmap_attrs(node).merge(
93
+ src: node.attr("src"), alt: node.attr("alt"))) do |ex|
94
+ figure_title(node, ex)
84
95
  ex << node.content
85
96
  end
86
97
  end.join("\n")
@@ -129,8 +140,9 @@ module Asciidoctor
129
140
  end
130
141
 
131
142
  def para_attrs(node)
132
- attr_code(keep_attrs(node).merge(align: node.attr("align"),
133
- id: Metanorma::Utils::anchor_or_uuid(node)))
143
+ attr_code(keep_attrs(node).
144
+ merge(align: node.attr("align"),
145
+ id: Metanorma::Utils::anchor_or_uuid(node)))
134
146
  end
135
147
 
136
148
  def paragraph(node)
@@ -143,8 +155,9 @@ module Asciidoctor
143
155
  end
144
156
 
145
157
  def quote_attrs(node)
146
- attr_code(keep_attrs(node).merge(align: node.attr("align"),
147
- id: Metanorma::Utils::anchor_or_uuid(node)))
158
+ attr_code(keep_attrs(node).
159
+ merge(align: node.attr("align"),
160
+ id: Metanorma::Utils::anchor_or_uuid(node)))
148
161
  end
149
162
 
150
163
  def quote_attribution(node, out)
@@ -168,11 +181,12 @@ module Asciidoctor
168
181
  end
169
182
 
170
183
  def listing_attrs(node)
171
- attr_code(keep_attrs(node).merge(lang: node.attr("language"),
172
- id: Metanorma::Utils::anchor_or_uuid(node),
173
- unnumbered: node.option?("unnumbered") ? "true" : nil,
174
- number: node.attr("number"),
175
- filename: node.attr("filename")))
184
+ attr_code(keep_attrs(node).
185
+ merge(lang: node.attr("language"),
186
+ id: Metanorma::Utils::anchor_or_uuid(node),
187
+ unnumbered: node.option?("unnumbered") ? "true" : nil,
188
+ number: node.attr("number"),
189
+ filename: node.attr("filename")))
176
190
  end
177
191
 
178
192
  # NOTE: html escaping is performed by Nokogiri
@@ -45,7 +45,6 @@ module Asciidoctor
45
45
  xref_cleanup(xmldoc)
46
46
  concept_cleanup(xmldoc)
47
47
  origin_cleanup(xmldoc)
48
- svgmap_cleanup(xmldoc)
49
48
  termdef_cleanup(xmldoc)
50
49
  RelatonIev::iev_cleanup(xmldoc, @bibdb)
51
50
  element_name_cleanup(xmldoc)
@@ -59,6 +58,7 @@ module Asciidoctor
59
58
  bookmark_cleanup(xmldoc)
60
59
  requirement_cleanup(xmldoc)
61
60
  bibdata_cleanup(xmldoc)
61
+ svgmap_cleanup(xmldoc)
62
62
  boilerplate_cleanup(xmldoc)
63
63
  smartquotes_cleanup(xmldoc)
64
64
  variant_cleanup(xmldoc)
@@ -172,7 +172,7 @@ module Asciidoctor
172
172
 
173
173
  def img_cleanup(xmldoc)
174
174
  return xmldoc unless @datauriimage
175
- xmldoc.xpath("//image").each { |i| i["src"] = datauri(i["src"]) }
175
+ xmldoc.xpath("//image").each { |i| i["src"] = Metanorma::Utils::datauri(i["src"], @localdir) }
176
176
  end
177
177
 
178
178
  def variant_cleanup(xmldoc)
@@ -29,7 +29,7 @@ module Asciidoctor
29
29
  def dl2_table_cleanup(xmldoc)
30
30
  q = "//table/following-sibling::*[1][self::p]"
31
31
  xmldoc.xpath(q).each do |s|
32
- if s.text =~ /^\s*key[^a-z]*$/i && !s.next_element.nil? && s.next_element.name == "dl"
32
+ if s.text =~ /^\s*key[^a-z]*$/i && s&.next_element&.name == "dl"
33
33
  s.next_element["key"] = "true"
34
34
  s.previous_element << s.next_element.remove
35
35
  s.remove
@@ -95,7 +95,7 @@ module Asciidoctor
95
95
  def formula_cleanup_where2(x)
96
96
  q = "//formula/following-sibling::*[1][self::p]"
97
97
  x.xpath(q).each do |s|
98
- if s.text =~ /^\s*where[^a-z]*$/i && !s.next_element.nil? && s.next_element.name == "dl"
98
+ if s.text =~ /^\s*where[^a-z]*$/i && s&.next_element&.name == "dl"
99
99
  s.next_element["key"] = "true"
100
100
  s.previous_element << s.next_element.remove
101
101
  s.remove
@@ -114,7 +114,7 @@ module Asciidoctor
114
114
  def figure_dl_cleanup2(xmldoc)
115
115
  q = "//figure/following-sibling::*[self::p]"
116
116
  xmldoc.xpath(q).each do |s|
117
- if s.text =~ /^\s*key[^a-z]*$/i && !s.next_element.nil? && s.next_element.name == "dl"
117
+ if s.text =~ /^\s*key[^a-z]*$/i && s&.next_element&.name == "dl"
118
118
  s.next_element["key"] = "true"
119
119
  s.previous_element << s.next_element.remove
120
120
  s.remove
@@ -125,7 +125,9 @@ module Asciidoctor
125
125
  # examples containing only figures become subfigures of figures
126
126
  def subfigure_cleanup(xmldoc)
127
127
  xmldoc.xpath("//example[figure]").each do |e|
128
- next unless e.elements.map { |m| m.name }.reject { |m| %w(name figure).include? m }.empty?
128
+ next unless e.elements.map { |m| m.name }.reject do |m|
129
+ %w(name figure).include? m
130
+ end.empty?
129
131
  e.name = "figure"
130
132
  end
131
133
  end
@@ -140,7 +142,8 @@ module Asciidoctor
140
142
  ELEMS_ALLOW_NOTES = %w[p formula ul ol dl figure].freeze
141
143
 
142
144
  # if a note is at the end of a section, it is left alone
143
- # if a note is followed by a non-note block, it is moved inside its preceding block if it is not delimited
145
+ # if a note is followed by a non-note block,
146
+ # it is moved inside its preceding block if it is not delimited
144
147
  # (so there was no way of making that block include the note)
145
148
  def note_cleanup(xmldoc)
146
149
  q = "//note[following-sibling::*[not(local-name() = 'note')]]"
@@ -150,8 +153,10 @@ module Asciidoctor
150
153
  prev = n.previous_element || next
151
154
  n.parent = prev if ELEMS_ALLOW_NOTES.include? prev.name
152
155
  end
153
- xmldoc.xpath("//note[@keep-separate]").each { |n| n.delete("keep-separate") }
154
- xmldoc.xpath("//termnote[@keep-separate]").each { |n| n.delete("keep-separate") }
156
+ xmldoc.xpath("//note[@keep-separate] | "\
157
+ "//termnote[@keep-separate]").each do |n|
158
+ n.delete("keep-separate")
159
+ end
155
160
  end
156
161
 
157
162
  def requirement_cleanup(x)
@@ -184,18 +189,50 @@ module Asciidoctor
184
189
  end
185
190
 
186
191
  def requirement_cleanup1(r)
187
- while d = r.at("./description[following-sibling::*[1][self::description]]")
192
+ while d = r.at("./description[following-sibling::*[1]"\
193
+ "[self::description]]")
188
194
  n = d.next.remove
189
195
  d << n.children
190
196
  end
191
- r.xpath("./description[normalize-space(.)='']").each { |d| d.replace("\n") }
197
+ r.xpath("./description[normalize-space(.)='']").each do |d|
198
+ d.replace("\n")
199
+ end
192
200
  end
193
201
 
194
202
  def svgmap_cleanup(xmldoc)
203
+ svgmap_moveattrs(xmldoc)
195
204
  svgmap_populate(xmldoc)
196
205
  Metanorma::Utils::svgmap_rewrite(xmldoc, @localdir)
197
206
  end
198
207
 
208
+ def guid?(x)
209
+ /^_[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i.
210
+ match(x)
211
+ end
212
+
213
+ def svgmap_moveattrs(xmldoc)
214
+ xmldoc.xpath("//svgmap").each do |s|
215
+ f = s.at(".//figure") or next
216
+ if t = s.at("./name") and !f.at("./name")
217
+ f.children.first.previous = t.remove
218
+ end
219
+ if s["id"] && guid?(f["id"])
220
+ f["id"] = s["id"]
221
+ s.delete("id")
222
+ end
223
+ svgmap_moveattrs1(s, f)
224
+ end
225
+ end
226
+
227
+ def svgmap_moveattrs1(s, f)
228
+ %w(unnumbered number subsequence keep-with-next
229
+ keep-lines-together).each do |a|
230
+ next if f[a] || !s[a]
231
+ f[a] = s[a]
232
+ s.delete(a)
233
+ end
234
+ end
235
+
199
236
  def svgmap_populate(xmldoc)
200
237
  xmldoc.xpath("//svgmap").each do |s|
201
238
  s1 = s.dup
@@ -204,8 +241,8 @@ module Asciidoctor
204
241
  s1.xpath(".//li").each do |li|
205
242
  t = li&.at(".//eref | .//link | .//xref") or next
206
243
  href = t.xpath("./following-sibling::node()")
207
- next if href.empty?
208
- s << %[<target href="#{svgmap_target(href)}">#{t.to_xml}</target>]
244
+ href.empty? or
245
+ s << %[<target href="#{svgmap_target(href)}">#{t.to_xml}</target>]
209
246
  end
210
247
  end
211
248
  end
@@ -215,7 +252,7 @@ module Asciidoctor
215
252
  next unless n.name == "link"
216
253
  n.children = n["target"]
217
254
  end
218
- nodeset.text.sub(/^[,;]/, "").strip
255
+ nodeset.text.sub(/^[,; ]/, "").strip
219
256
  end
220
257
  end
221
258
  end
@@ -106,7 +106,7 @@ module Asciidoctor
106
106
  def bibdata_cleanup(xmldoc)
107
107
  bibdata_anchor_cleanup(xmldoc)
108
108
  bibdata_docidentifier_cleanup(xmldoc)
109
- biblio_indirect_erefs(xmldoc, @internal_eref_namespaces&.uniq)
109
+ biblio_indirect_erefs(xmldoc, @internal_eref_namespaces&.uniq)
110
110
  end
111
111
 
112
112
  def bibdata_anchor_cleanup(xmldoc)
@@ -124,7 +124,7 @@ module Asciidoctor
124
124
  end
125
125
  end
126
126
 
127
- def gather_indirect_erefs(xmldoc, prefix)
127
+ def gather_indirect_erefs(xmldoc, prefix)
128
128
  xmldoc.xpath("//eref[@type = '#{prefix}']").each_with_object({}) do |e, m|
129
129
  e.delete("type")
130
130
  m[e["bibitemid"]] = true
@@ -160,7 +160,7 @@ module Asciidoctor
160
160
  def resolve_local_indirect_erefs(xmldoc, refs, prefix)
161
161
  refs.each_with_object([]) do |r, m|
162
162
  id = r.sub(/^#{prefix}_/, "")
163
- if xmldoc.at("//*[@id = '#{id}'][@type = '#{prefix}']")
163
+ if n = xmldoc.at("//*[@id = '#{id}']") and n.at("./ancestor-or-self::*[@type = '#{prefix}']")
164
164
  xmldoc.xpath("//eref[@bibitemid = '#{r}']").each do |e|
165
165
  indirect_eref_to_xref(e, id)
166
166
  end
@@ -2,6 +2,7 @@ require "nokogiri"
2
2
  require "pathname"
3
3
  require "open-uri"
4
4
  require "html2doc"
5
+ require "asciimath2unitsml"
5
6
  require_relative "./cleanup_block.rb"
6
7
  require_relative "./cleanup_footnotes.rb"
7
8
  require_relative "./cleanup_ref.rb"
@@ -73,13 +74,49 @@ module Asciidoctor
73
74
  end
74
75
  end
75
76
 
77
+ UNITSML_NS = "https://schema.unitsml.org/unitsml/1.0".freeze
78
+
79
+ def add_misc_container(xmldoc)
80
+ unless ins = xmldoc.at("//misc-container")
81
+ a = xmldoc.at("//termdocsource") || xmldoc.at("//bibdata")
82
+ a.next = "<misc-container/>"
83
+ ins = xmldoc.at("//misc-container")
84
+ end
85
+ ins
86
+ end
87
+
88
+ def mathml_unitsML(xmldoc)
89
+ return unless xmldoc.at(".//m:*", "m" => UNITSML_NS)
90
+ misc = add_misc_container(xmldoc)
91
+ unitsml = misc.add_child("<UnitsML xmlns='#{UNITSML_NS}'/>").first
92
+ %w(Unit CountedItem Quantity Dimension Prefix).each do |t|
93
+ gather_unitsml(unitsml, xmldoc, t)
94
+ end
95
+ end
96
+
97
+ def gather_unitsml(unitsml, xmldoc, t)
98
+ tags = xmldoc.xpath(".//m:#{t}", "m" => UNITSML_NS).each_with_object({}) do |x, m|
99
+ m[x["id"]] = x.remove
100
+ end
101
+ return if tags.empty?
102
+ set = unitsml.add_child("<#{t}Set/>").first
103
+ tags.values.each { |v| set << v }
104
+ end
105
+
106
+ def asciimath2unitsml_options
107
+ { multiplier: :space }
108
+ end
109
+
76
110
  def mathml_cleanup(xmldoc)
111
+ unitsml = Asciimath2UnitsML::Conv.new(asciimath2unitsml_options)
77
112
  xmldoc.xpath("//stem[@type = 'MathML']").each do |x|
78
113
  xml_unescape_mathml(x)
79
114
  mathml_namespace(x)
80
115
  mathml_preserve_space(x)
81
116
  mathml_italicise(x)
117
+ unitsml.MathML2UnitsML(x)
82
118
  end
119
+ mathml_unitsML(xmldoc)
83
120
  end
84
121
  end
85
122
  end