asciimath2unitsml 0.2.0 → 0.2.1

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: ca1751cf852b77599154aa142ea719f0510210ddebb667ace7225cb94f7d598f
4
- data.tar.gz: 332e23b81a688d1386a4f084dc3db1f401e1e7634beb70c17466e18a23d1f51a
3
+ metadata.gz: 939880ec148bae10c193dc7958d2866ff5788d7e98617158bfde25a736576b13
4
+ data.tar.gz: dc8d0afdfc6c134341735b55bfed5ae68b50da906ea5765e8404135d58adf011
5
5
  SHA512:
6
- metadata.gz: f300b5a9c8af814f4c61ff9be4407f45350fedfc76a7c9b3e4da90a793fcf5cf7004b24e5719a562cc2cb355bb8be355ee4d1e23909f6bbbd4060a97affcd7de
7
- data.tar.gz: abeedd889b14c45eeeb90a2f56fc5a09de04ca54f7b15f39677ad516fda17426dbd47977fdc71199ed77424639dd4c86a40164672dd81aad92fd512f872b1723
6
+ metadata.gz: f2f5e07977df15d3354ce4e509c585de929caf592ccd9ccd6974d5830b932b0982bd1c7c3cc0483c028e64846032925907316406f0f95cb9c6dda49ecb1ef2b6
7
+ data.tar.gz: e1f358839665b8b815772e32c30ecaea7581061962d7b87cb5e844aaddaed666ae1b95fb2885e7f8eff4bc0d656325660eeba5cf5a45414690614e987da7f31f
data/README.adoc CHANGED
@@ -1,3 +1,9 @@
1
+ image:https://img.shields.io/gem/v/asciimath2unitsml.svg["Gem Version", link="https://rubygems.org/gems/asciimath2unitsml"]
2
+ image:https://github.com/plurimath/asciimath2unitsml/workflows/rake/badge.svg["Build Status", link="https://github.com/plurimath/asciimath2unitsml/actions?workflow=rake"]
3
+ // image:https://codeclimate.com/github/plurimath/asciimath2unitsml/badges/gpa.svg["Code Climate", link="https://codeclimate.com/github/plurimath/asciimath2unitsml"]
4
+ image:https://img.shields.io/github/issues-pr-raw/plurimath/asciimath2unitsml.svg["Pull Requests", link="https://github.com/plurimath/asciimath2unitsml/pulls"]
5
+ image:https://img.shields.io/github/commits-since/plurimath/asciimath2unitsml/latest.svg["Commits since latest",link="https://github.com/plurimath/asciimath2unitsml/releases"]
6
+
1
7
  = asciimath2unitsml
2
8
  Convert Units expressions via MathML to UnitsML
3
9
 
@@ -43,6 +49,13 @@ https://github.com/unitsml/unitsdb/blob/master/units.yaml[]), that quantity is a
43
49
  otherwise, no quantity is added unless explicitly nominated in this way.
44
50
  * `unitsml(unit-string, name: NAME)` provides a name for the unit, if one is not already available
45
51
  from UnitsDB. For example, `unitsml(cal_th/cm^2, name: langley)`.
52
+ * `unitsml(unit-string, symbol: SYMBOL)` provides an alternate symbol for the unit, in AsciiMath.
53
+ The unit-string gives the canonical representation of the unit, but SYMBOL is what will be rendered.
54
+ For example, `unitsml(cal_th/cm^2, name: langley, symbol: La)`, or `unitsml(mm*s^-2, symbol: mm cdot s^-2)`.
55
+ (All variables in SYMBOL are rendered upright, as is the default for units.)
56
+
57
+ Standalone prefixes can be recognised by replacing the unit with hyphen; so `unitsml(p-)` corresponds
58
+ to the standalone prefix "pico" (and is rendered as "p").
46
59
 
47
60
  == Rendering
48
61
 
@@ -54,6 +67,9 @@ The gem follows the MathML Units convention of inserting a spacing invisible tim
54
67
  (`<mo rspace='thickmathspace'>&#x2062;</mo>`) between any numbers (`<mn>`) and unit expressions
55
68
  in MathML, and representing units in MathML as non-italic variables (`<mi mathvariant='normal'>`).
56
69
 
70
+ Space is not inserted between a number and a unit expression, when that unit expression wholly consists
71
+ of punctuation: _1 m_, _1 °C_, but _9° 7′ 22″_.
72
+
57
73
  == Example
58
74
 
59
75
  [source]
@@ -35,6 +35,10 @@ module Asciimath2UnitsML
35
35
  @multiplier = multiplier(options[:multiplier] || "\u00b7")
36
36
  end
37
37
 
