在最近的Erlang版本中删除了-extends功能
我有一些遗留模块大量使用-extends
如何让它在R17中运行?
答案 0 :(得分:2)
这是一项实验性功能,已在R17中删除。
因此,如果您真的必须使用R17,则必须在所有子模块中添加每个继承函数的定义:
inherited_function (Param) -> parent:inherited(Param).
我编写了一个简单的代码,插入所需的函数并直接导出到现有代码中。它需要在src目录中工作,可以访问ebin目录(调用Module:module_info(exports)) - 所以我会在项目的副本上使用它:o)。它对extend指令做了一些假设(没有空白字符),并且没有将添加的export指令拆分成几行,这可能是个问题,但它适用于我的例子
要修改的代码示例: 根模块
-module (gd_father).
-export([gdf1/0,gdf2/1,gdf2/2]).
gdf1() -> gd_father.
gdf2(P) -> {gd_father,P}.
gdf2(P1,P2) when is_list(P2) -> [gd_father,P1|P2];
gdf2(P1,P2) -> [gd_father,P1,P2].
儿童等级1
-module (father).
-extends(gd_father).
-export([ft1/1,ft2/0]).
-export([gdf2/1]).
ft1(X) -> {father,X}.
ft2() -> father.
gdf2(P1) -> {ovl_father,P1}.
2岁儿童
-module (child1).
-extends(father).
-export ([cd1/0]).
-export ([ft1/1]).
cd1() -> child1.
ft1(X) -> {ovl_child1,X}.
。
-module (child2).
-extends(father).
-export ([cd2/0]).
-export ([ft2/0,gdf1/0]).
cd2() -> child2.
ft2() -> ovl_child2.
gdf1() -> ovl_child2.
一个测试模块,用于验证它是否正常工作(使用R17进行编译在-extend指令使用情况下不会出错!)
-module (test).
-export([t/0]).
t() ->
gd_father = gd_father:gdf1(),
{gd_father,3} = gd_father:gdf2(3),
[gd_father,1,2] = gd_father:gdf2(1,2),
[gd_father,1,2,3] = gd_father:gdf2(1,[2,3]),
{father,4} = father:ft1(4),
father = father:ft2(),
{ovl_father,5} = father:gdf2(5),
[gd_father,1,2] = father:gdf2(1,2),
gd_father = father:gdf1(),
[gd_father,1,2,3] = father:gdf2(1,[2,3]),
child1 = child1:cd1(),
{ovl_child1,test} = child1:ft1(test),
father = child1:ft2(),
{ovl_father,5} = child1:gdf2(5),
[gd_father,1,2] = child1:gdf2(1,2),
gd_father = child1:gdf1(),
[gd_father,1,2,3] = child1:gdf2(1,[2,3]),
child2 = child2:cd2(),
ovl_child2 = child2:ft2(),
ovl_child2 = child2:gdf1(),
{father,4} = child2:ft1(4),
{ovl_father,5} = child2:gdf2(5),
[gd_father,1,2] = child2:gdf2(1,2),
[gd_father,1,2,3] = child2:gdf2(1,[2,3]),
ok.
转换模块:
-module (transform).
-export([transform_dir/0,transform_file/1]).
transform_dir() ->
{ok,AllFiles} = file:list_dir("."),
Files = [list_to_atom(lists:sublist(X,length(X)-4)) || X <- AllFiles, is_src(lists:reverse(X))],
transform_file(Files).
transform_file([]) -> ok;
transform_file([H|Q]) ->
{_,_,Add,Father,Lines} = transform_file(H),
mod_file(H,Add,Father,Lines),
transform_file(Q);
transform_file(Name) ->
FileName = atom_to_list(Name) ++ ".erl",
{ok,Bin} = file:read_file(FileName),
List = binary_to_list(Bin),
Lines = string:tokens(List,"\n"),
Father = to_atom([string:strip(X) || X <- Lines, is_extend(X)]),
OrExp = Name:module_info(exports),
case Father of
none -> {OrExp,OrExp,[],none,[]};
Father -> {_,Fa_Tot,_,_,_} = transform_file(Father),
Or = lists:usort(OrExp),
Tot = lists:usort(Fa_Tot ++ OrExp),
Add = lists:usort(lists:subtract(Tot,Or)),
{Or,Tot,Add,Father,Lines}
end.
is_extend([$-,$e,$x,$t,$e,$n,$d,$s|_]) -> true;
is_extend(_) -> false.
is_src([$l,$r,$e,$.|_]) -> true;
is_src(_) -> false.
to_atom([]) -> none;
to_atom([L]) ->
list_to_atom(tl(lists:takewhile(fun(X) -> X =/= $) end , lists:dropwhile(fun(X) -> X =/= $( end,L)))).
mod_file(_,[],_,_) -> ok;
mod_file(F,L,Father,Lines) ->
Export = lists:flatten(["\n%Replace expends directive by export\n-export([",
tl(lists:flatten([", " ++ atom_to_list(X) ++ "/" ++ integer_to_list(N) || {X,N} <- L])),
"]).\n"]),
Def = lists:flatten(["\n\n%Insert relay functions to replace the expends directive\n" |[add_def(X,Father) || X <- L]]),
NewLines = insert(Lines,Export,Def,[]),
file:write_file(atom_to_list(F)++".erl",NewLines,[write]).
insert([],_,Def,R) -> lists:reverse([Def|R]);
insert([H|Q],Export,Def,R) ->
Line = case is_extend(H) of
true -> Export;
false -> H
end,
insert(Q,Export,Def,[Line|R]).
add_def({N,A},F) ->
Args = args(A,[]),
atom_to_list(N) ++ Args ++ " -> " ++ atom_to_list(F) ++ ":" ++ atom_to_list(N) ++ Args ++ ".\n".
args(0,[]) -> "()";
args(0,R) -> "(" ++ lists:reverse(tl(R)) ++ ")";
args(A,R) -> args(A-1,[$,,A-1+$A,$P|R]).
结果在子级别2,编译完所有模块后,测试结果正常:
-module (child1).
%Replace expends directive by export
-export([ ft2/0, gdf1/0, gdf2/1, gdf2/2]).
-export ([cd1/0]).
-export ([ft1/1]).
cd1() -> child1.
ft1(X) -> {ovl_child1,X}.
%Insert relay functions to replace the expends directive
ft2() -> father:ft2().
gdf1() -> father:gdf1().
gdf2(PA) -> father:gdf2(PA).
gdf2(PB,PA) -> father:gdf2(PB,PA).
答案 1 :(得分:0)
您可以编写一个parse transform,在每次函数调用之前插入父模块的名称,这是1)不合格的; 2)不参考当前模块中的功能; 3)没有提到内置功能。
不应该太困难但是如果你真的大量使用extends
我仍然会这样做,因为这会使代码不易理解,如果抽象格式发生变化则可能需要维护。