如何在Erlang R17中使用-extends
在最近的Erlang版本中删除了-extends特性 我有一些遗留模块,它们大量使用了-extends如何在Erlang R17中使用-extends,erlang,extends,Erlang,Extends,在最近的Erlang版本中删除了-extends特性 我有一些遗留模块,它们大量使用了-extends 如何让它在R17中工作 这是一个在R17中被删除的实验特征 因此,如果您真的必须使用R17,则必须在所有子模块中添加每个继承函数的定义: inherited_function (Param) -> parent:inherited(Param). 我编写了一个简单的代码,插入所需的函数并直接导出到现有代码中。它需要在src目录下工作,并且可以访问ebin目录(调用Module:Modu
如何让它在R17中工作 这是一个在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}.
二级儿童
-module (child1).
-extends(father).
-export ([cd1/0]).
-export ([ft1/1]).
cd1() -> child1.
ft1(X) -> {ovl_child1,X}.
一个验证其工作的测试模块(使用R17编译时,在使用-extend指令时不会出现错误!)
转换模块:
-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) 未引用当前模块中的函数;3) 不引用内置函数
这应该不会太难,但我仍然只会在大量使用
扩展时这样做,因为这会降低代码的可理解性,并且在抽象格式发生变化时可能需要维护。我将更深入地了解解析转换,但是如果不递归地查看父定义以查找所有未修改的继承函数,我不理解这是如何工作的。@Pascal Oops没有考虑到父模块本身可以扩展另一个模块。所以这可能是行不通的。
-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]).
-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).