Skip to content

unitsml/unitsml-ruby

Repository files navigation

UnitsML in Ruby

GitHub Stars GitHub Forks License Build Status RubyGems Version

Purpose

UnitsML is a markup language for representing units of measurement in a machine-readable format.

It is designed to be used in various applications, including scientific computing, data analysis, and engineering.

The UnitsML Ruby library provides the following components:

XML syntax for:

  • representing units and quantity information Composite units

  • Parser for the UnitsML parser - Parses UnitsML expressions.

  • Unit Converter - Converts units between formats.

  • Formatter - Formats units for display in various formats.

The UnitsML Ruby library is a gem for parsing, manipulating, and converting unit expressions based on the Units Markup Language (UnitsML) specification. This library provides functionality to handle units of measurement in a standardized way across different formats.

Structure

The UnitsML Ruby library consists of several key components:

  • Parser: Parses string expressions into structured data

  • Transform: Transforms parsed data into domain objects

  • Formula: Represents compound unit expressions

  • Unit: Represents individual units

  • Prefix: Represents unit prefixes (k, m, μ, etc.)

  • Dimension: Represents physical dimensions

The library also includes the full UnitsDB units database, which contains standard units, prefixes, and dimensions.

Usage

AsciiUnits

The UnitsML Ruby library supports AsciiUnits, a text-based syntax for representing units of measurement in a compact and human-readable format.

The UnitsML Ruby library supports all available units defined in the official UnitsDB database.

Basic units

A basic unit is a unit that has an entry in the UnitsDB database with a unique identifier.

Basic units are represented in the library as Unitsml::Unit objects.

require 'unitsml'
unit = Unitsml.parse("m") # Parse a unit expression
unit.to_s # => "m"
unit.to_xml
# =>
<Unit xmlns="https://schema.unitsml.org/unitsml/1.0" xml:id="U_NISTu1" dimensionURL="#NISTd1">
  <UnitSystem name="SI" type="SI_derived" xml:lang="en-US"/>
  <UnitName xml:lang="en">meter</UnitName>
  <UnitSymbol type="HTML">m</UnitSymbol>
  <UnitSymbol type="MathMl">
    <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
      <mi mathvariant="normal">m</mi>
    </math>
  </UnitSymbol>
</Unit>

<Dimension xmlns="https://schema.unitsml.org/unitsml/1.0" xml:id="NISTd1">
  <Length symbol="L" powerNumerator="1"/>
</Dimension>

Prefixed units

A prefixed unit is a unit that has a prefix (like kilo, milli, micro, etc.) that modifies its value.

Prefixed units are represented in the library as Unitsml::Prefix objects.

The library supports the full range of prefixes defined in the UnitsDB database.

require 'unitsml'
unit = Unitsml.parse("um") # Parse a unit expression
unit.to_s # => "um"
unit.to_xml
# =>
<Unit xmlns="https://schema.unitsml.org/unitsml/1.0" xml:id="U_um" dimensionURL="#NISTd1">
  <UnitSystem name="SI" type="SI_derived" xml:lang="en-US"/>
  <UnitName xml:lang="en">um</UnitName>
  <UnitSymbol type="HTML">&micro;m</UnitSymbol>
  <UnitSymbol type="MathMl"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
  <mi mathvariant='normal'>µm</mi>
</math>
</UnitSymbol>
  <RootUnits>
    <EnumeratedRootUnit unit="meter" prefix="u"/>
  </RootUnits>
</Unit>

<Prefix xmlns="https://schema.unitsml.org/unitsml/1.0" prefixBase="10" prefixPower="-6" xml:id="NISTp10_-6">
  <PrefixName xml:lang="en">micro</PrefixName>
  <PrefixSymbol type="ASCII">u</PrefixSymbol>
  <PrefixSymbol type="unicode">μ</PrefixSymbol>
  <PrefixSymbol type="LaTeX">$mu$</PrefixSymbol>
  <PrefixSymbol type="HTML">&micro;</PrefixSymbol>
</Prefix>

<Dimension xmlns="https://schema.unitsml.org/unitsml/1.0" xml:id="NISTd1">
  <Length symbol="L" powerNumerator="1"/>
</Dimension>

Prefixed units: mm, kg, μm

Creating composite units

A composite unit is a unit that is derived from two or more basic units conjoined by multiplication or division.

Composite units are created using the Unitsml.parse method.

Compound units with operations: kg*s^-2 Units with powers: C^3 Square roots: sqrt(Hz) Units with prefixes: m/s, m2/s2

Format representation

The library supports representation of UnitsML-encoded units in various formats.

These formats include:

  • MathML

  • LaTeX

  • AsciiMath

  • HTML

  • Unicode

  • XML (in UnitsML)

Units can be converted to multiple formats as follows:

unit = Unitsml.parse("m/s")
unit.to_mathml     # MathML representation
unit.to_latex      # LaTeX representation
unit.to_asciimath  # AsciiMath representation
unit.to_html       # HTML representation
unit.to_unicode    # Unicode representation
unit.to_xml        # XML (in UnitsML) representation

Explicit parenthesis

When converting units to formats like MathML or LaTeX, you can specify whether to use explicit parentheses for clarity in complex expressions.

