Convert qdate_srv to be an ETS server (dialyzer doesn't like using tuples as keys for application:set_env)

This commit is contained in:
Jesse Gumm 2021-06-30 14:44:45 -05:00
parent 3d72448491
commit bbfef69d2e
5 changed files with 115 additions and 18 deletions

View file

@ -1,7 +1,7 @@
{application, qdate, {application, qdate,
[ [
{description, "Simple Date and Timezone handling for Erlang"}, {description, "Simple Date and Timezone handling for Erlang"},
{vsn, "0.6.0"}, {vsn, "0.7.0"},
{registered, []}, {registered, []},
{applications, [ {applications, [
kernel, kernel,
@ -9,9 +9,10 @@
erlware_commons, erlware_commons,
stdlib stdlib
]}, ]},
{modules, [qdate, qdate_srv]}, {modules, [qdate, qdate_srv, qdate_sup, qdate_app]},
{env, []}, {env, []},
{maintainers, ["Jesse Gumm"]}, {maintainers, ["Jesse Gumm"]},
{licenses, ["MIT"]}, {licenses, ["MIT"]},
{mod, {qdate_app, []}},
{links, [{"Github", "https://github.com/choptastic/qdate"}]} {links, [{"Github", "https://github.com/choptastic/qdate"}]}
]}. ]}.

View file

@ -156,7 +156,7 @@
-define(else, true). -define(else, true).
start() -> start() ->
application:load(qdate). application:ensure_all_started(qdate).
stop() -> stop() ->
ok. ok.
@ -1457,7 +1457,7 @@ preserve_ms_false_tests(_) ->
]}. ]}.
start_test() -> start_test() ->
application:start(qdate), qdate:start(),
set_timezone(?SELF_TZ), set_timezone(?SELF_TZ),
set_timezone(?SITE_KEY,?SITE_TZ), set_timezone(?SITE_KEY,?SITE_TZ),
set_timezone(?USER_KEY,?USER_TZ), set_timezone(?USER_KEY,?USER_TZ),

15
src/qdate_app.erl Normal file
View file

@ -0,0 +1,15 @@
-module(qdate_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
qdate_sup:start_link().
stop(_State) ->
ok.

View file

@ -1,12 +1,9 @@
% vim: ts=4 sw=4 et % vim: ts=4 sw=4 et
% Copyright (c) 2013-2015 Jesse Gumm % Copyright (c) 2013-2021 Jesse Gumm
% See LICENSE for licensing information. % See LICENSE for licensing information.
%
% NOTE: You'll probably notice that this isn't *actually* a server. It *used*
% to be a server, but is now instead just where we interact with the qdate
% application environment. Anyway, sorry for the confusion.
-module(qdate_srv). -module(qdate_srv).
-behaviour(gen_server).
-export([ -export([
set_timezone/1, set_timezone/1,
@ -28,6 +25,19 @@
get_formats/0 get_formats/0
]). ]).
%% API
-export([start_link/0]).
%% gen_server callbacks
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
%% Simple wrappers for unique keys %% Simple wrappers for unique keys
-define(BASETAG, qdate_var). -define(BASETAG, qdate_var).
-define(KEY(Name), {?BASETAG, Name}). -define(KEY(Name), {?BASETAG, Name}).
@ -39,6 +49,42 @@
-define(FORMATTAG, qdate_format). -define(FORMATTAG, qdate_format).
-define(FORMATKEY(Name), {?FORMATTAG, Name}). -define(FORMATKEY(Name), {?FORMATTAG, Name}).
-define(SERVER, ?MODULE).
-define(TABLE, ?MODULE).
-record(state, {}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
error_logger:info_msg("Creating qdate ETS Table: ~p",[?TABLE]),
?TABLE = ets:new(?TABLE, [public, {read_concurrency, true}, named_table]),
{ok, #state{}}.
handle_call({set, Key, Val}, _From, State) ->
ets:insert(?TABLE, {Key, Val}),
{reply, ok, State};
handle_call({unset, Key}, _From, State) ->
ets:delete(?TABLE, Key),
{reply, ok, State};
handle_call(_, _From, State) ->
{reply, invalid_request, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% PUBLIC API FUNCTIONS %% PUBLIC API FUNCTIONS
set_timezone(TZ) -> set_timezone(TZ) ->
@ -91,25 +137,22 @@ get_formats() ->
%% App Vars %% App Vars
set_env(Key, Val) -> set_env(Key, Val) ->
application:set_env(qdate, ?KEY(Key), Val). gen_server:call(?SERVER, {set, ?KEY(Key), Val}).
get_env(Key) -> get_env(Key) ->
get_env(Key, undefined). get_env(Key, undefined).
get_env(Key, Default) -> get_env(Key, Default) ->
%% Soon, this can just be replaced with application:get_env/3 case ets:lookup(?TABLE, ?KEY(Key)) of
%% which was introduced in R16B. [{__Key, Val}] -> Val;
case application:get_env(qdate, ?KEY(Key)) of [] -> Default
undefined -> Default;
{ok, Val} -> Val
end. end.
unset_env(Key) -> unset_env(Key) ->
application:unset_env(qdate, ?KEY(Key)). gen_server:call(?SERVER, {unset, ?KEY(Key)}).
get_all_env(FilterTag) -> get_all_env(FilterTag) ->
All = application:get_all_env(qdate), All = ets:tab2list(?TABLE),
%% Maybe this is a little nasty.
[{Key, V} || {{?BASETAG, {Tag, Key}}, V} <- All, Tag==FilterTag]. [{Key, V} || {{?BASETAG, {Tag, Key}}, V} <- All, Tag==FilterTag].
%% ProcDic Vars %% ProcDic Vars
@ -123,3 +166,9 @@ put_pd(Key, Val) ->
unset_pd(Key) -> unset_pd(Key) ->
put_pd(Key, undefined). put_pd(Key, undefined).

32
src/qdate_sup.erl Normal file
View file

@ -0,0 +1,32 @@
-module(qdate_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
-define(SERVER, ?MODULE).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
init([]) ->
SupFlags = #{},
ChildSpec = #{
id=>qdate_srv,
start=>{qdate_srv, start_link, []}
},
{ok, {SupFlags, [ChildSpec]}}.
%%%===================================================================
%%% Internal functions
%%%===================================================================