Current section
Files
Jump to
Current section
Files
src/eo_vsn.erl
%% Copyright © 2015 Pierre Fenoll ‹pierrefenoll@gmail.com›
%% See LICENSE for licensing information.
%% -*- coding: utf-8 -*-
-module(eo_vsn).
%% eo_vsn: handle VSNs loosely satisfaying SemVer.
-export([ get_vsn/1
, is_vsn/1
, '=<'/2
]).
-export_type([ vsn/0
]).
-type vsn() :: nonempty_list(non_neg_integer()).
%% API
-spec get_vsn (nonempty_string()) -> {true,vsn()} | false.
get_vsn (Str) ->
case re:run( Str, "^[^\\d]*(\\d+(?:[._]\\d+)*)(?:[^\\d].*)?$"
, [{capture,all_but_first,list}] ) of
{match, [Found]} ->
VSN = [list_to_integer(N) || N <- string:tokens(Found, "._")],
{true, VSN};
nomatch -> false
end.
-spec is_vsn (nonempty_string()) -> boolean().
is_vsn (Str) ->
false =/= get_vsn(Str).
-spec '=<' (vsn(), vsn()) -> boolean().
'=<' (VSNl0, VSNr0) ->
{VSNl, VSNr} =
case {length(VSNl0), length(VSNr0)} of
{Same, Same} -> {VSNl0, VSNr0};
{Big, Small} when Big > Small -> {VSNl0, pad(Big-Small, VSNr0)};
{Small, Big} -> {pad(Big-Small, VSNl0), VSNr0}
end,
cmp(VSNl, VSNr).
%% Internals
cmp ([X|Tl], [X|Tr]) -> cmp(Tl, Tr);
cmp ([L|_], [R|_]) when L < R -> true;
cmp ([_|_], [_|_]) -> false;
cmp ([], []) -> true.
pad (N, VSN) ->
VSN ++ lists:duplicate(N, 0).
%% End of Module.