Modified:
branches/RB-0.2/lib/ewgi/include/ewgi.hrl
branches/RB-0.2/lib/ewgi/src/ewgi_api.erl
branches/RB-0.2/lib/ewgi/src/ewgi_application.erl
branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl
branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl
Log:
Added further Dialyzer specifications
Modified: branches/RB-0.2/lib/ewgi/include/ewgi.hrl
==============================================================================
--- branches/RB-0.2/lib/ewgi/include/ewgi.hrl (original)
+++ branches/RB-0.2/lib/ewgi/include/ewgi.hrl Tue Nov 18 08:22:35 2008
@@ -60,15 +60,21 @@
-define(DEFAULT_CHUNKSIZE, 4096).
-%% Convenience records representing request/response contexts
+-type ewgi_propval() :: atom() | integer() | string() | binary().
+-type ewgi_prop() :: {ewgi_propval(), ewgi_propval()}.
+-type ewgi_proplist() :: [ewgi_prop()].
+
+%% These should go somewhere else:
+-type gb_tree_node() :: {any(), any(), any(), any()} | 'nil'.
+-type gb_tree() :: {non_neg_integer(), gb_tree_node()}.
-%% @type bag() = list()
--type bag() :: list().
+%% @type bag() = gb_tree()
+-type bag() :: gb_tree().
%%% Note: Dialyzer currently doesn't support recursive types. When it
does, this should change:
%%%-type ewgi_ri_callback() :: fun(('eof' | {data, binary()}) -> iolist()
| ewgi_ri_callback()).
%% @type ewgi_ri_callback() = function()
--type ewgi_ri_callback() :: fun(('eof' | {data, binary()}) -> iolist() |
function()).
+-type ewgi_ri_callback() :: fun(('eof' | {data, binary()}) -> iolist() |
function()) | iolist().
%% @type ewgi_read_input() = function()
-type ewgi_read_input() :: fun((ewgi_ri_callback(), integer()) ->
ewgi_ri_callback()).
@@ -79,6 +85,8 @@
%% @type ewgi_version() = {integer(), integer()}
-type ewgi_version() :: {integer(), integer()}.
+%% Convenience records representing request/response contexts
+
%% @type ewgi_spec() = {'ewgi_spec', function(), function(), string(),
%% ewgi_version(), bag()}
%% -type(ewgi_spec() :: {'ewgi_spec', ewgi_read_input(),
ewgi_write_error(),
@@ -129,7 +137,7 @@
%% ewgi_val(), ewgi_val(), ewgi_val()}
-record(ewgi_request, {
auth_type :: ewgi_val(),
- content_length :: integer(),
+ content_length :: non_neg_integer(),
content_type :: ewgi_val(),
ewgi = #ewgi_spec{} :: #ewgi_spec{},
gateway_interface :: ewgi_val(),
@@ -160,12 +168,15 @@
%% @type ewgi_message_body() = binary() | iolist() | stream()
-type ewgi_message_body() :: binary() | iolist() | stream().
+%% @type ewgi_header_list() = [{ewgi_header_key(), ewgi_header_val()}]
+-type ewgi_header_list() :: [{ewgi_header_key(), ewgi_header_val()}].
+
%% @type ewgi_response() = {'ewgi_response', ewgi_status(),
%% [{ewgi_header_key(), ewgi_header_val()}],
%% ewgi_message_body(), any()}
-record(ewgi_response, {
status :: ewgi_status(),
- headers = [] :: [{ewgi_header_key(), ewgi_header_val()}],
+ headers = [] :: ewgi_header_list(),
message_body :: ewgi_message_body(),
err :: any()}).
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_api.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_api.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_api.erl Tue Nov 18 08:22:35 2008
@@ -25,7 +25,7 @@
%%%-------------------------------------------------------------------
-module(ewgi_api).
--include("ewgi.hrl").
+-include_lib("ewgi.hrl").
%% Record helpers
-export([empty_request/0, empty_response/0, context/2, request/2,
response/2,
@@ -80,104 +80,137 @@
is_record(Response, ewgi_response) ->
#ewgi_context{request=Request, response=Response}.
-request(Req, Ctx) when is_record(Req, ewgi_request), is_record(Ctx,
ewgi_context) ->
+-spec request(#ewgi_request{}, #ewgi_context{}) -> #ewgi_context{}.
+request(Req, Ctx) when is_record(Req, ewgi_request),
+ is_record(Ctx, ewgi_context) ->
Ctx#ewgi_context{request=Req}.
-response(Rsp, Ctx) when is_record(Rsp, ewgi_response), is_record(Ctx,
ewgi_context) ->
+-spec response(#ewgi_response{}, #ewgi_context{}) -> #ewgi_context{}.
+response(Rsp, Ctx) when is_record(Rsp, ewgi_response),
+ is_record(Ctx, ewgi_context) ->
Ctx#ewgi_context{response=Rsp}.
+-spec response(#ewgi_context{}) -> #ewgi_response{}.
response(#ewgi_context{response=R}) ->
R.
+-spec request(#ewgi_context{}) -> #ewgi_request{}.
request(#ewgi_context{request=R}) ->
R.
+-spec response_headers(#ewgi_context{}) -> ewgi_header_list().
response_headers(#ewgi_context{response=#ewgi_response{headers=V}}) ->
V.
+-spec response_status(#ewgi_context{}) -> ewgi_status().
response_status(#ewgi_context{response=#ewgi_response{status=V}}) ->
V.
+-spec response_message_body(#ewgi_context{}) -> ewgi_message_body().
response_message_body(#ewgi_context{response=#ewgi_response{message_body=V}})
->
V.
+-spec response_error(#ewgi_context{}) -> any().
response_error(#ewgi_context{response=#ewgi_response{err=V}}) ->
V.
+-spec response_headers(ewgi_header_list(), #ewgi_context{}) ->
#ewgi_context{}.
response_headers(V, #ewgi_context{response=Rsp0}=Ctx0) ->
Rsp = Rsp0#ewgi_response{headers=V},
Ctx = Ctx0#ewgi_context{response=Rsp},
Ctx.
+-spec response_status(ewgi_status(), #ewgi_context{}) -> #ewgi_context{}.
response_status(V, #ewgi_context{response=Rsp0}=Ctx0) ->
Rsp = Rsp0#ewgi_response{status=V},
Ctx = Ctx0#ewgi_context{response=Rsp},
Ctx.
+-spec response_message_body(ewgi_message_body(), #ewgi_context{}) ->
#ewgi_context{}.
response_message_body(V, #ewgi_context{response=Rsp0}=Ctx0) ->
Rsp = Rsp0#ewgi_response{message_body=V},
Ctx = Ctx0#ewgi_context{response=Rsp},
Ctx.
+-spec response_error(any(), #ewgi_context{}) -> #ewgi_context{}.
response_error(V, #ewgi_context{response=Rsp0}=Ctx0) ->
Rsp = Rsp0#ewgi_response{err=V},
Ctx = Ctx0#ewgi_context{response=Rsp},
Ctx.
+-spec auth_type(#ewgi_context{}) -> ewgi_val().
auth_type(#ewgi_context{request=#ewgi_request{auth_type=V}}) ->
V.
+-spec content_length(#ewgi_context{}) -> non_neg_integer().
content_length(#ewgi_context{request=#ewgi_request{content_length=V}}) ->
V.
+-spec content_type(#ewgi_context{}) -> ewgi_val().
content_type(#ewgi_context{request=#ewgi_request{content_type=V}}) ->
V.
+-spec gateway_interface(#ewgi_context{}) -> ewgi_val().
gateway_interface(#ewgi_context{request=#ewgi_request{gateway_interface=V}})
->
V.
+-spec path_info(#ewgi_context{}) -> ewgi_val().
path_info(#ewgi_context{request=#ewgi_request{path_info=V}}) ->
V.
+-spec path_translated(#ewgi_context{}) -> ewgi_val().
path_translated(#ewgi_context{request=#ewgi_request{path_translated=V}}) ->
V.
+-spec query_string(#ewgi_context{}) -> ewgi_val().
query_string(#ewgi_context{request=#ewgi_request{query_string=V}}) ->
V.
+-spec remote_addr(#ewgi_context{}) -> ewgi_val().
remote_addr(#ewgi_context{request=#ewgi_request{remote_addr=V}}) ->
V.
+-spec remote_host(#ewgi_context{}) -> ewgi_val().
remote_host(#ewgi_context{request=#ewgi_request{remote_host=V}}) ->
V.
+-spec remote_ident(#ewgi_context{}) -> ewgi_val().
remote_ident(#ewgi_context{request=#ewgi_request{remote_ident=V}}) ->
V.
+-spec remote_user(#ewgi_context{}) -> ewgi_val().
remote_user(#ewgi_context{request=#ewgi_request{remote_user=V}}) ->
V.
+-spec remote_user_data(#ewgi_context{}) -> ewgi_val().
remote_user_data(#ewgi_context{request=#ewgi_request{remote_user_data=V}})
->
V.
+-spec request_method(#ewgi_context{}) -> ewgi_request_method().
request_method(#ewgi_context{request=#ewgi_request{request_method=V}}) ->
V.
+-spec script_name(#ewgi_context{}) -> ewgi_val().
script_name(#ewgi_context{request=#ewgi_request{script_name=V}}) ->
V.
+-spec server_name(#ewgi_context{}) -> ewgi_val().
server_name(#ewgi_context{request=#ewgi_request{server_name=V}}) ->
V.
+-spec server_port(#ewgi_context{}) -> ewgi_val().
server_port(#ewgi_context{request=#ewgi_request{server_port=V}}) ->
V.
+-spec server_protocol(#ewgi_context{}) -> ewgi_val().
server_protocol(#ewgi_context{request=#ewgi_request{server_protocol=V}}) ->
V.
+-spec server_software(#ewgi_context{}) -> ewgi_val().
server_software(#ewgi_context{request=#ewgi_request{server_software=V}}) ->
V.
+-spec get_header_value(string(), #ewgi_context{}) -> ewgi_header_val().
get_header_value(Hdr0, Ctx) when is_list(Hdr0) ->
Hdr = string:to_lower(Hdr0),
get_header1(Hdr, Ctx).
@@ -302,22 +335,36 @@
{"user-agent", H#ewgi_http_headers.http_user_agent},
{"x-http-method-override",
H#ewgi_http_headers.http_x_http_method_override}|Acc].
+-spec read_input(#ewgi_context{}) -> ewgi_ri_callback() | 'undefined'.
read_input(#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=F}}})
->
F.
-read_input(Callback, Length,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=F}}}) ->
+-spec read_input(ewgi_ri_callback(), non_neg_integer(), #ewgi_context{})
-> ewgi_ri_callback() | 'undefined'.
+read_input(Callback, Length,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=undefined}}})
+ when is_function(Callback, 1),
+ is_integer(Length),
+ Length >= 0 ->
+ undefined;
+read_input(Callback, Length,
#ewgi_context{request=#ewgi_request{ewgi=#ewgi_spec{read_input=F}}})
+ when is_function(F, 2),
+ is_function(Callback, 1),
+ is_integer(Length),
+ Length >= 0 ->
F(Callback, Length).
-%% @spec read_input_string(integer(), ewgi_context()) -> string()
+%% @spec read_input_string(non_neg_integer(), ewgi_context()) -> string()
| {error, no_input}
%% @doc Reads the client message body into a string from the EWGI context.
--spec read_input_string(integer(), #ewgi_context{}) -> string().
-
-read_input_string(L, Ctx) when is_integer(L) ->
- R = read_input(Ctx),
- Iol = R(read_input_string_cb([]), L),
- Bin = iolist_to_binary(Iol),
- binary_to_list(Bin).
+-spec read_input_string(non_neg_integer(), #ewgi_context{}) -> [byte()] |
{'error', 'no_input'}.
+read_input_string(L, Ctx) when is_integer(L), L >= 0 ->
+ case read_input(read_input_string_cb([]), L, Ctx) of
+ undefined ->
+ {error, no_input};
+ Iol ->
+ Bin = iolist_to_binary(Iol),
+ binary_to_list(Bin)
+ end.
+-spec read_input_string_cb(list()) -> ewgi_ri_callback().
read_input_string_cb(Acc) ->
F = fun(eof) ->
lists:reverse(Acc);
@@ -398,10 +445,9 @@
%% @doc URL encodes a proplist of parameters.
%% @end
%%--------------------------------------------------------------------
+-spec urlencode(ewgi_proplist()) -> string().
urlencode(Props) ->
- QuotedL = lists:foldl(fun({K, V}, AccIn) ->
- [[quote(K), $=, quote(V)] | AccIn]
- end, [], Props),
+ QuotedL = [[quote(K), $=, quote(V)] || {K, V} <- Props],
lists:flatten(join(QuotedL, $&)).
%%--------------------------------------------------------------------
@@ -410,13 +456,17 @@
%% @doc URL encodes the given term.
%% @end
%%--------------------------------------------------------------------
+-spec quote(ewgi_propval()) -> string().
quote(Term) when is_atom(Term) ->
quote(atom_to_list(Term));
quote(Term) when is_integer(Term) ->
quote(integer_to_list(Term));
-quote(Term) ->
+quote(Term) when is_binary(Term) ->
+ quote(binary_to_list(Term));
+quote(Term) when is_list(Term) ->
quote(Term, []).
+-spec quote(string(), string()) -> string().
quote([], Acc) ->
lists:reverse(Acc);
%% low alpha chars
@@ -452,13 +502,11 @@
%% returns the first proplist parsed from String or an error.
%% @end
%%--------------------------------------------------------------------
+-spec parse_kv(string()) -> {{string(), string()}, string()}.
parse_kv(String) ->
P = and_parser([until(fun is_equal/1), until(fun is_amp/1)]),
- case P(String) of
- {ok, [K, V], Rest} ->
- {{unquote(K), unquote(V)}, Rest};
- {error, Reason} -> {error, Reason}
- end.
+ {ok, [K, V], Rest} = P(String),
+ {{unquote(K), unquote(V)}, Rest}.
%%--------------------------------------------------------------------
%% @spec and_parser(Rules::rules()) -> parsed()|{error, Reason}
@@ -471,21 +519,19 @@
%% If a rule fails returns an error.
%% @end
%%--------------------------------------------------------------------
+-type parser() :: fun((list()) -> {'ok', list(), list()}).
+-spec and_parser([parser()]) -> parser().
and_parser(Rules) ->
fun(Tmpl) ->
and_parser(Rules, Tmpl, [])
end.
+
+-spec and_parser(list(), list(), list()) -> {'ok', list(), list()}.
and_parser([], Tmpl, SoFar) ->
{ok, lists:reverse(SoFar), Tmpl};
and_parser([Rule|T], Tmpl, SoFar) ->
- case Rule(Tmpl) of
- {error, Reason} ->
- {error, Reason};
- {ok, Rest} ->
- and_parser(T, Rest, SoFar);
- {ok, Tok, Rest} ->
- and_parser(T, Rest, [Tok|SoFar])
- end.
+ {ok, Tok, Rest} = Rule(Tmpl),
+ and_parser(T, Rest, [Tok|SoFar]).
%%--------------------------------------------------------------------
%% @spec until(predicate()) -> parsed()|{error, Reason}
@@ -496,8 +542,12 @@
%% output what it gets until P(H) is true.
%% @end
%%--------------------------------------------------------------------
+-type predicate() :: fun((list()) -> {'true', list()} | 'false').
+-spec until(predicate()) -> parser().
until(P) ->
fun (Tmpl) -> until(P, Tmpl, []) end.
+
+-spec until(predicate(), list(), list()) -> {'ok', list(), list()}.
until(_P, [], Parsed) -> %% end of string so end parsing
{ok, lists:reverse(Parsed), []};
until(P, String, Parsed) ->
@@ -515,6 +565,7 @@
%% @doc Match = character at the head of string.
%% @end
%%--------------------------------------------------------------------
+-spec is_equal(string()) -> bool().
is_equal([$=|Rest]) ->
{true, Rest};
is_equal(_) ->
@@ -526,6 +577,7 @@
%% @doc Match & character or &amp; entity at the beginning of
string.
%% @end
%%--------------------------------------------------------------------
+-spec is_amp(string()) -> bool().
is_amp("&"++Rest) ->
{true, Rest};
is_amp([$&|Rest]) ->
@@ -561,8 +613,9 @@
%% @doc convert char to hex code.
%% @end
%%--------------------------------------------------------------------
-to_hex(C) when C < 10 -> $0 + C;
-to_hex(C) when C < 16 -> $A + (C - 10).
+-spec to_hex(0..16) -> byte().
+to_hex(C) when C >= 0, C < 10 -> $0 + C;
+to_hex(C) when C >= 0, C < 16 -> $A + (C - 10).
%%--------------------------------------------------------------------
%% @spec from_hex(hex()) -> char()
@@ -570,6 +623,7 @@
%% @doc Used to get char from hex code.
%% @end
%%--------------------------------------------------------------------
+-spec from_hex(byte()) -> 0..16.
from_hex(C) when C >= $0, C =< $9 -> C - $0;
from_hex(C) when C >= $a, C =< $f -> C - $a + 10;
from_hex(C) when C >= $A, C =< $F -> C - $A + 10.
@@ -581,9 +635,11 @@
%% The result is reversed for efficiency.
%% @end
%%--------------------------------------------------------------------
+-spec join([string()], string() | char()) -> string().
join(Strings, Sep) ->
join(Strings, Sep, []).
+-spec join([string()], string() | char(), list()) -> string().
join([], _Sep, _Acc) ->
[];
join([Last], _Sep, Acc) ->
@@ -591,6 +647,7 @@
join([H|Rest], Sep, Acc) ->
join(Rest, Sep, [Sep, H|Acc]).
+-spec nhdr(atom() | binary() | string()) -> string().
nhdr(L) when is_atom(L) ->
nhdr(atom_to_list(L));
nhdr(L) when is_binary(L) ->
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_application.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_application.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_application.erl Tue Nov 18 08:22:35
2008
@@ -31,7 +31,7 @@
%% Useful middleware
-export([module_mw/1, rpc_mw/3, mfa_mw/2]).
--include("ewgi.hrl").
+-include_lib("ewgi.hrl").
%% @spec run(Application::ewgi_app(), Context::ewgi_context()) ->
Context1::ewgi_context()
%% @doc Runs an EWGI application with Context and returns the new Context1.
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_mochiweb.erl Tue Nov 18 08:22:35 2008
@@ -28,7 +28,7 @@
%% ewgi callbacks
-export([run/1]).
--include("ewgi.hrl").
+-include_lib("ewgi.hrl").
-define(EWGI2MOCHI(Err, Hdrs), {element(1, Err), Hdrs, element(2, Err)}).
Modified: branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl
==============================================================================
--- branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl (original)
+++ branches/RB-0.2/lib/ewgi/src/ewgi_yaws.erl Tue Nov 18 08:22:35 2008
@@ -28,7 +28,7 @@
-export([run/1]).
-include_lib("yaws_api.hrl").
--include("ewgi.hrl").
+-include_lib("ewgi.hrl").
-define(INTERNAL_ERROR, [{status, 500}, {content, "text/plain",
<<"Internal Server Error">>}]).
-define(BAD_REQUEST, [{status, 400}, {content, "text/plain", <<"Bad
Request">>}]).