Module: Unitsml::Utility
- Extended by:
- Unitsdb
- Defined in:
- lib/unitsml/utility.rb
Constant Summary
collapse
- UNITSML_NS =
"https://schema.unitsml.org/unitsml/1.0".freeze
- U2D =
{
"m" => { dimension: "Length", order: 1, symbol: "L" },
"g" => { dimension: "Mass", order: 2, symbol: "M" },
"kg" => { dimension: "Mass", order: 2, symbol: "M" },
"s" => { dimension: "Time", order: 3, symbol: "T" },
"A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
"K" => { dimension: "ThermodynamicTemperature", order: 5,
symbol: "Theta" },
"degK" => { dimension: "ThermodynamicTemperature", order: 5,
symbol: "Theta" },
"mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
"cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
"deg" => { dimension: "PlaneAngle", order: 8, symbol: "phi" },
}.freeze
- Dim2D =
Dimesion for dim_(dimesion) input
{
"dim_L" => U2D["m"],
"dim_M" => U2D["g"],
"dim_T" => U2D["s"],
"dim_I" => U2D["A"],
"dim_Theta" => U2D["K"],
"dim_N" => U2D["mol"],
"dim_J" => U2D["cd"],
"dim_phi" => U2D["deg"],
}.freeze
- DIMS_VECTOR =
%w[
ThermodynamicTemperature
AmountOfSubstance
LuminousIntensity
ElectricCurrent
PlaneAngle
Length
Mass
Time
].freeze
Class Method Summary
collapse
-
.combine_prefixes(p1, p2) ⇒ Object
-
.decompose_unit(u) ⇒ Object
-
.decompose_units_list(units) ⇒ Object
-
.dim_id(dims) ⇒ Object
-
.dimension(norm_text) ⇒ Object
-
.dimension1(dim) ⇒ Object
-
.dimension_components(dims) ⇒ Object
-
.dimid2dimensions(normtext) ⇒ Object
-
.display_exp(unit) ⇒ Object
-
.fields(unit) ⇒ Object
-
.float_to_display(float) ⇒ Object
-
.gather_units(units) ⇒ Object
-
.html_entity_to_unicode(string) ⇒ Object
-
.ox_element(node, attributes: []) ⇒ Object
-
.postprocess_normtext(units) ⇒ Object
-
.prefix_object(prefix) ⇒ Object
-
.prefixes(units) ⇒ Object
-
.quantity(normtext, quantity) ⇒ Object
-
.quantity_name(id) ⇒ Object
-
.rootunits(units) ⇒ Object
-
.string_to_html_entity(string) ⇒ Object
-
.unit(units, formula, dims, norm_text, name) ⇒ Object
-
.unit_id(text) ⇒ Object
-
.unitname(units, text, name) ⇒ Object
-
.units2dimensions(units) ⇒ Object
-
.unitsymbols(formula) ⇒ Object
-
.unitsystem(units) ⇒ Object
-
.update_nodes(element, nodes) ⇒ Object
Methods included from Unitsdb
dimensions_hash, filtered_units, find_id, insert_vectors, load_dimensions, load_units, load_yaml, parsable_dimensions, prefixes_hash, prefixs_ids, quantities, underscore, units, valid_path, vector
Class Method Details
.combine_prefixes(p1, p2) ⇒ Object
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# File 'lib/unitsml/utility.rb', line 126
def combine_prefixes(p1, p2)
return nil if p1.nil? && p2.nil?
return p1.symbolid if p2.nil?
return p2.symbolid if p1.nil?
return "unknown" if p1.base != p2.base
Unitsdb.prefixes_hash.each do |prefix_name, _|
p = prefix_object(prefix_name)
return p if p.base == p1.base && p.power == p1.power + p2.power
end
"unknown"
end
|
.decompose_unit(u) ⇒ Object
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# File 'lib/unitsml/utility.rb', line 84
def decompose_unit(u)
if u&.unit_name == "g" || u.system_type == "SI_base"
{ unit: u, prefix: u&.prefix }
elsif !u.si_derived_bases
{ unit: Unit.new("unknown") }
else
u.si_derived_bases.each_with_object([]) do |k, m|
prefix = if !k["prefix"].nil? && !k["prefix"].empty?
combine_prefixes(prefix_object(k["prefix"]), u.prefix)
else
u.prefix
end
unit_name = Unitsdb.load_units.dig(k.dig("id"), "unit_symbols", 0, "id")
exponent = (k["power"]&.to_i || 1) * (u.power_numerator&.to_f || 1)
m << { prefix: prefix,
unit: Unit.new(unit_name, exponent, prefix: prefix),
}
end
end
end
|
.decompose_units_list(units) ⇒ Object
80
81
82
|
# File 'lib/unitsml/utility.rb', line 80
def decompose_units_list(units)
gather_units(units.map { |u| decompose_unit(u) }.flatten)
end
|
.dim_id(dims) ⇒ Object
67
68
69
70
71
72
73
74
75
76
77
78
|
# File 'lib/unitsml/utility.rb', line 67
def dim_id(dims)
return nil if dims.nil? || dims.empty?
dimensions = Unitsdb.dimensions_hash.values
dim_hash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
dims_vector = DIMS_VECTOR.map { |h| dim_hash.dig(h, :exponent) }.join(":")
id = dimensions.select { |d| d[:vector] == dims_vector }&.first&.dig(:id) and return id.to_s
"D_" + dims.map do |d|
(U2D.dig(d[:unit], :symbol) || Dim2D.dig(d[:id], :symbol)) +
(d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
end.join("")
end
|
.dimension(norm_text) ⇒ Object
191
192
193
194
195
196
197
198
199
200
201
202
|
# File 'lib/unitsml/utility.rb', line 191
def dimension(norm_text)
return unless fields(norm_text)&.dig("dimension_url")
dim_id = fields(norm_text).dig("dimension_url").sub("#", '')
dim_node = ox_element("Dimension", attributes: { xmlns: UNITSML_NS, "xml:id": dim_id })
Ox.dump(
update_nodes(
dim_node,
dimid2dimensions(dim_id)&.compact&.map { |u| dimension1(u) }
)
)
end
|
.dimension1(dim) ⇒ Object
204
205
206
207
208
209
210
|
# File 'lib/unitsml/utility.rb', line 204
def dimension1(dim)
attributes = {
symbol: dim[:symbol],
powerNumerator: float_to_display(dim[:exponent])
}
ox_element(dim[:dimension], attributes: attributes)
end
|
.dimension_components(dims) ⇒ Object
267
268
269
270
271
272
273
|
# File 'lib/unitsml/utility.rb', line 267
def dimension_components(dims)
return if dims.nil? || dims.empty?
attributes = { xmlns: UNITSML_NS, "xml:id": dim_id(dims) }
dim_node = ox_element("Dimension", attributes: attributes)
Ox.dump(update_nodes(dim_node, dims.map { |u| dimension1(u) }))
end
|
.dimid2dimensions(normtext) ⇒ Object
216
217
218
219
220
221
222
223
224
225
226
227
228
|
# File 'lib/unitsml/utility.rb', line 216
def dimid2dimensions(normtext)
dims ||= Unitsdb.load_dimensions[normtext]
dims&.keys&.reject { |d| d.is_a?(Symbol) }&.map do |k|
humanized = k.split("_").map(&:capitalize).join
next unless DIMS_VECTOR.include?(humanized)
{
dimension: humanized,
symbol: dims.dig(k, "symbol"),
exponent: dims.dig(k, "powerNumerator")
}
end
end
|
.display_exp(unit) ⇒ Object
165
166
167
|
# File 'lib/unitsml/utility.rb', line 165
def display_exp(unit)
unit.power_numerator && unit.power_numerator != "1" ? "^#{unit.power_numerator}" : ""
end
|
.fields(unit) ⇒ Object
48
49
50
|
# File 'lib/unitsml/utility.rb', line 48
def fields(unit)
Unitsdb.units.dig(unit, :fields)
end
|
.float_to_display(float) ⇒ Object
212
213
214
|
# File 'lib/unitsml/utility.rb', line 212
def float_to_display(float)
float.to_f.round(1).to_s.sub(/\.0$/, "")
end
|
.gather_units(units) ⇒ Object
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# File 'lib/unitsml/utility.rb', line 105
def gather_units(units)
units.sort_by { |a| a[:unit]&.unit_name }.each_with_object([]) do |k, m|
if m.empty? || m[-1][:unit]&.unit_name != k[:unit]&.unit_name
m << k
else
m[-1][:unit]&.power_numerator = (k[:unit]&.power_numerator&.to_f || 1) + (m[-1][:unit]&.power_numerator&.to_f || 1)
m[-1] = {
prefix: combine_prefixes(prefix_object(m[-1][:prefix]), prefix_object(k[:prefix])),
unit: m[-1][:unit],
}
end
end
end
|
.html_entity_to_unicode(string) ⇒ Object
318
319
320
321
|
# File 'lib/unitsml/utility.rb', line 318
def html_entity_to_unicode(string)
entities = HTMLEntities.new
entities.decode(string)
end
|
.ox_element(node, attributes: []) ⇒ Object
299
300
301
302
303
|
# File 'lib/unitsml/utility.rb', line 299
def ox_element(node, attributes: [])
element = Ox::Element.new(node)
attributes&.each { |attr_key, attr_value| element[attr_key] = attr_value }
element
end
|
.postprocess_normtext(units) ⇒ Object
161
162
163
|
# File 'lib/unitsml/utility.rb', line 161
def postprocess_normtext(units)
units.map { |u| "#{u.prefix_name}#{u.unit_name}#{display_exp(u)}" }.join("*")
end
|
.prefix_object(prefix) ⇒ Object
119
120
121
122
123
124
|
# File 'lib/unitsml/utility.rb', line 119
def prefix_object(prefix)
return prefix unless prefix.is_a?(String)
return nil unless Unitsdb.prefixes.any?(prefix)
prefix.is_a?(String) ? Prefix.new(prefix) : prefix
end
|
.prefixes(units) ⇒ Object
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
# File 'lib/unitsml/utility.rb', line 230
def prefixes(units)
uniq_prefixes = units.map { |unit| unit.prefix }.compact.uniq {|d| d.prefix_name }
uniq_prefixes.map do |p|
prefix_attr = { xmlns: UNITSML_NS, prefixBase: p&.base, prefixPower: p&.power, "xml:id": p&.id }
prefix_node = ox_element("Prefix", attributes: prefix_attr)
contents = []
contents << (ox_element("PrefixName", attributes: { "xml:lang": "en" }) << p&.name)
contents << (ox_element("PrefixSymbol", attributes: { type: "ASCII" }) << p&.to_asciimath)
contents << (ox_element("PrefixSymbol", attributes: { type: "unicode" }) << p&.to_unicode)
contents << (ox_element("PrefixSymbol", attributes: { type: "LaTex" }) << p&.to_latex)
contents << (ox_element("PrefixSymbol", attributes: { type: "HTML" }) << p&.to_html)
Ox.dump(update_nodes(prefix_node, contents)).gsub("&", "&")
end.join("\n")
end
|
.quantity(normtext, quantity) ⇒ Object
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
# File 'lib/unitsml/utility.rb', line 275
def quantity(normtext, quantity)
units = Unitsdb.units
quantity_references = units.dig(normtext, :fields, "quantity_reference")
return unless units[normtext] && quantity_references.size == 1 ||
Unitsdb.quantities[quantity]
id = quantity || quantity_references&.first&.dig("url")
attributes = { xmlns: UNITSML_NS, "xml:id": id.sub('#', '') }
dim_url = units.dig(normtext, :fields, "dimension_url")
dim_url and attributes[:dimensionURL] = "#{dim_url}"
attributes[:quantityType] = "base"
quantity_element = ox_element("Quantity", attributes: attributes)
Ox.dump(update_nodes(quantity_element, quantity_name(id.sub('#', ''))))
end
|
.quantity_name(id) ⇒ Object
290
291
292
293
294
295
296
297
|
# File 'lib/unitsml/utility.rb', line 290
def quantity_name(id)
ret = []
Unitsdb.quantities[id]&.dig("quantity_name")&.each do |q|
node = (ox_element("QuantityName", attributes: { "xml:lang": "en-US" }) << q)
ret << node
end
ret
end
|
.rootunits(units) ⇒ Object
245
246
247
248
249
250
251
252
253
254
255
256
257
|
# File 'lib/unitsml/utility.rb', line 245
def rootunits(units)
return if units.size == 1 && !units[0].prefix
root_unit = ox_element("RootUnits")
units.each do |u|
attributes = { unit: u.enumerated_name }
attributes[:prefix] = u.prefix_name if u.prefix
u.power_numerator && u.power_numerator != "1" and
attributes[:powerNumerator] = u.power_numerator
root_unit << ox_element("EnumeratedRootUnit", attributes: attributes)
end
root_unit
end
|
.string_to_html_entity(string) ⇒ Object
310
311
312
313
314
315
316
|
# File 'lib/unitsml/utility.rb', line 310
def string_to_html_entity(string)
entities = HTMLEntities.new
entities.encode(
string.frozen? ? string : string.force_encoding('UTF-8'),
:hexadecimal,
)
end
|
.unit(units, formula, dims, norm_text, name) ⇒ Object
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/unitsml/utility.rb', line 140
def unit(units, formula, dims, norm_text, name)
attributes = { xmlns: UNITSML_NS, "xml:id": unit_id(norm_text) }
attributes[:dimensionURL] = "##{dim_id(dims)}" if dims
unit_node = ox_element("Unit", attributes: attributes)
nodes = Array(unitsystem(units))
nodes += Array(unitname(units, norm_text, name))
nodes += Array(unitsymbols(formula))
nodes += Array(rootunits(units))
Ox.dump(update_nodes(unit_node, nodes))
.gsub("<", "<")
.gsub(">", ">")
.gsub("&", "&")
.gsub(/−/, "−")
.gsub(/⋅/, "⋅")
end
|
.unit_id(text) ⇒ Object
259
260
261
262
263
264
265
|
# File 'lib/unitsml/utility.rb', line 259
def unit_id(text)
norm_text = text
text = text&.gsub(/[()]/, "")
/-$/.match(text) and return Unitsdb.prefixes[text.sub(/-$/, "")][:id]
unit_hash = Unitsdb.units[norm_text]
"U_#{unit_hash ? unit_hash[:id]&.gsub(/'/, '_') : norm_text&.gsub(/\*/, '.')&.gsub(/\^/, '')}"
end
|
.unitname(units, text, name) ⇒ Object
156
157
158
159
|
# File 'lib/unitsml/utility.rb', line 156
def unitname(units, text, name)
name ||= Unitsdb.units[text] ? Unit.new(text).enumerated_name : text
ox_element("UnitName", attributes: { "xml:lang": "en" }) << name
end
|
.units2dimensions(units) ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/unitsml/utility.rb', line 52
def units2dimensions(units)
norm = decompose_units_list(units)
return if norm.any? { |u| u.nil? || u[:unit].unit_name == "unknown" || u[:prefix] == "unknown" }
norm.map do |u|
unit_name = u[:unit].unit_name
{
dimension: U2D[unit_name][:dimension],
unit: unit_name,
exponent: u[:unit].power_numerator || 1,
symbol: U2D[unit_name][:symbol],
}
end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
end
|
.unitsymbols(formula) ⇒ Object
169
170
171
172
173
174
|
# File 'lib/unitsml/utility.rb', line 169
def unitsymbols(formula)
[
(ox_element("UnitSymbol", attributes: { type: "HTML" }) << formula.to_html),
(ox_element("UnitSymbol", attributes: { type: "MathMl" }) << Ox.parse(formula.to_mathml)),
]
end
|
.unitsystem(units) ⇒ Object
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
# File 'lib/unitsml/utility.rb', line 176
def unitsystem(units)
ret = []
if units.any? { |u| u.system_name != "SI" }
ret << ox_element("UnitSystem", attributes: { name: "not_SI", type: "not_SI", "xml:lang": 'en-US' })
end
if units.any? { |u| u.system_name == "SI" }
if units.size == 1
base = units[0].system_type == "SI-base"
base = true if units[0].unit_name == "g" && units[0]&.prefix_name == "k"
end
ret << ox_element("UnitSystem", attributes: { name: "SI", type: (base ? 'SI_base' : 'SI_derived'), "xml:lang": 'en-US' })
end
ret
end
|
.update_nodes(element, nodes) ⇒ Object
305
306
307
308
|
# File 'lib/unitsml/utility.rb', line 305
def update_nodes(element, nodes)
nodes&.each { |node| element << node unless node.nil? }
element
end
|