asciimath2unitsml 0.1.1 → 0.1.2

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: '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