added in module for semvar comparisons
This code implements comparisons using (list based) strings as semantic versions. It follows the stadard dictated by semvar.org. Signed-off-by: Eric Merritt <ericbmerritt@gmail.com>
This commit is contained in:
parent
251d8543b9
commit
9e6f98ba81
3 changed files with 101 additions and 3 deletions
|
@ -1,7 +1,11 @@
|
||||||
%% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-
|
%% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-
|
||||||
{application, erlware_commons,
|
{application, erlware_commons,
|
||||||
[{description, "Additional standard library for Erlang"},
|
[{description, "Additional standard library for Erlang"},
|
||||||
{vsn, "0.0.1"},
|
{vsn, "0.1.0"},
|
||||||
{modules, [ec_lists]},
|
{modules, [
|
||||||
|
ec_lists,
|
||||||
|
ec_string,
|
||||||
|
ec_semver
|
||||||
|
]},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [kernel, stdlib]}]}.
|
{applications, [kernel, stdlib]}]}.
|
||||||
|
|
|
@ -48,7 +48,7 @@ fetch(List, Fun)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% Test Functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
-ifndef(NOTEST).
|
-ifndef(NOTEST).
|
||||||
|
|
94
src/ec_semver.erl
Normal file
94
src/ec_semver.erl
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2011, Erlware LLC
|
||||||
|
%%% @doc
|
||||||
|
%%% Helper functions for working with semver versioning strings.
|
||||||
|
%%% See http://semver.org/ for the spec.
|
||||||
|
%%% @end
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(ec_semver).
|
||||||
|
|
||||||
|
-exports([
|
||||||
|
compare/2
|
||||||
|
]).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
%% @doc Is semver version string A bigger than version string B?
|
||||||
|
%% <pre>
|
||||||
|
%% Example: compare("3.2.5alpha", "3.10.6") returns: false
|
||||||
|
%% </pre>
|
||||||
|
-spec compare(VsnA::string(), VsnB::string()) -> boolean().
|
||||||
|
compare(VsnA, VsnB) ->
|
||||||
|
compare_toks(tokens(VsnA),tokens(VsnB)).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Internal Functions
|
||||||
|
%%%===================================================================
|
||||||
|
tokens(Vsn) ->
|
||||||
|
[MajorVsn, MinorVsn, RawPatch] = string:tokens(Vsn, "."),
|
||||||
|
{PatchVsn, PatchString} = split_patch(RawPatch),
|
||||||
|
{MajorVsn, MinorVsn, PatchVsn, PatchString}.
|
||||||
|
|
||||||
|
split_patch(RawPatch) ->
|
||||||
|
{PatchVsn, PatchStr} = split_patch(RawPatch, {"", ""}),
|
||||||
|
{lists:reverse(PatchVsn), PatchStr}.
|
||||||
|
|
||||||
|
split_patch([], Acc) ->
|
||||||
|
Acc;
|
||||||
|
split_patch([Dig|T], {PatchVsn, PatchStr}) when Dig >= $0 andalso Dig =< $9 ->
|
||||||
|
split_patch(T, {[Dig|PatchVsn], PatchStr});
|
||||||
|
split_patch(PatchStr, {PatchVsn, ""}) ->
|
||||||
|
{PatchVsn, PatchStr}.
|
||||||
|
|
||||||
|
compare_toks({MajA, MinA, PVA, PSA}, {MajB, MinB, PVB, PSB}) ->
|
||||||
|
compare_toks2({to_int(MajA), to_int(MinA), to_int(PVA), PSA},
|
||||||
|
{to_int(MajB), to_int(MinB), to_int(PVB), PSB}).
|
||||||
|
|
||||||
|
compare_toks2({MajA, _MinA, _PVA, _PSA}, {MajB, _MinB, _PVB, _PSB}) when MajA > MajB ->
|
||||||
|
true;
|
||||||
|
compare_toks2({_Maj, MinA, _PVA, _PSA}, {_Maj, MinB, _PVB, _PSB}) when MinA > MinB ->
|
||||||
|
true;
|
||||||
|
compare_toks2({_Maj, _Min, PVA, _PSA}, {_Maj, _Min, PVB, _PSB}) when PVA > PVB ->
|
||||||
|
true;
|
||||||
|
compare_toks2({_Maj, _Min, _PV, ""}, {_Maj, _Min, _PV, PSB}) when PSB /= ""->
|
||||||
|
true;
|
||||||
|
compare_toks2({_Maj, _Min, _PV, PSA}, {_Maj, _Min, _PV, ""}) when PSA /= ""->
|
||||||
|
false;
|
||||||
|
compare_toks2({_Maj, _Min, _PV, PSA}, {_Maj, _Min, _PV, PSB}) when PSA > PSB ->
|
||||||
|
true;
|
||||||
|
compare_toks2(_ToksA, _ToksB) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
to_int(String) ->
|
||||||
|
case catch list_to_integer(String) of
|
||||||
|
Integer when is_integer(Integer) ->
|
||||||
|
Integer;
|
||||||
|
_ ->
|
||||||
|
throw(invalid_semver_string)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Test Functions
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
-ifndef(NOTEST).
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
split_patch_test() ->
|
||||||
|
?assertMatch({"123", "alpha1"}, split_patch("123alpha1")).
|
||||||
|
|
||||||
|
compare_test() ->
|
||||||
|
?assertMatch(true, compare("1.2.3", "1.2.3alpha")),
|
||||||
|
?assertMatch(true, compare("1.2.3beta", "1.2.3alpha")),
|
||||||
|
?assertMatch(true, compare("1.2.4", "1.2.3")),
|
||||||
|
?assertMatch(true, compare("1.3.3", "1.2.3")),
|
||||||
|
?assertMatch(true, compare("2.2.3", "1.2.3")),
|
||||||
|
?assertMatch(true, compare("4.2.3", "3.10.3")),
|
||||||
|
?assertMatch(false, compare("1.2.3", "2.2.3")),
|
||||||
|
?assertThrow(invalid_semver_string, compare("1.b.2", "1.3.4")),
|
||||||
|
?assertThrow(invalid_semver_string, compare("1.2.2", "1.3.t")).
|
||||||
|
|
||||||
|
-endif.
|
Loading…
Add table
Add a link
Reference in a new issue