README.md

[![Hex pm](https://img.shields.io/hexpm/v/kaur.svg)](https://hex.pm/packages/kaur)
[![Build
Status](https://travis-ci.org/fewlinesco/kaur.svg?branch=master)](https://travis-ci.org/fewlinesco/kaur)
[![Inline docs](http://inch-ci.org/github/fewlinesco/kaur.svg)](http://inch-ci.org/github/fewlinesco/kaur)

# Kaur

> Pronounced |kɔː|

A bunch of helper functions to ease the development of your applications.

## Installation

```elixir
def deps do
  [{:kaur, "~> 1.1.0"}]
end
```

## Usage

### `:ok`, `:error` tuples A.K.A `Result` tuples

`{:ok, value}` and `{:error, reason}` is a common pattern in Erlang and Elixir. The `Kaur.Result` module adds functions
to help deal with these values without getting out of your pipeline.

You can have a look at [the documentation](https://hexdocs.pm/kaur) to know what's available or you can take a look at
[how we use it in Kaur itself](https://github.com/fewlinesco/kaur/blob/master/lib/kaur/environment.ex#L61..L65).

Just below you will find a small example of how your code could look like using `Kaur.Result`. In this example we try
to determine if a person can rent a car. People can rent a car if they are between 21 and 99 year old and have a bonus
greater than 0.8.

#### Example without Kaur

```elixir
defmodule Person do
  defstruct [:name, :age, :bonus]
end

defmodule MyModule do
  def rent_a_car(person = %Person{}) do
    with {:ok, person1} <- validate_age(person),
         {:ok, person2} <- validate_bonus(person1)
    do
      {:ok, display_driving_message(person2)}
    else
      {:error, reason} ->
        {:error, handle_error(person, reason)}
    end
  end

  defp display_driving_message(person) do
    "Welcome #{person.name}, you can rent a car"
  end

  defp handle_error(person, {:bonus, expected_bonus}) do
    "Sorry #{person.name}, but you need a bonus of #{expected_bonus} but have only #{person.bonus}."
  end
  defp handle_error(person, {:license_type, expected_license}) do
    "Sorry #{person.name}, but you need a #{expected_license} license but have a #{person.license_type} license."
  end
  defp handle_error(person, {:too_old, maximum_age}) do
    "Sorry #{person.name}, but you need to be younger than #{maximum_age}"
  end
  defp handle_error(person, {:too_young, minimum_age}) do
    "Sorry #{person.name}, but you need to be older than #{minimum_age}"
  end

  defp validate_age(%{age: age}) when age > 99, do: {:error, {:too_old, 99}}
  defp validate_age(%{age: age}) when age < 21, do: {:error, {:too_young, 21}}
  defp validate_age(person), do: {:ok, person}

  defp validate_bonus(person = %{bonus: bonus}) when bonus > 0.8, do: {:ok, person}
  defp validate_bonus(_person), do: {:error, {:bonus, 0.8}}
end
```

#### Example using Kaur

```elixir
defmodule MyModule do
  alias Kaur.Result

  def rent_a_car(person = %Person{}) do
    person
    |> validate_age()
    |> Result.and_then(&validate_bonus/1)
    |> Result.map(&display_driving_message/1)
    |> Result.map_error(&handle_error(person, &1))
  end

  # ... Same business logic as before
end
```

Execution

```
iex> MyModule.rent_a_car %Person{name: "Jane", age: 42, bonus: 0.9}
{:ok, "Welcome Jane, you can rent a car"}

iex> MyModule.rent_a_car %Person{name: "John", age: 42, bonus: 0.5}
{:error, Sorry John, but you need a bonus of 0.8 but have only 0.5."}

iex> MyModule.rent_a_car %Person{name: "Robert", age: 11, bonus: 0.9}
{:error, "Sorry Robert, but you need to be older than 21"}

iex> MyModule.rent_a_car %Person{name: "Mary", age: 122, bonus: 0.8}
{:error, "Sorry Mary, but you need to be younger than 99"}
```

### Security

A small module which can generate API keys:

```
iex>  Kaur.Secure.generate_api_key
"UtiE9qs-7FbJs8OIt5nCiw=="

iex> Kaur.Secure.generate_api_key
"BTxaJNrA_QsAhWSLKOMj8A==
```

### Environment Variables

We love environment variables but, unfortunately, Elixir configuration doesn't play well with them. If we use
`System.get_env` in `config/*.exs` files, they will be evaluated at compile time.

We would really want to have our configuration based on environment variables. A common pattern is to use
`{:system, "ENVIRONMENT_VARIABLE"}` wherever we need a value to be fetched at runtime. That's common but, unfortunately,
that's not built-in so we have to handle this behaviour ourselves.

`Kaur.Environment` abstracts how we read application configuration so it can automatically handle the loading of
environment variables when it's needed.

```
# config/config.exs
config :my_app, :my_key, {:system, "MY_KEY"}
config :my_app, :my_key2, "MY STATIC VALUE"

iex> Kaur.Environment.read(:my_app, :my_key)
{:ok, "VALUE DYNAMICALLY LOADED"}

iex> Kaur.Environment.read(:my_app, :my_key2)
{:ok, "MY STATIC VALUE"}

iex> Kaur.Environment.read(:my_app, :something_else)
{:error, :no_value}
```

## Code of Conduct

By participating in this project, you agree to abide by its [CODE OF CONDUCT](CODE_OF_CONDUCT.md).

## Contributing

You can see the specific [CONTRIBUTING](CONTRIBUTING.md) guide.

## License

Kaur is released under [The MIT License (MIT)](https://opensource.org/licenses/MIT).