Skip to content

Commit

Permalink
[#28] Working implementation of DRY
Browse files Browse the repository at this point in the history
  • Loading branch information
jfacorro committed Apr 24, 2015
1 parent 8e58350 commit 718f943
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 15 deletions.
33 changes: 25 additions & 8 deletions src/elvis_code.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
find_by_location/2,
code_zipper/1,
code_zipper/2,
map/3
map/2,
fold/3,
content_zipper/1
]).

%% Specific
Expand Down Expand Up @@ -129,20 +131,35 @@ is_at_location(Node = #{attrs := #{location := {Line, NodeCol}}},
is_at_location(_, _) ->
false.

-spec map(ktn_code:tree_node(), fun(), list()) -> ktn_code:tree_node().
'map'(Root, Fun, Args) ->
Zipper = content_zipper(Root),
do_map(Fun, Args, Zipper).
-spec fold(fun(), list(), ktn_code:tree_node()) -> ktn_code:tree_node().
fold(Fun, Args, Zipper) ->
do_fold(Fun, Args, Zipper).

-spec do_map(zipper:zipper(), fun(), list()) -> ktn_code:tree_node().
do_map(Fun, Args, Zipper) ->
-spec do_fold(fun(), list(), zipper:zipper()) -> ktn_code:tree_node().
do_fold(Fun, Args, Zipper) ->
NewZipper = zipper:edit(Fun, Args, Zipper),
NextZipper = zipper:next(NewZipper),
case zipper:is_end(NextZipper) of
true ->
zipper:root(NewZipper);
false ->
do_map(Fun, Args, NextZipper)
do_fold(Fun, Args, NextZipper)
end.

-spec map(ktn_code:tree_node(), fun()) -> [ktn_code:tree_node()].
'map'(Fun, Zipper) ->
do_map(Fun, [], Zipper).

-spec do_map(fun(), list(), zipper:zipper()) -> [ktn_code:tree_node()].
do_map(Fun, Results, Zipper) ->
NewNode = Fun(zipper:node(Zipper)),
NextZipper = zipper:next(Zipper),
NewResults = [NewNode | Results],
case zipper:is_end(NextZipper) of
true ->
lists:reverse(NewResults);
false ->
do_map(Fun, NewResults, NextZipper)
end.

%%% Processing functions
Expand Down
55 changes: 48 additions & 7 deletions src/elvis_style.erl
Original file line number Diff line number Diff line change
Expand Up @@ -724,21 +724,62 @@ spec_includes_record(Node) ->

-spec find_repeated_nodes(ktn_code:tree_node()) -> [ktn_code:tree_node()].
find_repeated_nodes(Root) ->
elvis_code:map(Root, fun remove_location/1, []).
TypeAttrs = #{var => [location, name, text]},
MapFun =
fun(Node) ->
Loc = ktn_code:attr(location, Node),
Zipper = elvis_code:content_zipper(Node),
StrippedNode = remove_attrs_zipper(Zipper, TypeAttrs),
{Loc , StrippedNode}
end,

ZipperRoot = elvis_code:content_zipper(Root),
LocationNodePairs = elvis_code:map(MapFun, ZipperRoot),

Repeated = [{Node1, [Loc1, Loc2]}
|| {Loc1, Node1} <- LocationNodePairs,
{Loc2, Node2} <- LocationNodePairs,
Loc1 =/= Loc2,
Node1 == Node2,
count_nodes(Node1) >= 5],

GroupFun =
fun({Key, Vals}, Map) ->
ValsSet = maps:get(Key, Map, sets:new()),
NewValsSet = lists:foldl(fun sets:add_element/2, ValsSet, Vals),
maps:put(Key, NewValsSet, Map)
end,

-spec remove_location(ktn_code:tree_node()) -> ktn_code:tree_node().
remove_location(Nodes) when is_list(Nodes) ->
lists:map(fun remove_location/1, Nodes);
remove_location(#{attrs := Attrs} = Node) ->
AttrsNoLoc = maps:remove(location, Attrs),
GroupedRepeated = lists:foldl(GroupFun, #{}, Repeated),

lists:map(fun sets:to_list/1, maps:values(GroupedRepeated)).

-spec remove_attrs_zipper(zipper:zipper(), map()) -> ktn_code:tree_node().
remove_attrs_zipper(Zipper, TypeAttrs) ->
elvis_code:fold(fun remove_attrs/2, [TypeAttrs], Zipper).

-spec remove_attrs(ktn_code:tree_node(), map()) -> ktn_code:tree_node().
remove_attrs(Nodes, TypeAttrs) when is_list(Nodes) ->
ktn_lists:map(fun remove_attrs/2, [TypeAttrs], Nodes);
remove_attrs(#{attrs := Attrs, type := Type} = Node, TypeAttrs) ->
AttrsName = maps:get(Type, TypeAttrs, [location]),
AttrsNoLoc = maps:without(AttrsName, Attrs),
case maps:get(node_attrs, Node, undefined) of
undefined ->
Node#{attrs => AttrsNoLoc};
NodeAttrs ->
NodeAttrsNoLoc =
[{Key, elvis_code:map(Value, fun remove_location/1, [])}
[{ Key
, remove_attrs_zipper(elvis_code:content_zipper(Value), TypeAttrs)}
|| {Key, Value} <- maps:to_list(NodeAttrs)],

Node#{attrs => AttrsNoLoc,
node_attrs => maps:from_list(NodeAttrsNoLoc)}
end.

-spec count_nodes(ktn_code:tree_node()) -> non_neg_integer().
count_nodes(Node) ->
Zipper = elvis_code:content_zipper(Node),
lists:foldl(fun erlang:'+'/2,
0,
elvis_code:map(fun(_) -> 1 end, Zipper)).

0 comments on commit 718f943

Please sign in to comment.