Current section
Files
Jump to
Current section
Files
lib/enver.ex
defmodule Enver do
@moduledoc """
Documentation for Enver.
"""
alias Enver.AtomParser
alias Enver.BooleanParser
alias Enver.BinaryParser
alias Enver.CharlistParser
alias Enver.FloatParser
alias Enver.IntegerParser
@type bof :: map()
@type fetch_app_env :: (:error, :env -> {:ok, map()} | :error)
@type get_sys_env :: (() -> map())
@type invalid :: {:error, String.t()}
@type key :: String.t()
@type parse_opts :: map()
@type parser :: (val(), map() -> valid() | invalid())
@type proto_val() :: String.t()
@type type :: atom()
@type val :: String.t()
@type valid ::
AtomParser.valid()
| BooleanParser.valid()
| BinaryParser.valid()
| CharlistParser.valid()
| FloatParser.valid()
| IntegerParser.valid()
#######
# API #
#######
@spec fetch_env(key(), map()) :: valid() | invalid()
def fetch_env(key, bof \\ bag_of_functions()) do
with {:ok, proto_val} <- fetch_proto_val(key, bof.get_sys_env),
{:ok, parse_opts} <- fetch_parse_opts(key, bof.fetch_app_env),
{:ok, parser} <- fetch_parser(parse_opts.type),
{:ok, _} = valid <- parser.(proto_val, parse_opts) do
valid
else
{:error, _} = invalid ->
invalid
end
end
################
# Undocumented #
################
@doc false
@type bag_of_functions() :: bof()
def bag_of_functions() do
%{
fetch_app_env: &Application.fetch_env/2,
get_sys_env: &System.get_env/0
}
end
@doc false
@spec fetch_parse_opts(key(), fetch_app_env()) :: {:ok, parse_opts()} | invalid()
def fetch_parse_opts(key, fetch_app_env) do
case fetch_app_env.(:enver, :fetch_env) do
{:ok, %{^key => %{type: _} = val}} ->
{:ok, val}
_ ->
{:error, "No parse options for key: #{inspect(key)}"}
end
end
@doc false
@spec fetch_parser(type()) :: {:ok, parser()} | invalid()
def fetch_parser(:atom), do: {:ok, &AtomParser.parse/2}
def fetch_parser(:boolean), do: {:ok, &BooleanParser.parse/2}
def fetch_parser(:binary), do: {:ok, &BinaryParser.parse/2}
def fetch_parser(:charlist), do: {:ok, &CharlistParser.parse/2}
def fetch_parser(:float), do: {:ok, &FloatParser.parse/2}
def fetch_parser(:integer), do: {:ok, &IntegerParser.parse/2}
def fetch_parser(type), do: {:error, "No parser for type: #{inspect(type)}"}
@doc false
@spec fetch_proto_val(key(), get_sys_env()) :: {:ok, proto_val()} | invalid()
def fetch_proto_val(key, get_sys_env) do
case get_sys_env.() do
%{^key => val} ->
{:ok, val}
_ ->
{:error, "No environment variable for key: #{inspect(key)}"}
end
end
end