Skip to content

Commit

Permalink
Adopt erlfmt (#1)
Browse files Browse the repository at this point in the history
This is an attempt to define some consistent formatting rules for our Erlang code.

I made some research and I tested various options, so far the one that I prefer is [erlfmt](https://github.com/WhatsApp/erlfmt) from WhatsApp. Like most non-builtin formatters, this is opinionated. But the choices they made are well thought, and seem to be a good starting point.


You have both the option to reformat the code inline:

```
rebar3 fmt
```

or check the formatting:

```
rebar3 fmt --check
```

This last command is especially useful for CI integration.
  • Loading branch information
weppos authored Mar 21, 2024
1 parent 8b1ebce commit 4fa399f
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
_build
.tool-versions
rebar3
10 changes: 10 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
{cover_enabled, true}.
{cover_print_enabled, true}.
{erl_opts, [warnings_as_errors]}.

{project_plugins, [
erlfmt
]}.

{eunit_opts, [verbose]}.

{erlfmt, [
write,
{print_width, 140}
]}.
21 changes: 10 additions & 11 deletions src/base32.app.src
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{application, base32,
[
{description, "Erlang implementation of base32 encoding and decoding"},
{vsn, "0.1"},
{registered, []},
{applications, [
kernel,
stdlib
]},
{env, []}
]}.
{application, base32, [
{description, "Erlang implementation of base32 encoding and decoding"},
{vsn, "0.1"},
{registered, []},
{applications, [
kernel,
stdlib
]},
{env, []}
]}.
169 changes: 100 additions & 69 deletions src/base32.erl
Original file line number Diff line number Diff line change
Expand Up @@ -30,61 +30,65 @@ encode(List) when is_list(List) -> encode(list_to_binary(List), []).
encode(Bin, Opts) when is_binary(Bin) andalso is_list(Opts) ->
Hex = proplists:get_bool(hex, Opts),
Lower = proplists:get_bool(lower, Opts),
Fun = case Hex of
true -> fun(I) -> hex_enc(Lower, I) end;
false -> fun(I) -> std_enc(Lower, I) end
end,
Fun =
case Hex of
true -> fun(I) -> hex_enc(Lower, I) end;
false -> fun(I) -> std_enc(Lower, I) end
end,
{Encoded0, Rest} = encode_body(Fun, Bin),
{Encoded1, PadBy} = encode_rest(Fun, Rest),
Padding = case proplists:get_bool(nopad, Opts) of
true -> <<>>;
false -> list_to_binary(lists:duplicate(PadBy, $=))
end,
Padding =
case proplists:get_bool(nopad, Opts) of
true -> <<>>;
false -> list_to_binary(lists:duplicate(PadBy, $=))
end,
<<Encoded0/binary, Encoded1/binary, Padding/binary>>;
encode(List, Opts) when is_list(List) andalso is_list(Opts) ->
encode(list_to_binary(List), Opts).

encode_body(Fun, Bin) ->
Offset = 5 * (byte_size(Bin) div 5),
<<Body:Offset/binary, Rest/binary>> = Bin,
{<< <<(Fun(I))>> || <<I:5>> <= Body>>, Rest}.
{<<<<(Fun(I))>> || <<I:5>> <= Body>>, Rest}.

encode_rest(Fun, Bin) ->
Whole = bit_size(Bin) div 5,
Offset = 5 * Whole,
<<Body:Offset/bits, Rest/bits>> = Bin,
Body0 = << <<(Fun(I))>> || <<I:5>> <= Body>>,
{Body1, Pad} = case Rest of
<<I:3>> -> {<<(Fun(I bsl 2))>>, 6};
<<I:1>> -> {<<(Fun(I bsl 4))>>, 4};
<<I:4>> -> {<<(Fun(I bsl 1))>>, 3};
<<I:2>> -> {<<(Fun(I bsl 3))>>, 1};
<<>> -> {<<>>, 0}
end,
Body0 = <<<<(Fun(I))>> || <<I:5>> <= Body>>,
{Body1, Pad} =
case Rest of
<<I:3>> -> {<<(Fun(I bsl 2))>>, 6};
<<I:1>> -> {<<(Fun(I bsl 4))>>, 4};
<<I:4>> -> {<<(Fun(I bsl 1))>>, 3};
<<I:2>> -> {<<(Fun(I bsl 3))>>, 1};
<<>> -> {<<>>, 0}
end,
{<<Body0/binary, Body1/binary>>, Pad}.

std_enc(_, I) when is_integer(I) andalso I >= 26 andalso I =< 31 -> I + 24;
std_enc(Lower, I) when is_integer(I) andalso I >= 0 andalso I =< 25 ->
case Lower of
true -> I + $a;
false -> I + $A
true -> I + $a;
false -> I + $A
end.

hex_enc(_, I) when is_integer(I) andalso I >= 0 andalso I =< 9 -> I + 48;
hex_enc(Lower, I) when is_integer(I) andalso I >= 10 andalso I =< 31 ->
case Lower of
true -> I + 87;
false -> I + 55
true -> I + 87;
false -> I + 55
end.

decode(Bin) when is_binary(Bin) -> decode(Bin, []);
decode(List) when is_list(List) -> decode(list_to_binary(List), []).

decode(Bin, Opts) when is_binary(Bin) andalso is_list(Opts) ->
Fun = case proplists:get_bool(hex, Opts) of
true -> fun hex_dec/1;
false -> fun std_dec/1
end,
Fun =
case proplists:get_bool(hex, Opts) of
true -> fun hex_dec/1;
false -> fun std_dec/1
end,
decode(Fun, Bin, <<>>);
decode(List, Opts) when is_list(List) andalso is_list(Opts) ->
decode(list_to_binary(List), Opts).
Expand All @@ -99,7 +103,8 @@ decode(Fun, <<X, "=">>, Bits) ->
<<Bits/bits, (Fun(X) bsr 3):2>>;
decode(Fun, <<X, Rest/binary>>, Bits) ->
decode(Fun, Rest, <<Bits/bits, (Fun(X)):5>>);
decode(_Fun, <<>>, Bin) -> Bin.
decode(_Fun, <<>>, Bin) ->
Bin.

std_dec(I) when I >= $2 andalso I =< $7 -> I - 24;
std_dec(I) when I >= $a andalso I =< $z -> I - $a;
Expand All @@ -112,90 +117,116 @@ hex_dec(I) when I >= $A andalso I =< $Z -> I - 55.
-ifdef(TEST).

std_cases() ->
[{<<"">>, <<"">>},
{<<"f">>, <<"MY======">>},
{<<"fo">>, <<"MZXQ====">>},
{<<"foo">>, <<"MZXW6===">>},
{<<"foob">>, <<"MZXW6YQ=">>},
{<<"fooba">>, <<"MZXW6YTB">>},
{<<"foobar">>, <<"MZXW6YTBOI======">>}].
[
{<<"">>, <<"">>},
{<<"f">>, <<"MY======">>},
{<<"fo">>, <<"MZXQ====">>},
{<<"foo">>, <<"MZXW6===">>},
{<<"foob">>, <<"MZXW6YQ=">>},
{<<"fooba">>, <<"MZXW6YTB">>},
{<<"foobar">>, <<"MZXW6YTBOI======">>}
].

lower_cases(Cases) ->
[{I, << <<(string:to_lower(C))>> || <<C>> <= O >>} || {I, O} <- Cases ].
[{I, <<<<(string:to_lower(C))>> || <<C>> <= O>>} || {I, O} <- Cases].

nopad_cases(Cases) ->
[{I, << <<C>> || <<C>> <= O, C =/= $= >>} || {I, O} <- Cases].
[{I, <<<<C>> || <<C>> <= O, C =/= $=>>} || {I, O} <- Cases].

stringinput_cases(Cases) -> [{binary_to_list(I), O} || {I, O} <- Cases].

stringoutput_cases(Cases) -> [{I, binary_to_list(O)} || {I, O} <- Cases].

std_encode_test_() ->
[ ?_assertEqual(Out, encode(In)) || {In, Out} <- std_cases() ].
[?_assertEqual(Out, encode(In)) || {In, Out} <- std_cases()].

std_decode_test_() ->
[ ?_assertEqual(Out, decode(In)) || {Out, In} <- std_cases() ].
[?_assertEqual(Out, decode(In)) || {Out, In} <- std_cases()].

std_encode_lower_test_() ->
[ ?_assertEqual(Out, encode(In, [lower])) ||
{In, Out} <- lower_cases(std_cases()) ].
[
?_assertEqual(Out, encode(In, [lower]))
|| {In, Out} <- lower_cases(std_cases())
].

std_decode_lower_test_() ->
[ ?_assertEqual(Out, decode(In)) || {Out, In} <- lower_cases(std_cases()) ].
[?_assertEqual(Out, decode(In)) || {Out, In} <- lower_cases(std_cases())].

std_encode_nopad_test_() ->
[ ?_assertEqual(Out, encode(In, [nopad]))
|| {In, Out} <- nopad_cases(std_cases()) ].
[
?_assertEqual(Out, encode(In, [nopad]))
|| {In, Out} <- nopad_cases(std_cases())
].

std_encode_lower_nopad_test_() ->
[ ?_assertEqual(Out, encode(In, [lower,nopad]))
|| {In, Out} <- nopad_cases(lower_cases(std_cases())) ].
[
?_assertEqual(Out, encode(In, [lower, nopad]))
|| {In, Out} <- nopad_cases(lower_cases(std_cases()))
].

std_encode_string_test_() ->
[ ?_assertEqual(Out, encode(In))
|| {In, Out} <- stringinput_cases(std_cases()) ].
[
?_assertEqual(Out, encode(In))
|| {In, Out} <- stringinput_cases(std_cases())
].

std_decode_string_test_() ->
[ ?_assertEqual(Out, decode(In))
|| {Out, In} <- stringoutput_cases(std_cases()) ].
[
?_assertEqual(Out, decode(In))
|| {Out, In} <- stringoutput_cases(std_cases())
].

hex_cases() ->
[{<<>>, <<>>},
{<<"f">>, <<"CO======">>},
{<<"fo">>, <<"CPNG====">>},
{<<"foo">>, <<"CPNMU===">>},
{<<"foob">>, <<"CPNMUOG=">>},
{<<"fooba">>, <<"CPNMUOJ1">>},
{<<"foobar">>, <<"CPNMUOJ1E8======">>}].
[
{<<>>, <<>>},
{<<"f">>, <<"CO======">>},
{<<"fo">>, <<"CPNG====">>},
{<<"foo">>, <<"CPNMU===">>},
{<<"foob">>, <<"CPNMUOG=">>},
{<<"fooba">>, <<"CPNMUOJ1">>},
{<<"foobar">>, <<"CPNMUOJ1E8======">>}
].

hex_encode_test_() ->
[ ?_assertEqual(Out, encode(In, [hex])) || {In, Out} <- hex_cases() ].
[?_assertEqual(Out, encode(In, [hex])) || {In, Out} <- hex_cases()].

hex_decode_test_() ->
[ ?_assertEqual(Out, decode(In, [hex])) || {Out, In} <- hex_cases() ].
[?_assertEqual(Out, decode(In, [hex])) || {Out, In} <- hex_cases()].

hex_encode_lower_test_() ->
[ ?_assertEqual(Out, encode(In, [hex,lower]))
|| {In, Out} <- lower_cases(hex_cases()) ].
[
?_assertEqual(Out, encode(In, [hex, lower]))
|| {In, Out} <- lower_cases(hex_cases())
].

hex_decode_lower_test_() ->
[ ?_assertEqual(Out, decode(In, [hex]))
|| {Out, In} <- lower_cases(hex_cases()) ].
[
?_assertEqual(Out, decode(In, [hex]))
|| {Out, In} <- lower_cases(hex_cases())
].

hex_encode_nopad_test_() ->
[ ?_assertEqual(Out, encode(In, [hex,nopad]))
|| {In, Out} <- nopad_cases(hex_cases()) ].
[
?_assertEqual(Out, encode(In, [hex, nopad]))
|| {In, Out} <- nopad_cases(hex_cases())
].

hex_encode_lower_nopad_test_() ->
[ ?_assertEqual(Out, encode(In, [hex,lower,nopad]))
|| {In, Out} <- nopad_cases(lower_cases(hex_cases())) ].
[
?_assertEqual(Out, encode(In, [hex, lower, nopad]))
|| {In, Out} <- nopad_cases(lower_cases(hex_cases()))
].

hex_encode_string_test_() ->
[ ?_assertEqual(Out, encode(In, [hex]))
|| {In, Out} <- stringinput_cases(hex_cases()) ].
[
?_assertEqual(Out, encode(In, [hex]))
|| {In, Out} <- stringinput_cases(hex_cases())
].

hex_decode_string_test_() ->
[ ?_assertEqual(Out, decode(In, [hex]))
|| {Out, In} <- stringoutput_cases(hex_cases()) ].
[
?_assertEqual(Out, decode(In, [hex]))
|| {Out, In} <- stringoutput_cases(hex_cases())
].

-endif.

0 comments on commit 4fa399f

Please sign in to comment.