38
+ def float_to_display(f)
39
+ ret = f.to_f.round(1).to_s.sub(/\.0$/, "")
40
+ end
41
+
38
42
  def prefix(units)
39
43
  units.map { |u| u[:prefix] }.reject { |u| u.nil? }.uniq.map do |p|
40
44
  <<~END
@@ -61,7 +65,7 @@ module Asciimath2UnitsML
61
65
 
62
66
  def units2dimensions(units)
63
67
  norm = decompose_units(units)
64
- return if norm.any? { |u| u[:unit] == "unknown" || u[:prefix] == "unknown" }
68
+ return if norm.any? { |u| u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil? }
65
69
  norm.map do |u|
66
70
  { dimension: U2D[u[:unit]][:dimension],
67
71
  unit: u[:unit],
@@ -71,7 +75,7 @@ module Asciimath2UnitsML
71
75
  end
72
76
 
73
77
  def dimension1(u)
74
- %(<#{u[:dimension]} symbol="#{u[:symbol]}" powerNumerator="#{u[:exponent]}"/>)
78
+ %(<#{u[:dimension]} symbol="#{u[:symbol]}" powerNumerator="#{float_to_display(u[:exponent])}"/>)
75
79
  end
76
80
 
77
81
  def dim_id(dims)
@@ -81,7 +85,9 @@ module Asciimath2UnitsML
81
85
  AmountOfSubstance LuminousIntensity PlaneAngle)
82
86
  .map { |h| dimhash.dig(h, :exponent) }.join(":")
83
87
  id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }&.first&.id and return id.to_s
84
- "D_" + dims.map { |d| U2D[d[:unit]][:symbol] + (d[:exponent] == 1 ? "" : d[:exponent].to_s) }.join("")
88
+ "D_" + dims.map do |d|
89
+ U2D[d[:unit]][:symbol] + (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
90
+ end.join("")
85
91
  end
86
92
 
87
93
  def decompose_units(units)
@@ -94,7 +100,7 @@ module Asciimath2UnitsML
94
100
  else
95
101
  m[-1] = { prefix: combine_prefixes(@prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]),
96
102
  unit: m[-1][:unit],
97
- exponent: (k[:exponent]&.to_i || 1) + (m[-1][:exponent]&.to_i || 1) }
103
+ exponent: (k[:exponent]&.to_f || 1) + (m[-1][:exponent]&.to_f || 1) }
98
104
  end
99
105
  end
100
106
  end
@@ -102,7 +108,8 @@ module Asciimath2UnitsML
102
108
  # treat g not kg as base unit: we have stripped the prefix k in parsing
103
109
  # reduce units down to basic units
104
110
  def decompose_unit(u)
105
- if u[:unit] == "g" then u
111
+ if u[:unit].nil? then u
112
+ elsif u[:unit] == "g" then u
106
113
  elsif @units[u[:unit]].system_type == "SI_base" then u
107
114
  elsif !@units[u[:unit]].si_derived_bases
108
115
  { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
@@ -111,7 +118,7 @@ module Asciimath2UnitsML
111
118
  m << { prefix: !k[:prefix].nil? && !k[:prefix].empty? ?
112
119
  combine_prefixes(@prefixes_id[k[:prefix]], @prefixes[u[:prefix]]) : u[:prefix],
113
120
  unit: @units_id[k[:id]].symbolid,
114
- exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_i || 1) }
121
+ exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_f || 1) }
115
122
  end
116
123
  end
117
124
  end
@@ -121,7 +128,7 @@ module Asciimath2UnitsML
121
128
  return p1.symbolid if p2.nil?
122
129
  return p2.symbolid if p1.nil?
123
130
  return "unknown" if p1.base != p2.base
124
- @prefixes.each do |p|
131
+ @prefixes.each do |_, p|
125
132
  return p.symbolid if p.base == p1.base && p.power == p1.power + p2.power
126
133
  end
127
134
  "unknown"
@@ -94,12 +94,17 @@ module Asciimath2UnitsML
94
94
  /\^-?\d+/.r.map { |m| m.sub(/\^/, "") }
95
95
  multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } }
96
96
  unit =
97
+ seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } |
98
+ seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
99
+ seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
97
100
  seq(unit1, exponent._? & multiplier) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0] )} } |
98
101
  seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0] )} } |
99
102
  seq(prefix1, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0] ) } } |
100
103
  seq(prefix2, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0] ) } } |
