Pronounced |kɔː|
A bunch of helper functions to ease the development of your applications.
def deps do
[{:kaur, "~> 1.1.0"}]
end
{: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 to know what's available or you can take a look at how we use it in Kaur itself.
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.
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
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"}
A small module which can generate API keys:
iex> Kaur.Secure.generate_api_key
"UtiE9qs-7FbJs8OIt5nCiw=="
iex> Kaur.Secure.generate_api_key
"BTxaJNrA_QsAhWSLKOMj8A==
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}
By participating in this project, you agree to abide by its CODE OF CONDUCT.
You can see the specific CONTRIBUTING guide.
Kaur is released under The MIT License (MIT).