class Asciimath2UnitsML::Conv
Constants
- Dim2D
- U2D
Public Class Methods
new(options = {})
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 19 def initialize(options = {}) @dimensions_id = read_yaml("../unitsdb/dimensions.yaml") .each_with_object({}) do |(k, v), m| m[k.to_s] = UnitsDB::Dimension.new(k, v) end @dimensions = flip_name_and_symbols(@dimensions_id) @prefixes_id = read_yaml("../unitsdb/prefixes.yaml") .each_with_object({}) do |(k, v), m| m[k] = UnitsDB::Prefix.new(k, v) end @prefixes = flip_name_and_symbol(@prefixes_id) @quantities = read_yaml("../unitsdb/quantities.yaml") .each_with_object({}) do |(k, v), m| m[k.to_s] = UnitsDB::Quantity.new(k, v) end @units_id = read_yaml("../unitsdb/units.yaml") .each_with_object({}) do |(k, v), m| m[k.to_s] = UnitsDB::Unit.new(k.to_s, v) end @units = flip_name_and_symbols(@units_id) @symbols = @units.merge(@dimensions).each_with_object({}) do |(_k, v), m| v.symbolids.each { |x| m[x] = v.symbols_hash[x] } end @parser, @dim_parser = parsers @multiplier = multiplier(options[:multiplier] || "\u22c5") end
Public Instance Methods
Asciimath2UnitsML(expression)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 115 def Asciimath2UnitsML(expression) xml = Nokogiri::XML(asciimath2mathml(expression)) MathML2UnitsML(xml).to_xml end
MathML2UnitsML(xml)
click to toggle source
www.w3.org/TR/mathml-units/ section 2: delimit number Invisible-Times unit
# File lib/asciimath2unitsml/parse.rb, line 122 def MathML2UnitsML(xml) xml.is_a? String and xml = Nokogiri::XML(xml) xml.xpath(".//m:mtext", "m" => MATHML_NS).each do |x| next unless %r{^unitsml\(.+\)$}.match?(x.text) text = x.text.sub(%r{^unitsml\((.+)\)$}m, "\\1") units, origtext, normtext, quantity, name, symbol, multiplier = parse(text) rendering = if symbol embeddedmathml(asciimath2mathml(symbol)) else mathmlsymbol(units, false, multiplier) end x.replace("#{delimspace(rendering, x)}"\ "<mrow xref='#{unit_id(origtext)}'>#{rendering}</mrow>\n"\ "#{unitsml(units, origtext, normtext, quantity, name)}") end dedup_ids(xml) end
ambig_units()
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 187 def ambig_units u = @units_id.each_with_object({}) do |(_k, v), m| v.symbolids.each do |x| next if %r{[*/^]}.match?(x) next unless v.symbols_hash[x][:html] != x m[v.symbols_hash[x][:html]] ||= [] m[v.symbols_hash[x][:html]] << x end end u.each_key { |k| u[k] = u[k].unshift(k) if @symbols.dig(k, :html) == k } render_ambig_units(u) end
asciimath2mathml(expression)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 174 def asciimath2mathml(expression) AsciiMath::MathMLBuilder.new(msword: true).append_expression( AsciiMath.parse(HTMLEntities.new.decode(expression)).ast, ).to_s.gsub(/<math>/, "<math xmlns='#{MATHML_NS}'>") end
combine_prefixes(p1, p2)
click to toggle source
# File lib/asciimath2unitsml/conv.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 @prefixes.each do |_, p| return p.symbolid if p.base == p1.base && p.power == p1.power + p2.power end "unknown" end
compose_name(_units, text)
click to toggle source
TODO: compose name from the component units
# File lib/asciimath2unitsml/unit.rb, line 61 def compose_name(_units, text) text end
decompose_unit(u)
click to toggle source
treat g not kg as base unit: we have stripped the prefix k in parsing reduce units down to basic units
# File lib/asciimath2unitsml/conv.rb, line 106 def decompose_unit(u) if u[:unit].nil? || u[:unit] == "g" || @units[u[:unit]].system_type == "SI_base" then u elsif !@units[u[:unit]].si_derived_bases { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] } else @units[u[:unit]].si_derived_bases.each_with_object([]) do |k, m| prefix = if !k[:prefix].nil? && !k[:prefix].empty? combine_prefixes(@prefixes_id[k[:prefix]], @prefixes[u[:prefix]]) else u[:prefix] end m << { prefix: prefix, unit: @units_id[k[:id]].symbolid, exponent: (k[:power]&.to_i || 1) * (u[:exponent]&.to_f || 1) } end end end
decompose_units(units)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 65 def decompose_units(units) gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten) end
dedup_ids(xml)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 160 def dedup_ids(xml) %w(Unit Dimension Prefix Quantity).each do |t| xml.xpath(".//m:#{t}/@xml:id", "m" => UNITSML_NS).map(&:text) .uniq.each do |v| xml.xpath(".//*[@xml:id = '#{v}']").each_with_index do |n, i| next if i.zero? n.remove end end end xml end
delimspace(rendering, elem)
click to toggle source
if previous sibling's last descendent non-whitespace is MathML and mn or mi, no space
# File lib/asciimath2unitsml/parse.rb, line 144 def delimspace(rendering, elem) prec_text_elem = elem.xpath("./preceding-sibling::*[namespace-uri() = '#{MATHML_NS}']/"\ "descendant::text()[normalize-space()!='']"\ "[last()]/parent::*").last return "" if prec_text_elem.nil? || !%w(mn mi).include?(prec_text_elem&.name) text = HTMLEntities.new.encode(Nokogiri::XML("<mrow>#{rendering}</mrow>") .text.strip) if /\p{L}|\p{N}/.match?(text) "<mo rspace='thickmathspace'>⁢</mo>" else "<mo>⁢</mo>" end end
dim_id(dims)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 68 def dim_id(dims) return nil if dims.nil? || dims.empty? dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h } dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature AmountOfSubstance LuminousIntensity PlaneAngle) .map { |h| dimhash.dig(h, :exponent) }.join(":") id = @dimensions_id&.values&.select { |d| d.vector == dimsvector } &.first&.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(normtext)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 95 def dimension(normtext) return unless @units[normtext]&.dimension dims = dimid2dimensions(@units[normtext]&.dimension) <<~XML <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}"> #{dims.map { |u| dimension1(u) }.join("\n")} </Dimension> XML end
dimension1(dim)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 63 def dimension1(dim) %(<#{dim[:dimension]} symbol="#{dim[:symbol]}" powerNumerator="#{float_to_display(dim[:exponent])}"/>) end
dimension_components(dims)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 3 def dimension_components(dims) return if dims.nil? || dims.empty? <<~XML <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}"> #{dims.map { |u| dimension1(u) }.join("\n")} </Dimension> XML end
dimensions_parser(exponent, multiplier)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 13 def dimensions_parser(exponent, multiplier) dim1 = /#{@dimensions.keys.sort_by(&:length).reverse.join("|")}/.r dimension = seq("sqrt(", dim1, ")") { |x| { dim: x[1], display_exponent: "0.5" } } | seq(dim1, exponent._? & (multiplier | ")".r)) { |x| { dim: x[0], display_exponent: (x[1][0]) } } | seq(dim1, exponent._?).eof { |x| { dim: x[0], display_exponent: (x[1][0]) } } dimensions1 = "(".r >> lazy { dimensions } << ")" | dimension dimensions = dimensions1.join(multiplier) # rubocop:disable Style/RedundantAssignment dimensions end
dimid2dimensions(normtext)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 87 def dimid2dimensions(normtext) @dimensions_id[normtext].keys.map do |k| { dimension: k, symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol], exponent: @dimensions_id[normtext].exponent(k) } end end
display_exp(unit)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 97 def display_exp(unit) unit[:exponent] && unit[:exponent] != "1" ? "^#{unit[:exponent]}" : "" end
embeddedmathml(mathml)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 180 def embeddedmathml(mathml) x = Nokogiri::XML(mathml) x.xpath(".//m:mi", "m" => MATHML_NS) .each { |mi| mi["mathvariant"] = "normal" } x.children.to_xml end
flip_name_and_symbol(hash)
click to toggle source
# File lib/asciimath2unitsml/read.rb, line 26 def flip_name_and_symbol(hash) hash.each_with_object({}) do |(_k, v), m| next if v.name.nil? || v.name.empty? m[v.symbolid] = v end end
flip_name_and_symbols(hash)
click to toggle source
# File lib/asciimath2unitsml/read.rb, line 34 def flip_name_and_symbols(hash) hash.each_with_object({}) do |(_k, v), m| next if v.name.nil? || v.name.empty? v.symbolids.each { |s| m[s] = v } end end
float_to_display(float)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 46 def float_to_display(float) float.to_f.round(1).to_s.sub(/\.0$/, "") end
gather_dimensions(units)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 91 def gather_dimensions(units) units.sort_by { |a| a[:dim] }.each_with_object([]) do |k, m| if m.empty? || m[-1][:dim] != k[:dim] then m << k else m[-1] = { dim: m[-1][:dim], exponent: (k[:exponent]&.to_f || 1) + (m[-1][:exponent]&.to_f || 1), } end end end
gather_units(units)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 69 def gather_units(units) if units[0][:dim] then gather_dimensions(units) else gather_units1(units) end end
gather_units1(units)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 75 def gather_units1(units) units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m| if m.empty? || m[-1][:unit] != k[:unit] then m << k else m[-1] = { prefix: combine_prefixes( @prefixes[m[-1][:prefix]], @prefixes[k[:prefix]] ), unit: m[-1][:unit], exponent: (k[:exponent]&.to_f || 1) + (m[-1][:exponent]&.to_f || 1), } end end end
html2adoc(elem)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 217 def html2adoc(elem) elem.gsub(%r{<i>}, "__").gsub(%r{</i>}, "__") .gsub(%r{<sup>}, "^").gsub(%r{</sup>}, "^") .gsub(%r{<sub>}, "~").gsub(%r{</sub>}, "~") end
htmlent(xml)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 19 def htmlent(xml) HTMLEntities.new.decode(xml).split(/([<>&])/).map do |c| /[<>'"]/.match?(c) ? c : HTMLEntities.new.encode(c, :hexadecimal) end.join end
htmlsymbol(units, normalise)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 25 def htmlsymbol(units, normalise) units.map do |u| if u[:multiplier] u[:multiplier] == "*" ? @multiplier[:html] : u[:multiplier] elsif u[:unit].nil? && u[:prefix] @prefixes[u[:prefix]].html else base = (u[:prefix] || "") + render(normalise ? @units[u[:unit]].symbolid : u[:unit], :html) htmlsymbol_exponent(u, base) end end.join end
htmlsymbol_exponent(unit, base)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 39 def htmlsymbol_exponent(unit, base) if unit[:display_exponent] == "0.5" base = "√#{base}" elsif unit[:display_exponent] exp = "<sup>#{unit[:display_exponent].sub(/-/, '−')}</sup>" base += exp end base end
mathmlsymbol(units, normalise, multiplier = nil)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 49 def mathmlsymbol(units, normalise, multiplier = nil) multiplier = multiplier ? "<mo>#{multiplier}</mo>" : @multiplier[:mathml] units.map do |u| if u[:multiplier] u[:multiplier] == "*" ? multiplier : "<mo>#{u[:multiplier]}</mo>" elsif u[:unit].nil? && u[:prefix] %(<mi mathvariant='normal'>#{htmlent(@prefixes[u[:prefix]].html)}</mi>) else mathmlsymbol1(u, normalise) end end.join end
mathmlsymbol1(unit, normalise)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 62 def mathmlsymbol1(unit, normalise) base = if unit[:dim] render(normalise ? @dimensions[unit[:dim]].symbolid : unit[:dim], :mathml) else render(normalise ? @units[unit[:unit]].symbolid : unit[:unit], :mathml) end unit[:prefix] and base = mathmlsymbol1_prefixed(unit, base) mathmlsymbol_exponent(unit, base) end
mathmlsymbol1_prefixed(unit, base)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 74 def mathmlsymbol1_prefixed(unit, base) prefix = htmlent(@prefixes[unit[:prefix]].html) if /<mi mathvariant='normal'>/.match?(base) base.sub(/<mi mathvariant='normal'>/, "<mi mathvariant='normal'>#{prefix}") else "<mrow><mi mathvariant='normal'>#{prefix}#{base}</mrow>" end end
mathmlsymbol_exponent(unit, base)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 84 def mathmlsymbol_exponent(unit, base) if unit[:display_exponent] == "0.5" base = "<msqrt>#{base}</msqrt>" elsif unit[:display_exponent] exp = "<mn>#{unit[:display_exponent]}</mn>" .sub(/<mn>-/, "<mo>−</mo><mn>") base = "<msup><mrow>#{base}</mrow><mrow>#{exp}</mrow></msup>" end base end
mathmlsymbolwrap(units, normalise)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 95 def mathmlsymbolwrap(units, normalise) <<~XML <math xmlns='#{MATHML_NS}'><mrow>#{mathmlsymbol(units, normalise)}</mrow></math> XML end
multiplier(val)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 3 def multiplier(val) case val when :space { html: " ", mathml: "<mo rspace='thickmathspace'>⁢</mo>" } when :nospace { html: "", mathml: "<mo>⁢</mo>" } else { html: HTMLEntities.new.encode(val), mathml: "<mo>#{HTMLEntities.new.encode(val)}</mo>" } end end
normalise_units(units)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 28 def normalise_units(units) units.map do |u| u1 = u.dup u1[:multiplier] and u1[:multiplier] = "*" u1[:exponent] and u1[:display_exponent] = u1[:exponent] u1 end end
parse(expr)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 48 def parse(expr) text = Array(expr.split(/,\s*/)) if /dim_/.match?(text[0]) then parse_dimensions(text) else parse_units(text) end end
parse_dimensions(text)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 65 def parse_dimensions(text) units = @dim_parser.parse!(text[0]) if !units || Rsec::INVALID[units] raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0 end Rsec::Fail.reset postprocess(units, text, false) end
parse_units(text)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 55 def parse_units(text) units = @parser.parse!(text[0]) if !units || Rsec::INVALID[units] raise Rsec::SyntaxError.new "error parsing UnitsML expression", x, 1, 0 end Rsec::Fail.reset postprocess(units, text, true) end
parsers()
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 4 def parsers exponent = /\^\(-?\d+\)/.r.map { |m| m.sub(/\^/, "").gsub(/[()]/, "") } | /\^-?\d+/.r.map { |m| m.sub(/\^/, "") } multiplier = %r{\*|//|/}.r.map { |x| { multiplier: x[0] } } units = units_parse(exponent, multiplier) dimensions = dimensions_parser(exponent, multiplier) [units.eof, dimensions.eof] end
postprocess(units, text, is_units)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 75 def postprocess(units, text, is_units) units = postprocess1(units.flatten) normtext = postprocess_normtext(units, is_units) [units, text[0], normtext, postprocess_extr(text, "quantity"), postprocess_extr(text, "name"), postprocess_extr(text, "symbol"), postprocess_extr(text, "multiplier")] end
postprocess1(units)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 101 def postprocess1(units) inverse = false units.each_with_object([]) do |u, m| if u[:multiplier] inverse = !inverse if u[:multiplier] == "/" else u[:exponent] = inverse ? "-#{u[:display_exponent] || '1'}" : u[:display_exponent] u[:exponent] = u[:exponent]&.sub(/^--+/, "") end m << u end end
postprocess_extr(text, name)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 91 def postprocess_extr(text, name) text[1..-1]&.select do |x| /^#{name}:/.match(x) end&.first&.sub(/^#{name}:\s*/, "") end
postprocess_normtext(units, is_units)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 83 def postprocess_normtext(units, is_units) units_only(units).each.map do |u| if is_units then "#{u[:prefix]}#{u[:unit]}#{display_exp(u)}" else "#{u[:dim]}#{display_exp(u)}" end end.join("*") end
prefix(units)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 50 def prefix(units) units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p| <<~XML <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}' prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'> <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName> <PrefixSymbol type="ASCII">#{@prefixes[p].ascii}</PrefixSymbol> <PrefixSymbol type="unicode">#{@prefixes[p].unicode}</PrefixSymbol> <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol> <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol> </Prefix> XML end.join("\n") end
quantity(normtext, quantity)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 146 def quantity(normtext, quantity) return unless @units[normtext] && @units[normtext].quantities.size == 1 || @quantities[quantity] id = quantity || @units[normtext].quantities.first @units[normtext]&.dimension and dim = %( dimensionURL="##{@units[normtext].dimension}") <<~XML <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base"> #{quantityname(id)} </Quantity> XML end
quantityname(id)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 138 def quantityname(id) ret = "" @quantities[id].names.each do |q| ret += %(<QuantityName xml:lang="en-US">#{q}</QuantityName>) end ret end
read_yaml(path)
click to toggle source
# File lib/asciimath2unitsml/read.rb, line 3 def read_yaml(path) validate_yaml(symbolize_keys(YAML .load_file(File.join(File.join(File.dirname(__FILE__), path)))), path) end
render(unit, style)
click to toggle source
# File lib/asciimath2unitsml/render.rb, line 15 def render(unit, style) @symbols[unit][style] || unit end
render_ambig_units(u)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 201 def render_ambig_units(u) maxcols = 0 u.each { |_, v| maxcols = v.size if maxcols < v.size } puts %([cols="#{maxcols + 1}*"]\n|===\n|Symbol | Unit + ID #{'| ' * (maxcols - 1)}\n) puts "\n\n" u.keys.sort_by do |a| [-u[a].size, a.gsub(%r{&[^;]+;}, "") .gsub(/[^A-Za-z]/, "").downcase] end.each do |k| print "| #{html2adoc(k)} " u[k].sort_by(&:size).each { |v1| print "| #{@units[v1].name}: `#{v1}` " } puts "#{'| ' * (maxcols - u[k].size)}\n" end puts "|===\n" end
rootunits(units)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 72 def rootunits(units) return if units_only(units).any? { |x| x[:unit].nil? } return if units.size == 1 && !units[0][:prefix] exp = units_only(units).map do |u| prefix = " prefix='#{u[:prefix]}'" if u[:prefix] u[:exponent] && u[:exponent] != "1" and arg = " powerNumerator='#{u[:exponent]}'" "<EnumeratedRootUnit unit='#{@units[u[:unit]].name}'#{prefix}#{arg}/>" end.join("\n") <<~XML <RootUnits>#{exp}</RootUnits> XML end
symbol_key(val)
click to toggle source
# File lib/asciimath2unitsml/validate.rb, line 50 def symbol_key(val) symbol = val[:unit_symbols]&.each_with_object([]) do |s, m| m << (s["id"] || s[:id]) end || val.dig(:symbol, :ascii) || val[:symbol] # || val[:short] !symbol.nil? && val[:unit_symbols] && !symbol.is_a?(Array) and symbol = [symbol] symbol end
symbolize_keys(hash)
click to toggle source
# File lib/asciimath2unitsml/read.rb, line 8 def symbolize_keys(hash) return hash if hash.is_a? String hash.inject({}) do |result, (key, value)| new_key = case key when String then key.to_sym else key end new_value = case value when Hash then symbolize_keys(value) when Array then value.map { |m| symbolize_keys(m) } else value end result[new_key] = new_value result end end
unit(units, _origtext, normtext, dims, name)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 13 def unit(units, _origtext, normtext, dims, name) return if units_only(units).any? { |x| x[:unit].nil? } dimid = dim_id(dims) norm_units = normalise_units(units) <<~XML <Unit xmlns='#{UNITSML_NS}' xml:id='#{unit_id(normtext)}'#{dimid ? " dimensionURL='##{dimid}'" : ''}> #{unitsystem(units)} #{unitname(norm_units, normtext, name)} #{unitsymbol(norm_units)} #{rootunits(units)} </Unit> XML end
unit_id(text)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 7 def unit_id(text) text = text.gsub(/[()]/, "") /-$/.match(text) and return @prefixes[text.sub(/-$/, "")].id "U_#{@units[text] ? @units[text].id.gsub(/'/, '_') : text.gsub(/\*/, '.').gsub(/\^/, '')}" end
unitname(units, text, name)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 55 def unitname(units, text, name) name ||= @units[text] ? @units[text].name : compose_name(units, text) "<UnitName xml:lang='en'>#{name}</UnitName>" end
units2dimensions(units)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 39 def units2dimensions(units) norm = decompose_units(units) return units2dimensions_dim_input(norm) if norm[0][:dim] return if norm.any? do |u| u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil? end norm.map do |u| { dimension: U2D[u[:unit]][:dimension], unit: u[:unit], exponent: u[:exponent] || 1, symbol: U2D[u[:unit]][:symbol] } end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] } end
units2dimensions_dim_input(norm)
click to toggle source
# File lib/asciimath2unitsml/dimensions.rb, line 54 def units2dimensions_dim_input(norm) norm.map do |u| { dimension: Dim2D[u[:dim]][:dimension], exponent: u[:exponent] || 1, id: u[:dim], symbol: Dim2D[u[:dim]][:symbol] } end.sort { |a, b| Dim2D[a[:id]][:order] <=> Dim2D[b[:id]][:order] } end
units_only(units)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 3 def units_only(units) units.reject { |u| u[:multiplier] } end
units_parse(exponent, multiplier)
click to toggle source
# File lib/asciimath2unitsml/parse.rb, line 24 def units_parse(exponent, multiplier) prefix2 = /#{@prefixes.keys.select { |x| x.size == 2 }.join("|")}/.r prefix1 = /#{@prefixes.keys.select { |x| x.size == 1 }.join("|")}/.r unit_keys = @units.keys.reject do |k| /\*|\^|\/|^1$/.match(k) || @units[k].prefixed end.map { |k| Regexp.escape(k) } unit1 = /#{unit_keys.sort_by(&:length).reverse.join("|")}/.r unit = seq("sqrt(", unit1, ")") { |x| { prefix: nil, unit: x[1], display_exponent: "0.5" } } | seq("sqrt(", prefix1, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } | seq("sqrt(", prefix2, unit1, ")") { |x| { prefix: x[1], unit: x[2], display_exponent: "0.5" } } | seq(unit1, exponent._? & (multiplier | ")".r)) { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } | seq(unit1, exponent._?).eof { |x| { prefix: nil, unit: x[0], display_exponent: (x[1][0]) } } | seq(prefix1, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } | seq(prefix2, unit1, exponent._?) { |x| { prefix: x[0], unit: x[1], display_exponent: (x[2][0]) } } | "1".r.map { |_| { prefix: nil, unit: "1", display_exponent: nil } } units1 = "(".r >> lazy { units } << ")" | unit units = seq(prefix2, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } | # rubocop:disable Style/RedundantAssignment seq(prefix1, "-") { |x| [{ prefix: x[0], unit: nil, display_exponent: nil }] } | units1.join(multiplier) units end
unitsml(units, origtext, normtext, quantity, name)
click to toggle source
# File lib/asciimath2unitsml/conv.rb, line 160 def unitsml(units, origtext, normtext, quantity, name) dims = units2dimensions(units) <<~XML #{unit(units, origtext, normtext, dims, name)} #{prefix(units)} #{dimension(normtext)} #{dimension_components(dims)} #{quantity(normtext, quantity)} XML end
unitsymbol(units)
click to toggle source
# File lib/asciimath2unitsml/unit.rb, line 65 def unitsymbol(units) <<~XML <UnitSymbol type="HTML">#{htmlsymbol(units, true)}</UnitSymbol> <UnitSymbol type="MathML">#{mathmlsymbolwrap(units, true)}</UnitSymbol> XML end
unitsystem(units)
click to toggle source
kg exception
# File lib/asciimath2unitsml/unit.rb, line 38 def unitsystem(units) return if units_only(units).any? { |x| x[:unit].nil? } ret = [] units = units_only(units) units.any? { |x| @units[x[:unit]].system_name != "SI" } and ret << "<UnitSystem name='not_SI' type='not_SI' xml:lang='en-US'/>" if units.any? { |x| @units[x[:unit]].system_name == "SI" } base = units.size == 1 && @units[units[0][:unit]].system_type == "SI-base" base = true if units.size == 1 && units[0][:unit] == "g" && units[0][:prefix] == "k" ret << "<UnitSystem name='SI' type='#{base ? 'SI_base' : 'SI_derived'}' xml:lang='en-US'/>" end ret.join("\n") end
validate_symbols(acc, val)
click to toggle source
# File lib/asciimath2unitsml/validate.rb, line 28 def validate_symbols(acc, val) symbol = symbol_key(val) !symbol.nil? or raise StandardError.new "No symbol provided for unit: #{val}" Array(symbol)&.each do |s| acc[s] && s != "1" and raise StandardError.new "symbol #{s} is not unique in #{val}: "\ "already used for #{acc[s]}" acc[s] = val end acc end
validate_unit(unit)
click to toggle source
# File lib/asciimath2unitsml/validate.rb, line 15 def validate_unit(unit) if unit[:quantity_reference] unit[:quantity_reference].is_a?(Array) or raise StandardError .new "No quantity_reference array provided for unit: #{unit}" end if unit[:unit_name] unit[:unit_name].is_a?(Array) or raise StandardError .new "No unit_name array provided for unit: #{unit}" end end
validate_unit_symbol_cardinality(sym, key)
click to toggle source
# File lib/asciimath2unitsml/validate.rb, line 41 def validate_unit_symbol_cardinality(sym, key) return true if sym.nil? !sym[:id].nil? && !sym[:ascii].nil? && !sym[:html].nil? && !sym[:mathml].nil? && !sym[:latex].nil? && !sym[:unicode].nil? and return true raise StandardError.new "malformed unit_symbol for #{key}: #{sym}" end
validate_yaml(hash, path)
click to toggle source
# File lib/asciimath2unitsml/validate.rb, line 3 def validate_yaml(hash, path) return hash if path == "../unitsdb/quantities.yaml" return hash if path == "../unitsdb/dimensions.yaml" hash.each_with_object({}) do |(k, v), m| path == "../unitsdb/units.yaml" and validate_unit(v) m = validate_symbols(m, v) v[:unit_symbols]&.each { |s| validate_unit_symbol_cardinality(s, k) } end hash end