DeferredConfig v0.1.0 DeferredConfig
Seamlessly add runtime config to your library, with the
“system tuples” or the {m,f,a}
patterns.
Seamlessly?
In your application startup, add the following line:
defmodule Mine.Application do
def start(_type, _args) do
DeferredConfig.populate(:mine) # <-- this one
...
end
end
Where :mine
is the name of your OTP app.
Now you and users of your app or lib can configure as follows, and it’ll work — regardless of if they’re running it from iex, or a release with env vars set:
config :mine,
# string from env var, or `nil` if missing.
port1: {:system, "PORT"},
# string from env var |> integer; `nil` if missing.
port2: {:system, "PORT", {String, :to_integer}},
# string from env var, or "4000" as default.
port3: {:system, "PORT", "4000"},
# converts env var to integer, or 4000 as default.
port4: {:system, "PORT", 4000, {String, :to_integer}}
Accessing config does not change.
Since you can use arbitrary transformation functions, you can do advanced transformations if you need to:
# lib/mine/ip.ex
defmodule Mine.Ip do
@doc ":inet_res uses `{0,0,0,0}` for ipv4 addrs"
def str2ip(str) do
case :inet_parse:address(str) do
{:ok, ip = {_, _, _, _}} -> ip
{:error, _} -> nil
end
end
end
# config.exs
config :my_app,
port: {:system, "MY_IP", {127,0,0,1}, {Mine.Ip, :str2ip}
See README.md
for explanation of rationale.
TL;DR: REPLACE_OS_VARS
is string-only and release-only,
and {:system, ...}
support among libraries is spotty
and easy to get wrong in ways that bite your users
come release time. This library tries to make it easier
to do the right thing with 1 LOC. Other libraries add special
config files and/or special config accessors, which
is more complex than necessary.
Summary
Functions
Application.put_env/3
for config kvlist
Default recognize/transform pairs used in populating deferred config. Currently r/t pairs for :system tuples and :apply mfa tuples
Return transformed copy of recognized system tuples: gets from env, optionally converts it, with optional default if env returned nothing
Populate deferred values in an app’s config.
Best run during Application.start/2
Recognize mfa tuple, like {:apply, {File, :read!, ["name"]}}
.
Returns true
on recognition, false
otherwise
Recognizer for system tuples of forms:
{:system, "VAR"}
{:system, "VAR", default_value}
{:system, "VAR", {String, :to_integer}}
{:system, "VAR", default_value, {String, :to_integer}}
Returnstrue
when it matches one,false
otherwise
Given a config kvlist, and an enumerable of
{&recognize/1, &transform/1}
functions,
returns a kvlist with the values transformed
via replacing walk
Return evaluated {:apply, {mod, fun, args}}
tuple
Functions
Application.put_env/3
for config kvlist
Default recognize/transform pairs used in populating deferred config. Currently r/t pairs for :system tuples and :apply mfa tuples.
Return transformed copy of recognized system tuples: gets from env, optionally converts it, with optional default if env returned nothing.
Populate deferred values in an app’s config.
Best run during Application.start/2
.
By default attempts to populate the common
{:system, "VAR"}
tuple form for getting values from
System.get_env/1
, and the more
general {:apply, {Mod, fun, [args]}}
form as well.
System tuples support optional
defaults and conversion functions, see
Peerage.DeferredConfig.get_system_tuple/1
.
Can be extended by passing in a different
enumerable of {&recognizer/1, &transformer/1}
functions.
Recognize mfa tuple, like {:apply, {File, :read!, ["name"]}}
.
Returns true
on recognition, false
otherwise.
Recognizer for system tuples of forms:
{:system, "VAR"}
{:system, "VAR", default_value}
{:system, "VAR", {String, :to_integer}}
{:system, "VAR", default_value, {String, :to_integer}}
Returnstrue
when it matches one,false
otherwise.
Given a config kvlist, and an enumerable of
{&recognize/1, &transform/1}
functions,
returns a kvlist with the values transformed
via replacing walk.