asciimath2unitsml 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '049ec45166f29cb157a85f9a5d3ac4ec6b1235ed1e673879623477b0b793c402'
4
- data.tar.gz: 1671804ae7f17bc92268b7c77f7206d216f0c7b08a4318d7e9a3df116f45c47c
3
+ metadata.gz: 3d06ecf91cb804e1a5827a46ef0e458a0fe1b444a476bc6e9d99ff2dd6c06d37
4
+ data.tar.gz: 615d0c46c6beb12bea4fb427379ba49835679fb3f1efd56692909d049e9e9be7
5
5
  SHA512:
6
- metadata.gz: 6a4f6944f43e7a5336b648d8db1027bd93b4672d2ac22f90dc7277d4a6553959623db23b043bbd792cf9c4b351862980cee35b0828d44ac060ec21207fe7bf41
7
- data.tar.gz: 8c8836120abac3f0a3fa49877efe3619c188af201e82d3afd37e56327063c624e629ac953b96eb5842cadf7186c354827773979d0291d94ab346ee528f699283
6
+ metadata.gz: 270b64a21c8a566907c1d0a3e81e20f126bd48d277631678b65d662eb8d80da92799e127c0d75f0555226762157eefd1cf27135f3daa1b79693199c00758fa22
7
+ data.tar.gz: b78b7cc95c55fde702b677e8e0a70126066341afeed726d4e3d00958b4cd4ad4d11850ef694329eca640019b5354bb34fb7efd246d023c065e7c37388c9de87e
data/README.adoc CHANGED
@@ -89,6 +89,7 @@ The converter is run as:
89
89
  ----
90
90
  c = Asciimath2UnitsML::Conv.new()
91
91
  c.Asciimath2UnitsML({Asciimath string containing "unitsml()"})
92
+ c.MathML2UnitsML({MathML document containing <mtext>unitsml()</mtext>})
92
93
  c.MathML2UnitsML({Nokogiri parse of MathML document containing <mtext>unitsml()</mtext>})
93
94
  ----
94
95
 
@@ -32,17 +32,21 @@ module Asciimath2UnitsML
32
32
  end
33
33
  end
34
34
 
35
+ def units_only(units)
36
+ units.reject { |u| u[:multiplier] }
37
+ end
38
+
35
39
  def unit_id(text)
36
40
  "U_" +
37
41
  (@units[text.to_sym] ? @units[text.to_sym][:id] : text.gsub(/\*/, ".").gsub(/\^/, ""))
38
42
  end
39
43
 
40
- def unit(units, text, dims)
44
+ def unit(units, origtext, normtext, dims)
41
45
  dimid = dim_id(dims)
42
46
  <<~END
43
- <Unit xmlns='#{UNITSML_NS}' xml:id='#{unit_id(text)}'#{dimid ? " dimensionURL='##{dimid}'" : ""}>
47
+ <Unit xmlns='#{UNITSML_NS}' xml:id='#{unit_id(origtext)}'#{dimid ? " dimensionURL='##{dimid}'" : ""}>
44
48
  #{unitsystem(units)}
45
- #{unitname(units, text)}
49
+ #{unitname(units, normtext)}
46
50
  #{unitsymbol(units)}
47
51
  #{rootunits(units)}
48
52
  </Unit>
@@ -51,6 +55,7 @@ module Asciimath2UnitsML
51
55
 
52
56
  def unitsystem(units)
53
57
  ret = []
58
+ units = units_only(units)
54
59
  units.any? { |x| @units[x[:unit].to_sym][:si] != true } and
55
60
  ret << "<UnitSystem name='not_SI' type='not_SI' xml:lang='en-US'/>"
56
61
  if units.any? { |x| @units[x[:unit].to_sym][:si] == true }
@@ -79,21 +84,27 @@ module Asciimath2UnitsML
79
84
 
80
85
  def htmlsymbol(units)
81
86
  units.map do |u|
82
- u[:exponent] and exp = "<sup>#{u[:exponent].sub(/-/, "&#x2212;")}</sup>"
83
- "#{u[:prefix]}#{u[:unit]}#{exp}"
84
- end.join(@multiplier[:html])
87
+ if u[:multiplier] then u[:multiplier] == "*" ? @multiplier[:html] : u[:multiplier]
88
+ else
89
+ u[:display_exponent] and exp = "<sup>#{u[:display_exponent].sub(/-/, "&#x2212;")}</sup>"
90
+ "#{u[:prefix]}#{u[:unit]}#{exp}"
91
+ end
92
+ end.join("")
85
93
  end
86
94
 
87
95
  def mathmlsymbol(units)
88
96
  exp = units.map do |u|
89
- base = "<mi mathvariant='normal'>#{u[:prefix]}#{u[:unit]}</mi>"
90
- if u[:exponent]
91
- exp = "<mn>#{u[:exponent]}</mn>".sub(/<mn>-/, "<mo>&#x2212;</mo><mn>")
92
- "<msup><mrow>#{base}</mrow><mrow>#{exp}</mrow></msup>"
97
+ if u[:multiplier] then u[:multiplier] == "*" ? @multiplier[:mathml] : "<mo>#{u[:multiplier]}</mo>"
93
98
  else
