# Constantine

Type-safe macro to define constants in Elixir language. All expressions and checks are evaluated in compile time.

# Usage

How many times you suffered from runtime errors when your application depends on external system env, configs, files? Forgot to configure env variables before production build and your application crashed in a random unpredictable runtime moment? Compiler is your friend, so let him to check your env. Forget runtime errors because missing or wrong configuration! Define constants like a ninja using `const/2` and `constp/2` macro. The first argument is type and the second is module attribute / macro expression what produces value of given type. Below you can find list of supported types. **Empty string and nil are not allowed as const.**

{:enum, values = [_|_]}

# Example

defmodule API do

  import Constantine, only: [const: 2]
  const :string,      @host     System.get_env("API_HOST")
  const :pos_integer, @port     System.get_env("API_PORT") |> String.to_integer
  const :string,      @trx_url  "http://#{@host}:#{@port}/trx"
  const :binary,      @privkey  "#{:code.priv_dir(:api)}/privkey.pem" |>!

  def trx(params = %{}) do
    request = Poison.encode!(params)
    %HTTPoison.Response{body: response} =!(@trx_url, request, ["X-Signature": sign(request)])

  defp sign(data) do
    :crypto.sign(:rsa, :sha256, data, @privkey)


# Public constants

Also constants can be defined using normal `macro` semantics. In this case they will be available outside of module.

defmodule MyCrypto do

  import Constantine, only: [const: 2]
  const :binary, privkey "#{:code.priv_dir(:my_crypto)}/privkey.pem" |>!

  defp sign(data) do
    :crypto.sign(:rsa, :sha256, data, privkey())

defmodule OuterWorld do

  require MyCrypto

  def work(params = %{}) do
    |> do_work!(params)