Remove dependency on a server

Everything just uses application vars and procdict now.
This commit is contained in:
Jesse Gumm 2015-04-30 14:31:41 -05:00
parent cd1faf8631
commit bb33398614
5 changed files with 67 additions and 199 deletions

View file

@ -7,6 +7,6 @@
kernel, kernel,
stdlib stdlib
]}, ]},
{mod, { qdate_app, []}}, {modules, [qdate, qdate_srv]},
{env, []} {env, []}
]}. ]}.

View file

@ -95,10 +95,10 @@
-define(else, true). -define(else, true).
start() -> start() ->
application:start(qdate). application:load(qdate).
stop() -> stop() ->
application:stop(qdate). ok.
to_string(Format) -> to_string(Format) ->
to_string(Format, os:timestamp()). to_string(Format, os:timestamp()).
@ -616,6 +616,7 @@ try_registered_parsers(RawDate) ->
try_parsers(_RawDate,[]) -> try_parsers(_RawDate,[]) ->
undefined; undefined;
try_parsers(RawDate,[{ParserKey,Parser}|Parsers]) -> try_parsers(RawDate,[{ParserKey,Parser}|Parsers]) ->
io:format("Trying Parser: ~p~n", [ParserKey]),
try Parser(RawDate) of try Parser(RawDate) of
{{_,_,_},{_,_,_}} = DateTime -> {{_,_,_},{_,_,_}} = DateTime ->
{DateTime,undefined}; {DateTime,undefined};
@ -686,7 +687,6 @@ tz_test_() ->
simple_test(SetupData), simple_test(SetupData),
compare_test(SetupData), compare_test(SetupData),
tz_tests(SetupData), tz_tests(SetupData),
test_process_die(SetupData),
parser_format_test(SetupData), parser_format_test(SetupData),
test_deterministic_parser(SetupData), test_deterministic_parser(SetupData),
test_disambiguation(SetupData), test_disambiguation(SetupData),
@ -820,38 +820,6 @@ parser_format_test(_) ->
?_assertEqual("2/8/2008 12:00am",to_string(longdate,"20080208")) ?_assertEqual("2/8/2008 12:00am",to_string(longdate,"20080208"))
]}. ]}.
test_process_die(_) ->
TZ = "MST",
Caller = self(),
Pid = spawn(fun() ->
set_timezone(TZ),
Caller ! tz_set,
receive tz_set_ack -> ok end,
Caller ! get_timezone()
end),
PidTZFromOtherProc = receive
tz_set ->
T = get_timezone(Pid),
Pid ! tz_set_ack,
T
after 1000 -> fail
end,
ReceivedTZ = receive
TZ -> TZ
after 2000 ->
fail
end,
[
%% Verify we can read the spawned process's TZ from another proc
?_assertEqual(TZ,PidTZFromOtherProc),
%% Verify the spawned process properly set the TZ
?_assertEqual(TZ,ReceivedTZ),
%% Verify the now-dead spawned process's TZ is cleared
?_assertEqual(undefined,get_timezone(Pid))
].
arith_tests(_) -> arith_tests(_) ->
{inorder,[ {inorder,[
?_assertEqual({{2012,2,29},{23,59,59}}, to_date(add_seconds(-1, {{2012,3,1},{0,0,0}}))), ?_assertEqual({{2012,2,29},{23,59,59}}, to_date(add_seconds(-1, {{2012,3,1},{0,0,0}}))),

View file

@ -1,20 +0,0 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
-module(qdate_app).
-behaviour(application).
%% Application callbacks
-export([start/2, stop/1]).
%% ===================================================================
%% Application callbacks
%% ===================================================================
start(_StartType, _StartArgs) ->
qdate_sup:start_link().
stop(_State) ->
ok.

View file

@ -1,22 +1,11 @@
% vim: ts=4 sw=4 et % vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm % Copyright (c) 2013-2015 Jesse Gumm
% See LICENSE for licensing information. % See LICENSE for licensing information.
-module(qdate_srv). -module(qdate_srv).
-behaviour(gen_server).
-define(SRV, ?MODULE). -define(SRV, ?MODULE).
-export([
start_link/0,
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
code_change/3,
terminate/2
]).
-export([ -export([
set_timezone/1, set_timezone/1,
set_timezone/2, set_timezone/2,
@ -37,135 +26,98 @@
get_formats/0 get_formats/0
]). ]).
%% Simple wrappers for unique keys
-define(BASETAG, qdate_var).
-define(KEY(Name), {?BASETAG, Name}).
-define(TZTAG, qdate_tz).
-define(TZKEY(Name), {?TZTAG, Name}).
-define(PARSERTAG, qdate_parser).
-define(PARSERKEY(Name), {?PARSERTAG, Name}).
-define(FORMATTAG, qdate_format).
-define(FORMATKEY(Name), {?FORMATTAG, Name}).
%% PUBLIC API FUNCTIONS %% PUBLIC API FUNCTIONS
start_link() ->
gen_server:start_link({local, ?SRV}, ?MODULE, [], []).
set_timezone(TZ) -> set_timezone(TZ) ->
set_timezone(self(),TZ). put_pd(?TZTAG, TZ).
set_timezone(Key,TZ) -> set_timezone(Key, TZ) ->
ok = gen_server:call(?SRV,{set_timezone,Key,TZ}). set_env(?TZKEY(Key), TZ).
get_timezone() -> get_timezone() ->
get_timezone(self()). get_pd(?TZTAG).
get_timezone(Key) -> get_timezone(Key) ->
gen_server:call(?SRV,{get_timezone,Key}). get_env(?TZKEY(Key)).
clear_timezone() -> clear_timezone() ->
clear_timezone(self()). unset_pd(?TZTAG).
clear_timezone(Key) -> clear_timezone(Key) ->
ok = gen_server:call(?SRV, {clear_timezone, Key}). unset_env(?TZKEY(Key)).
register_parser(Parser) when is_function(Parser,1) -> register_parser(Parser) when is_function(Parser,1) ->
register_parser(erlang:make_ref(),Parser). register_parser(erlang:make_ref(),Parser).
register_parser(Key,Parser) when is_function(Parser,1) -> register_parser(Key,Parser) when is_function(Parser,1) ->
Key = gen_server:call(?SRV,{register_parser,Key,Parser}). set_env(?PARSERKEY(Key), Parser).
deregister_parser(Key) -> deregister_parser(Key) ->
ok = gen_server:call(?SRV,{deregister_parser,Key}). unset_env(?PARSERKEY(Key)).
deregister_parsers() -> deregister_parsers() ->
ok = gen_server:call(?SRV,{deregister_parsers}). [deregister_parser(Key) || {Key, _} <- get_parsers()].
get_parsers() -> get_parsers() ->
gen_server:call(?SRV,get_parsers). get_all_env(?PARSERTAG).
register_format(Key,Format) -> register_format(Key, Format) ->
ok = gen_server:call(?SRV,{register_format,Key,Format}). set_env(?FORMATKEY(Key), Format).
get_format(Key) -> get_format(Key) ->
gen_server:call(?SRV,{get_format,Key}). get_env(?FORMATKEY(Key)).
deregister_format(Key) -> deregister_format(Key) ->
ok = gen_server:call(?SRV,{deregister_format,Key}). unset_env(?FORMATKEY(Key)).
get_formats() -> get_formats() ->
gen_server:call(?SRV, get_formats). get_all_env(?FORMATTAG).
%% SERVER FUNCTIONS
-record(state, {tz, parsers, formats}).
init(_) ->
State = #state{tz=dict:new(),parsers=dict:new(),formats=dict:new()},
{ok, State}.
handle_cast(_,State) ->
{noreply, State}.
handle_info({'DOWN', MonitorRef, process, Pid, _Reason}, State) ->
erlang:demonitor(MonitorRef),
NewTZ = dict:erase(Pid, State#state.tz),
NewParsers = dict:erase(Pid, State#state.parsers),
NewFormats = dict:erase(Pid, State#state.formats),
NewState = State#state{tz=NewTZ, parsers=NewParsers, formats=NewFormats},
{noreply, NewState };
handle_info(_, State) ->
{noreply, State}.
handle_call({set_timezone,Key,TZ}, _From, State) ->
monitor_if_pid(Key),
NewTZ = dict:store(Key, TZ, State#state.tz),
NewState = State#state{tz=NewTZ},
{reply, ok, NewState};
handle_call({clear_timezone,Key},_From, State) ->
NewTZ = dict:erase(Key, State#state.tz),
NewState = State#state{tz=NewTZ},
{reply, ok, NewState};
handle_call({get_timezone,Key},_From, State) ->
Reply = case dict:find(Key, State#state.tz) of
error -> undefined;
{ok,TZ} -> TZ
end,
{reply, Reply, State};
handle_call({register_parser,Key,Parser},_From,State) ->
NewParsers = dict:store(Key, Parser, State#state.parsers),
NewState = State#state{parsers=NewParsers},
{reply, Key, NewState};
handle_call(get_parsers,_From,State) ->
Reply = dict:to_list(State#state.parsers),
{reply, Reply, State};
handle_call({deregister_parser,Key},_From,State) ->
NewParsers = dict:erase(Key, State#state.parsers),
NewState = State#state{parsers=NewParsers},
{reply, ok, NewState};
handle_call({deregister_parsers},_From,State) ->
NewState = State#state{parsers=dict:new()},
{reply, ok, NewState};
handle_call({register_format,Key,Format},_From,State) ->
NewFormats = dict:store(Key, Format, State#state.formats),
NewState = State#state{formats=NewFormats},
{reply, ok, NewState};
handle_call({get_format,Key},_From,State) ->
Reply = case dict:find(Key, State#state.formats) of
error -> undefined;
{ok, Format} -> Format
end,
{reply, Reply,State};
handle_call(get_formats,_From,State) ->
Reply = dict:to_list(State#state.formats),
{reply, Reply, State};
handle_call({deregister_format,Key},_From,State) ->
NewFormats = dict:erase(Key, State#state.formats),
NewState = State#state{formats=NewFormats},
{reply, ok, NewState}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVersion, State, _Extra) ->
{ok, State}.
%% PRIVATE TOOLS %% PRIVATE TOOLS
monitor_if_pid(Key) when is_pid(Key) -> %% App Vars
erlang:monitor(process,Key);
monitor_if_pid(_) -> set_env(Key, Val) ->
do_nothing. application:set_env(qdate, ?KEY(Key), Val).
get_env(Key) ->
get_env(Key, undefined).
get_env(Key, Default) ->
%% Soon, this can just be replaced with application:get_env/3
%% which was introduced in R16B.
case application:get_env(qdate, ?KEY(Key)) of
undefined -> Default;
{ok, Val} -> Val
end.
unset_env(Key) ->
application:unset_env(qdate, ?KEY(Key)).
get_all_env(FilterTag) ->
All = application:get_all_env(qdate),
%% Maybe this is a little nasty.
[{Key, V} || {{?BASETAG, {Tag, Key}}, V} <- All, Tag==FilterTag].
%% ProcDic Vars
get_pd(Key) ->
erlang:get(?KEY(Key)).
put_pd(Key, Val) ->
erlang:put(?KEY(Key), Val),
ok.
unset_pd(Key) ->
put_pd(Key, undefined).

View file

@ -1,32 +0,0 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
-module(qdate_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
%% ===================================================================
%% API functions
%% ===================================================================
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% ===================================================================
%% Supervisor callbacks
%% ===================================================================
init([]) ->
Server = ?CHILD(qdate_srv, worker),
{ok, { {one_for_one, 5, 10}, [Server]} }.