# `SimpleEnum`
[🔗](https://github.com/ImNotAVirus/simple_enum/blob/v1.0.0/lib/simple_enum.ex#L1)

SimpleEnum is a simple library that implements Enumerations in Elixir.

An Enumeration is a user-defined type that consists of a set of several named
constants that are known as Enumerators.  
The purpose of SimpleEnum is to provide an equivalent for the Elixir language.

SimpleEnum is:

- **fast**: being based on a macro system, access to the Enum will be resolved
at compile time when it is possible (see. [Fast vs Slow access](guides/fast_vs_slow_access.md))
- **simple**: the use of the library has been designed to be as simple as possible
for a developer to use. In addition to providing Enums, it automatically defines their
[types](guides/enum_types.md), [helpers and guards](guides/helpers.md).

## Installation

The package can be installed by adding `simple_enum` to your list of dependencies
in `mix.exs`:

```elixir
# my_app/mix.exs
def deps do
  [
    {:simple_enum, "~> 1.0"}
  ]
end
```

Then, update your dependencies:

```sh-session
$ mix deps.get
```

Optionally, if you use the formatter, add this line to `.formatter.exs`:

```elixir
# my_app/.formatter.exs
[
  import_deps: [:simple_enum]
]
```

## Basic Usage

``` elixir
iex> defmodule MyEnums do
...>   import SimpleEnum, only: [defenum: 2]
...>
...>   defenum :color, [:blue, :green, :red]
...>   defenum :day, monday: "MON", tuesday: "TUE", wednesday: "WED"
...> end

iex> require MyEnums

iex> MyEnums.color(:blue)
0
iex> MyEnums.color(0)
:blue
iex> MyEnums.day(:monday)
"MON"
iex> MyEnums.day("MON")
:monday
iex> MyEnums.day("MONN")
** (ArgumentError) invalid value "MONN" for Enum MyEnums.day/1. Expected one of [:monday, :tuesday, :wednesday, "MON", "TUE", "WED"]

iex> MyEnums.color_keys()
[:blue, :green, :red]
iex> MyEnums.color_values()
[0, 1, 2]
iex> MyEnums.color_enumerators()
[blue: 0, green: 1, red: 2]

iex> MyEnums.is_color(:blue)
true
iex> MyEnums.is_color(:nope)
false
iex> MyEnums.is_color_key(:blue)
true
iex> MyEnums.is_color_key(0)
false
iex> MyEnums.is_color_value(0)
true
iex> MyEnums.is_color_value(:blue)
false
```

# `defenum`
*macro* 

Defines a set of macros to create and access Enumerations.

The name of the generated macros and types will be `name` (which has to be an atom).  
The `enumerators` argument has to be either:

 * A keyword list composed of strings (to create a string-based Enumeration)
 * A keyword list composed of integers (to create an integer-based Enumeration)
 * A list of atoms (to create an integer-based Enumeration)

For more details about [string-based Enumeration](guides/string_based_enum.md) and
[integer-based Enumeration](guides/integer_based_enum.md), you can check the
corresponding guide.

## Options

 * `:allow_duplicate_keys` - when `true`, allows duplicate keys
   in the enumerators list. Defaults to `false`.
   Note: when duplicates exist, `name/1` and `name/2` will return
   the value of the first match (standard Keyword list behavior).
   `name_keys/0` returns deduplicated keys.
 * `:allow_duplicate_values` - when `true`, allows duplicate values
   in the enumerators list. Defaults to `false`.
   Note: when duplicates exist, `name/1` will return the first
   matching key for a given value.
   `name_values/0` returns deduplicated values.

The following macros are generated:

 * `name/1` for bidirectional key/value lookup
 * `name/2` to access a key, a value or its tuple by specifying the return type
 * `name_keys/0` to get the list of all keys
 * `name_values/0` to get the list of all values
 * `name_enumerators/0` to get the keyword list of all enumerators
 * `is_name/1` guard to check if a value is a valid key or value
 * `is_name_key/1` guard to check if a value is a valid key
 * `is_name_value/1` guard to check if a value is a valid value

The following types are generated:

 * `@type enum :: :key1 | :key2 | :value1 | :value2`
 * `@type enum_keys :: :key1 | :key2`
 * `@type enum_values :: :value1 | :value2`

For more details about [types](guides/enum_types.md) you can also check the
corresponding guide.

All these macros are public macros (as defined by `defmacro/2`).

See the "Examples" section for examples on how to use these macros.

## Examples

    defmodule MyApp.Enums do
      import SimpleEnum, only: [defenum: 2]
      defenum :color, [:blue, :green, :red]
    end

In the example above, a set of macros named `color` but with different arities
will be defined to manipulate the underlying Enumeration.

    # Import the module to make the color macros locally available
    import MyApp.Enums
    
    # Bidirectional key/value lookup
    color(:blue)    #=> 0
    color(:green)   #=> 1
    color(:red)     #=> 2
    color(0)        #=> :blue
    color(1)        #=> :green
    color(2)        #=> :red
    
    # Lookup with explicit return type
    color(:red, :key)   #=> :red
    color(2, :key)      #=> :red
    color(:red, :value) #=> 2
    color(2, :value)    #=> 2
    color(:red, :tuple) #=> {:red, 2}
    color(2, :tuple)    #=> {:red, 2}

Helpers allow inspecting the Enumeration:

    color_keys()         #=> [:blue, :green, :red]
    color_values()       #=> [0, 1, 2]
    color_enumerators()  #=> [blue: 0, green: 1, red: 2]

Guards are also generated to check membership:

    is_color(:blue) #=> true
    is_color(0)     #=> true
    is_color(:nope) #=> false

    is_color_key(:blue) #=> true
    is_color_key(0)     #=> false

    is_color_value(0)     #=> true
    is_color_value(:blue) #=> false

---

*Consult [api-reference.md](api-reference.md) for complete listing*
