Erlang Trick O’ The Day

Posted: June 2nd, 2009 | Author: kevin | Filed under: Erlang | Comments Off

I’ve been researching Erlang <-> Javascript integration for a client project and decided to take a look at how CouchDB integrates with Spidermonkey. Along the way I found the couch_os_process:init/1 function:

init([Command, Options, PortOptions]) ->
    case code:priv_dir(couch) of
    {error, bad_name} ->
        % small hack, in dev mode "app" is couchdb. Fixing requires renaming
        % src/couch to src/couch. Not really worth the hassle.-Damien
        PrivDir = code:priv_dir(couchdb);
    PrivDir -> ok
    end,
    Spawnkiller = filename:join(PrivDir, "couchspawnkillable"),
    BaseProc = #os_proc{
        command=Command,
        port=open_port({spawn, Spawnkiller ++ " " ++ Command}, PortOptions),
        writer=fun writejson/2,
        reader=fun readjson/1
    },
    KillCmd = readline(BaseProc),
    Pid = self(),
    spawn(fun() ->
            % this ensure the real os process is killed when this process dies.
            erlang:monitor(process, Pid),
            receive _ -> ok end,
            os:cmd(?b2l(KillCmd))
        end),
    OsProc =
    lists:foldl(fun(Opt, Proc) ->
        case Opt of
        {writer, Writer} when is_function(Writer) ->
            Proc#os_proc{writer=Writer};
        {reader, Reader} when is_function(Reader) ->
            Proc#os_proc{reader=Reader};
        {timeout, TimeOut} when is_integer(TimeOut) ->
            Proc#os_proc{timeout=TimeOut}
        end
    end, BaseProc, Options),
    {ok, OsProc}.

The neat bit is the call to list:foldl/3 at the end of the function. It folds over a list of configuration options and pops them into an Erlang record. I would’ve never thought to use a fold this way. Neat!


Comments are closed.