README.md

# coers

[![Build Status][gh-actions-badge]][gh-actions]
[![Erlang Versions][erlang-badge]][versions]
[![Tag][github-tag-badge]][github-tag]

[![Project Logo][logo]][logo-large]

*A small library for coercion to primitive Erlang types*

## About

Coers is a very small library to provide small coercion on primitive types in Erlang.
This library was built essentially for internal tools at derniercri.io

## Build & Test

``` shell
$ rebar3 compile
$ rebar3 check
```

The later includes not only unit tests, but also other checks and coverage
assessment.

## Usage

Each coercion is wrapped into a [special record](https://github.com/erlsci/results/blob/main/include/results.hrl): 

```erlang
-record(result, {
  value :: term(),
  error :: term(),
}).
```

If a coercion fail, the `value` field is undefined and the `error` field is populated with
an appropriate error. If the coersion succeed, the `value` field becomes the coerced data and the 
`error` field is undefined.

You can use these functions from the coers API to examine the coercion status:

- `coers:value(Result)`
- `coers:error(Result)`
- `coers:has_error(Result)`

For example : 

```erlang
1> R1 = coers:to_int("10").
{result,10,undefined}
2> R2 = coers:to_int("foo").
{result,undefined,{badarg,"Could not convert \"foo\" (type any) to int"}}
```

Additional convenience functions are available via the [results library](https://github.com/erlsci/results):

``` erlang
3> results:has_values([R1, R2]).
[true,false]
4> results:has_errors([R1, R2]).
[false,true]
5> results:values([R1, R2]).
[10,undefined]
```

Note that fractions are supported (via the [rationals](https://github.com/erlsci/rationals) Erlang library):

``` erlang
6> coers:to_rational("1/42").
{result,{fraction,1,42},undefined}
7> coers:to_rational(<<"1/42">>).
{result,{fraction,1,42},undefined}
8> coers:to_rational({1, 42}).
{result,{fraction,1,42},undefined}
```

Example usgage in LFE:

``` lisp
(defun ->lfe (arg)
  (case arg
   (#"#t" 'true)
   (#"#f" 'false)
   (#"NIL" 'nil)
   (_ (cond ((?= `#(result true ,val) (coers:to_int arg))
             val)
            ((?= `#(result true ,val) (coers:to_float arg))
             val)
            ((?= `#(result true ,val) (coers:to_bool arg))
             val)
            ((?= `#(result true ,val) (coers:to_string arg))
             val)
            ('true arg)))))
```

## License

MIT

Copyright © 2020-2021, Erlang-Aided Enrichment Center

Copyright © 2016, Xavier van De Woestyne


[//]: ---Named-Links---

[logo]: priv/images/logo-v1.png
[logo-large]: priv/images/logo-v1.svg
[gh-actions-badge]: https://github.com/erlsci/coers/workflows/ci%2Fcd/badge.svg
[gh-actions]: https://github.com/erlsci/coers/actions
[erlang-badge]: https://img.shields.io/badge/erlang-19%20to%2023-blue.svg
[versions]: https://github.com/erlsci/coers/blob/master/.github/workflows/cicd.yml
[github-tag]: https://github.com/erlsci/coers/tags
[github-tag-badge]: https://img.shields.io/github/tag/erlsci/coers.svg