101
- "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
102
- units = unit.join(multiplier)
104
+ "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
105
+ units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
106
+ seq(prefix1, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
107
+ unit.join(multiplier)
103
108
  parser = units.eof
104
109
  end
105
110
 
@@ -117,11 +122,12 @@ module Asciimath2UnitsML
117
122
  units = postprocess1(units)
118
123
  quantity = text[1..-1]&.select { |x| /^quantity:/.match(x) }&.first&.sub(/^quantity:\s*/, "")
119
124
  name = text[1..-1]&.select { |x| /^name:/.match(x) }&.first&.sub(/^name:\s*/, "")
125
+ symbol = text[1..-1]&.select { |x| /^symbol:/.match(x) }&.first&.sub(/^symbol:\s*/, "")
120
126
  normtext = units_only(units).each.map do |u|
121
127
  exp = u[:exponent] && u[:exponent] != "1" ? "^#{u[:exponent]}" : ""
122
128
  "#{u[:prefix]}#{u[:unit]}#{exp}"
123
129
  end.join("*")
124
- [units, text[0], normtext, quantity, name]
130
+ [units, text[0], normtext, quantity, name, symbol]
125
131
  end
126
132
 
127
133
  def postprocess1(units)
@@ -148,7 +154,7 @@ module Asciimath2UnitsML
148
154
  "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
149
155
  "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
150
156
  "deg" => { dimension: "PlaneAngle", order: 8, symbol: "Phi" },
151
- }
157
+ }.freeze
152
158
 
153
159
  def Asciimath2UnitsML(expression)
154
160
  xml = Nokogiri::XML(asciimath2mathml(expression))
@@ -161,14 +167,21 @@ module Asciimath2UnitsML
161
167
  xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x|
162
168
  next unless %r{^unitsml\(.+\)$}.match(x.text)
163
169
  text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
