diff options
Diffstat (limited to 'server/_build/default/lib/cowboy/src/cowboy_constraints.erl')
-rw-r--r-- | server/_build/default/lib/cowboy/src/cowboy_constraints.erl | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/server/_build/default/lib/cowboy/src/cowboy_constraints.erl b/server/_build/default/lib/cowboy/src/cowboy_constraints.erl new file mode 100644 index 0000000..6509c4b --- /dev/null +++ b/server/_build/default/lib/cowboy/src/cowboy_constraints.erl @@ -0,0 +1,174 @@ +%% Copyright (c) 2014-2017, Loïc Hoguin <essen@ninenines.eu> +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(cowboy_constraints). + +-export([validate/2]). +-export([reverse/2]). +-export([format_error/1]). + +-type constraint() :: int | nonempty | fun(). +-export_type([constraint/0]). + +-type reason() :: {constraint(), any(), any()}. +-export_type([reason/0]). + +-spec validate(binary(), constraint() | [constraint()]) + -> {ok, any()} | {error, reason()}. +validate(Value, Constraints) when is_list(Constraints) -> + apply_list(forward, Value, Constraints); +validate(Value, Constraint) -> + apply_list(forward, Value, [Constraint]). + +-spec reverse(any(), constraint() | [constraint()]) + -> {ok, binary()} | {error, reason()}. +reverse(Value, Constraints) when is_list(Constraints) -> + apply_list(reverse, Value, Constraints); +reverse(Value, Constraint) -> + apply_list(reverse, Value, [Constraint]). + +-spec format_error(reason()) -> iodata(). +format_error({Constraint, Reason, Value}) -> + apply_constraint(format_error, {Reason, Value}, Constraint). + +apply_list(_, Value, []) -> + {ok, Value}; +apply_list(Type, Value0, [Constraint|Tail]) -> + case apply_constraint(Type, Value0, Constraint) of + {ok, Value} -> + apply_list(Type, Value, Tail); + {error, Reason} -> + {error, {Constraint, Reason, Value0}} + end. + +%% @todo {int, From, To}, etc. +apply_constraint(Type, Value, int) -> + int(Type, Value); +apply_constraint(Type, Value, nonempty) -> + nonempty(Type, Value); +apply_constraint(Type, Value, F) when is_function(F) -> + F(Type, Value). + +%% Constraint functions. + +int(forward, Value) -> + try + {ok, binary_to_integer(Value)} + catch _:_ -> + {error, not_an_integer} + end; +int(reverse, Value) -> + try + {ok, integer_to_binary(Value)} + catch _:_ -> + {error, not_an_integer} + end; +int(format_error, {not_an_integer, Value}) -> + io_lib:format("The value ~p is not an integer.", [Value]). + +nonempty(Type, <<>>) when Type =/= format_error -> + {error, empty}; +nonempty(Type, Value) when Type =/= format_error, is_binary(Value) -> + {ok, Value}; +nonempty(format_error, {empty, Value}) -> + io_lib:format("The value ~p is empty.", [Value]). + +-ifdef(TEST). + +validate_test() -> + F = fun(_, Value) -> + try + {ok, binary_to_atom(Value, latin1)} + catch _:_ -> + {error, not_a_binary} + end + end, + %% Value, Constraints, Result. + Tests = [ + {<<>>, [], <<>>}, + {<<"123">>, int, 123}, + {<<"123">>, [int], 123}, + {<<"123">>, [nonempty, int], 123}, + {<<"123">>, [int, nonempty], 123}, + {<<>>, nonempty, error}, + {<<>>, [nonempty], error}, + {<<"hello">>, F, hello}, + {<<"hello">>, [F], hello}, + {<<"123">>, [F, int], error}, + {<<"123">>, [int, F], error}, + {<<"hello">>, [nonempty, F], hello}, + {<<"hello">>, [F, nonempty], hello} + ], + [{lists:flatten(io_lib:format("~p, ~p", [V, C])), fun() -> + case R of + error -> {error, _} = validate(V, C); + _ -> {ok, R} = validate(V, C) + end + end} || {V, C, R} <- Tests]. + +reverse_test() -> + F = fun(_, Value) -> + try + {ok, atom_to_binary(Value, latin1)} + catch _:_ -> + {error, not_an_atom} + end + end, + %% Value, Constraints, Result. + Tests = [ + {<<>>, [], <<>>}, + {123, int, <<"123">>}, + {123, [int], <<"123">>}, + {123, [nonempty, int], <<"123">>}, + {123, [int, nonempty], <<"123">>}, + {<<>>, nonempty, error}, + {<<>>, [nonempty], error}, + {hello, F, <<"hello">>}, + {hello, [F], <<"hello">>}, + {123, [F, int], error}, + {123, [int, F], error}, + {hello, [nonempty, F], <<"hello">>}, + {hello, [F, nonempty], <<"hello">>} + ], + [{lists:flatten(io_lib:format("~p, ~p", [V, C])), fun() -> + case R of + error -> {error, _} = reverse(V, C); + _ -> {ok, R} = reverse(V, C) + end + end} || {V, C, R} <- Tests]. + +int_format_error_test() -> + {error, Reason} = validate(<<"string">>, int), + Bin = iolist_to_binary(format_error(Reason)), + true = is_binary(Bin), + ok. + +nonempty_format_error_test() -> + {error, Reason} = validate(<<>>, nonempty), + Bin = iolist_to_binary(format_error(Reason)), + true = is_binary(Bin), + ok. + +fun_format_error_test() -> + F = fun + (format_error, {test, <<"value">>}) -> + formatted; + (_, _) -> + {error, test} + end, + {error, Reason} = validate(<<"value">>, F), + formatted = format_error(Reason), + ok. + +-endif. |