下面的代碼(這是一個公認有點hackish)開始一個gen_server
採用一個字符串作爲參數,然後滿足Erlang I/O Protocol足以滿足epp_dodger:parse/2
,以便能夠讀取和解析從該過程中的字符串。
下面是使用它的一個例子:曾經的字符串耗盡
1> {ok,P} = iostr:start("-module(x).\n-export([f/0]).\nf() -> ok.\n").
2> epp_dodger:parse(P,1).
{ok,[{tree,attribute,
{attr,1,[],none},
{attribute,
{tree,atom,{attr,1,[],none},module},
[{tree,atom,{attr,1,[],none},x}]}},
{tree,attribute,
{attr,2,[],none},
{attribute,
{tree,atom,{attr,2,[],none},export},
[{tree,list,
{attr,2,[],none},
{list,
[{tree,arity_qualifier,
{attr,2,[],none},
{arity_qualifier,
{tree,atom,{attr,...},f},
{tree,integer,{...},...}}}],
none}}]}},
{tree,function,
{attr,3,[],none},
{func,
{tree,atom,{attr,3,[],none},f},
[{tree,clause,
{attr,3,[],none},
{clause,[],none,[{atom,3,ok}]}}]}}]}
的進程死亡。
注意,代碼可能會缺少一些東西—處理Unicode的正確,例如—但它應該給你如何在需要時做出更強大的I/O服務器用於此目的的一個好主意。通過將字符串作爲文件和包括'ram`選項,但生成的`IODevice`不`epp_dodger`工作開/ 2`的字符串:
-module(iostr).
-behaviour(gen_server).
-export([start_link/1, start/1, stop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {
data,
line = 1,
lines
}).
start_link(Data) ->
gen_server:start_link(?MODULE, [Data], []).
start(Data) ->
gen_server:start(?MODULE, [Data], []).
stop(Pid) ->
gen_server:cast(Pid, stop).
init([Data0]) ->
Data = [Line++"\n" || Line <- string:tokens(Data0, "\n")],
{ok, #state{data=Data,lines=length(Data)}}.
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(stop, State) ->
{stop, normal, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({io_request,From,ReplyAs,{get_until,_,_,_,_,_}},
#state{data=[],lines=L}=State) ->
From ! {io_reply, ReplyAs, {eof,L}},
{stop, normal, State};
handle_info({io_request,From,ReplyAs,{get_until,_,_,M,F,Args}},
#state{data=Data,line=L}=State) ->
case handler(Data,L,[],M,F,Args) of
eof ->
Lines = State#state.lines,
From ! {io_reply, ReplyAs, {eof,Lines}},
{stop, normal, State#state{data=[]}};
{ok,Result,Rest,NData,NL} ->
From ! {io_reply, ReplyAs, Result},
case Rest of
[] ->
{noreply, State#state{data=NData,line=NL}};
_ ->
{noreply, State#state{data=[Rest|NData],line=NL}}
end
end;
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
handler([Input|Data],L,Cont,M,F,Extra) ->
case catch apply(M,F,[Cont,Input|Extra]) of
{done,eof,_} ->
eof;
{done,Result,Rest} ->
{ok,Result,Rest,Data,L+1};
{more,NCont} ->
case Data of
[] -> eof;
_ -> handler(Data,L+1,NCont,M,F,Extra)
end
end.
理論上你可以做一個'文件因爲當它傳遞到'io'模塊時它會中斷。我相信這是一個錯誤。 –
我已經報告錯誤處理使用'ram'選項產生的'IODevice'作爲錯誤。 –
不是一個錯誤。我混淆了兩個獨立的'IODevice'類型,一個來自'file'模塊,另一個來自'io'模塊。 –