Erlang Trick O’ The Day
Posted: June 2nd, 2009 | Author: kevin | Filed under: Erlang | Comments OffI’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!