Thursday, 28 April 2016

Taming configuration files - macro substitution

So What's the problem?

In the last few blog on global state, I proposed the solution to global state was a server.  I still stand by that, and that concept still needs a bit of fleshing out.  In the end the global state will probably be in a stand alone server connected to by clients using udp or tcp.  Before we get there I will define a server connection library that I can use in a number of servers.

The point is this approach will require late binding, configuration files that depend on the global state server will of necessity not be fully defined until runtime, and the current term parser has no concept of macro substitution.

Extension to term definition

The term definition is extended by the inclusion of a macro definition:

{macro, Name, DataDef} 

which is included in the configuration file as required.

To substitute a macro for a value, the result of the substitution must be the same as if the value were used in its stead, therefore our validation rule for macro substitution is:

maybe_validate(DataDef,{macro,_Name,DataDef},State) ->
    {true,State};

This rule is included in term_defs.erl.

Substitution Code

The code for the substitution is also relatively simple:

-module (substitute).

-export([substitute/2,test/0]).

-type proplist()::[{any(),any()}].
-spec substitute(Data,SubstList) -> OutData when
      Data :: any(),
      SubstList :: proplist(),
      OutData :: any().

substitute(X, SL) when is_list(X) ->
    list_sub(X ,[],SL);
substitute({macro,Name,Def},SL) ->
    macro_sub(Name,Def,SL);
substitute(X, SL) when is_tuple(X) ->
    L = tuple_to_list(X),
    NL = list_sub(L, [], SL),
    list_to_tuple(NL);
substitute(X,_) ->
    X.


list_sub([], Acc, _) ->
    lists:reverse(Acc);
list_sub([H|T], Acc, SL) ->
    list_sub(T,[substitute(H,SL)|Acc],SL).

macro_sub(Name,Def,SL) ->
    {_,V}=proplists:lookup(Name,SL),
    true = term_defs:validate(Def,V),
    V.




No comments:

Post a Comment

Your comments are welcome.