Skip to content

Instantly share code, notes, and snippets.

@savonarola
Created March 18, 2009 13:40
Show Gist options
  • Save savonarola/81123 to your computer and use it in GitHub Desktop.
Save savonarola/81123 to your computer and use it in GitHub Desktop.
-module(model).
-export([new/2,behaviour_info/1, super/2, call/2, state/1, call/3]).
behaviour_info(callbacks) -> [{init,1},{handle,2}].
call_stack(N) ->
{'EXIT', {_Error, CallStack}} = (catch 1 = 2),
lists:nthtail(N, tl(CallStack)).
caller_module(N) ->
[{CallerModule,_Method,_Arity} | _T ] = call_stack(N + 1),
CallerModule.
find(Pred,Tuple) ->
find(Pred,Tuple,1).
find(Pred,Tuple,N)->
S = size(Tuple),
case N > S of
true -> undef;
false ->
E = element(N,Tuple),
case Pred(E) of
true -> {N, E};
false -> find(Pred, Tuple, N + 1)
end
end.
new(ModelName,Params) ->
init_state(ModelName, Params).
init_state(ModelName, Params) ->
list_to_tuple(lists:reverse(init_state(ModelName,Params, []))).
init_state(ModelName, Params, Generated) ->
case ModelName:init(Params) of
{ok, State, {ParentName, ParentParams}} ->
init_state(ParentName, ParentParams, [{ModelName,State}|Generated]);
{ok, State} ->
[{ModelName,State}|Generated];
{error,Reason} ->
exit({error_creating_model,Reason});
_ ->
exit({bad_returned_value,{ModelName,init,[Params]}})
end.
state(Model)->
CallerModule = caller_module(1),
%error_logger:info_msg("Model: ~p, CallerModule: ~p~n",[Model, CallerModule]),
{_N, {_Name, State}} = find(fun({Module,_State}) -> Module =:= CallerModule end, Model),
State.
call(Model, Request, N) ->
ModelCnt = size(Model),
case N > ModelCnt of
true -> exit({no_handler, Model, Request});
false ->
{ModelName,_State} = element(N, Model),
case (catch ModelName:handle(Model, Request)) of
{'EXIT',{function_clause,[{ModelName,handle,[Model,Request]} | _Stack ]}} ->
model:call(Model, Request, N + 1);
{'EXIT', Reason} ->
exit(Reason);
ok ->
{Model, ok};
{ok, Result} ->
{Model,Result};
{ok, Result, InternalState} ->
{setelement(N, Model, {ModelName,InternalState}), Result};
{ok, Result, InternalState, NewModel} ->
{setelement(N, NewModel, {ModelName,InternalState}), Result};
{error, Reason} ->
exit(Reason)
end
end.
call(Model, Request) ->
call(Model,Request,1).
super(Model, Request) ->
CallerModule = caller_module(1),
{N,_} = find(fun({Module,_State}) -> Module =:= CallerModule end, Model),
model:call(Model, Request, N).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment