src/ds_util.erl

-module(ds_util).

-export([
    to_bool/1,
    to_atom/1,
    normalize_updater_key/1,
    normalize_updater_pair/2,
    normalize_updaters/1
]).

to_bool(V) ->
    if
        V=="false";
        V==<<"false">>;
        V==false;
        V==0;
        V=="0";
        V==undefined;
        V=="" -> false;
        V == <<>> -> false;
        true -> true
    end.

to_atom(V) when is_list(V) -> list_to_atom(V);
to_atom(V) when is_atom(V) -> V;
to_atom(V) when is_binary(V) -> list_to_atom(binary_to_list(V));
to_atom(V) when is_integer(V) -> list_to_atom(integer_to_list(V));
to_atom(V) -> throw({cannot_convert_to_atom,V}).

normalize_updater_key(Key) when is_atom(Key) ->
    {Key, 0};
normalize_updater_key({Key, Int}) when is_atom(Key), is_integer(Int), Int>=0 ->
    {Key, Int};
normalize_updater_key(Key) ->
    error({invalid_updater_key, Key}).

normalize_updaters(Updaters) ->
    lists:map(fun({Key, MFA}) ->
        ds_util:normalize_updater_pair(Key, MFA)
    end, Updaters).

normalize_updater_pair({Key, 0}, {Mod, Fun}) when is_atom(Key), is_atom(Mod), is_atom(Fun) ->
    {{Key, 0}, {Mod, Fun, 1}};
normalize_updater_pair(Key, {Mod, Fun, 1}) when is_atom(Key), is_atom(Mod), is_atom(Fun) ->
    {{Key, 0}, {Mod, Fun, 1}};
normalize_updater_pair(Key, {Mod, Fun}) when is_atom(Key), is_atom(Mod), is_atom(Fun) ->
    {{Key, 0}, {Mod, Fun, 1}};

normalize_updater_pair(Key={KeyTag, KeyArgs}, MFA = {Mod, Fun, Args})
  when is_atom(KeyTag), is_atom(Mod), is_atom(Fun), is_integer(Args), KeyArgs >=0, KeyArgs==Args-1 ->
    {Key, MFA};
normalize_updater_pair({Key, KeyArgs}, MFA = {_, _, Args}) when KeyArgs =/= Args -1 ->
    Reason = fmt("KeyArgs (~p) needs to be exactly 1 less than Args (~p) in the MFA tuple", [KeyArgs, Args]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key, MFA={Mod, _, _}) when not(is_atom(Mod)) ->
    Reason = fmt("Mod (~p) must be an atom", [Mod]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key, MFA={_, Fun, _}) when not(is_atom(Fun)) ->
    Reason = fmt("Fun (~p) must be an atom", [Fun]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key, MFA={_, _, Args}) when not(is_integer(Args)) ->
    Reason = fmt("Args (element 3 from the MFA tuple) (~p) must be an integer greater than or equal to 1", [Args]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key={KeyTag, _}, MFA) when not(is_atom(KeyTag)) ->
    Reason = fmt("KeyTag (~p) must be an atom", [KeyTag]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key={_, KeyArgs}, MFA) when not(is_integer(KeyArgs)) ->
    Reason = fmt("KeyArgs (~p) must be an integer", [KeyArgs]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key={_KeyTag, KeyArgs}, MFA={Mod, Fun}) ->
    Reason = fmt("If the KeyArgs (~p) part of the Key (~p) is greater than 0, then MFA (~p) must be provided explicitly as a 3-tuple, specifying the arity (number of arguments) of the function call. Expected MFA value here is: {~p, ~p, ~p}", [KeyArgs, Key, MFA, Mod, Fun, KeyArgs+1]),
    invalid_update_pair(Key, MFA, Reason);
normalize_updater_pair(Key, MFA) ->
    Reason = "There is something wrong with the formatting of your MFA or your Key. Please review the specs for register_updater/2",
    invalid_update_pair(Key, MFA, Reason).

invalid_update_pair(Key, MFA, Reason) ->
    error({invalid_key_and_mfa_combo, [{key, Key}, {mfa, MFA}, {description, Reason}]}).

fmt(Msg, Args) ->
    lists:flatten(io_lib:format(Msg, Args)).