-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.