-module(gourd).
-export([load/0, load/1, load/2]).
-type maybe_binary() :: nomatch | binary().
-spec load() -> ok | {error, any()}.
load() ->
case application:get_application() of
{ok, App} ->
load(App);
undefined ->
{error, application_undefined}
end.
-spec load(atom()) -> ok | {error, any()}.
load(App) ->
DefaultPath =
filename:join(
code:priv_dir(App), <<"gourd.toml">>),
load(App, DefaultPath).
-spec load(atom(), binary()) -> ok | {error, any()}.
load(AppName, Path) ->
case tomerl:read_file(Path) of
{error, _Err} = E ->
E;
{ok, Data} ->
maps:foreach(fun(K, V) ->
application:set_env(AppName, binary_to_atom(K), replace_env_variable(V))
end,
Data),
ok
end.
-spec replace_env_variable(binary() | list() | map() | integer() | float()) ->
binary() | list() | map() | integer() | float().
replace_env_variable(S) when is_binary(S) ->
case env_variable(S) of
nomatch ->
S;
S2 ->
S2
end;
replace_env_variable(L) when is_list(L) ->
lists:map(fun replace_env_variable/1, L);
replace_env_variable(M) when is_map(M) ->
maps:map(fun replace_env_variable/2, M);
replace_env_variable(V) ->
V.
-spec replace_env_variable(any(), any()) -> any().
replace_env_variable(_K, V) ->
replace_env_variable(V).
-spec env_variable(binary()) -> maybe_binary().
env_variable(S) ->
case string:split(S, "${", all) of
[_] ->
nomatch;
L ->
list_to_binary(lists:map(fun handle_env_var/1, L))
end.
-spec handle_env_var(binary()) -> list() | binary().
handle_env_var(S) ->
case string:split(S, "}") of
[_] ->
S;
[ReplaceMe, KeepMe] ->
case gourd_util:os_getenv(binary_to_list(ReplaceMe)) of
false ->
S;
ReplaceText ->
[ReplaceText, KeepMe]
end
end.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
replace_env_variable_test() ->
meck:new(gourd_util),
meck:expect(gourd_util, os_getenv, fun(X) -> X end),
?assertEqual(<<"foobar">>, replace_env_variable(<<"${foobar}">>)),
?assertEqual(<<"barfoo">>, replace_env_variable(<<"barfoo">>)),
?assertEqual([<<"foobar">>, <<"stuff">>, <<"barfoo">>],
replace_env_variable([<<"${foobar}">>, <<"stuff">>, <<"${barfoo}">>])),
?assertEqual(#{<<"hello">> => <<"world">>},
replace_env_variable(#{<<"hello">> => <<"${world}">>})),
?assertEqual(<<"this is something and not something else">>,
replace_env_variable(<<"this is ${something} and not ${something} else">>)).
-endif.