94
- base
99
+ base = "<mi mathvariant='normal'>#{u[:prefix]}#{u[:unit]}</mi>"
100
+ if u[:display_exponent]
101
+ exp = "<mn>#{u[:display_exponent]}</mn>".sub(/<mn>-/, "<mo>&#x2212;</mo><mn>")
102
+ "<msup><mrow>#{base}</mrow><mrow>#{exp}</mrow></msup>"
103
+ else
104
+ base
105
+ end
95
106
  end
96
- end.join(@multiplier[:mathml])
107
+ end.join("")
97
108
  end
98
109
 
99
110
  def mathmlsymbolwrap(units)
@@ -106,9 +117,9 @@ module Asciimath2UnitsML
106
117
 
107
118
  def rootunits(units)
108
119
  return if units.size == 1
109
- exp = units.map do |u|
120
+ exp = units_only(units).map do |u|
110
121
  prefix = " prefix='#{u[:prefix]}'" if u[:prefix]
111
- exponent = " powerNumerator='#{u[:exponent]}'" if u[:exponent]
122
+ exponent = " powerNumerator='#{u[:exponent]}'" if u[:exponent] && u[:exponent] != "1"
112
123
  "<EnumeratedRootUnit unit='#{@units[u[:unit].to_sym][:name]}'#{prefix}#{exponent}/>"
113
124
  end.join("\n")
114
125
  <<~END
@@ -159,7 +170,7 @@ module Asciimath2UnitsML
159
170
  end
160
171
 
161
172
  def normalise_units(units)
162
- gather_units(units.map { |u| normalise_unit(u) }.flatten)
173
+ gather_units(units_only(units).map { |u| normalise_unit(u) }.flatten)
163
174
  end
164
175
 
165
176
  def gather_units(units)
@@ -197,10 +208,10 @@ module Asciimath2UnitsML
197
208
  "unknown"
198
209
  end
199
210
 
200
- def unitsml(units, text)
211
+ def unitsml(units, origtext, normtext)
201
212
  dims = units2dimensions(units)
202
213
  <<~END
203
- #{unit(units, text, dims)}
214
+ #{unit(units, origtext, normtext, dims)}
204
215
  #{prefix(units)}
205
216
  #{dimension(dims)}
206
217
  END
@@ -38,10 +38,10 @@ module Asciimath2UnitsML
38
38
  end.map { |k| Regexp.escape(k) }
39
39
  unit1 = /#{unit_keys.sort_by(&:length).reverse.join("|")}/.r
40
40
  exponent = /\^-?\d+/.r.map { |m| m.sub(/\^/, "") }
41
- multiplier = /\*/.r
42
- unit = seq(unit1, exponent._?) { |x| { prefix: nil, unit: x[0], exponent: x[1][0] } } |
43
- seq(prefix, unit1, exponent._?) { |x| { prefix: x[0][0], unit: x[1], exponent: x[2][0] } }
44
- units_tail = seq(multiplier, unit) { |u| u[1] }
41
+ multiplier = %r{[*/]}.r.map { |x| { multiplier: x } }
42
+ unit = seq(unit1, exponent._?) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0] )} } |
43
+ seq(prefix, unit1, exponent._?) { |x| { prefix: x[0][0], unit: x[1], display_exponent: (x[2][0] ) } }
44
+ units_tail = seq(multiplier, unit) { |x| [x[0], x[1]] }
45
45
  units = seq(unit, units_tail.star) { |x| [x[0], x[1]].flatten }
46
46
  parser = units.eof
47
47
  end
@@ -52,7 +52,29 @@ module Asciimath2UnitsML
52
52
  raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
53
53
  end
54
54
  Rsec::Fail.reset
55
- units
55
+ postprocess(units, x)
56
+ end
57
+
58
+ def postprocess(units, text)
59
+ units = postprocess1(units)
60
+ normtext = units_only(units).each.map do |u|
61
+ exp = u[:exponent] && u[:exponent] != "1" ? "^#{u[:exponent]}" : ""
62
+ "#{u[:prefix]}#{u[:unit]}#{exp}"
63
+ end.join("*")
64
+ [units, text, normtext]
65
+ end
66
+
67
+ def postprocess1(units)
68
+ inverse = false
69
+ units.each_with_object([]) do |u, m|
70
+ if u[:multiplier]
71
+ inverse = (u[:multiplier] == "/")
72
+ else
73
+ u[:exponent] = inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent]
74
+ u[:exponent] = u[:exponent]&.sub(/^--+/, "")
75
+ end
76
+ m << u
77
+ end
56
78
  end
57
79
 