164
- units, origtext, normtext, quantity, name = parse(text)
165
- delim = x&.previous_element&.name == "mn" ? "<mo rspace='thickmathspace'>&#x2062;</mo>" : ""
166
- x.replace("#{delim}<mrow xref='#{unit_id(origtext)}'>#{mathmlsymbol(units, false)}</mrow>\n"\
170
+ units, origtext, normtext, quantity, name, symbol = parse(text)
171
+ rendering = symbol ? embeddedmathml(asciimath2mathml(symbol)) : mathmlsymbol(units, false)
172
+ delim = x&.previous_element&.name == "mn" ? delimspace(rendering) : ""
173
+ x.replace("#{delim}<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
167
174
  "#{unitsml(units, origtext, normtext, quantity, name)}")
168
175
  end
169
176
  dedup_ids(xml)
170
177
  end
171
178
 
179
+ def delimspace(x)
180
+ text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{x}</mrow>").text.strip)
181
+ /[[:alnum:]]/.match(text) ?
182
+ "<mo rspace='thickmathspace'>&#x2062;</mo>" : "<mo>&#x2062;</mo>"
183
+ end
184
+
172
185
  def dedup_ids(xml)
173
186
  %w(Unit Dimension Prefix Quantity).each do |t|
174
187
  xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map { |a| a.text }.uniq.each do |v|
@@ -187,6 +200,12 @@ module Asciimath2UnitsML
187
200
  gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
188
201
  end
189
202
 
203
+ def embeddedmathml(mathml)
204
+ x = Nokogiri::XML(mathml)
205
+ x.xpath(".//m:mi", "m" => MATHML_NS).each { |mi| mi["mathvariant"] = "normal" }
206
+ x.children.to_xml
207
+ end
208
+
190
209
  def ambig_units
191
210
  u = @units_id.each_with_object({}) do |(k, v), m|
192
211
  v.symbolids.each do |x|
@@ -10,6 +10,7 @@ module Asciimath2UnitsML
10
10
  { html: HTMLEntities.new.encode(x), mathml: "<mo>#{HTMLEntities.new.encode(x)}</mo>" }
11
11
  end
12
12
  end
13
+
13
14
  def render(unit, style)
14
15
  @symbols[unit][style] || unit
15
16
  end
@@ -17,33 +18,56 @@ module Asciimath2UnitsML
17
18
  def htmlsymbol(units, normalise)
18
19
  units.map do |u|
19
20
  if u[:multiplier] then u[:multiplier] == "*" ? @multiplier[:html] : u[:multiplier]
21
+ elsif u[:unit].nil? && u[:prefix]
22
+ @prefixes[u[:prefix]].html
20
23
  else
21
- u[:display_exponent] and exp = "<sup>#{u[:display_exponent].sub(/-/, "&#x2212;")}</sup>"
22
- base = render(normalise ? @units[u[:unit]].symbolid : u[:unit], :html)
23
- "#{u[:prefix]}#{base}#{exp}"
24
+ base = (u[:prefix] || "") + render(normalise ? @units[u[:unit]].symbolid : u[:unit], :html)
25
+ htmlsymbol_exponent(u, base)
24
26
  end
25
27
  end.join("")
26
28
  end
27
29
 
30
+ def htmlsymbol_exponent(u, base)
31
+ if u[:display_exponent] == "0.5"
32
+ base = "&#x221a;#{base}"
33
+ elsif u[:display_exponent]
34
+ exp = "<sup>#{u[:display_exponent].sub(/-/, "&#x2212;")}</sup>"
35
+ base += exp
36
+ end
37
+ base
38
+ end
39
+
28
40
  def mathmlsymbol(units, normalise)
29
41
  exp = units.map do |u|
30
42
  if u[:multiplier] then u[:multiplier] == "*" ? @multiplier[:mathml] : "<mo>#{u[:multiplier]}</mo>"
43
+ elsif u[:unit].nil? && u[:prefix]
44
+ %(<mi mathvariant='normal'>#{@prefixes[u[:prefix]].html}</mi>)
31
45
  else
32
- base = render(normalise ? @units[u[:unit]].symbolid : u[:unit], :mathml)
33
- if u[:prefix]
34
- base = base.match(/<mi mathvariant='normal'>/) ?
35
- base.sub(/<mi mathvariant='normal'>/, "<mi mathvariant='normal'>#{u[:prefix]}") :
36
- "<mrow><mi mathvariant='normal'>#{u[:prefix]}#{base}</mrow>"
37
- end
38
- if u[:display_exponent]
39
- exp = "<mn>#{u[:display_exponent]}</mn>".sub(/<mn>-/, "<mo>&#x2212;</mo><mn>")
40
- base = "<msup><mrow>#{base}</mrow><mrow>#{exp}</mrow></msup>"
41
- end
42
- base
46
+ mathmlsymbol1(u, normalise)
43
47
  end
44
48
  end.join("")
45
49
  end
46
50
 
51
+ def mathmlsymbol1(u, normalise)
52
+ base = render(normalise ? @units[u[:unit]].symbolid : u[:unit], :mathml)
53
+ if u[:prefix]
54
+ base = base.match(/<mi mathvariant='normal'>/) ?
55
+ base.sub(/<mi mathvariant='normal'>/, "<mi mathvariant='normal'>#{u[:prefix]}") :
56
+ "<mrow><mi mathvariant='normal'>#{u[:prefix]}#{base}</mrow>"
57
+ end
58
+ mathmlsymbol_exponent(u, base)
59
+ end
60
+
61
+ def mathmlsymbol_exponent(u, base)
62
+ if u[:display_exponent] == "0.5"
63
+ base = "<msqrt>#{base}</msqrt>"
64
+ elsif u[:display_exponent]
65
+ exp = "<mn>#{u[:display_exponent]}</mn>".sub(/<mn>-/, "<mo>&#x2212;</mo><mn>")
66
+ base = "<msup><mrow>#{base}</mrow><mrow>#{exp}</mrow></msup>"
67
+ end
68
+ base
69
+ end
70
+
47
71
  def mathmlsymbolwrap(units, normalise)
48
72
  <<~END
49
73
  <math xmlns='#{MATHML_NS}'><mrow>#{mathmlsymbol(units, normalise)}</mrow></math>
@@ -6,11 +6,12 @@ module Asciimath2UnitsML
6
6
 
7
7
  def unit_id(text)
8
8
  text = text.gsub(/[()]/, "")
9
- "U_" +
10
- (@units[text] ? @units[text].id : text.gsub(/\*/, ".").gsub(/\^/, ""))
9
+ /-$/.match(text) and return @prefixes[text.sub(/-$/, "")].id
10
+ "U_" + (@units[text] ? @units[text].id : text.gsub(/\*/, ".").gsub(/\^/, ""))
11
11
  end
12
12
 
13
13
  def unit(units, origtext, normtext, dims, name)
14
+ return if units_only(units).any? { |x| x[:unit].nil? }
14
15
  dimid = dim_id(dims)
15
16
  norm_units = normalise_units(units)
16
17
  <<~END
@@ -34,6 +35,7 @@ module Asciimath2UnitsML
34
35
 
35
36
  # kg exception
36
37
  def unitsystem(units)
38
+ return if units_only(units).any? { |x| x[:unit].nil? }
37
39
  ret = []
38
40
  units = units_only(units)
39
41
  units.any? { |x| @units[x[:unit]].system_name != "SI" } and
@@ -64,6 +66,7 @@ module Asciimath2UnitsML
64
66
  end
65
67
 
66
68
  def rootunits(units)
69
+ return if units_only(units).any? { |x| x[:unit].nil? }
67
70
  return if units.size == 1 && !units[0][:prefix]
68
71
  exp = units_only(units).map do |u|
69
72
  prefix = " prefix='#{u[:prefix]}'" if u[:prefix]
@@ -1,3 +1,3 @@
1
1
  module Asciimath2UnitsML
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.2.1'.freeze
3
3
  end
@@ -2437,3 +2437,24 @@ NISTq43:
2437
2437
  quantity_type: derived
2438
2438
  quantity_name:
2439
2439
  - organ dose equivalent
2440
+
2441
+ NISTq1000:
2442
+ dimension_url: "#NISTd85"
2443
+ quantity_type: derived
2444
+ quantity_name:
2445
+ - mass fraction
2446
+ - mole fraction
2447
+ unit_reference:
2448
+ - name: parts per million
2449
+ url: "#NISTu400"
2450
+
2451
+ NISTq1001:
2452
+ dimension_url: "#NISTd16"
2453
+ quantity_type: derived
2454
+ quantity_name:
2455
+ - apparent power
2456
+ unit_reference:
2457
+ - name: var
2458
+ url: "#NISTu401"
2459
+
2460
+
@@ -4372,6 +4372,12 @@
4372
4372
  mathml: "<mi mathvariant='normal'>&#8243;</mi>"
4373
4373
  latex: \ensuremath{\mathrm{''}}
4374
4374
  unicode: "″"
4375
+ - id: "as"
4376
+ ascii: "as"
4377
+ html: "as"
4378
+ mathml: "<mi mathvariant='normal'>as</mi>"
4379
+ latex: \ensuremath{\mathrm{as}}
4380
+ unicode: "as"
4375
4381
  root_units:
4376
4382
  enumerated_root_units:
4377
4383
  - unit: "arc_second"
@@ -6543,6 +6549,12 @@
6543
6549
  mathml: "<msub><mrow><mi mathvariant='normal'>cal</mi></mrow><mrow><mi mathvariant='normal'>th</mi></mrow></msub>"
6544
6550
  latex: \ensuremath{\mathrm{cal_th}}
6545
6551
  unicode: "cal_th"
6552
+ - id: "cal"
6553
+ ascii: "cal"
6554
+ html: "cal"
6555
+ mathml: "<mi mathvariant='normal'>cal</mi>"
6556
+ latex: \ensuremath{\mathrm{cal}}
6557
+ unicode: "cal"
6546
6558
  root_units:
6547
6559
  enumerated_root_units:
6548
6560
  - unit: "thermo_calorie"
@@ -10620,3 +10632,61 @@
10620
10632
  - name: "length"
10621
10633
  url: "#NISTq1"
10622
10634
 
10635
+ "NISTu400":
10636
+ dimension_url: "#NISTd85"
10637
+ short:
10638
+ root: false
10639
+ unit_system:
10640
+ type: "SI_derived_non-special"
10641
+ name: "SI"
10642
+ unit_name:
10643
+ - "parts per million"
10644
+ unit_symbols:
10645
+ - id: "ppm"
10646
+ ascii: "ppm"
10647
+ html: "ppm"
10648
+ mathml: "<mi mathvariant='normal'>ppm</mi>"
10649
+ latex: \ensuremath{\mathrm{ppm}}
10650
+ unicode: "ppm"
10651
+ quantity_reference:
10652
+ - name: "mass quantity"
10653
+ url: "#NISTq1000"
10654
+
10655
+ "NISTu401":
10656
+ dimension_url: "#NISTd16"
10657
+ short: var
10658
+ root: true
10659
+ unit_system:
10660
+ type: "SI_derived_non-special"
10661
+ name: "SI"
10662
+ unit_name:
10663
+ - "var"
10664
+ unit_symbols:
10665
+ - id: "var"
10666
+ ascii: "var"
10667
+ html: "var"
10668
+ mathml: "<mi mathvariant='normal'>var</mi>"
10669
+ latex: \ensuremath{\mathrm{var}}
10670
+ unicode: "var"
10671
+ root_units:
10672
+ enumerated_root_units:
10673
+ - unit: "volt"
10674
+ power_denominator: 1
10675
+ power_numerator: 1
10676
+ - unit: "ampere"
10677
+ power_denominator: 1
10678
+ power_numerator: 1
10679
+ quantity_reference:
10680
+ - name: "apparent power"
10681
+ url: "#NISTq1001"
10682
+ si_derived_bases:
10683
+ - id: NISTu1
10684
+ prefix:
10685
+ power: 2
10686
+ - id: NISTu27
10687
+ prefix: p10_3
10688
+ power: 1
10689
+ - id: NISTu3
10690
+ prefix:
10691
+ power: -3
10692
+
data/spec/conv_spec.rb CHANGED
@@ -106,6 +106,96 @@ RSpec.describe Asciimath2UnitsML do
106
106
  OUTPUT
107
107
  end
108
108
 
109
+ it "does not insert space before non-alphabetic units" do
110
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
111
+ 1 "unitsml(degK)" + 1 "unitsml(prime)"
112
+ INPUT
113
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
114
+ <mn>1</mn>
115
+ <mo rspace='thickmathspace'>&#x2062;</mo>
116
+ <mrow xref='U_NISTu5'>
117
+ <mi mathvariant='normal'>&#xB0;K</mi>
118
+ </mrow>
119
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_NISTu5' dimensionURL='#NISTd5'>
120
+ <UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
121
+ <UnitName xml:lang='en'>kelvin</UnitName>
122
+ <UnitSymbol type='HTML'>K</UnitSymbol>
123
+ <UnitSymbol type='MathML'>
124
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
125
+ <mrow>
126
+ <mi mathvariant='normal'>K</mi>
127
+ </mrow>
128
+ </math>
129
+ </UnitSymbol>
130
+ </Unit>
131
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='NISTd5'>
132
+ <ThermodynamicTemperature symbol='Theta' powerNumerator='1'/>
133
+ </Dimension>
134
+ <Quantity xmlns='http://unitsml.nist.gov/2005' xml:id='NISTq5' dimensionURL='#NISTd5' quantityType='base'>
135
+ <QuantityName xml:lang='en-US'>thermodynamic temperature</QuantityName>
136
+ </Quantity>
137
+ <mo>+</mo>
138
+ <mn>1</mn>
139
+ <mo>&#x2062;</mo>
140
+ <mrow xref='U_NISTu147'>
141
+ <mi mathvariant='normal'>&#x2032;</mi>
142
+ </mrow>
143
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_NISTu147'>
144
+ <UnitSystem name='not_SI' type='not_SI' xml:lang='en-US'/>
145
+ <UnitName xml:lang='en'>minute (minute of arc)</UnitName>
146
+ <UnitSymbol type='HTML'>&#x2032;</UnitSymbol>
147
+ <UnitSymbol type='MathML'>
148
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
149
+ <mrow>
150
+ <mi mathvariant='normal'>&#x2032;</mi>
151
+ </mrow>
152
+ </math>
153
+ </UnitSymbol>
154
+ </Unit>
155
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='NISTd9'>
156
+ <PlaneAngle symbol='Phi' powerNumerator='1'/>
157
+ </Dimension>
158
+ <Quantity xmlns='http://unitsml.nist.gov/2005' xml:id='NISTq9' dimensionURL='#NISTd9' quantityType='base'>
159
+ <QuantityName xml:lang='en-US'>plane angle</QuantityName>
160
+ <QuantityName xml:lang='en-US'>angle</QuantityName>
161
+ </Quantity>
162
+ </math>
163
+ OUTPUT
164
+ end
165
+
166
+ it "deals with sqrt units" do
167
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
168
+ 1 "unitsml(sqrt(Hz))"
169
+ INPUT
170
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
171
+ <mn>1</mn>
172
+ <mo rspace='thickmathspace'>&#x2062;</mo>
173
+ <mrow xref='U_sqrtHz'>
174
+ <msqrt>
175
+ <mi mathvariant='normal'>Hz</mi>
176
+ </msqrt>
177
+ </mrow>
178
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_Hz0.5' dimensionURL='#D_T-0.5'>
179
+ <UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
180
+ <UnitName xml:lang='en'>Hz^0.5</UnitName>
181
+ <UnitSymbol type='HTML'>&#x221A;Hz</UnitSymbol>
182
+ <UnitSymbol type='MathML'>
183
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
184
+ <mrow>
185
+ <msqrt>
186
+ <mi mathvariant='normal'>Hz</mi>
187
+ </msqrt>
188
+ </mrow>
189
+ </math>
190
+ </UnitSymbol>
191
+ </Unit>
192
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='D_T-0.5'>
193
+ <Time symbol='T' powerNumerator='-0.5'/>
194
+ </Dimension>
195
+ </math>
196
+ OUTPUT
197
+ end
198
+
109
199
  it "deals with kg and g" do
110
200
  expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
111
201
  1 "unitsml(kg)" + 1 "unitsml(g)"
@@ -359,6 +449,34 @@ INPUT
359
449
  OUTPUT
360
450
  end
361
451
 
452
+ it "deals with standalone prefixes" do
453
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
454
+ "unitsml(p-)" "unitsml(da-)"
455
+ INPUT
456
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
457
+ <mrow xref='NISTp10_-12'>
458
+ <mi mathvariant='normal'>p</mi>
459
+ </mrow>
460
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='-12' xml:id='NISTp10_-12'>
461
+ <PrefixName xml:lang='en'>pico</PrefixName>
462
+ <PrefixSymbol type='ASCII'>p</PrefixSymbol>
463
+ <PrefixSymbol type='unicode'>p</PrefixSymbol>
464
+ <PrefixSymbol type='LaTeX'>p</PrefixSymbol>
465
+ <PrefixSymbol type='HTML'>p</PrefixSymbol>
466
+ </Prefix>
467
+ <mrow xref='NISTp10_1'>
468
+ <mi mathvariant='normal'>da</mi>
469
+ </mrow>
470
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='1' xml:id='NISTp10_1'>
471
+ <PrefixName xml:lang='en'>deka</PrefixName>
472
+ <PrefixSymbol type='ASCII'>da</PrefixSymbol>
473
+ <PrefixSymbol type='unicode'>da</PrefixSymbol>
474
+ <PrefixSymbol type='LaTeX'>da</PrefixSymbol>
475
+ <PrefixSymbol type='HTML'>da</PrefixSymbol>
476
+ </Prefix>
477
+ </math>
478
+ OUTPUT
479
+ end
362
480
 
363
481
  it "deals with units division" do
364
482
  expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
@@ -695,6 +813,73 @@ OUTPUT
695
813
  OUTPUT
696
814
  end
697
815
 
816
+ it "deals with dimension decomposition with like units" do
817
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
818
+ 9 "unitsml(mW*cm^(-2))"
819
+ INPUT
820
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
821
+ <mn>9</mn>
822
+ <mo rspace='thickmathspace'>&#x2062;</mo>
823
+ <mrow xref='U_mW.cm-2'>
824
+ <mi mathvariant='normal'>mW</mi>
825
+ <mo>&#xB7;</mo>
826
+ <msup>
827
+ <mrow>
828
+ <mi mathvariant='normal'>cm</mi>
829
+ </mrow>
830
+ <mrow>
831
+ <mo>&#x2212;</mo>
832
+ <mn>2</mn>
833
+ </mrow>
834
+ </msup>
835
+ </mrow>
836
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_mW.cm-2'>
837
+ <UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
838
+ <UnitName xml:lang='en'>mW*cm^-2</UnitName>
839
+ <UnitSymbol type='HTML'>
840
+ mW&#xB7;cm
841
+ <sup>&#x2212;2</sup>
842
+ </UnitSymbol>
843
+ <UnitSymbol type='MathML'>
844
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
845
+ <mrow>
846
+ <mi mathvariant='normal'>mW</mi>
847
+ <mo>&#xB7;</mo>
848
+ <msup>
849
+ <mrow>
850
+ <mi mathvariant='normal'>cm</mi>
851
+ </mrow>
852
+ <mrow>
853
+ <mo>&#x2212;</mo>
854
+ <mn>2</mn>
855
+ </mrow>
856
+ </msup>
857
+ </mrow>
858
+ </math>
859
+ </UnitSymbol>
860
+ <RootUnits>
861
+ <EnumeratedRootUnit unit='watt' prefix='m'/>
862
+ <EnumeratedRootUnit unit='meter' prefix='c' powerNumerator='-2'/>
863
+ </RootUnits>
864
+ </Unit>
865
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='-3' xml:id='NISTp10_-3'>
866
+ <PrefixName xml:lang='en'>milli</PrefixName>
867
+ <PrefixSymbol type='ASCII'>m</PrefixSymbol>
868
+ <PrefixSymbol type='unicode'>m</PrefixSymbol>
869
+ <PrefixSymbol type='LaTeX'>m</PrefixSymbol>
870
+ <PrefixSymbol type='HTML'>m</PrefixSymbol>
871
+ </Prefix>
872
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='-2' xml:id='NISTp10_-2'>
873
+ <PrefixName xml:lang='en'>centi</PrefixName>
874
+ <PrefixSymbol type='ASCII'>c</PrefixSymbol>
875
+ <PrefixSymbol type='unicode'>c</PrefixSymbol>
876
+ <PrefixSymbol type='LaTeX'>c</PrefixSymbol>
877
+ <PrefixSymbol type='HTML'>c</PrefixSymbol>
878
+ </Prefix>
879
+ </math>
880
+ OUTPUT
881
+ end
882
+
698
883
  it "deals with quantity input" do
699
884
  expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
700
885
  9 "unitsml(m, quantity: NISTq103)"
@@ -803,5 +988,96 @@ INPUT
803
988
  OUTPUT
804
989
  end
805
990
 
991
+ it "deals with symbol input" do
992
+ expect(xmlpp(Asciimath2UnitsML::Conv.new().Asciimath2UnitsML(<<~INPUT))).to be_equivalent_to xmlpp(<<~OUTPUT)
993
+ 9 "unitsml(m, symbol: La)" + 10 "unitsml(cm*s^-2, symbol: cm cdot s^-2)"
994
+ INPUT
995
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
996
+ <mn>9</mn>
997
+ <mo rspace='thickmathspace'>&#x2062;</mo>
998
+ <mrow xref='U_NISTu1'>
999
+ <math>
1000
+ <mi mathvariant='normal'>L</mi>
1001
+ <mi mathvariant='normal'>a</mi>
1002
+ </math>
1003
+ </mrow>
1004
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_NISTu1' dimensionURL='#NISTd1'>
1005
+ <UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
1006
+ <UnitName xml:lang='en'>meter</UnitName>
1007
+ <UnitSymbol type='HTML'>m</UnitSymbol>
1008
+ <UnitSymbol type='MathML'>
1009
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
1010
+ <mrow>
1011
+ <mi mathvariant='normal'>m</mi>
1012
+ </mrow>
1013
+ </math>
1014
+ </UnitSymbol>
1015
+ </Unit>
1016
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='NISTd1'>
1017
+ <Length symbol='L' powerNumerator='1'/>
1018
+ </Dimension>
1019
+ <mo>+</mo>
1020
+ <mn>10</mn>
1021
+ <mo rspace='thickmathspace'>&#x2062;</mo>
1022
+ <mrow xref='U_cm.s-2'>
1023
+ <math>
1024
+ <mi mathvariant='normal'>c</mi>
1025
+ <mi mathvariant='normal'>m</mi>
1026
+ <mo>&#x22C5;</mo>
1027
+ <msup>
1028
+ <mrow>
1029
+ <mi mathvariant='normal'>s</mi>
1030
+ </mrow>
1031
+ <mrow>
1032
+ <mo>&#x2212;</mo>
1033
+ </mrow>
1034
+ </msup>
1035
+ <mn>2</mn>
1036
+ </math>
1037
+ </mrow>
1038
+ <Unit xmlns='http://unitsml.nist.gov/2005' xml:id='U_cm.s-2' dimensionURL='#NISTd28'>
1039
+ <UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
1040
+ <UnitName xml:lang='en'>cm*s^-2</UnitName>
1041
+ <UnitSymbol type='HTML'>
1042
+ cm&#xB7;s
1043
+ <sup>&#x2212;2</sup>
1044
+ </UnitSymbol>
1045
+ <UnitSymbol type='MathML'>
1046
+ <math xmlns='http://www.w3.org/1998/Math/MathML'>
1047
+ <mrow>
1048
+ <mi mathvariant='normal'>cm</mi>
1049
+ <mo>&#xB7;</mo>
1050
+ <msup>
1051
+ <mrow>
1052
+ <mi mathvariant='normal'>s</mi>
1053
+ </mrow>
1054
+ <mrow>
1055
+ <mo>&#x2212;</mo>
1056
+ <mn>2</mn>
1057
+ </mrow>
1058
+ </msup>
1059
+ </mrow>
1060
+ </math>
1061
+ </UnitSymbol>
1062
+ <RootUnits>
1063
+ <EnumeratedRootUnit unit='meter' prefix='c'/>
1064
+ <EnumeratedRootUnit unit='second' powerNumerator='-2'/>
1065
+ </RootUnits>
1066
+ </Unit>
1067
+ <Prefix xmlns='http://unitsml.nist.gov/2005' prefixBase='10' prefixPower='-2' xml:id='NISTp10_-2'>
1068
+ <PrefixName xml:lang='en'>centi</PrefixName>
1069
+ <PrefixSymbol type='ASCII'>c</PrefixSymbol>
1070
+ <PrefixSymbol type='unicode'>c</PrefixSymbol>
1071
+ <PrefixSymbol type='LaTeX'>c</PrefixSymbol>
1072
+ <PrefixSymbol type='HTML'>c</PrefixSymbol>
1073
+ </Prefix>
1074
+ <Dimension xmlns='http://unitsml.nist.gov/2005' xml:id='NISTd28'>
1075
+ <Length symbol='L' powerNumerator='1'/>
1076
+ <Time symbol='T' powerNumerator='-2'/>
1077
+ </Dimension>
1078
+ </math>
1079
+ OUTPUT
1080
+ end
1081
+
806
1082
 
807
1083
  end
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.2.0
4
+ version: 0.2.1
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-03-04 00:00:00.000000000 Z
11
+ date: 2021-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciimath