Browse Source

Add the 'function' constraint

Loïc Hoguin 12 years ago
parent
commit
c2c333de8a
2 changed files with 15 additions and 3 deletions
  1. 2 1
      guide/routing.md
  2. 13 2
      src/cowboy_router.erl

+ 2 - 1
guide/routing.md

@@ -207,7 +207,7 @@ name, and the optional third element is the constraint's arguments.
 The following constraints are currently defined:
 The following constraints are currently defined:
 
 
  *  {Name, int}
  *  {Name, int}
- *  {Name, function, (fun(Value) -> true | {true, NewValue} | false)}
+ *  {Name, function, fun ((Value) -> true | {true, NewValue} | false)}
 
 
 The `int` constraint will check if the binding is a binary string
 The `int` constraint will check if the binding is a binary string
 representing an integer, and if it is, will convert the value to integer.
 representing an integer, and if it is, will convert the value to integer.
@@ -215,6 +215,7 @@ representing an integer, and if it is, will convert the value to integer.
 The `function` constraint will pass the binding value to a user specified
 The `function` constraint will pass the binding value to a user specified
 function that receives the binary value as its only argument and must
 function that receives the binary value as its only argument and must
 return whether it fulfills the constraint, optionally modifying the value.
 return whether it fulfills the constraint, optionally modifying the value.
+The value thus returned can be of any type.
 
 
 Note that constraint functions SHOULD be pure and MUST NOT crash.
 Note that constraint functions SHOULD be pure and MUST NOT crash.
 
 

+ 13 - 2
src/cowboy_router.erl

@@ -33,7 +33,8 @@
 -export_type([bindings/0]).
 -export_type([bindings/0]).
 -export_type([tokens/0]).
 -export_type([tokens/0]).
 
 
--type constraints() :: [{atom(), int}].
+-type constraints() :: [{atom(), int}
+	| {atom(), function, fun ((binary()) -> true | {true, any()} | false)}].
 -export_type([constraints/0]).
 -export_type([constraints/0]).
 
 
 -type route_match() :: binary() | string().
 -type route_match() :: binary() | string().
@@ -297,7 +298,9 @@ check_constraints([Constraint|Tail], Bindings) ->
 check_constraint({_, int}, Value) ->
 check_constraint({_, int}, Value) ->
 	try {true, list_to_integer(binary_to_list(Value))}
 	try {true, list_to_integer(binary_to_list(Value))}
 	catch _:_ -> false
 	catch _:_ -> false
-	end.
+	end;
+check_constraint({_, function, Fun}, Value) ->
+	Fun(Value).
 
 
 %% @doc Split a hostname into a list of tokens.
 %% @doc Split a hostname into a list of tokens.
 -spec split_host(binary()) -> tokens().
 -spec split_host(binary()) -> tokens().
@@ -524,6 +527,14 @@ match_constraints_test() ->
 		<<"ninenines.eu">>, <<"/path/123/">>),
 		<<"ninenines.eu">>, <<"/path/123/">>),
 	{error, notfound, path} = match(Dispatch,
 	{error, notfound, path} = match(Dispatch,
 		<<"ninenines.eu">>, <<"/path/NaN/">>),
 		<<"ninenines.eu">>, <<"/path/NaN/">>),
+	Dispatch2 = [{'_', [],
+		[{[<<"path">>, username], [{username, function,
+		fun(Value) -> Value =:= cowboy_bstr:to_lower(Value) end}],
+		match, []}]}],
+	{ok, _, [], [{username, <<"essen">>}], _, _} = match(Dispatch2,
+		<<"ninenines.eu">>, <<"/path/essen">>),
+	{error, notfound, path} = match(Dispatch2,
+		<<"ninenines.eu">>, <<"/path/ESSEN">>),
 	ok.
 	ok.
 
 
 -endif.
 -endif.