58
80
  U2D = {
@@ -73,12 +95,14 @@ module Asciimath2UnitsML
73
95
 
74
96
  # https://www.w3.org/TR/mathml-units/ section 2: delimit number Invisible-Times unit
75
97
  def MathML2UnitsML(xml)
98
+ xml.is_a? String and xml = Nokogiri::XML(xml)
76
99
  xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x|
77
100
  next unless %r{^unitsml\(.+\)$}.match(x.text)
78
101
  text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
79
- units = parse(text)
102
+ units, origtext, normtext = parse(text)
80
103
  delim = x&.previous_element&.name == "mn" ? "<mo rspace='thickmathspace'>&#x2062;</mo>" : ""
81
- x.replace("#{delim}<mrow xref='#{unit_id(text)}'>#{mathmlsymbol(units)}</mrow>\n#{unitsml(units, text)}")
104
+ x.replace("#{delim}<mrow xref='#{unit_id(text)}'>#{mathmlsymbol(units)}</mrow>\n"\
105
+ "#{unitsml(units, origtext, normtext)}")
82
106
  end
83
107
  xml
84
108
  end
@@ -1,3 +1,3 @@
1
1
  module Asciimath2UnitsML
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
data/spec/conv_spec.rb CHANGED
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  RSpec.describe Asciimath2UnitsML do
4
4
  it "converts an AsciiMath string to MathML + UnitsML" do
5
5
  expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
6
- 32 + 5 xx 7 "unitsml(kg^-2)" xx 9 "unitsml(g)" xx 1 "unitsml(kg*s^-2)" xx 812 "unitsml(m*s^-2)" - 9 "unitsml(C^3*A)" + 7 "unitsml(hp)"
6
+ 32 + 5 xx 7 "unitsml(kg^-2)" xx 9 "unitsml(g)" xx 1 "unitsml(kg*s^-2)" xx 812 "unitsml(m*s^-2)" - 9 "unitsml(C^3*A)" + 7 "unitsml(hp)" + 13 "unitsml(A/C^-3)"
7
7
  INPUT
8
8
  <math xmlns='http://www.w3.org/1998/Math/MathML'>
9
9
  <mn>32</mn>
@@ -246,6 +246,72 @@ RSpec.describe Asciimath2UnitsML do
246
246
  OUTPUT
247
247
  end
248
248
 
249
+ it "converts MathML to MatML + UnitsML" do
250
+ input = <<~INPUT
251
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
252
+ <mn>32</mn>
253
+ <mo>+</mo>
254
+ <mn>5</mn>
255
+ <mo>&#xD7;</mo>
256
+ <mn>7</mn>
257
+ <mtext>unitsml(kg^-2)</mtext>
258
+ </math>
259
+ INPUT
260
+ output = <<~OUTPUT
261
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
262
+ <mn>32</mn>
263
+ <mo>+</mo>
264
+ <mn>5</mn>
265
+ <mo>&#xD7;</mo>
266
+ <mn>7</mn>
267
+ <mo rspace='thickmathspace'>&#x2062;</mo>
268
+ <mrow xref='U_kg-2'>
269
+ <msup>
270
+ <mrow>
271
+ <mi mathvariant='normal'>kg</mi>
272
+ </mrow>
273
+ <mrow>
274
+ <mo>&#x2212;</mo>
275
+ <mn>2</mn>
276
+ </mrow>
277
+ </msup>
278
+ </mrow>
279
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_kg-2' dimensionURL='#D_M-2'>
280
+ <UnitSystem name='SI' type='SI_base' xml:lang='en-US'/>
281
+ <UnitName xml:lang='en'>kg^-2</UnitName>
282
+ <UnitSymbol type='HTML'>
283
+ kg
284
+ <sup>&#x2212;2</sup>
285
+ </UnitSymbol>
286
+ <UnitSymbol type='MathML'>
287
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
288
+ <mrow>
289
+ <msup>
290
+ <mrow>
291
+ <mi mathvariant='normal'>kg</mi>
292
+ </mrow>
293
+ <mrow>
294
+ <mo>&#x2212;</mo>
295
+ <mn>2</mn>
296
+ </mrow>
297
+ </msup>
298
+ </mrow>
299
+ </math>
300
+ </UnitSymbol>
301
+ </Unit>
302
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='3' xml:id='NISTp10_3'>
303
+ <PrefixName xml:lang='en'>kilo</PrefixName>
304
+ <PrefixSymbol type='ASCII'>k</PrefixSymbol>
305
+ </Prefix>
306
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='D_M-2'>
307
+ <Mass symbol='M' powerNumerator='-2'/>
308
+ </Dimension>
309
+ </math>
310
+ OUTPUT
311
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().MathML2UnitsML(input).to_xml)).to be_equivalent_to xmlpp(output)
312
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().MathML2UnitsML(Nokogiri::XML(input)).to_xml)).to be_equivalent_to xmlpp(output)
313
+ end
314
+
249
315
  it "raises error for illegal unit" do
250
316
  expect{xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))}.to raise_error(Rsec::SyntaxError)
251
317
  12 "unitsml(que?)"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciimath2unitsml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-19 00:00:00.000000000 Z
11
+ date: 2021-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciimath