Skip to content

Commit

Permalink
[#89] Add specs.
Browse files Browse the repository at this point in the history
Bonus Track: more functions for user_default
  • Loading branch information
Brujo Benavides committed Nov 6, 2015
1 parent 211449c commit c6c2395
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 13 deletions.
40 changes: 29 additions & 11 deletions src/ktn_random.erl
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,26 @@
handle_info/2
]).

-type state() :: {}.

-spec start_link() -> {ok, pid()}.
start_link() ->
Seed = os:timestamp(),
gen_server:start_link({local, ?MODULE}, ?MODULE, Seed, []).

-spec generate() -> nonempty_string().
generate() ->
gen_server:call(?MODULE, random_string).

-spec generate(pos_integer()) -> nonempty_string().
generate(Length) ->
gen_server:call(?MODULE, {random_string, Length}).

-spec uniform(non_neg_integer()) -> non_neg_integer().
uniform(Max) ->
gen_server:call(?MODULE, {random_uniform, Max}).

-spec uniform(non_neg_integer(), non_neg_integer()) -> non_neg_integer().
uniform(Min, Max) ->
gen_server:call(?MODULE, {random_uniform, Min, Max}).

Expand All @@ -43,30 +50,41 @@ uniform(Min, Max) ->
pick(List) -> lists:nth(uniform(length(List)), List).

%% Callback implementation
-spec init(erlang:timestamp()) -> {ok, state()}.
init(Seed) ->
_ = random:seed(Seed),
{ok, {}}. % no state necessary, random uses process dictionary

-spec handle_call
(random_string, _, state()) ->
{reply, nonempty_string(), state()};
({random_string, pos_integer()}, _, state()) ->
{reply, nonempty_string(), state()};
({random_uniform, non_neg_integer()}, _, state()) ->
{reply, non_neg_integer(), state()};
({random_uniform, non_neg_integer(), non_neg_integer()}, _, state()) ->
{reply, non_neg_integer(), state()}.
handle_call(random_string, _From, State) ->
{reply, random_string(), State};
handle_call({random_string, Length}, _From, State) ->
{reply, random_string(Length), State};
handle_call({random_uniform, Max}, _From, State) ->
{reply, random_uniform(Max), State};
handle_call({random_uniform, Min, Max}, _From, State) ->
{reply, random_uniform(Min, Max), State};
handle_call(_Other, _From, State) ->
{noreply, State}.
{reply, random_uniform(Min, Max), State}.

%% Unused callbacks
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Msg, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVersion, State, _Extra) ->
{ok, State}.
-spec handle_cast(_, state()) -> {noreply, state()}.
handle_cast(_Msg, State) -> {noreply, State}.

-spec handle_info(_, state()) -> {noreply, state()}.
handle_info(_Msg, State) -> {noreply, State}.

-spec terminate(_, state()) -> ok.
terminate(_Reason, _State) -> ok.

-spec code_change(_, state(), _) -> {ok, state()}.
code_change(_OldVersion, State, _Extra) -> {ok, State}.

%% internal
random_string() ->
Expand Down
3 changes: 2 additions & 1 deletion src/ktn_recipe.erl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ initial_fun(Transitions) ->
InitialFun -> InitialFun
end.

-spec normalize(atom() | transitions()) -> normalized_transitions().
-spec normalize(module() | transitions()) -> normalized_transitions().
normalize(Mod) when is_atom(Mod) ->
Transitions = Mod:transitions(),
[ case Transition of
Expand Down Expand Up @@ -182,6 +182,7 @@ pretty_print_normalized(NormalizedTransitions) ->
%% correct arity.
%% It does not verify structural properties of the FSM defined by the transition
%% table (e.g. connected, acyclic, arboreal).
-spec verify(atom() | transitions()) -> term().
verify(Mod) when is_atom(Mod) ->
InitialState = #{recipe_type => implicit, recipe => Mod},
run(ktn_recipe_verify, InitialState);
Expand Down
19 changes: 19 additions & 0 deletions src/ktn_recipe_verify.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,27 @@
, verify_transition_exports/1
]).

-type error() :: term().

-type state() :: #{ recipe_type => implicit | explicit
, recipe => module() | ktn_recipe:transitions()
, transitions => ktn_recipe:normalized_transitions()
, error => error()
}.

-spec transitions() -> verify_exports
| verify_normalizability
| verify_transitions
| verify_transition_exports
.
transitions() ->
[ verify_exports
, verify_normalizability
, verify_transitions
, verify_transition_exports
].

