0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-15 12:40:25 +00:00

Change the type of bindings from a list to a map

Maps make more sense because the keys are unique.
This commit is contained in:
Loïc Hoguin 2017-02-19 16:51:16 +01:00
parent 91ae70b06c
commit 9255cdf1d7
No known key found for this signature in database
GPG key ID: 71366FF21851DF03
6 changed files with 25 additions and 33 deletions

View file

@ -197,8 +197,6 @@ And any other combination.
=== Bindings === Bindings
// @todo Bindings should probably be a map themselves.
Bindings are the host and path components that you chose Bindings are the host and path components that you chose
to extract when defining the routes of your application. to extract when defining the routes of your application.
They are only available after the routing. They are only available after the routing.
@ -222,10 +220,7 @@ To retrieve everything that was bound:
[source,erlang] [source,erlang]
Bindings = cowboy_req:bindings(Req). Bindings = cowboy_req:bindings(Req).
They are returned as a list of key/value pairs, with They are returned as a map, with keys being atoms.
keys being atoms.
// ...
The Cowboy router also allows you to capture many host The Cowboy router also allows you to capture many host
or path segments at once using the `...` qualifier. or path segments at once using the `...` qualifier.

View file

@ -8,10 +8,10 @@ cowboy_req:bindings - Access all values bound from the route
[source,erlang] [source,erlang]
---- ----
bindings(Req :: cowboy_req:req()) -> [{Name :: atom(), any()}] bindings(Req :: cowboy_req:req()) -> cowboy_router:bindings()
---- ----
Return all bindings as a list of key/value pairs. Return a map containing all bindings.
== Arguments == Arguments
@ -27,7 +27,7 @@ automatically converting numbers to integer).
== Changelog == Changelog
* *2.0*: Only the values are returned, it is no longer wrapped in a tuple. * *2.0*: Only the values are returned, they are no longer wrapped in a tuple.
* *1.0*: Function introduced. * *1.0*: Function introduced.
== Examples == Examples

View file

@ -33,7 +33,7 @@ a 404 response otherwise.
[source,erlang] [source,erlang]
---- ----
bindings() :: [{atom(), binary()}] bindings() :: #{atom() => any()}
---- ----
Bindings found during routing. Bindings found during routing.

View file

@ -326,18 +326,18 @@ binding(Name, Req) ->
-spec binding(atom(), req(), Default) -> any() | Default when Default::any(). -spec binding(atom(), req(), Default) -> any() | Default when Default::any().
binding(Name, #{bindings := Bindings}, Default) when is_atom(Name) -> binding(Name, #{bindings := Bindings}, Default) when is_atom(Name) ->
case lists:keyfind(Name, 1, Bindings) of case Bindings of
{_, Value} -> Value; #{Name := Value} -> Value;
false -> Default _ -> Default
end; end;
binding(Name, _, Default) when is_atom(Name) -> binding(Name, _, Default) when is_atom(Name) ->
Default. Default.
-spec bindings(req()) -> [{atom(), any()}]. -spec bindings(req()) -> cowboy_router:bindings().
bindings(#{bindings := Bindings}) -> bindings(#{bindings := Bindings}) ->
Bindings; Bindings;
bindings(_) -> bindings(_) ->
[]. #{}.
-spec header(binary(), req()) -> binary() | undefined. -spec header(binary(), req()) -> binary() | undefined.
header(Name, Req) -> header(Name, Req) ->

View file

@ -28,7 +28,7 @@
-export([compile/1]). -export([compile/1]).
-export([execute/2]). -export([execute/2]).
-type bindings() :: [{atom(), binary()}]. -type bindings() :: #{atom() => any()}.
-type tokens() :: [binary()]. -type tokens() :: [binary()].
-export_type([bindings/0]). -export_type([bindings/0]).
-export_type([tokens/0]). -export_type([tokens/0]).
@ -218,10 +218,10 @@ match([], _, _) ->
{error, notfound, host}; {error, notfound, host};
%% If the host is '_' then there can be no constraints. %% If the host is '_' then there can be no constraints.
match([{'_', [], PathMatchs}|_Tail], _, Path) -> match([{'_', [], PathMatchs}|_Tail], _, Path) ->
match_path(PathMatchs, undefined, Path, []); match_path(PathMatchs, undefined, Path, #{});
match([{HostMatch, Fields, PathMatchs}|Tail], Tokens, Path) match([{HostMatch, Fields, PathMatchs}|Tail], Tokens, Path)
when is_list(Tokens) -> when is_list(Tokens) ->
case list_match(Tokens, HostMatch, []) of case list_match(Tokens, HostMatch, #{}) of
false -> false ->
match(Tail, Tokens, Path); match(Tail, Tokens, Path);
{true, Bindings, HostInfo} -> {true, Bindings, HostInfo} ->
@ -276,21 +276,19 @@ check_constraints([Field|Tail], Bindings) when is_atom(Field) ->
check_constraints(Tail, Bindings); check_constraints(Tail, Bindings);
check_constraints([Field|Tail], Bindings) -> check_constraints([Field|Tail], Bindings) ->
Name = element(1, Field), Name = element(1, Field),
case lists:keyfind(Name, 1, Bindings) of case Bindings of
false -> #{Name := Value} ->
check_constraints(Tail, Bindings);
{_, Value} ->
Constraints = element(2, Field), Constraints = element(2, Field),
case cowboy_constraints:validate(Value, Constraints) of case cowboy_constraints:validate(Value, Constraints) of
true -> true ->
check_constraints(Tail, Bindings); check_constraints(Tail, Bindings);
{true, Value2} -> {true, Value2} ->
Bindings2 = lists:keyreplace(Name, 1, Bindings, check_constraints(Tail, Bindings#{Name => Value2});
{Name, Value2}),
check_constraints(Tail, Bindings2);
false -> false ->
nomatch nomatch
end end;
_ ->
check_constraints(Tail, Bindings)
end. end.
-spec split_host(binary()) -> tokens(). -spec split_host(binary()) -> tokens().
@ -369,13 +367,13 @@ list_match([E|Tail], [E|TailMatch], Binds) ->
%% Bind E to the variable name V and continue, %% Bind E to the variable name V and continue,
%% unless V was already defined and E isn't identical to the previous value. %% unless V was already defined and E isn't identical to the previous value.
list_match([E|Tail], [V|TailMatch], Binds) when is_atom(V) -> list_match([E|Tail], [V|TailMatch], Binds) when is_atom(V) ->
case lists:keyfind(V, 1, Binds) of case Binds of
{_, E} -> #{V := E} ->
list_match(Tail, TailMatch, Binds); list_match(Tail, TailMatch, Binds);
{_, _} -> #{V := _} ->
false; false;
false -> _ ->
list_match(Tail, TailMatch, [{V, E}|Binds]) list_match(Tail, TailMatch, Binds#{V => E})
end; end;
%% Match complete. %% Match complete.
list_match([], [], Binds) -> list_match([], [], Binds) ->

View file

@ -114,10 +114,9 @@ binding(Config) ->
<<"default">> = do_get_body("/args/binding/undefined/default", Config), <<"default">> = do_get_body("/args/binding/undefined/default", Config),
ok. ok.
%% @todo Do we really want a key/value list here instead of a map?
bindings(Config) -> bindings(Config) ->
doc("Values bound from request URI path."), doc("Values bound from request URI path."),
<<"[{key,<<\"bindings\">>}]">> = do_get_body("/bindings", Config), <<"#{key => <<\"bindings\">>}">> = do_get_body("/bindings", Config),
ok. ok.
header(Config) -> header(Config) ->