Skip to main content

README.md

# Defconst

[![CI](https://github.com/aram356/defconst/actions/workflows/ci.yml/badge.svg)](https://github.com/aram356/defconst/actions/workflows/ci.yml)
[![Hex.pm](https://img.shields.io/hexpm/v/defconst.svg)](https://hex.pm/packages/defconst)
[![Docs](https://img.shields.io/badge/hex-docs-blue.svg)](https://hexdocs.pm/defconst)
[![License](https://img.shields.io/hexpm/l/defconst.svg)](LICENSE)

This package provides `defconst` macro for defining a single constant and `defenum` macro for defining a list of enumerated constant values. The defined constants and enumerated constants are referencable in any expression as well as in guards statements.

Documentation is published at [hexdocs.pm/defconst](https://hexdocs.pm/defconst).

## Requirements

Elixir `~> 1.15` (tested on 1.15–1.19 / OTP 26–28). The library has no runtime dependencies.

## Installation

Defconst can be installed by adding `defconst` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:defconst, "~> 0.4.0"}
  ]
end
```

## Usage

### defconst

Define `ConstType1` module with constants

```elixir
defmodule ConstType1 do
  use Defconst

  defconst :one, 1
  defconst :two, 2
end
```

Use `ConstType1` module

```elixir
defmodule ConstUse1 do
  require ConstType1

  def const_value(x) do
    case x do
      ConstType1.one -> "one"
      ConstType1.two -> "two"
    end
  end

  def const_guard(x) when x == ConstType1.two do
    "two"
  end
end
```

### Introspection

Modules that `use Defconst` also expose:

- `constants/0` — all constants as `[{name, value}, ...]`
- `value_of/1` — the value for a constant name
- `constant_of/1` — the constant name for a value (a list if several share the value, `nil` if none)

```elixir
ConstType1.constants()        #=> [{:one, 1}, {:two, 2}]
ConstType1.value_of(:one)     #=> 1
ConstType1.constant_of(2)     #=> :two
```

### defenum

Define `EnumType1` module with default values

```elixir
defmodule EnumType1 do
  use Defconst

  defenum [
    :zero,
    :one,
    :two
  ]
end

```

Use `EnumType1` module

```elixir
defmodule EnumUse1 do
  require EnumType1

  def enum_value(x) do
    case x do
      EnumType1.zero -> "zero"
      EnumType1.one -> "one"
      EnumType1.two -> "two"
      _ -> "unknown"
    end
  end

  def enum_guard(x) when x == EnumType1.two do
    "two"
  end
end
```

Define `EnumType2` with specific values

```elixir
defmodule EnumType2 do
  use Defconst

  defenum [
    {:one, 1},
    {:nine, 9},
    {:ten, "ten"}
  ]
end
```

Define `EnumType3` using `EnumGenerator3`

```elixir
defmodule EnumGenerator3 do
  @behaviour Defconst.Enum.Generator

  def next_value(_constant_name, previous_value) do
    previous_value <> previous_value
  end
end
```

```elixir
defmodule TestEnumType3 do
  use Defconst

  defenum [
    {:one, "one"},
    {:nine, "nine"},
    :ten
  ],
  EnumGenerator3
end
```

## Development

```sh
mix deps.get
mix test
mix format --check-formatted
mix credo --strict
mix dialyzer
mix docs
```

The toolchain is pinned in `.tool-versions` (Elixir 1.19.5 / OTP 28). CI runs the test suite
across Elixir 1.15–1.19 / OTP 26–28, a formatting check, and a quality job
(`mix credo --strict` + `mix dialyzer`).

## Releasing

Releases are published to Hex automatically by CI
([`.github/workflows/release.yml`](.github/workflows/release.yml)):

1. Bump `@version` in `mix.exs` and update [`CHANGELOG.md`](CHANGELOG.md); merge to `main`.
2. Sync and confirm the merged `main` carries the target version:
   ```sh
   git fetch origin --tags
   git show origin/main:mix.exs | grep '@version'   # expect the version you're releasing
   ```
3. Create the tag **on the released commit** and push it (don't let the Release UI auto-create
   the tag — that can place it on the wrong commit):
   ```sh
   git tag vX.Y.Z origin/main
   git push origin vX.Y.Z
   ```
4. Create the GitHub Release from that existing tag:
   ```sh
   gh release create vX.Y.Z --verify-tag --title "vX.Y.Z" --notes "See CHANGELOG.md"
   ```
5. CI (`release.yml`) re-verifies the tag matches `mix.exs` and runs `mix hex.publish`
   (package + docs).

This requires a `HEX_API_KEY` secret (a write-scoped Hex key) configured in the repository's
Actions secrets.

## License

Apache-2.0 — see [LICENSE](LICENSE).