Mizur

Pronounced /'meʒə/

Mizur is a tool to simplify the management, conversion and mapping of units. The manipulation of measurement units should (at best) be typesafe.

Mizur Logo (A special thanks to @fh-d for this awesome logo !)

Some examples

Basic example

Definition of a metric system for computing distances :


defmodule Distance do 
  use Mizur.System
  type m
  type cm = m / 100 
  type mm = m / 1000 
  type km = m * 1000
end

Using this module provides the following functions:

  • Distance.m/0 : to reference the type Distance.m
  • Distance.cm/0 : to reference the type Distance.cm
  • Distance.mm/0 : to reference the type Distance.mm
  • Distance.km/0 : to reference the type Distance.km

and :

  • Distance.m/1 : to create packed values in the Distance.m type
  • Distance.cm/1 : to create packed values in the Distance.cm type
  • Distance.mm/1 : to create packed values in the Distance.mm type
  • Distance.km/1 : to create packed values in the Distance.km type

and sigils : Distance.sigil_t(value, ['typename']).

Example of common Mizur usage

a = Distance.m(200)
b = Distance.cm(200)
result = Mizur.add(a, b)
assert result = Distance.m(202)

Using infix notation

You can use infix notation for operations on units of measurements using use Mizur.Infix.

As with the import directive, you can use the :except and :only parameters (exactly in the same way as usingimport).

The main difference with import is that use will overwrite the correct operators of the Kernel module.

Manage arithmetic operations on datetime

defmodule MyTime do 

  use Mizur.System
  type sec
  type min  = sec * 60 
  type hour = sec * 60 * 60
  type day  = sec * 60 * (60 * 24)

  def now do 
    DateTime.utc_now()
    |> DateTime.to_unix(:second)
    |> sec()
  end

  def new(year, month, day, hour, min, sec) do
    ndt = NaiveDateTime.new(year, month, day, hour, min, sec) 
    case ndt do 
      {:error, message} -> raise RuntimeError, message: "#{message}"
      {:ok, value} ->
        DateTime.from_naive!(value, "Etc/UTC")
        |> DateTime.to_unix(:second)
        |> sec()
    end
  end

  def to_datetime(value) do 
    elt = Mizur.from(value, to: sec())
    int = round(Mizur.unwrap(elt))
    DateTime.from_unix!(int) #beurk, it is unsafe
  end
  
end

use Mizur.Infix, only: [+: 2, -: 2]
import MyTime

# Create a typed_value of the current timestamp:
a = now()

# Add two days and four hour
b = a + ~t(2)day + ~t(4)hour # I use Sigils... 

# Sub ten minuts 
c = b - ~t(10)min

# Convert into DateTime 
result = to_datetime(c)

Other examples

The test module gives many usage examples : Test module

Installation

If available in Hex, the package can be installed by adding mizur to your list of dependencies in mix.exs:

def deps do
  [{:mizur, "~> 0.1.1"}]
end

Special Thanks

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/mizur/readme.html.