-spec verify_exports(state()) -> {ok, state()} | {error, state()}.
verify_exports(State = #{recipe_type := implicit, recipe := Mod}) ->
% Ensure that the module exported transitions/0, process_result/1 and
% process_error/1.
Expand All @@ -44,6 +58,7 @@ verify_exports(State = #{recipe_type := explicit}) ->
% Nothing needs to be done here for explicit recipes.
{ok, State}.

-spec verify_normalizability(state()) -> {ok, state()} | {error, state()}.
verify_normalizability(State = #{recipe := Recipe}) ->
try
{ok, State#{transitions => ktn_recipe:normalize(Recipe)}}
Expand All @@ -52,6 +67,7 @@ verify_normalizability(State = #{recipe := Recipe}) ->
{error, State#{error => NormalizationError}}
end.

-spec verify_transitions(state()) -> {ok, state()} | {error, state()}.
verify_transitions(
State = #{recipe_type := implicit, transitions := Transitions}
) ->
Expand Down Expand Up @@ -116,6 +132,7 @@ verify_transitions(F, Transitions) ->
InvalidElements -> {invalid_transition_table_elements, InvalidElements}
end.

-spec verify_transition_exports(state()) -> {ok, state()} | {error, state()}.
verify_transition_exports(State = #{transitions := Transitions}) ->
% Gather all the step functions mentioned in the transition table...
% ...and ensure that they are exported.
Expand Down Expand Up @@ -148,8 +165,10 @@ verify_transition_exports(State = #{transitions := Transitions}) ->
NotExported -> {error, State#{error => {not_exported, NotExported}}}
end.

-spec process_result(state()) -> ok.
process_result(_State) ->
ok.

-spec process_error(state()) -> {error, error()}.
process_error(#{error := Error}) ->
{error, Error}.
3 changes: 2 additions & 1 deletion src/ktn_rpc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ multicall(M, F, A) ->
Errors = [Error || {badrpc, Error} <- Results],
case {Errors, BadNodes} of
{[], []} -> ok;
{[], BadNodes} -> {error, {bad_nodes, [{mfa, {M, F, A}}, {nodes, BadNodes}]}};
{[], BadNodes} ->
{error, {bad_nodes, [{mfa, {M, F, A}}, {nodes, BadNodes}]}};
{Errors, _} -> {error, {unknown, [{mfa, {M, F, A}}, {errors, Errors}]}}
end.
10 changes: 10 additions & 0 deletions src/ktn_task.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,27 @@
wait_for_success/3
]).

-type task(T) :: fun(() -> T).

-spec wait_for(task(T1), T2) -> {error, {timeout, {badmatch, T1}}} | T2
when is_subtype(T2, T1).
wait_for(Task, ExpectedAnswer) ->
wait_for(Task, ExpectedAnswer, 200, 10).

-spec wait_for(task(T1), T2, pos_integer(), pos_integer()) ->
{error, {timeout, {badmatch, T1}}} | T2
when is_subtype(T2, T1).
wait_for(Task, ExpectedAnswer, SleepTime, Retries) ->
wait_for_success(fun() ->
ExpectedAnswer = Task()
end, SleepTime, Retries).

-spec wait_for_success(task(T)) -> {error, {timeout, term()}} | T.
wait_for_success(Task) ->
wait_for_success(Task, 200, 10).

-spec wait_for_success(task(T), pos_integer(), pos_integer()) ->
{error, {timeout, term()}} | T.
wait_for_success(Task, SleepTime, Retries) ->
wait_for_success(Task, undefined, SleepTime, Retries).

Expand Down
16 changes: 16 additions & 0 deletions src/ktn_type.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
get/1
]).

-type type() :: integer
| float
| list
| tuple
| binary
| bitstring
| boolean
| function
| pid
| port
| reference
| atom
| unknown
.

-spec get(term()) -> type().
get(X) when is_integer(X) -> integer;
get(X) when is_float(X) -> float;
get(X) when is_list(X) -> list;
Expand Down
21 changes: 21 additions & 0 deletions src/ktn_user_default.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,36 @@
-export([
xref/0
,l_all/1
, cmd/1
, all_modules/0
, mk/0
]).

-spec xref() -> proplists:proplist().
xref() ->
xref:d("ebin").

-spec l_all([module()]) -> [{module(), code:load_ret()}].
l_all(Mods) when is_list(Mods) ->
lists:foldl(fun(Mod, A) ->
Ret=[{Mod, shell_default:l(Mod)}],
lists:append(A, Ret)
end, [], Mods);
l_all(Mod) ->
l_all([Mod]).

-spec cmd(iodata()) -> _.
cmd(Cmd) ->
io:format("~s~n", [os:cmd(Cmd)]).

-spec all_modules() -> module().
all_modules() ->
[ list_to_atom(
re:replace(
filename:basename(F), "[.]beam$", "", [{return, list}]))
|| P <- code:get_path(),
string:str(P, code:lib_dir()) == 0,
F <- filelib:wildcard(filename:join(P, "*.beam"))].

-spec mk() -> up_to_date.
mk() -> up_to_date = make:all([load]).

0 comments on commit c6c2395

Please sign in to comment.