asciimath2unitsml 0.3.0 → 0.4.0
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/.github/workflows/rake.yml +2 -23
- data/.hound.yml +5 -0
- data/.rubocop.yml +4 -8
- data/Gemfile +1 -1
- data/README.adoc +19 -1
- data/Rakefile +1 -1
- data/asciimath2unitsml.gemspec +14 -17
- data/bin/rspec +1 -2
- data/lib/asciimath2unitsml.rb +0 -1
- data/lib/asciimath2unitsml/conv.rb +74 -119
- data/lib/asciimath2unitsml/dimensions.rb +117 -0
- data/lib/asciimath2unitsml/parse.rb +127 -137
- data/lib/asciimath2unitsml/read.rb +42 -0
- data/lib/asciimath2unitsml/render.rb +48 -31
- data/lib/asciimath2unitsml/unit.rb +29 -23
- data/lib/asciimath2unitsml/validate.rb +59 -0
- data/lib/asciimath2unitsml/version.rb +1 -1
- data/lib/unitsdb/dimensions.yaml +65 -8
- data/lib/unitsdb_ruby/unitsdb.rb +87 -55
- data/spec/conv_spec.rb +1447 -1227
- data/spec/spec_helper.rb +10 -10
- metadata +23 -19
@@ -0,0 +1,117 @@
|
|
1
|
+
module Asciimath2UnitsML
|
2
|
+
class Conv
|
3
|
+
def dimension_components(dims)
|
4
|
+
return if dims.nil? || dims.empty?
|
5
|
+
|
6
|
+
<<~XML
|
7
|
+
<Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
|
8
|
+
#{dims.map { |u| dimension1(u) }.join("\n")}
|
9
|
+
</Dimension>
|
10
|
+
XML
|
11
|
+
end
|
12
|
+
|
13
|
+
U2D = {
|
14
|
+
"m" => { dimension: "Length", order: 1, symbol: "L" },
|
15
|
+
"g" => { dimension: "Mass", order: 2, symbol: "M" },
|
16
|
+
"kg" => { dimension: "Mass", order: 2, symbol: "M" },
|
17
|
+
"s" => { dimension: "Time", order: 3, symbol: "T" },
|
18
|
+
"A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
|
19
|
+
"K" => { dimension: "ThermodynamicTemperature", order: 5,
|
20
|
+
symbol: "Theta" },
|
21
|
+
"degK" => { dimension: "ThermodynamicTemperature", order: 5,
|
22
|
+
symbol: "Theta" },
|
23
|
+
"mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
|
24
|
+
"cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
|
25
|
+
"deg" => { dimension: "PlaneAngle", order: 8, symbol: "phi" },
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
Dim2D = {
|
29
|
+
"dim_L" => U2D["m"],
|
30
|
+
"dim_M" => U2D["g"],
|
31
|
+
"dim_T" => U2D["s"],
|
32
|
+
"dim_I" => U2D["A"],
|
33
|
+
"dim_Theta" => U2D["K"],
|
34
|
+
"dim_N" => U2D["mol"],
|
35
|
+
"dim_J" => U2D["cd"],
|
36
|
+
"dim_phi" => U2D["deg"],
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
def units2dimensions(units)
|
40
|
+
norm = decompose_units(units)
|
41
|
+
return units2dimensions_dim_input(norm) if norm[0][:dim]
|
42
|
+
return if norm.any? do |u|
|
43
|
+
u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
norm.map do |u|
|
47
|
+
{ dimension: U2D[u[:unit]][:dimension],
|
48
|
+
unit: u[:unit],
|
49
|
+
exponent: u[:exponent] || 1,
|
50
|
+
symbol: U2D[u[:unit]][:symbol] }
|
51
|
+
end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
|
52
|
+
end
|
53
|
+
|
54
|
+
def units2dimensions_dim_input(norm)
|
55
|
+
norm.map do |u|
|
56
|
+
{ dimension: Dim2D[u[:dim]][:dimension],
|
57
|
+
exponent: u[:exponent] || 1,
|
58
|
+
id: u[:dim],
|
59
|
+
symbol: Dim2D[u[:dim]][:symbol] }
|
60
|
+
end.sort { |a, b| Dim2D[a[:id]][:order] <=> Dim2D[b[:id]][:order] }
|
61
|
+
end
|
62
|
+
|
63
|
+
def dimension1(dim)
|
64
|
+
%(<#{dim[:dimension]} symbol="#{dim[:symbol]}"
|
65
|
+
powerNumerator="#{float_to_display(dim[:exponent])}"/>)
|
66
|
+
end
|
67
|
+
|
68
|
+
def dim_id(dims)
|
69
|
+
return nil if dims.nil? || dims.empty?
|
70
|
+
|
71
|
+
dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
|
72
|
+
dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
|
73
|
+
AmountOfSubstance LuminousIntensity PlaneAngle)
|
74
|
+
.map { |h| dimhash.dig(h, :exponent) }.join(":")
|
75
|
+
id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
|
76
|
+
&.first&.id and return id.to_s
|
77
|
+
"D_" + dims.map do |d|
|
78
|
+
(U2D.dig(d[:unit], :symbol) || Dim2D.dig(d[:id], :symbol)) +
|
79
|
+
(d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
|
80
|
+
end.join("")
|
81
|
+
end
|
82
|
+
|
83
|
+
def decompose_units(units)
|
84
|
+
gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
|
85
|
+
end
|
86
|
+
|
87
|
+
def dimid2dimensions(normtext)
|
88
|
+
@dimensions_id[normtext].keys.map do |k|
|
89
|
+
{ dimension: k,
|
90
|
+
symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
|
91
|
+
exponent: @dimensions_id[normtext].exponent(k) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def dimension(normtext)
|
96
|
+
return unless @units[normtext]&.dimension
|
97
|
+
|
98
|
+
dims = dimid2dimensions(@units[normtext]&.dimension)
|
99
|
+
<<~XML
|
100
|
+
<Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
|
101
|
+
#{dims.map { |u| dimension1(u) }.join("\n")}
|
102
|
+
</Dimension>
|
103
|
+
XML
|
104
|
+
end
|
105
|
+
|
106
|
+
def unitsml(units, origtext, normtext, quantity, name)
|
107
|
+
dims = units2dimensions(units)
|
108
|
+
<<~XML
|
109
|
+
#{unit(units, origtext, normtext, dims, name)}
|
110
|
+
#{prefix(units)}
|
111
|
+
#{dimension(normtext)}
|
112
|
+
#{dimension_components(dims)}
|
113
|
+
#{quantity(normtext, quantity)}
|
114
|
+
XML
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -1,143 +1,111 @@
|
|
1
1
|
module Asciimath2UnitsML
|
2
2
|
class Conv
|
3
3
|
include Rsec::Helpers
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
next if v.name.nil? || v.name.empty?
|
12
|
-
m[v.symbolid] = v
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def flip_name_and_symbols(hash)
|
17
|
-
hash.each_with_object({}) do |(k, v), m|
|
18
|
-
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
|
4
|
+
def parsers
|
5
|
+
exponent = /\^\(-?\d+\)/.r.map { |m| m.sub(/\^/, "").gsub(/[()]/, "") } |
|
6
|
+
/\^-?\d+/.r.map { |m| m.sub(/\^/, "") }
|
7
|
+
multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } }
|
8
|
+
units = units_parse(exponent, multiplier)
|
9
|
+
dimensions = dimensions_parser(exponent, multiplier)
|
10
|
+
[units.eof, dimensions.eof]
|
42
11
|
end
|
43
12
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
end
|
68
|
-
|
69
|
-
def symbolize_keys(hash)
|
70
|
-
return hash if hash.is_a? String
|
71
|
-
hash.inject({}) do |result, (key, value)|
|
72
|
-
new_key = case key
|
73
|
-
when String then key.to_sym
|
74
|
-
else key
|
75
|
-
end
|
76
|
-
new_value = case value
|
77
|
-
when Hash then symbolize_keys(value)
|
78
|
-
when Array then value.map { |m| symbolize_keys(m) }
|
79
|
-
else value
|
80
|
-
end
|
81
|
-
result[new_key] = new_value
|
82
|
-
result
|
83
|
-
end
|
13
|
+
def dimensions_parser(exponent, multiplier)
|
14
|
+
dim1 = /#{@dimensions.keys.sort_by(&:length).reverse.join("|")}/.r
|
15
|
+
dimension =
|
16
|
+
seq("sqrt(", dim1, ")") { |x| { dim: x[1], display_exponent: "0.5" } } |
|
17
|
+
seq(dim1, exponent._? & (multiplier | ")".r)) { |x| { dim: x[0], display_exponent: (x[1][0]) } } |
|
18
|
+
seq(dim1, exponent._?).eof { |x| { dim: x[0], display_exponent: (x[1][0]) } }
|
19
|
+
dimensions1 = "(".r >> lazy { dimensions } << ")" | dimension
|
20
|
+
dimensions = dimensions1.join(multiplier) # rubocop:disable Style/RedundantAssignment
|
21
|
+
dimensions
|
84
22
|
end
|
85
23
|
|
86
|
-
def
|
24
|
+
def units_parse(exponent, multiplier)
|
87
25
|
prefix2 = /#{@prefixes.keys.select { |x| x.size == 2 }.join("|")}/.r
|
88
26
|
prefix1 = /#{@prefixes.keys.select { |x| x.size == 1 }.join("|")}/.r
|
89
27
|
unit_keys = @units.keys.reject do |k|
|
90
28
|
/\*|\^|\/|^1$/.match(k) || @units[k].prefixed
|
91
29
|
end.map { |k| Regexp.escape(k) }
|
92
30
|
unit1 = /#{unit_keys.sort_by(&:length).reverse.join("|")}/.r
|
93
|
-
|
94
|
-
|
95
|
-
multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } }
|
96
|
-
unit =
|
31
|
+
|
32
|
+
unit =
|
97
33
|
seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } |
|
98
34
|
seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
|
99
35
|
seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } |
|
100
|
-
seq(unit1, exponent._? & multiplier) { |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._?
|
103
|
-
seq(prefix2, unit1, exponent._?
|
104
|
-
"1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
|
105
|
-
|
36
|
+
seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
|
37
|
+
seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } |
|
38
|
+
seq(prefix1, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
|
39
|
+
seq(prefix2, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } |
|
40
|
+
"1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } }
|
41
|
+
units1 = "(".r >> lazy { units } << ")" | unit
|
42
|
+
units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } | # rubocop:disable Style/RedundantAssignment
|
106
43
|
seq(prefix1, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } |
|
107
|
-
|
108
|
-
|
44
|
+
units1.join(multiplier)
|
45
|
+
units
|
109
46
|
end
|
110
47
|
|
111
|
-
def parse(
|
112
|
-
text = Array(
|
48
|
+
def parse(expr)
|
49
|
+
text = Array(expr.split(/,\s*/))
|
50
|
+
if /dim_/.match?(text[0]) then parse_dimensions(text)
|
51
|
+
else parse_units(text)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_units(text)
|
113
56
|
units = @parser.parse!(text[0])
|
114
57
|
if !units || Rsec::INVALID[units]
|
115
58
|
raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
|
116
59
|
end
|
60
|
+
|
61
|
+
Rsec::Fail.reset
|
62
|
+
postprocess(units, text, true)
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_dimensions(text)
|
66
|
+
units = @dim_parser.parse!(text[0])
|
67
|
+
if !units || Rsec::INVALID[units]
|
68
|
+
raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0
|
69
|
+
end
|
70
|
+
|
117
71
|
Rsec::Fail.reset
|
118
|
-
postprocess(units, text)
|
119
|
-
end
|
120
|
-
|
121
|
-
def postprocess(units, text)
|
122
|
-
units = postprocess1(units)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
72
|
+
postprocess(units, text, false)
|
73
|
+
end
|
74
|
+
|
75
|
+
def postprocess(units, text, is_units)
|
76
|
+
units = postprocess1(units.flatten)
|
77
|
+
normtext = postprocess_normtext(units, is_units)
|
78
|
+
[units, text[0], normtext, postprocess_extr(text, "quantity"),
|
79
|
+
postprocess_extr(text, "name"), postprocess_extr(text, "symbol"),
|
80
|
+
postprocess_extr(text, "multiplier")]
|
81
|
+
end
|
82
|
+
|
83
|
+
def postprocess_normtext(units, is_units)
|
84
|
+
units_only(units).each.map do |u|
|
85
|
+
if is_units then "#{u[:prefix]}#{u[:unit]}#{display_exp(u)}"
|
86
|
+
else "#{u[:dim]}#{display_exp(u)}"
|
87
|
+
end
|
130
88
|
end.join("*")
|
131
|
-
|
89
|
+
end
|
90
|
+
|
91
|
+
def postprocess_extr(text, name)
|
92
|
+
text[1..-1]&.select do |x|
|
93
|
+
/^#{name}:/.match(x)
|
94
|
+
end&.first&.sub(/^#{name}:\s*/, "")
|
95
|
+
end
|
96
|
+
|
97
|
+
def display_exp(unit)
|
98
|
+
unit[:exponent] && unit[:exponent] != "1" ? "^#{unit[:exponent]}" : ""
|
132
99
|
end
|
133
100
|
|
134
101
|
def postprocess1(units)
|
135
102
|
inverse = false
|
136
|
-
units.each_with_object([]) do |u, m|
|
103
|
+
units.each_with_object([]) do |u, m|
|
137
104
|
if u[:multiplier]
|
138
|
-
inverse =
|
105
|
+
inverse = !inverse if u[:multiplier] == "/"
|
139
106
|
else
|
140
|
-
u[:exponent] =
|
107
|
+
u[:exponent] =
|
108
|
+
inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent]
|
141
109
|
u[:exponent] = u[:exponent]&.sub(/^--+/, "")
|
142
110
|
end
|
143
111
|
m << u
|
@@ -149,36 +117,53 @@ module Asciimath2UnitsML
|
|
149
117
|
MathML2UnitsML(xml).to_xml
|
150
118
|
end
|
151
119
|
|
152
|
-
# https://www.w3.org/TR/mathml-units/ section 2:
|
120
|
+
# https://www.w3.org/TR/mathml-units/ section 2:
|
121
|
+
# delimit number Invisible-Times unit
|
153
122
|
def MathML2UnitsML(xml)
|
154
123
|
xml.is_a? String and xml = Nokogiri::XML(xml)
|
155
124
|
xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x|
|
156
|
-
next unless %r{^unitsml\(.+\)$}.match(x.text)
|
125
|
+
next unless %r{^unitsml\(.+\)$}.match?(x.text)
|
126
|
+
|
157
127
|
text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1")
|
158
|
-
units, origtext, normtext, quantity, name, symbol, multiplier =
|
159
|
-
|
160
|
-
|
161
|
-
|
128
|
+
units, origtext, normtext, quantity, name, symbol, multiplier =
|
129
|
+
parse(text)
|
130
|
+
rendering = if symbol
|
131
|
+
embeddedmathml(asciimath2mathml(symbol))
|
132
|
+
else
|
133
|
+
mathmlsymbol(units, false, multiplier)
|
134
|
+
end
|
135
|
+
x.replace("#{delimspace(rendering, x)}"\
|
136
|
+
"<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\
|
162
137
|
"#{unitsml(units, origtext, normtext, quantity, name)}")
|
163
138
|
end
|
164
139
|
dedup_ids(xml)
|
165
140
|
end
|
166
141
|
|
167
|
-
# if previous sibling's last descendent non-whitespace is MathML and
|
142
|
+
# if previous sibling's last descendent non-whitespace is MathML and
|
143
|
+
# mn or mi, no space
|
168
144
|
def delimspace(rendering, elem)
|
169
|
-
prec_text_elem =
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
145
|
+
prec_text_elem =
|
146
|
+
elem.xpath("./preceding-sibling::*[namespace-uri() = '#{MATHML_NS}']/"\
|
147
|
+
"descendant::text()[normalize-space()!='']"\
|
148
|
+
"[last()]/parent::*").last
|
149
|
+
return "" if prec_text_elem.nil? ||
|
150
|
+
!%w(mn mi).include?(prec_text_elem&.name)
|
151
|
+
|
152
|
+
text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>")
|
153
|
+
.text.strip)
|
154
|
+
if /\p{L}|\p{N}/.match?(text)
|
155
|
+
"<mo rspace='thickmathspace'>⁢</mo>"
|
156
|
+
else "<mo>⁢</mo>"
|
157
|
+
end
|
175
158
|
end
|
176
159
|
|
177
160
|
def dedup_ids(xml)
|
178
161
|
%w(Unit Dimension Prefix Quantity).each do |t|
|
179
|
-
xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map
|
162
|
+
xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map(&:text)
|
163
|
+
.uniq.each do |v|
|
180
164
|
xml.xpath(".//*[@xml:id = '#{v}']").each_with_index do |n, i|
|
181
|
-
next if i
|
165
|
+
next if i.zero?
|
166
|
+
|
182
167
|
n.remove
|
183
168
|
end
|
184
169
|
end
|
@@ -187,45 +172,50 @@ module Asciimath2UnitsML
|
|
187
172
|
end
|
188
173
|
|
189
174
|
def asciimath2mathml(expression)
|
190
|
-
AsciiMath::MathMLBuilder.new(:
|
191
|
-
AsciiMath.parse(HTMLEntities.new.decode(expression)).ast
|
192
|
-
gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
|
175
|
+
AsciiMath::MathMLBuilder.new(msword: true).append_expression(
|
176
|
+
AsciiMath.parse(HTMLEntities.new.decode(expression)).ast,
|
177
|
+
).to_s.gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>")
|
193
178
|
end
|
194
179
|
|
195
180
|
def embeddedmathml(mathml)
|
196
181
|
x = Nokogiri::XML(mathml)
|
197
|
-
x.xpath(".//m:mi", "m" => MATHML_NS)
|
182
|
+
x.xpath(".//m:mi", "m" => MATHML_NS)
|
183
|
+
.each { |mi| mi["mathvariant"] = "normal" }
|
198
184
|
x.children.to_xml
|
199
185
|
end
|
200
186
|
|
201
187
|
def ambig_units
|
202
|
-
u = @units_id.each_with_object({}) do |(
|
188
|
+
u = @units_id.each_with_object({}) do |(_k, v), m|
|
203
189
|
v.symbolids.each do |x|
|
204
|
-
next if %r{[*/^]}.match(x)
|
190
|
+
next if %r{[*/^]}.match?(x)
|
205
191
|
next unless v.symbols_hash[x][:html] != x
|
192
|
+
|
206
193
|
m[v.symbols_hash[x][:html]] ||= []
|
207
194
|
m[v.symbols_hash[x][:html]] << x
|
208
195
|
end
|
209
196
|
end
|
210
|
-
u.
|
197
|
+
u.each_key { |k| u[k] = u[k].unshift(k) if @symbols.dig(k, :html) == k }
|
211
198
|
render_ambig_units(u)
|
212
199
|
end
|
213
200
|
|
214
201
|
def render_ambig_units(u)
|
215
202
|
maxcols = 0
|
216
203
|
u.each { |_, v| maxcols = v.size if maxcols < v.size }
|
217
|
-
puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{
|
204
|
+
puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{'| ' * (maxcols - 1)}\n)
|
218
205
|
puts "\n\n"
|
219
|
-
u.keys.sort_by
|
206
|
+
u.keys.sort_by do |a|
|
207
|
+
[-u[a].size, a.gsub(%r{&[^;]+;}, "")
|
208
|
+
.gsub(/[^A-Za-z]/, "").downcase]
|
209
|
+
end.each do |k|
|
220
210
|
print "| #{html2adoc(k)} "
|
221
|
-
u[k].sort_by
|
222
|
-
puts "#{
|
211
|
+
u[k].sort_by(&:size).each { |v1| print "| #{@units[v1].name}: `#{v1}` " }
|
212
|
+
puts "#{'| ' * (maxcols - u[k].size)}\n"
|
223
213
|
end
|
224
214
|
puts "|===\n"
|
225
215
|
end
|
226
216
|
|
227
|
-
def html2adoc(
|
228
|
-
|
217
|
+
def html2adoc(elem)
|
218
|
+
elem.gsub(%r{<i>}, "__").gsub(%r{</i>}, "__")
|
229
219
|
.gsub(%r{<sup>}, "^").gsub(%r{</sup>}, "^")
|
230
220
|
.gsub(%r{<sub>}, "~").gsub(%r{</sub>}, "~")
|
231
221
|
end
|