asciimath2unitsml 0.2.0 → 0.2.1

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