A pair of parentheses is typically used for two purposes:

  1. For grouping to indicate operator precedence in mathematical expressions. When expressing units, most of the time, parentheses are used to indicate operator precedence, parentheses are only kept in cases where it indicates precedence. When parentheses are not needed for precedence, such as in the expression (m/s), the parentheses can be removed whilch simplifies the expression into m/s.

  2. For indicating that an expression is a compound unit. These parentheses are explicit parentheses that cannot be removed without changing the meaning of the expression.

UnitsML Ruby provides an option explicit_parenthesis to control the inclusion of parentheses in the output.

In an expression:

  • (…​) is considered an implicit parenthesis for grouping and operator precedence and can be removed without changing the meaning of the expression.

  • …​ is considered an explicit parenthesis, which indicates that the parentheses need to be preserved in the output regardless of operator precedence.

The explicit_parenthesis option allows you to control how parentheses are considered in the output formats. It can be set to true or false.

Syntax for using explicit_parenthesis is as follows:

unit.to_asciimath(explicit_parenthesis: true) # or false
unit.to_mathml(explicit_parenthesis: true) # or false
unit.to_latex(explicit_parenthesis: true) # or false

When explicit_parenthesis is set to:

true

(default) the usage of (…​) and …​ is differentiated as implicit and explicit parentheses, respectively.

false

all parentheses are treated as grouping parentheses, there is no difference between (…​) and …​.

Example 1. By default explicit_parenthesis is true and double parentheses are considered explicit parentheses
Unitsml.parse("((m/s))").to_asciimath
> "(m/s^-1)" # Only one of the two pairs of parentheses are included in the output

If an extra pair of parentheses is included, it will be considered as grouping parentheses and will not be included in the Unitsml::Formula or the output.

Example 2. By default explicit_parenthesis is true and double parentheses are considered explicit parentheses
Unitsml.parse("(((m/s)))").to_asciimath
> "(m/s^-1)" # the third pair of parentheses are ignored as grouping parentheses
Unitsml.parse("(((((m/s)))))").to_asciimath
> "((m/s^-1))" # the fifth pair of parentheses are ignored as grouping parentheses
unit = Unitsml.parse("((m/s))")
unit.to_asciimath # equivalent to (explicit_parenthesis: true) => "(m/s^-1)"
unit = Unitsml.parse("((m/s))*((m/s))")
unit.to_asciimath(explicit_parenthesis: true) # "(m/s^-1)*(m/s^-1)"

When explicit_parenthesis is false, all parentheses are treated as grouping parentheses and therefore will be reduced to only the necessary parentheses for operator precedence.

Example 3. When explicit_parenthesis is false, all parentheses are treated as grouping parentheses
unit = Unitsml.parse("(m/s)")
unit.to_asciimath(explicit_parenthesis: false) # => "m/s"
unit = Unitsml.parse("((m/s))*((m/s))")
unit.to_asciimath(explicit_parenthesis: false) # "m/s^-1*m/s^-1"

Installation

Add this line to your application’s Gemfile:

gem 'unitsml'

And then execute:

$ bundle install

Or install it yourself with:

$ gem install unitsml

Usage

UnitsML Ruby provides functionality to represent and convert units between different formats including MathML, LaTeX, AsciiMath, HTML, Unicode, and XML(Unitsml schema based elements).

Basic Usage

require 'unitsml'

Unitsml.parse("mm*kg/s^2") # Parse a unit expression

Format Conversions

Units can be converted to different formats:

unit = Unitsml.parse("m/s") # Create a unit example

# Convert to different formats
unit.to_mathml
unit.to_latex
unit.to_asciimath
unit.to_html
unit.to_unicode
unit.to_xml

Extenders

An Extender is the symbol between units (like multiplication or division):

formula = Unitsml.parse("m*m") # the '*' is the extender
formula.to_mathml
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
  <mi mathvariant="normal">m</mi>
  <mo>&#x22c5;</mo>
  <mi mathvariant="normal">m</mi>
</math>

The output of extenders can be customized by passing the multiplier argument:

formula = Unitsml.parse("m/m")
formula.to_asciimath(multiplier: "·") # the '·' is the extender for the output
> "m·m^-1"

The multiplier argument is supported in all supported conversions.

Supported multipliers

The multiplier argument supports following types of input:

  • :space - Represents multiplication with a space

  • :nospace - Represents multiplication with no space

  • Custom symbols - Like "·", "/", "*", "aA", "12", etc.

Plurimath support

This gem requires the Plurimath gem to provide to_plurimath method functionality. You need to explicitly install it, please follow the installtion instructions in the Plurimath repository.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Submodules

When developing or contributing to UnitsML Ruby, you’ll need to ensure the submodules are available. After cloning the repository, verify that the submodules exist in the directory.

If not, populate the submodules by running:

$ git submodule update --init --recursive

unitsdb is the only submodule required in this gem for now.

Code of Conduct

Everyone interacting in the Unitsml project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

This project is licensed under the BSD 2-clause License.

See the LICENSE.md file for details.

Copyright Ribose.

About

UnitsML for Ruby

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 7