# GenEnum
[](https://hex.pm/packages/coingaming/gen_enum/)
[](https://coingaming.hexdocs.pm/gen_enum/)
<img src="priv/gen_enum_logo.png" width="300"/>
Enumerations are common abstraction to express the limited set of values. In Elixir language enumeration values are usually expressed as atoms. **&GenEnum.defenum/1** macro generates compile/runtime utilities for given enumeration. Argument is
- non empty list of enum values (atoms), example: **[:LINUX, :MAC, :WINDOWS]**
- **OR** keyword list of options
- `:module` is Elixir module name (main module of enumeration definition) - can be `nil`/unset, example: **OS**
- `:database_type` is atom (alias for database type for given enum) - can be `nil`/unset, example: **:os**
- `:values` is non empty list of enum values (atoms), example: **[:LINUX, :MAC, :WINDOWS]**
## Installation
The package can be installed
by adding `gen_enum` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:gen_enum, "~> 0.3"}
]
end
```
## Example
Let's use **&GenEnum.defenum/1** macro and generate **OS** enumeration:
```elixir
require GenEnum
GenEnum.defenum(module: OS, database_type: :os, values: [:LINUX, :MAC, :WINDOWS])
```
Under **OS** module namespace this expression generates 4 additional modules:
### 1) OS.EctoEnum
Module contains standard [EctoEnum](https://github.com/gjaldon/ecto_enum) definition of given enumeration. Can be used for Ecto integration and database migrations (read EctoEnum manual). If `:database_type` is `nil`/unset then this module will not be generated.
### 2) OS.Items
Module contains **macro** wrappers for the every value of given enum. It's recommended to use macro wrappers instead of the atom literals to avoid runtime errors (for example, after refactoring)
```elixir
iex> require OS.Items
OS.Items
iex> OS.Items.linux
:LINUX
iex> OS.Items.mac
:MAC
```
### 3) OS.Meta
Module contains **@type t** definition for enumeration and **macro** helpers for guards, Ecto migrations and any other places where those macros are useful
```elixir
iex> require OS.Meta
OS.Meta
```
- **OS.Meta.t** definition is useful for **@type** and **@specs** notations
```elixir
defmodule Game do
require OS.Items
@spec choose_os(pos_integer) :: OS.Meta.t
def choose_os(min_fps) when (min_fps <= 30), do: OS.Items.linux
def choose_os(min_fps) when (min_fps <= 60), do: OS.Items.mac
def choose_os(_), do: OS.Items.windows
end
```
- **database_type** macro wrapper for database type of enum in Ecto migrations. If `:database_type` argument is `nil`/unset then this macro will not be generated.
```elixir
iex> OS.Meta.database_type
:os
```
- **values** list of all possible enumeration values
```elixir
iex> OS.Meta.values
[:LINUX, :MAC, :WINDOWS]
```
- **is_type** useful macro for guard expressions
```elixir
iex> OS.Meta.is_type OS.Items.mac
true
iex> OS.Meta.is_type :HELLO
false
```
### 4) OS.Utils
Module contains some helper **functions**
- **to_enum** and **to_enum!** are polymorphic functions to convert term into enumeration value (if it is possible)
```elixir
iex> OS.Utils.to_enum :mac
{:ok, :MAC}
iex> OS.Utils.to_enum "mac"
{:ok, :MAC}
iex> OS.Utils.to_enum "Mac\n"
{:ok, :MAC}
iex> OS.Utils.to_enum "MacOs"
{:error, "can not convert value to Elixir.OS, got invalid string from: \"MacOs\""}
iex> OS.Utils.to_enum! :mac
:MAC
iex> OS.Utils.to_enum! "mac"
:MAC
iex> OS.Utils.to_enum! "Mac\n"
:MAC
iex> OS.Utils.to_enum! "MacOs"
** (RuntimeError) can not convert value to Elixir.OS, got invalid string from: "MacOs"
iex:4: OS.Utils.to_enum!/1
iex> OS.Utils.values
[:LINUX, :MAC, :WINDOWS]
```