-module(erlang_ds_builder). -export([ build/0, default_updaters/0, default_type_modules/0 ]). default_updaters() -> [ {boolize, {ds_util, to_bool}}, {atomize, {ds_util, to_atom}} ]. default_type_modules() -> [ erlang_ds_dict ]. build() -> Updaters0 = case application:get_env(erlang_ds, updaters) of {ok, U} -> U; undefined -> U = default_updaters(), application:set_env(erlang_ds, updaters, U), logger:info("Erlang DS: No updaters defined in the application config.~nUsing the default: ~p",[U]), U end, TypeModules0 = case application:get_env(erlang_ds, type_handlers) of {ok, T} -> verify_type_handlers(T); undefined -> T = default_type_modules(), application:set_env(erlang_ds, type_handlers, T), logger:info("Erlang DS: No type_handlers defined in the application config.~nUsing the default: ~p",[T]), T end, Updaters = ds_util:normalize_updaters(Updaters0), TypeModules = verify_type_handlers(TypeModules0), logger:info("Erlang DS: Generating and building erlang_ds_lookup..."), {Time, _} = timer:tc(fun() -> build(Updaters, TypeModules) end), logger:info("Erlang: DS: erlang_ds_lookup built in ~p ms", [Time div 1000]). verify_type_handlers(Ts) -> Good = lists:all(fun(T) -> is_atom(T) end, Ts), case Good of true -> Ts; false -> error({erlang_ds, {invalid_type_handlers_from_config, Ts}}) end. build(Updaters, TypeModules) -> Header = header(), UpdaterBody = updater_body(Updaters), TypeBody = type_body(TypeModules), Modtext = lists:flatten([Header, "\n", UpdaterBody, "\n", TypeBody]), logger:info("Erlang DS Generated Module:~n~s",[Modtext]), Forms = merl:quote(Modtext), Res = merl:compile_and_load(Forms), case Res of {ok, _} -> ok; error -> logger:error("Erlang DS: Unable to compile the lookup module (erlang_ds_lookup).~n~s~n",[Modtext]) end. header() -> "-module(erlang_ds_lookup). -export([ updater/1, type_handlers/0 ]).\n". type_body(Mods) -> io_lib:format("type_handlers() -> ~p.", [Mods]). updater_body([]) -> "updater(Updater) -> error({erlang_ds_lookup, {unregistered_updater, Updater}}).\n"; updater_body([H|T]) -> UpdaterClause = build_updater_clause(H), [UpdaterClause | updater_body(T)]. build_updater_clause({{Key, 0}, {Mod, Fun, 1}}) -> io_lib:format("updater(~p) -> fun(Val) -> ~p:~p(Val) end;\n", [Key, Mod, Fun]); build_updater_clause({{Key, KeyArgs}, {Mod, Fun, NumArgs}}) when KeyArgs==NumArgs-1 -> Args0 = lists:map(fun(X) -> "Arg" ++ integer_to_list(X) end, lists:seq(1, KeyArgs)), Args = string:join(Args0, ", "), io_lib:format("updater({~p, ~s}) -> fun(Val) -> ~p:~p(~s, Val) end;\n", [Key, Args, Mod, Fun, Args]).