[erlang-questions] How do I elegantly check many conditions?
Gaspar Chilingarov
nm@REDACTED
Fri Mar 20 18:29:25 CET 2009
Practically agree with previous speaker, but I will do it a little bit
in other way ;)
%
% store all necessary data to pass between validators in
% #validator_state struct
%
run_checks(FunList, Data) ->
run_checks(FunList, Data, #validator_state{}).
%
% evaluate validation chain
%
run_checks([], Data, State) ->
{valid, Data, State};
run_checks([F | FunList], Data, State) ->
case ?MODULE:F(Data, State) of
{valid, NewData, NewState} ->
run_checks(FunList, NewData, NewState);
Error = {error, _ErrorMsg, _NewState} ->
% you can add to error reporting in WHICH
% validator it failed
% like
% {error, F, _ErrorMsg, _NewState}
Error
% for ease of programming validators I would add also
% shortcut return codes like
% valid -> run_checks(FunList, Data, State);
% and
% {error, Error} -> {error, Error, State};
end.
And I will end up with functions like
% check functions
check_email(PropList, State) ->
do something and return values ....
check_name(PropList, State) ->
do something and return values ....
and checking will be as easy as
% InputData is better to be a proplist - much more easier to work with
% or it may be a record of some type
% just tuple will reduce code flexibility in a long run
run_checks([check_email, check_name, check_valid_password], InputData)
So changing order of validation or adding new validator is as easy as
just writing one more functions and adding it to run_checks call.
And it's also very readable - looking on run_checks invocation you can
easily determine which checks are run and in which order.
I do not hesitate to make check_* functions global - because this will
also ease writing tests for them (if you use test driver environment).
Disclaimer - I wrote this code out of my head and do not test it, thou
it should compile with minimal changes, I think :)
/Gaspar
PS. BTW with minimal changes this approach also solves a problem with
destructive variable update, which generated great flame here in a last
days.
Just extend Data variable to something flexible (in my case I user FIFO
stack there) and you will get powerful interpretator of "meta commands"
(like check_email, check_name and so on).
Adam Kelly wrote:
> 2009/3/20 ryeguy <ryeguy1@REDACTED>:
>> Now I don't want to have a 5 level deep if or case statement, but what
>> other options do I have? Splitting it into separate functions sounds
>> like a good idea, but then I just have to check the return value of
>> the functions in some sort of conditional and it's back to the
>> original problem.
>
> I've added this function to my libraries:
>
> run_checks([]) -> ok;
> run_checks([H|T]) when is_function(H, 0) ->
> case H() of
> ok -> run_checks(T);
> Error -> Error
> end.
>
> at which point the problem is simply
>
> case run_checks([
> fun() ->check_email(Email) end,
> fun() ->check_username(Username) end,
> ... ]) of
> ok -> ...;
> {error, Reason} -> ...
> end.
>
> Adam.
--
Gaspar Chilingarov
tel +37493 419763 (mobile - leave voice mail message)
icq 63174784
skype://gasparch
e mailto:nm@REDACTED mailto:gasparch@REDACTED
w http://gasparchilingarov.com/
More information about the erlang-questions
mailing list