asciimath2unitsml 0.3.1 → 0.3.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 +4 -4
- data/lib/asciimath2unitsml/conv.rb +59 -47
- data/lib/asciimath2unitsml/parse.rb +44 -73
- data/lib/asciimath2unitsml/validate.rb +57 -0
- data/lib/asciimath2unitsml/version.rb +1 -1
- data/spec/conv_spec.rb +29 -29
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f51b82e234fddaf66252f77a276a3acf68dae4356502a3c900253f5d4d4dffcf
|
4
|
+
data.tar.gz: 59dd18f009952329c1c07af2132ec06123c06dd3caea4ee7f22f17c0f4ec1cbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a925e3db85d3086d676c07c101609e87674d620394f5fa0a536ab3652f3aa9c0cc6a74507d79264e0154bf51ea4121d47b7275a94212bc934b822b0392a9970
|
7
|
+
data.tar.gz: 59d98ebd629a20e8f03dc32a1870474e5808b9d38f51a87feec5eae9f0746535bed9dcf38b1faf3939319bb3989b1d926088e8d834388e48f045070e3749312a
|
@@ -7,6 +7,7 @@ require_relative "string"
|
|
7
7
|
require_relative "parse"
|
8
8
|
require_relative "render"
|
9
9
|
require_relative "unit"
|
10
|
+
require_relative "validate"
|
10
11
|
|
11
12
|
module Asciimath2UnitsML
|
12
13
|
MATHML_NS = "http://www.w3.org/1998/Math/MathML".freeze
|
@@ -14,56 +15,57 @@ module Asciimath2UnitsML
|
|
14
15
|
|
15
16
|
class Conv
|
16
17
|
def initialize(options = {})
|
17
|
-
@dimensions_id = read_yaml("../unitsdb/dimensions.yaml")
|
18
|
-
each_with_object({}) do |(k, v), m|
|
18
|
+
@dimensions_id = read_yaml("../unitsdb/dimensions.yaml")
|
19
|
+
.each_with_object({}) do |(k, v), m|
|
19
20
|
m[k.to_s] = UnitsDB::Dimension.new(k, v)
|
20
21
|
end
|
21
|
-
@prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
|
22
|
-
each_with_object({}) do |(k, v), m|
|
22
|
+
@prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
|
23
|
+
.each_with_object({}) do |(k, v), m|
|
23
24
|
m[k] = UnitsDB::Prefix.new(k, v)
|
24
25
|
end
|
25
26
|
@prefixes = flip_name_and_symbol(@prefixes_id)
|
26
|
-
@quantities = read_yaml("../unitsdb/quantities.yaml")
|
27
|
-
each_with_object({}) do |(k, v), m|
|
27
|
+
@quantities = read_yaml("../unitsdb/quantities.yaml")
|
28
|
+
.each_with_object({}) do |(k, v), m|
|
28
29
|
m[k.to_s] = UnitsDB::Quantity.new(k, v)
|
29
30
|
end
|
30
|
-
@units_id = read_yaml("../unitsdb/units.yaml")
|
31
|
-
each_with_object({}) do |(k, v), m|
|
31
|
+
@units_id = read_yaml("../unitsdb/units.yaml")
|
32
|
+
.each_with_object({}) do |(k, v), m|
|
32
33
|
m[k.to_s] = UnitsDB::Unit.new(k.to_s, v)
|
33
34
|
end
|
34
35
|
@units = flip_name_and_symbols(@units_id)
|
35
|
-
@symbols = @units.each_with_object({}) do |(
|
36
|
+
@symbols = @units.each_with_object({}) do |(_k, v), m|
|
36
37
|
v.symbolids.each { |x| m[x] = v.symbols_hash[x] }
|
37
38
|
end
|
38
39
|
@parser = parser
|
39
|
-
@multiplier = multiplier(options[:multiplier] || "\
|
40
|
+
@multiplier = multiplier(options[:multiplier] || "\u22c5")
|
40
41
|
end
|
41
42
|
|
42
|
-
def float_to_display(
|
43
|
-
|
43
|
+
def float_to_display(float)
|
44
|
+
float.to_f.round(1).to_s.sub(/\.0$/, "")
|
44
45
|
end
|
45
46
|
|
46
47
|
def prefix(units)
|
47
|
-
units.map { |u| u[:prefix] }.reject
|
48
|
+
units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p|
|
48
49
|
<<~END
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
<Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
|
51
|
+
prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
|
52
|
+
<PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
|
53
|
+
<PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol>
|
54
|
+
<PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol>
|
55
|
+
<PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
|
56
|
+
<PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
|
57
|
+
</Prefix>
|
57
58
|
END
|
58
59
|
end.join("\n")
|
59
60
|
end
|
60
61
|
|
61
62
|
def dimension_components(dims)
|
62
63
|
return if dims.nil? || dims.empty?
|
64
|
+
|
63
65
|
<<~END
|
64
|
-
|
65
|
-
|
66
|
-
|
66
|
+
<Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
|
67
|
+
#{dims.map { |u| dimension1(u) }.join("\n")}
|
68
|
+
</Dimension>
|
67
69
|
END
|
68
70
|
end
|
69
71
|
|
@@ -87,27 +89,29 @@ module Asciimath2UnitsML
|
|
87
89
|
return if norm.any? do |u|
|
88
90
|
u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
|
89
91
|
end
|
92
|
+
|
90
93
|
norm.map do |u|
|
91
94
|
{ dimension: U2D[u[:unit]][:dimension],
|
92
95
|
unit: u[:unit],
|
93
96
|
exponent: u[:exponent] || 1,
|
94
|
-
symbol: U2D[u[:unit]][:symbol] }
|
97
|
+
symbol: U2D[u[:unit]][:symbol] }
|
95
98
|
end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
|
96
99
|
end
|
97
100
|
|
98
101
|
def dimension1(u)
|
99
|
-
%(<#{u[:dimension]} symbol="#{u[:symbol]}"
|
102
|
+
%(<#{u[:dimension]} symbol="#{u[:symbol]}"
|
100
103
|
powerNumerator="#{float_to_display(u[:exponent])}"/>)
|
101
104
|
end
|
102
105
|
|
103
106
|
def dim_id(dims)
|
104
107
|
return nil if dims.nil? || dims.empty?
|
108
|
+
|
105
109
|
dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
|
106
|
-
dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
|
110
|
+
dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
|
107
111
|
AmountOfSubstance LuminousIntensity PlaneAngle)
|
108
112
|
.map { |h| dimhash.dig(h, :exponent) }.join(":")
|
109
|
-
id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
|
110
|
-
first&.id and return id.to_s
|
113
|
+
id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
|
114
|
+
&.first&.id and return id.to_s
|
111
115
|
"D_" + dims.map do |d|
|
112
116
|
U2D[d[:unit]][:symbol] +
|
113
117
|
(d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
|
@@ -119,15 +123,17 @@ module Asciimath2UnitsML
|
|
119
123
|
end
|
120
124
|
|
121
125
|
def gather_units(units)
|
122
|
-
units.
|
126
|
+
units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m|
|
123
127
|
if m.empty? || m[-1][:unit] != k[:unit] then m << k
|
124
128
|
else
|
125
129
|
m[-1] = {
|
126
130
|
prefix: combine_prefixes(
|
127
|
-
@prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]
|
131
|
+
@prefixes[m[-1][:prefix]], @prefixes[k[:prefix]]
|
132
|
+
),
|
128
133
|
unit: m[-1][:unit],
|
129
134
|
exponent: (k[:exponent]&.to_f || 1) +
|
130
|
-
|
135
|
+
(m[-1][:exponent]&.to_f || 1),
|
136
|
+
}
|
131
137
|
end
|
132
138
|
end
|
133
139
|
end
|
@@ -142,9 +148,12 @@ module Asciimath2UnitsML
|
|
142
148
|
{ prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
|
143
149
|
else
|
144
150
|
@units[u[:unit]].si_derived_bases.each_with_object([]) do |k, m|
|
145
|
-
prefix = !k[:prefix].nil? && !k[:prefix].empty?
|
146
|
-
|
147
|
-
|
151
|
+
prefix = if !k[:prefix].nil? && !k[:prefix].empty?
|
152
|
+
combine_prefixes(@prefixes_id[k[:prefix]],
|
153
|
+
@prefixes[u[:prefix]])
|
154
|
+
else
|
155
|
+
u[:prefix]
|
156
|
+
end
|
148
157
|
m << { prefix: prefix,
|
149
158
|
unit: @units_id[k[:id]].symbolid,
|
150
159
|
exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_f || 1) }
|
@@ -157,6 +166,7 @@ module Asciimath2UnitsML
|
|
157
166
|
return p1.symbolid if p2.nil?
|
158
167
|
return p2.symbolid if p1.nil?
|
159
168
|
return "unknown" if p1.base != p2.base
|
169
|
+
|
160
170
|
@prefixes.each do |_, p|
|
161
171
|
return p.symbolid if p.base == p1.base && p.power == p1.power + p2.power
|
162
172
|
end
|
@@ -174,13 +184,14 @@ module Asciimath2UnitsML
|
|
174
184
|
def quantity(normtext, quantity)
|
175
185
|
return unless @units[normtext] && @units[normtext].quantities.size == 1 ||
|
176
186
|
@quantities[quantity]
|
187
|
+
|
177
188
|
id = quantity || @units[normtext].quantities.first
|
178
189
|
@units[normtext]&.dimension and
|
179
190
|
dim = %( dimensionURL="##{@units[normtext].dimension}")
|
180
191
|
<<~END
|
181
|
-
|
182
|
-
|
183
|
-
|
192
|
+
<Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
|
193
|
+
#{quantityname(id)}
|
194
|
+
</Quantity>
|
184
195
|
END
|
185
196
|
end
|
186
197
|
|
@@ -193,23 +204,24 @@ module Asciimath2UnitsML
|
|
193
204
|
end
|
194
205
|
|
195
206
|
def dimension(normtext)
|
196
|
-
return unless @units[normtext]&.dimension
|
207
|
+
return unless @units[normtext]&.dimension
|
208
|
+
|
197
209
|
dims = dimid2dimensions(@units[normtext]&.dimension)
|
198
210
|
<<~END
|
199
|
-
|
200
|
-
|
201
|
-
|
211
|
+
<Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
|
212
|
+
#{dims.map { |u| dimension1(u) }.join("\n")}
|
213
|
+
</Dimension>
|
202
214
|
END
|
203
215
|
end
|
204
216
|
|
205
217
|
def unitsml(units, origtext, normtext, quantity, name)
|
206
218
|
dims = units2dimensions(units)
|
207
219
|
<<~END
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
220
|
+
#{unit(units, origtext, normtext, dims, name)}
|
221
|
+
#{prefix(units)}
|
222
|
+
#{dimension(normtext)}
|
223
|
+
#{dimension_components(dims)}
|
224
|
+
#{quantity(normtext, quantity)}
|
213
225
|
END
|
214
226
|
end
|
215
227
|
end
|
@@ -3,71 +3,29 @@ module Asciimath2UnitsML
|
|
3
3
|
include Rsec::Helpers
|
4
4
|
|
5
5
|
def read_yaml(path)
|
6
|
-
validate_yaml(symbolize_keys(YAML
|
6
|
+
validate_yaml(symbolize_keys(YAML
|
7
|
+
.load_file(File.join(File.join(File.dirname(__FILE__), path)))), path)
|
7
8
|
end
|
8
9
|
|
9
10
|
def flip_name_and_symbol(hash)
|
10
|
-
hash.each_with_object({}) do |(
|
11
|
+
hash.each_with_object({}) do |(_k, v), m|
|
11
12
|
next if v.name.nil? || v.name.empty?
|
13
|
+
|
12
14
|
m[v.symbolid] = v
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
18
|
def flip_name_and_symbols(hash)
|
17
|
-
hash.each_with_object({}) do |(
|
19
|
+
hash.each_with_object({}) do |(_k, v), m|
|
18
20
|
next if v.name.nil? || v.name.empty?
|
19
|
-
v.symbolids.each { |s| m[s] = v }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def validate_yaml(hash, path)
|
24
|
-
return hash if path == "../unitsdb/quantities.yaml"
|
25
|
-
return hash if path == "../unitsdb/dimensions.yaml"
|
26
|
-
hash.each_with_object({}) do |(k, v), m|
|
27
|
-
path == "../unitsdb/units.yaml" and validate_unit(v)
|
28
|
-
m = validate_symbols(m, v)
|
29
|
-
v[:unit_symbols]&.each { |s| validate_unit_symbol_cardinality(s, k) }
|
30
|
-
end
|
31
|
-
hash
|
32
|
-
end
|
33
|
-
|
34
|
-
def validate_unit(v)
|
35
|
-
if v[:quantity_reference]
|
36
|
-
v[:quantity_reference].is_a?(Array) or
|
37
|
-
raise StandardError.new "No quantity_reference array provided for unit: #{v}"
|
38
|
-
end
|
39
|
-
if v[:unit_name]
|
40
|
-
v[:unit_name].is_a?(Array) or raise StandardError.new "No unit_name array provided for unit: #{v}"
|
41
|
-
end
|
42
|
-
end
|
43
21
|
|
44
|
-
|
45
|
-
symbol = symbol_key(v)
|
46
|
-
!symbol.nil? or raise StandardError.new "No symbol provided for unit: #{v}"
|
47
|
-
Array(symbol)&.each do |s|
|
48
|
-
m[s] && s != "1" and
|
49
|
-
raise StandardError.new "symbol #{s} is not unique in #{v}: already used for #{m[s]}"
|
50
|
-
m[s] = v
|
22
|
+
v.symbolids.each { |s| m[s] = v }
|
51
23
|
end
|
52
|
-
m
|
53
|
-
end
|
54
|
-
|
55
|
-
def validate_unit_symbol_cardinality(us, k)
|
56
|
-
return true if us.nil?
|
57
|
-
!us[:id].nil? && !us[:ascii].nil? && !us[:html].nil? && !us[:mathml].nil? && !us[:latex].nil? &&
|
58
|
-
!us[:unicode].nil? and return true
|
59
|
-
raise StandardError.new "malformed unit_symbol for #{k}: #{us}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def symbol_key(v)
|
63
|
-
symbol = v[:unit_symbols]&.each_with_object([]) { |s, m| m << (s["id"] || s[:id]) } ||
|
64
|
-
v.dig(:symbol, :ascii) || v[:symbol] #|| v[:short]
|
65
|
-
symbol = [symbol] if !symbol.nil? && v[:unit_symbols] && !symbol.is_a?(Array)
|
66
|
-
symbol
|
67
24
|
end
|
68
25
|
|
69
26
|
def symbolize_keys(hash)
|
70
27
|
return hash if hash.is_a? String
|
28
|
+
|
71
29
|
hash.inject({}) do |result, (key, value)|
|
72
30
|
new_key = case key
|
73
31
|
when String then key.to_sym
|
@@ -97,10 +55,10 @@ module Asciimath2UnitsML
|
|
97
55
|
seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } |
|
98
56
|
seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
|
99
57
|
seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
|
100
|
-
seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]
|
101
|
-
seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]
|
102
|
-
seq(prefix1, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]
|
103
|
-
seq(prefix2, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]
|
58
|
+
seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
|
59
|
+
seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
|
60
|
+
seq(prefix1, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
|
61
|
+
seq(prefix2, unit1, exponent._? ) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
|
104
62
|
"1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
|
105
63
|
units1 = "(".r >> lazy{units} << ")" | unit
|
106
64
|
units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
|
@@ -115,6 +73,7 @@ module Asciimath2UnitsML
|
|
115
73
|
if !units || Rsec::INVALID[units]
|
116
74
|
raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
|
117
75
|
end
|
76
|
+
|
118
77
|
Rsec::Fail.reset
|
119
78
|
postprocess(units, text)
|
120
79
|
end
|
@@ -134,11 +93,12 @@ module Asciimath2UnitsML
|
|
134
93
|
|
135
94
|
def postprocess1(units)
|
136
95
|
inverse = false
|
137
|
-
units.each_with_object([]) do |u, m|
|
96
|
+
units.each_with_object([]) do |u, m|
|
138
97
|
if u[:multiplier]
|
139
|
-
inverse = !inverse if
|
98
|
+
inverse = !inverse if u[:multiplier] == "/"
|
140
99
|
else
|
141
|
-
u[:exponent] =
|
100
|
+
u[:exponent] =
|
101
|
+
inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent]
|
142
102
|
u[:exponent] = u[:exponent]&.sub(/^--+/, "")
|
143
103
|
end
|
144
104
|
m << u
|
@@ -155,11 +115,13 @@ module Asciimath2UnitsML
|
|
155
115
|
xml.is_a? String and xml = Nokogiri::XML(xml)
|
156
116
|
xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x|
|
157
117
|
next unless %r{^unitsml\(.+\)$}.match(x.text)
|
118
|
+
|
158
119
|
text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
|
159
120
|
units, origtext, normtext, quantity, name, symbol, multiplier = parse(text)
|
160
121
|
rendering = symbol ? embeddedmathml(asciimath2mathml(symbol)) :
|
161
122
|
mathmlsymbol(units, false, multiplier)
|
162
|
-
x.replace("#{delimspace(rendering, x)}
|
123
|
+
x.replace("#{delimspace(rendering, x)}"\
|
124
|
+
"<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
|
163
125
|
"#{unitsml(units, origtext, normtext, quantity, name)}")
|
164
126
|
end
|
165
127
|
dedup_ids(xml)
|
@@ -167,19 +129,25 @@ module Asciimath2UnitsML
|
|
167
129
|
|
168
130
|
# if previous sibling's last descendent non-whitespace is MathML and mn or mi, no space
|
169
131
|
def delimspace(rendering, elem)
|
170
|
-
prec_text_elem =
|
171
|
-
|
172
|
-
|
173
|
-
|
132
|
+
prec_text_elem =
|
133
|
+
elem.xpath("./preceding-sibling::*[namespace-uri() = '#{MATHML_NS}']/"\
|
134
|
+
"descendant::text()[normalize-space()!=''][last()]/parent::*").last
|
135
|
+
return "" if prec_text_elem.nil? ||
|
136
|
+
!%w(mn mi).include?(prec_text_elem&.name)
|
137
|
+
|
138
|
+
text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>")
|
139
|
+
.text.strip)
|
174
140
|
/\p{L}|\p{N}/.match(text) ?
|
175
141
|
"<mo rspace='thickmathspace'>⁢</mo>" : "<mo>⁢</mo>"
|
176
142
|
end
|
177
143
|
|
178
144
|
def dedup_ids(xml)
|
179
145
|
%w(Unit Dimension Prefix Quantity).each do |t|
|
180
|
-
xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map
|
146
|
+
xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map(&:text)
|
147
|
+
.uniq.each do |v|
|
181
148
|
xml.xpath(".//*[@xml:id = '#{v}']").each_with_index do |n, i|
|
182
|
-
next if i
|
149
|
+
next if i.zero?
|
150
|
+
|
183
151
|
n.remove
|
184
152
|
end
|
185
153
|
end
|
@@ -189,26 +157,28 @@ module Asciimath2UnitsML
|
|
189
157
|
|
190
158
|
def asciimath2mathml(expression)
|
191
159
|
AsciiMath::MathMLBuilder.new(:msword => true).append_expression(
|
192
|
-
AsciiMath.parse(HTMLEntities.new.decode(expression)).ast).to_s
|
193
|
-
|
160
|
+
AsciiMath.parse(HTMLEntities.new.decode(expression)).ast).to_s
|
161
|
+
.gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
|
194
162
|
end
|
195
163
|
|
196
164
|
def embeddedmathml(mathml)
|
197
165
|
x = Nokogiri::XML(mathml)
|
198
|
-
x.xpath(".//m:mi", "m" => MATHML_NS)
|
166
|
+
x.xpath(".//m:mi", "m" => MATHML_NS)
|
167
|
+
.each { |mi| mi["mathvariant"] = "normal" }
|
199
168
|
x.children.to_xml
|
200
169
|
end
|
201
170
|
|
202
171
|
def ambig_units
|
203
|
-
u = @units_id.each_with_object({}) do |(
|
172
|
+
u = @units_id.each_with_object({}) do |(_k, v), m|
|
204
173
|
v.symbolids.each do |x|
|
205
174
|
next if %r{[*/^]}.match(x)
|
206
175
|
next unless v.symbols_hash[x][:html] != x
|
176
|
+
|
207
177
|
m[v.symbols_hash[x][:html]] ||= []
|
208
178
|
m[v.symbols_hash[x][:html]] << x
|
209
179
|
end
|
210
180
|
end
|
211
|
-
u.
|
181
|
+
u.each_key { |k| u[k] = u[k].unshift(k) if @symbols.dig(k, :html) == k }
|
212
182
|
render_ambig_units(u)
|
213
183
|
end
|
214
184
|
|
@@ -217,16 +187,17 @@ module Asciimath2UnitsML
|
|
217
187
|
u.each { |_, v| maxcols = v.size if maxcols < v.size }
|
218
188
|
puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{"| " * (maxcols - 1)}\n)
|
219
189
|
puts "\n\n"
|
220
|
-
u.keys.sort_by { |a| [-u[a].size, a.gsub(%r{\&[^;]+;}, "")
|
190
|
+
u.keys.sort_by { |a| [-u[a].size, a.gsub(%r{\&[^;]+;}, "")
|
191
|
+
.gsub(/[^A-Za-z]/, "").downcase] }.each do |k|
|
221
192
|
print "| #{html2adoc(k)} "
|
222
|
-
u[k].sort_by
|
223
|
-
puts "#{
|
193
|
+
u[k].sort_by(&:size).each { |v1| print "| #{@units[v1].name}: `#{v1}` " }
|
194
|
+
puts "#{'| ' * (maxcols - u[k].size) }\n"
|
224
195
|
end
|
225
196
|
puts "|===\n"
|
226
197
|
end
|
227
198
|
|
228
|
-
def html2adoc(
|
229
|
-
|
199
|
+
def html2adoc(elem)
|
200
|
+
elem.gsub(%r{<i>}, "__").gsub(%r{</i>}, "__")
|
230
201
|
.gsub(%r{<sup>}, "^").gsub(%r{</sup>}, "^")
|
231
202
|
.gsub(%r{<sub>}, "~").gsub(%r{</sub>}, "~")
|
232
203
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Asciimath2UnitsML
|
2
|
+
class Conv
|
3
|
+
def validate_yaml(hash, path)
|
4
|
+
return hash if path == "../unitsdb/quantities.yaml"
|
5
|
+
return hash if path == "../unitsdb/dimensions.yaml"
|
6
|
+
|
7
|
+
hash.each_with_object({}) do |(k, v), m|
|
8
|
+
path == "../unitsdb/units.yaml" and validate_unit(v)
|
9
|
+
m = validate_symbols(m, v)
|
10
|
+
v[:unit_symbols]&.each { |s| validate_unit_symbol_cardinality(s, k) }
|
11
|
+
end
|
12
|
+
hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate_unit(v)
|
16
|
+
if v[:quantity_reference]
|
17
|
+
v[:quantity_reference].is_a?(Array) or
|
18
|
+
raise StandardError.new "No quantity_reference array provided for unit: #{v}"
|
19
|
+
end
|
20
|
+
if v[:unit_name]
|
21
|
+
v[:unit_name].is_a?(Array) or
|
22
|
+
raise StandardError.new "No unit_name array provided for unit: #{v}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_symbols(m, v)
|
27
|
+
symbol = symbol_key(v)
|
28
|
+
!symbol.nil? or
|
29
|
+
raise StandardError.new "No symbol provided for unit: #{v}"
|
30
|
+
Array(symbol)&.each do |s|
|
31
|
+
m[s] && s != "1" and
|
32
|
+
raise StandardError.new "symbol #{s} is not unique in #{v}: "\
|
33
|
+
"already used for #{m[s]}"
|
34
|
+
m[s] = v
|
35
|
+
end
|
36
|
+
m
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_unit_symbol_cardinality(us, k)
|
40
|
+
return true if us.nil?
|
41
|
+
|
42
|
+
!us[:id].nil? && !us[:ascii].nil? && !us[:html].nil? &&
|
43
|
+
!us[:mathml].nil? && !us[:latex].nil? &&
|
44
|
+
!us[:unicode].nil? and return true
|
45
|
+
raise StandardError.new "malformed unit_symbol for #{k}: #{us}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def symbol_key(v)
|
49
|
+
symbol = v[:unit_symbols]&.each_with_object([]) do |s, m|
|
50
|
+
m << (s["id"] || s[:id])
|
51
|
+
end || v.dig(:symbol, :ascii) || v[:symbol] #|| v[:short]
|
52
|
+
!symbol.nil? && v[:unit_symbols] && !symbol.is_a?(Array) and
|
53
|
+
symbol = [symbol]
|
54
|
+
symbol
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/spec/conv_spec.rb
CHANGED
@@ -11,7 +11,7 @@ RSpec.describe Asciimath2UnitsML do
|
|
11
11
|
<mo rspace='thickmathspace'>⁢</mo>
|
12
12
|
<mrow xref='U_mm.s-2'>
|
13
13
|
<mi mathvariant='normal'>mm</mi>
|
14
|
-
<mo>&#
|
14
|
+
<mo>⋅</mo>
|
15
15
|
<msup>
|
16
16
|
<mrow>
|
17
17
|
<mi mathvariant='normal'>s</mi>
|
@@ -26,14 +26,14 @@ RSpec.describe Asciimath2UnitsML do
|
|
26
26
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
27
27
|
<UnitName xml:lang='en'>mm*s^-2</UnitName>
|
28
28
|
<UnitSymbol type='HTML'>
|
29
|
-
mm&#
|
29
|
+
mm⋅s
|
30
30
|
<sup>−2</sup>
|
31
31
|
</UnitSymbol>
|
32
32
|
<UnitSymbol type='MathML'>
|
33
33
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
34
34
|
<mrow>
|
35
35
|
<mi mathvariant='normal'>mm</mi>
|
36
|
-
<mo>&#
|
36
|
+
<mo>⋅</mo>
|
37
37
|
<msup>
|
38
38
|
<mrow>
|
39
39
|
<mi mathvariant='normal'>s</mi>
|
@@ -418,7 +418,7 @@ OUTPUT
|
|
418
418
|
<mo rspace='thickmathspace'>⁢</mo>
|
419
419
|
<mrow xref='U_kg.s-2'>
|
420
420
|
<mi mathvariant='normal'>kg</mi>
|
421
|
-
<mo>&#
|
421
|
+
<mo>⋅</mo>
|
422
422
|
<msup>
|
423
423
|
<mrow>
|
424
424
|
<mi mathvariant='normal'>s</mi>
|
@@ -433,14 +433,14 @@ OUTPUT
|
|
433
433
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
434
434
|
<UnitName xml:lang='en'>kg*s^-2</UnitName>
|
435
435
|
<UnitSymbol type='HTML'>
|
436
|
-
kg&#
|
436
|
+
kg⋅s
|
437
437
|
<sup>−2</sup>
|
438
438
|
</UnitSymbol>
|
439
439
|
<UnitSymbol type='MathML'>
|
440
440
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
441
441
|
<mrow>
|
442
442
|
<mi mathvariant='normal'>kg</mi>
|
443
|
-
<mo>&#
|
443
|
+
<mo>⋅</mo>
|
444
444
|
<msup>
|
445
445
|
<mrow>
|
446
446
|
<mi mathvariant='normal'>s</mi>
|
@@ -474,7 +474,7 @@ OUTPUT
|
|
474
474
|
<mo rspace='thickmathspace'>⁢</mo>
|
475
475
|
<mrow xref='U_kg.s-2'>
|
476
476
|
<mi mathvariant='normal'>kg</mi>
|
477
|
-
<mo>&#
|
477
|
+
<mo>⋅</mo>
|
478
478
|
<msup>
|
479
479
|
<mrow>
|
480
480
|
<mi mathvariant='normal'>s</mi>
|
@@ -500,23 +500,23 @@ OUTPUT
|
|
500
500
|
<mi mathvariant='normal'>K</mi>
|
501
501
|
<mo>/</mo>
|
502
502
|
<mi mathvariant='normal'>kg</mi>
|
503
|
-
<mo>&#
|
503
|
+
<mo>⋅</mo>
|
504
504
|
<mi mathvariant='normal'>m</mi>
|
505
505
|
</mrow>
|
506
506
|
<Unit xmlns='https://schema.unitsml.org/unitsml/1.0' xml:id='U_K.kg-1.m-1' dimensionURL='#D_L-1M-1Theta'>
|
507
507
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
508
508
|
<UnitName xml:lang='en'>K*kg^-1*m^-1</UnitName>
|
509
509
|
<UnitSymbol type='HTML'>
|
510
|
-
K&#
|
510
|
+
K⋅kg
|
511
511
|
<sup>−1</sup>
|
512
|
-
&#
|
512
|
+
⋅m
|
513
513
|
<sup>−1</sup>
|
514
514
|
</UnitSymbol>
|
515
515
|
<UnitSymbol type='MathML'>
|
516
516
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
517
517
|
<mrow>
|
518
518
|
<mi mathvariant='normal'>K</mi>
|
519
|
-
<mo>&#
|
519
|
+
<mo>⋅</mo>
|
520
520
|
<msup>
|
521
521
|
<mrow>
|
522
522
|
<mi mathvariant='normal'>kg</mi>
|
@@ -526,7 +526,7 @@ OUTPUT
|
|
526
526
|
<mn>1</mn>
|
527
527
|
</mrow>
|
528
528
|
</msup>
|
529
|
-
<mo>&#
|
529
|
+
<mo>⋅</mo>
|
530
530
|
<msup>
|
531
531
|
<mrow>
|
532
532
|
<mi mathvariant='normal'>m</mi>
|
@@ -726,7 +726,7 @@ INPUT
|
|
726
726
|
<mo rspace='thickmathspace'>⁢</mo>
|
727
727
|
<mrow xref='U_A.C3'>
|
728
728
|
<mi mathvariant='normal'>A</mi>
|
729
|
-
<mo>&#
|
729
|
+
<mo>⋅</mo>
|
730
730
|
<msup>
|
731
731
|
<mrow>
|
732
732
|
<mi mathvariant='normal'>C</mi>
|
@@ -740,14 +740,14 @@ INPUT
|
|
740
740
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
741
741
|
<UnitName xml:lang='en'>A*C^3</UnitName>
|
742
742
|
<UnitSymbol type='HTML'>
|
743
|
-
A&#
|
743
|
+
A⋅C
|
744
744
|
<sup>3</sup>
|
745
745
|
</UnitSymbol>
|
746
746
|
<UnitSymbol type='MathML'>
|
747
747
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
748
748
|
<mrow>
|
749
749
|
<mi mathvariant='normal'>A</mi>
|
750
|
-
<mo>&#
|
750
|
+
<mo>⋅</mo>
|
751
751
|
<msup>
|
752
752
|
<mrow>
|
753
753
|
<mi mathvariant='normal'>C</mi>
|
@@ -791,23 +791,23 @@ INPUT
|
|
791
791
|
<mi mathvariant='normal'>J</mi>
|
792
792
|
<mo>/</mo>
|
793
793
|
<mi mathvariant='normal'>kg</mi>
|
794
|
-
<mo>&#
|
794
|
+
<mo>⋅</mo>
|
795
795
|
<mi mathvariant='normal'>K</mi>
|
796
796
|
</mrow>
|
797
797
|
<Unit xmlns='https://schema.unitsml.org/unitsml/1.0' xml:id='U_NISTu13.u27p10_3e-1/1.u5e-1/1' dimensionURL='#D_L2M0T-2Theta-1'>
|
798
798
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
799
799
|
<UnitName xml:lang='en'>joule per kilogram kelvin</UnitName>
|
800
800
|
<UnitSymbol type='HTML'>
|
801
|
-
J&#
|
801
|
+
J⋅kg
|
802
802
|
<sup>−1</sup>
|
803
|
-
&#
|
803
|
+
⋅K
|
804
804
|
<sup>−1</sup>
|
805
805
|
</UnitSymbol>
|
806
806
|
<UnitSymbol type='MathML'>
|
807
807
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
808
808
|
<mrow>
|
809
809
|
<mi mathvariant='normal'>J</mi>
|
810
|
-
<mo>&#
|
810
|
+
<mo>⋅</mo>
|
811
811
|
<msup>
|
812
812
|
<mrow>
|
813
813
|
<mi mathvariant='normal'>kg</mi>
|
@@ -817,7 +817,7 @@ INPUT
|
|
817
817
|
<mn>1</mn>
|
818
818
|
</mrow>
|
819
819
|
</msup>
|
820
|
-
<mo>&#
|
820
|
+
<mo>⋅</mo>
|
821
821
|
<msup>
|
822
822
|
<mrow>
|
823
823
|
<mi mathvariant='normal'>K</mi>
|
@@ -1131,7 +1131,7 @@ INPUT
|
|
1131
1131
|
<mo rspace='thickmathspace'>⁢</mo>
|
1132
1132
|
<mrow xref='U_mW.cm-2'>
|
1133
1133
|
<mi mathvariant='normal'>mW</mi>
|
1134
|
-
<mo>&#
|
1134
|
+
<mo>⋅</mo>
|
1135
1135
|
<msup>
|
1136
1136
|
<mrow>
|
1137
1137
|
<mi mathvariant='normal'>cm</mi>
|
@@ -1146,14 +1146,14 @@ INPUT
|
|
1146
1146
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
1147
1147
|
<UnitName xml:lang='en'>mW*cm^-2</UnitName>
|
1148
1148
|
<UnitSymbol type='HTML'>
|
1149
|
-
mW&#
|
1149
|
+
mW⋅cm
|
1150
1150
|
<sup>−2</sup>
|
1151
1151
|
</UnitSymbol>
|
1152
1152
|
<UnitSymbol type='MathML'>
|
1153
1153
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
1154
1154
|
<mrow>
|
1155
1155
|
<mi mathvariant='normal'>mW</mi>
|
1156
|
-
<mo>&#
|
1156
|
+
<mo>⋅</mo>
|
1157
1157
|
<msup>
|
1158
1158
|
<mrow>
|
1159
1159
|
<mi mathvariant='normal'>cm</mi>
|
@@ -1254,7 +1254,7 @@ INPUT
|
|
1254
1254
|
<UnitSymbol type='HTML'>
|
1255
1255
|
cal
|
1256
1256
|
<sub>th</sub>
|
1257
|
-
&#
|
1257
|
+
⋅cm
|
1258
1258
|
<sup>−2</sup>
|
1259
1259
|
</UnitSymbol>
|
1260
1260
|
<UnitSymbol type='MathML'>
|
@@ -1268,7 +1268,7 @@ INPUT
|
|
1268
1268
|
<mi mathvariant='normal'>th</mi>
|
1269
1269
|
</mrow>
|
1270
1270
|
</msub>
|
1271
|
-
<mo>&#
|
1271
|
+
<mo>⋅</mo>
|
1272
1272
|
<msup>
|
1273
1273
|
<mrow>
|
1274
1274
|
<mi mathvariant='normal'>cm</mi>
|
@@ -1348,14 +1348,14 @@ INPUT
|
|
1348
1348
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
1349
1349
|
<UnitName xml:lang='en'>cm*s^-2</UnitName>
|
1350
1350
|
<UnitSymbol type='HTML'>
|
1351
|
-
cm&#
|
1351
|
+
cm⋅s
|
1352
1352
|
<sup>−2</sup>
|
1353
1353
|
</UnitSymbol>
|
1354
1354
|
<UnitSymbol type='MathML'>
|
1355
1355
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
1356
1356
|
<mrow>
|
1357
1357
|
<mi mathvariant='normal'>cm</mi>
|
1358
|
-
<mo>&#
|
1358
|
+
<mo>⋅</mo>
|
1359
1359
|
<msup>
|
1360
1360
|
<mrow>
|
1361
1361
|
<mi mathvariant='normal'>s</mi>
|
@@ -1412,14 +1412,14 @@ INPUT
|
|
1412
1412
|
<UnitSystem name='SI' type='SI_derived' xml:lang='en-US'/>
|
1413
1413
|
<UnitName xml:lang='en'>cm*s^-2</UnitName>
|
1414
1414
|
<UnitSymbol type='HTML'>
|
1415
|
-
cm&#
|
1415
|
+
cm⋅s
|
1416
1416
|
<sup>−2</sup>
|
1417
1417
|
</UnitSymbol>
|
1418
1418
|
<UnitSymbol type='MathML'>
|
1419
1419
|
<math xmlns='http://www.w3.org/1998/Math/MathML'>
|
1420
1420
|
<mrow>
|
1421
1421
|
<mi mathvariant='normal'>cm</mi>
|
1422
|
-
<mo>&#
|
1422
|
+
<mo>⋅</mo>
|
1423
1423
|
<msup>
|
1424
1424
|
<mrow>
|
1425
1425
|
<mi mathvariant='normal'>s</mi>
|
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.3.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2021-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: asciimath
|
@@ -245,6 +245,7 @@ files:
|
|
245
245
|
- lib/asciimath2unitsml/render.rb
|
246
246
|
- lib/asciimath2unitsml/string.rb
|
247
247
|
- lib/asciimath2unitsml/unit.rb
|
248
|
+
- lib/asciimath2unitsml/validate.rb
|
248
249
|
- lib/asciimath2unitsml/version.rb
|
249
250
|
- lib/unitsdb/dimensions.yaml
|
250
251
|
- lib/unitsdb/prefixes.yaml
|