README.md

# 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](images/logo.png)
(A special thanks to [@fh-d](https://github.com/fh-d) for this awesome logo !)

- [Presentation](#content)
- [Some examples](#some-examples)
- [Installation](#installation)
- [Special thanks](#special-thanks)

## Some examples

### Basic example

Definition of a metric system for computing distances :

```elixir 

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

```elixir
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 using` import`).

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


### Manage arithmetic operations on datetime

```elixir 
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](https://github.com/xvw/mizur/blob/master/test/mizur_test.exs)

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `mizur` to your list of dependencies in `mix.exs`:

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

## Special Thanks

- [@julien-leclercq](https://github.com/julien-leclercq), a lot of help about unit-comprehension
- [@Fenntasy](https://github.com/Fenntasy), help for the design
- [@fh-d](https://github.com/fh-d), for the logo
- [@tgautier](https://github.com/tgautier) and the LilleFP team !

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/mizur/readme.html](https://hexdocs.pm/mizur/readme.html).