Packages
caffeine_lang
6.3.0
6.3.1
6.3.0
6.2.2
6.2.1
6.2.0
6.1.2
6.1.1
6.1.0
6.0.0
5.6.0
5.5.0
5.4.4
5.4.3
5.4.2
5.4.1
5.4.0
5.3.0
5.2.0
5.1.1
5.1.0
5.0.12
5.0.11
5.0.10
5.0.8
5.0.7
5.0.6
5.0.5
5.0.4
5.0.1
5.0.0
4.10.0
4.9.0
4.8.3
4.8.2
4.8.1
4.8.0
4.7.9
4.7.8
4.7.7
4.7.6
4.7.5
4.6.7
4.6.6
4.6.5
4.6.4
4.6.3
4.6.2
4.6.0
4.5.1
4.5.0
4.4.4
4.4.3
4.4.1
4.4.0
4.3.7
4.3.6
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.0.2
1.0.1
0.1.0
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.2
0.0.1
A compiler for generating reliability artifacts from service expectation definitions.
Current section
Files
Jump to
Current section
Files
src/caffeine_lang@string_distance.erl
-module(caffeine_lang@string_distance).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/caffeine_lang/string_distance.gleam").
-export([levenshtein/2, closest_match/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/caffeine_lang/string_distance.gleam", 45).
-spec build_row_loop(
list(integer()),
list(binary()),
binary(),
list(integer()),
integer()
) -> {list(integer()), integer()}.
build_row_loop(Prev_row, B_remaining, A_char, Acc, Prev_val) ->
case {B_remaining, Prev_row} of
{[], _} ->
{Acc, Prev_val};
{[B_char | B_rest], [Diag | Prev_rest]} ->
Above = case Prev_rest of
[V | _] ->
V;
[] ->
0
end,
Cost = case A_char =:= B_char of
true ->
0;
false ->
1
end,
Val = gleam@int:min(
Prev_val + 1,
gleam@int:min(Above + 1, Diag + Cost)
),
build_row_loop(Prev_rest, B_rest, A_char, [Val | Acc], Val);
{_, []} ->
{Acc, Prev_val}
end.
-file("src/caffeine_lang/string_distance.gleam", 34).
?DOC(" Builds one row of the Levenshtein matrix.\n").
-spec build_row(list(integer()), list(binary()), binary(), integer()) -> list(integer()).
build_row(Prev_row, B_graphemes, A_char, Initial_val) ->
{Row, _} = build_row_loop(
Prev_row,
B_graphemes,
A_char,
[Initial_val],
Initial_val
),
lists:reverse(Row).
-file("src/caffeine_lang/string_distance.gleam", 10).
?DOC(false).
-spec levenshtein(binary(), binary()) -> integer().
levenshtein(A, B) ->
A_graphemes = gleam@string:to_graphemes(A),
B_graphemes = gleam@string:to_graphemes(B),
B_len = erlang:length(B_graphemes),
Initial_row = gleam@int:range(B_len, -1, [], fun(Acc, I) -> [I | Acc] end),
Result_row = gleam@list:index_fold(
A_graphemes,
Initial_row,
fun(Prev_row, A_char, I@1) ->
build_row(Prev_row, B_graphemes, A_char, I@1 + 1)
end
),
case gleam@list:last(Result_row) of
{ok, D} ->
D;
{error, nil} ->
0
end.
-file("src/caffeine_lang/string_distance.gleam", 73).
?DOC(false).
-spec closest_match(binary(), list(binary())) -> gleam@option:option(binary()).
closest_match(Target, Candidates) ->
Target_len = string:length(Target),
Threshold = gleam@int:max(
2,
erlang:trunc((erlang:float(Target_len) * 0.4) + 0.99)
),
Result = gleam@list:fold(
Candidates,
none,
fun(Best, Candidate) ->
Dist = levenshtein(Target, Candidate),
case Dist > Threshold of
true ->
Best;
false ->
case Best of
none ->
{some, {Candidate, Dist}};
{some, {_, Best_dist}} ->
case Dist < Best_dist of
true ->
{some, {Candidate, Dist}};
false ->
Best
end
end
end
end
),
case Result of
{some, {Name, _}} ->
{some, Name};
none ->
none
end.