From e035ae3dbf9562b3b61ea3989bfdab35e7b0c954 Mon Sep 17 00:00:00 2001 From: Eric Merritt Date: Tue, 4 Sep 2012 20:27:19 -0500 Subject: [PATCH] fixes to dialyzer All types should now be correct and dialyzer runs successfully Signed-off-by: Jordan Wilberding --- Makefile | 4 ++-- src/ec_assoc_list.erl | 8 +++++--- src/ec_dict.erl | 6 ++++-- src/ec_dictionary.erl | 34 ++++++++++++++------------------ src/ec_file.erl | 45 ++++++++++++++++++++----------------------- src/ec_gb_trees.erl | 6 ++++-- src/ec_lists.erl | 2 +- src/ec_orddict.erl | 6 ++++-- src/ec_plists.erl | 25 +++++++++++++++--------- src/ec_rbdict.erl | 26 +++++++++++++------------ src/ec_semver.erl | 12 +++++++----- src/ec_talk.erl | 25 ++++++++++++++---------- 12 files changed, 107 insertions(+), 92 deletions(-) diff --git a/Makefile b/Makefile index 11948ac..d32718a 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ $(ERLWARE_COMMONS_PLT): @echo Building local plt at $(ERLWARE_COMMONS_PLT) @echo - dialyzer --output_plt $(ERLWARE_COMMONS_PLT) --build_plt \ - --apps erts kernel stdlib -r deps + --apps erts kernel stdlib eunit -r deps dialyzer: $(ERLWARE_COMMONS_PLT) dialyzer --plt $(ERLWARE_COMMONS_PLT) -Wrace_conditions --src src @@ -49,7 +49,7 @@ shell: compile # rebuilt). However, eunit runs the tests, which probably # fails (thats probably why You want them in the shell). This # runs eunit but tells make to ignore the result. - - @$(REBAR) eunit + - @$(REBAR) skip_deps=true eunit @$(ERL) $(ERLFLAGS) clean: diff --git a/src/ec_assoc_list.erl b/src/ec_assoc_list.erl index dc83d25..80919aa 100644 --- a/src/ec_assoc_list.erl +++ b/src/ec_assoc_list.erl @@ -29,8 +29,10 @@ %%%=================================================================== %%% Types %%%=================================================================== --opaque dictionary(K, V) :: {ec_assoc_list, - [{ec_dictionary:key(K), ec_dictionary:value(V)}]}. +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(K, V) :: {ec_assoc_list, + [{ec_dictionary:key(K), ec_dictionary:value(V)}]}. %%%=================================================================== %%% API @@ -82,7 +84,7 @@ remove(Key, {ec_assoc_list, Data}) -> has_value(Value, {ec_assoc_list, Data}) -> lists:keymember(Value, 2, Data). --spec size(Object::dictionary(_K, _V)) -> integer(). +-spec size(Object::dictionary(_K, _V)) -> non_neg_integer(). size({ec_assoc_list, Data}) -> length(Data). diff --git a/src/ec_dict.erl b/src/ec_dict.erl index 0cd119e..1c5d319 100644 --- a/src/ec_dict.erl +++ b/src/ec_dict.erl @@ -31,7 +31,9 @@ %%%=================================================================== %%% Types %%%=================================================================== --opaque dictionary(_K, _V) :: dict(). +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(_K, _V) :: dict(). %%%=================================================================== %%% API @@ -88,7 +90,7 @@ has_value(Value, Data) -> false, Data). --spec size(Object::dictionary(_K, _V)) -> integer(). +-spec size(Object::dictionary(_K, _V)) -> non_neg_integer(). size(Data) -> dict:size(Data). diff --git a/src/ec_dictionary.erl b/src/ec_dictionary.erl index 771bec9..1061665 100644 --- a/src/ec_dictionary.erl +++ b/src/ec_dictionary.erl @@ -10,9 +10,6 @@ %%%------------------------------------------------------------------- -module(ec_dictionary). -%%% Behaviour Callbacks --export([behaviour_info/1]). - %% API -export([new/1, has_key/2, @@ -38,30 +35,27 @@ {callback, data}). --opaque dictionary(_K, _V) :: #dict_t{}. +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(_K, _V) :: #dict_t{}. -type key(T) :: T. -type value(T) :: T. +-callback new() -> any(). +-callback has_key(key(any()), any()) -> boolean(). +-callback get(key(any()), any()) -> any(). +-callback add(key(any()), value(any()), T) -> T. +-callback remove(key(any()), T) -> T. +-callback has_value(value(any()), any()) -> boolean(). +-callback size(any()) -> non_neg_integer(). +-callback to_list(any()) -> [{key(any()), value(any())}]. +-callback from_list([{key(any()), value(any())}]) -> any(). +-callback keys(any()) -> [key(any())]. + %%%=================================================================== %%% API %%%=================================================================== -%% @doc export the behaviour callbacks for this type -%% @private -behaviour_info(callbacks) -> - [{new, 0}, - {has_key, 2}, - {get, 2}, - {add, 3}, - {remove, 2}, - {has_value, 2}, - {size, 1}, - {to_list, 1}, - {from_list, 1}, - {keys, 1}]; -behaviour_info(_) -> - undefined. - %% @doc create a new dictionary object from the specified module. The %% module should implement the dictionary behaviour. %% diff --git a/src/ec_file.erl b/src/ec_file.erl index f26149e..cc40c07 100644 --- a/src/ec_file.erl +++ b/src/ec_file.erl @@ -23,7 +23,6 @@ ]). -export_type([ - path/0, option/0 ]). @@ -43,14 +42,13 @@ %%============================================================================ %% Types %%============================================================================ --type path() :: string(). --type option() :: [atom()]. - +-type option() :: recursive. +-type void() :: ok. %%%=================================================================== %%% API %%%=================================================================== %% @doc copy an entire directory to another location. --spec copy(path(), path(), Options::[option()]) -> ok. +-spec copy(file:name(), file:name(), Options::[option()]) -> void(). copy(From, To, []) -> copy(From, To); copy(From, To, [recursive] = Options) -> @@ -63,7 +61,7 @@ copy(From, To, [recursive] = Options) -> end. %% @doc copy a file including timestamps,ownership and mode etc. --spec copy(From::string(), To::string()) -> ok. +-spec copy(From::file:filename(), To::file:filename()) -> ok. copy(From, To) -> try ec_file_copy(From, To) @@ -81,7 +79,7 @@ md5sum(Value) -> %%
 %% Example: remove("./tmp_dir", [recursive]).
 %% 
--spec remove(path(), Options::[option()]) -> ok | {error, Reason::term()}. +-spec remove(file:name(), Options::[option()]) -> ok | {error, Reason::term()}. remove(Path, Options) -> try ok = ec_file_remove(Path, Options) @@ -90,12 +88,12 @@ remove(Path, Options) -> end. %% @doc delete a file. --spec remove(path()) -> ok | {error, Reason::term()}. +-spec remove(file:name()) -> ok | {error, Reason::term()}. remove(Path) -> remove(Path, []). %% @doc indicates witha boolean if the path supplied refers to symlink. --spec is_symlink(path()) -> boolean(). +-spec is_symlink(file:name()) -> boolean(). is_symlink(Path) -> case file:read_link_info(Path) of {ok, #file_info{type = symlink}} -> @@ -107,7 +105,7 @@ is_symlink(Path) -> %% @doc make a unique temorory directory. Similar function to BSD stdlib %% function of the same name. --spec insecure_mkdtemp() -> TmpDirPath::path(). +-spec insecure_mkdtemp() -> TmpDirPath::file:name(). insecure_mkdtemp() -> random:seed(now()), UniqueNumber = erlang:integer_to_list(erlang:trunc(random:uniform() * 1000000000000)), @@ -128,7 +126,7 @@ insecure_mkdtemp() -> %% @doc Makes a directory including parent dirs if they are missing. --spec mkdir_path(path()) -> ok. +-spec mkdir_path(file:name()) -> ok. mkdir_path(Path) -> %% We are exploiting a feature of ensuredir that that creates all %% directories up to the last element in the filename, then ignores @@ -144,7 +142,7 @@ mkdir_path(Path) -> %% @doc consult an erlang term file from the file system. %% Provide user readible exeption on failure. --spec consult(FilePath::path()) -> term(). +-spec consult(FilePath::file:name()) -> term(). consult(FilePath) -> case file:consult(FilePath) of {ok, [Term]} -> @@ -160,7 +158,7 @@ consult(FilePath) -> end. %% @doc read a file from the file system. Provide UEX exeption on failure. --spec read(FilePath::string()) -> binary(). +-spec read(FilePath::file:filename()) -> binary(). read(FilePath) -> try {ok, FileBin} = file:read_file(FilePath), @@ -173,7 +171,7 @@ read(FilePath) -> end. %% @doc write a file to the file system. Provide UEX exeption on failure. --spec write(FileName::string(), Contents::string()) -> ok. +-spec write(FileName::file:filename(), Contents::string()) -> ok. write(FileName, Contents) -> case file:write_file(FileName, Contents) of ok -> @@ -187,13 +185,13 @@ write(FileName, Contents) -> end. %% @doc write a term out to a file so that it can be consulted later. --spec write_term(string(), term()) -> ok. +-spec write_term(file:filename(), term()) -> ok. write_term(FileName, Term) -> write(FileName, lists:flatten(io_lib:fwrite("~p. ", [Term]))). %% @doc Finds files and directories that match the regexp supplied in %% the TargetPattern regexp. --spec find(FromDir::path(), TargetPattern::string()) -> [path()]. +-spec find(FromDir::file:name(), TargetPattern::string()) -> [file:name()]. find([], _) -> []; find(FromDir, TargetPattern) -> @@ -214,7 +212,7 @@ find(FromDir, TargetPattern) -> %%%=================================================================== %%% Internal Functions %%%=================================================================== --spec find_in_subdirs(path(), string()) -> [path()]. +-spec find_in_subdirs(file:name(), string()) -> [file:name()]. find_in_subdirs(FromDir, TargetPattern) -> lists:foldl(fun(CheckFromDir, Acc) when CheckFromDir == FromDir -> @@ -228,14 +226,14 @@ find_in_subdirs(FromDir, TargetPattern) -> [], filelib:wildcard(filename:join(FromDir, "*"))). --spec ec_file_remove(path(), [{atom(), any()}]) -> ok. +-spec ec_file_remove(file:name(), [option()]) -> ok | {error, Reason::any()}. ec_file_remove(Path, Options) -> case lists:member(recursive, Options) of false -> file:delete(Path); true -> remove_recursive(Path, Options) end. --spec remove_recursive(path(), Options::list()) -> ok. +-spec remove_recursive(file:name(), Options::list()) -> ok. remove_recursive(Path, Options) -> case filelib:is_dir(Path) of false -> @@ -247,7 +245,7 @@ remove_recursive(Path, Options) -> ok = file:del_dir(Path) end. --spec tmp() -> path(). +-spec tmp() -> file:name(). tmp() -> case erlang:system_info(system_architecture) of "win32" -> @@ -257,7 +255,7 @@ tmp() -> end. %% Copy the subfiles of the From directory to the to directory. --spec copy_subfiles(path(), path(), [option()]) -> ok. +-spec copy_subfiles(file:name(), file:name(), [option()]) -> void(). copy_subfiles(From, To, Options) -> Fun = fun(ChildFrom) -> @@ -266,13 +264,13 @@ copy_subfiles(From, To, Options) -> end, lists:foreach(Fun, filelib:wildcard(filename:join(From, "*"))). --spec ec_file_copy(path(), path()) -> ok. +-spec ec_file_copy(file:name(), file:name()) -> ok. ec_file_copy(From, To) -> {ok, _} = file:copy(From, To), {ok, FileInfo} = file:read_file_info(From), ok = file:write_file_info(To, FileInfo). --spec make_dir_if_dir(path()) -> ok. +-spec make_dir_if_dir(file:name()) -> ok. make_dir_if_dir(File) -> case filelib:is_dir(File) of true -> ok; @@ -356,5 +354,4 @@ find_test() -> find(BaseDir, "file[a-z]+\$")), remove(BaseDir, [recursive]). - -endif. diff --git a/src/ec_gb_trees.erl b/src/ec_gb_trees.erl index d7ec574..7427740 100644 --- a/src/ec_gb_trees.erl +++ b/src/ec_gb_trees.erl @@ -30,7 +30,9 @@ %%%=================================================================== %%% Types %%%=================================================================== --opaque dictionary(K, V) :: {non_neg_integer(), ec_gb_tree_node(K, V)}. +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(K, V) :: {non_neg_integer(), ec_gb_tree_node(K, V)}. -type ec_gb_tree_node(K, V) :: 'nil' | {K, V, ec_gb_tree_node(K, V), @@ -124,7 +126,7 @@ has_value(Value, Data) -> %% @doc return the current number of key value pairs in the dictionary %% %% @param Object the object return the size for. --spec size(Object::dictionary(_K, _V)) -> integer(). +-spec size(Object::dictionary(_K, _V)) -> non_neg_integer(). size(Data) -> gb_trees:size(Data). diff --git a/src/ec_lists.erl b/src/ec_lists.erl index 1545eeb..cbc1f0b 100644 --- a/src/ec_lists.erl +++ b/src/ec_lists.erl @@ -23,7 +23,7 @@ %% the third value is the element passed to the function. The purpose %% of this is to allow a list to be searched where some internal state %% is important while the input element is not. --spec search(fun(), list()) -> {ok, Result::term(), Element::term()}. +-spec search(fun(), list()) -> {ok, Result::term(), Element::term()} | not_found. search(Fun, [H|T]) -> case Fun(H) of {ok, Value} -> diff --git a/src/ec_orddict.erl b/src/ec_orddict.erl index 9ae4a86..1244d60 100644 --- a/src/ec_orddict.erl +++ b/src/ec_orddict.erl @@ -31,7 +31,9 @@ %%%=================================================================== %%% Types %%%=================================================================== --opaque dictionary(K, V) :: [{K, V}]. +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(K, V) :: [{K, V}]. %%%=================================================================== %%% API @@ -88,7 +90,7 @@ has_value(Value, Data) -> false, Data). --spec size(Object::dictionary(_K, _V)) -> integer(). +-spec size(Object::dictionary(_K, _V)) -> non_neg_integer(). size(Data) -> orddict:size(Data). diff --git a/src/ec_plists.erl b/src/ec_plists.erl index a90bc38..cd14697 100644 --- a/src/ec_plists.erl +++ b/src/ec_plists.erl @@ -13,6 +13,13 @@ filter/2, filter/3]). +-export_type([thunk/0]). + +%%============================================================================= +%% Types +%%============================================================================= +-type thunk() :: fun((any()) -> any()). + %%============================================================================= %% Public API %%============================================================================= @@ -25,7 +32,7 @@ map(Fun, List) -> map(Fun, List, infinity). --spec map(fun(), [any()], non_neg_integer()) -> [any()]. +-spec map(thunk(), [any()], timeout() | infinity) -> [any()]. map(Fun, List, Timeout) -> run_list_fun_in_parallel(map, Fun, List, Timeout). @@ -43,29 +50,29 @@ map(Fun, List, Timeout) -> %% 2> ftmap(fun(N) -> factorial(N) end, [1, 2, 1000000, "not num"], 100) %% [{value, 1}, {value, 2}, timeout, {badmatch, ...}] %% --spec ftmap(fun(), [any()]) -> [{value, any()} | any()]. +-spec ftmap(thunk(), [any()]) -> [{value, any()} | any()]. ftmap(Fun, List) -> ftmap(Fun, List, infinity). --spec ftmap(fun(), [any()], non_neg_integer()) -> [{value, any()} | any()]. +-spec ftmap(thunk(), [any()], timeout() | infinity) -> [{value, any()} | any()]. ftmap(Fun, List, Timeout) -> run_list_fun_in_parallel(ftmap, Fun, List, Timeout). %% @doc Returns a list of the elements in the supplied list which %% the function Fun returns true. A timeout is optional. In the %% event of a timeout the filter operation fails. --spec filter(fun(), [any()]) -> [any()]. +-spec filter(thunk(), [any()]) -> [any()]. filter(Fun, List) -> filter(Fun, List, infinity). --spec filter(fun(), [any()], integer()) -> [any()]. +-spec filter(thunk(), [any()], timeout() | infinity) -> [any()]. filter(Fun, List, Timeout) -> run_list_fun_in_parallel(filter, Fun, List, Timeout). %%============================================================================= %% Internal API %%============================================================================= --spec run_list_fun_in_parallel(atom(), fun(), [any()], integer()) -> [any()]. +-spec run_list_fun_in_parallel(atom(), thunk(), [any()], timeout() | infinity) -> [any()]. run_list_fun_in_parallel(ListFun, Fun, List, Timeout) -> LocalPid = self(), Pids = @@ -79,7 +86,7 @@ run_list_fun_in_parallel(ListFun, Fun, List, Timeout) -> end, List), gather(ListFun, Pids). --spec wait(pid(), fun(), any(), integer()) -> any(). +-spec wait(pid(), thunk(), any(), timeout() | infinity) -> any(). wait(Parent, Fun, E, Timeout) -> WaitPid = self(), Child = spawn(fun() -> @@ -88,7 +95,7 @@ wait(Parent, Fun, E, Timeout) -> wait(Parent, Child, Timeout). --spec wait(pid(), pid(), integer()) -> any(). +-spec wait(pid(), pid(), timeout() | infinity) -> any(). wait(Parent, Child, Timeout) -> receive {Child, Ret} -> @@ -146,7 +153,7 @@ filter_gather([{Pid, E} | Rest]) -> filter_gather([]) -> []. --spec do_f(pid(), fun(), any()) -> no_return(). +-spec do_f(pid(), thunk(), any()) -> no_return(). do_f(Parent, F, E) -> try Result = F(E), diff --git a/src/ec_rbdict.erl b/src/ec_rbdict.erl index 547e339..1bfcecc 100644 --- a/src/ec_rbdict.erl +++ b/src/ec_rbdict.erl @@ -68,12 +68,13 @@ %%%=================================================================== %%% Types %%%=================================================================== - --opaque dictionary(K, V) :: empty | {color(), - dictionary(K, V), - ec_dictionary:key(K), - ec_dictionary:value(V), - dictionary(K, V)}. +%% This should be opaque, but that kills dialyzer so for now we export it +%% however you should not rely on the internal representation here +-type dictionary(K, V) :: empty | {color(), + dictionary(K, V), + ec_dictionary:key(K), + ec_dictionary:value(V), + dictionary(K, V)}. -type color() :: r | b. @@ -116,7 +117,7 @@ get(K, Default, {_, _, K1, _, Right}) when K > K1 -> get(_, _, {_, _, _, Val, _}) -> Val. --spec add(ec_dicitonary:key(K), ec_dictionary:value(V), +-spec add(ec_dictionary:key(K), ec_dictionary:value(V), dictionary(K, V)) -> dictionary(K, V). add(Key, Value, Dict) -> {_, L, K1, V1, R} = add1(Key, Value, Dict), @@ -133,7 +134,7 @@ has_value(Value, Dict) -> end, false, Dict). --spec size(dictionary(_K, _V)) -> integer(). +-spec size(dictionary(_K, _V)) -> non_neg_integer(). size(T) -> size1(T). @@ -227,7 +228,7 @@ erase_aux(K, {r, A, Xk, Xv, B}) -> end. -spec erase_min(dictionary(K, V)) -> - {dictionary(K, V), {ec_dictionary:key(K), ec_dictionary:value(V)}, boolean}. + {dictionary(K, V), {ec_dictionary:key(K), ec_dictionary:value(V)}, boolean()}. erase_min({b, empty, Xk, Xv, empty}) -> {empty, {Xk, Xv}, true}; erase_min({b, empty, Xk, Xv, {r, A, Yk, Yv, B}}) -> @@ -274,7 +275,8 @@ unbalright(b, A, Xk, Xv, D}, false}. --spec fold(fun(), dictionary(K, V), dictionary(K, V)) -> dictionary(K, V). +-spec fold(fun((ec_dictionary:key(K), ec_dictionary:value(V), any()) -> any()), + any(), dictionary(K, V)) -> any(). fold(_, Acc, empty) -> Acc; fold(F, Acc, {_, A, Xk, Xv, B}) -> fold(F, F(Xk, Xv, fold(F, Acc, B)), A). @@ -295,7 +297,7 @@ to_list({_, A, Xk, Xv, B}, List) -> %% Balance a tree afer (possibly) adding a node to the left/right. -spec lbalance(color(), dictionary(K, V), - ec_dictinary:key(K), ec_dictionary:value(V), + ec_dictionary:key(K), ec_dictionary:value(V), dictionary(K, V)) -> dictionary(K, V). lbalance(b, {r, {r, A, Xk, Xv, B}, Yk, Yv, C}, Zk, Zv, @@ -307,7 +309,7 @@ lbalance(b, {r, A, Xk, Xv, {r, B, Yk, Yv, C}}, Zk, Zv, lbalance(C, A, Xk, Xv, B) -> {C, A, Xk, Xv, B}. -spec rbalance(color(), dictionary(K, V), - ec_dictinary:key(K), ec_dictionary:value(V), + ec_dictionary:key(K), ec_dictionary:value(V), dictionary(K, V)) -> dictionary(K, V). rbalance(b, A, Xk, Xv, diff --git a/src/ec_semver.erl b/src/ec_semver.erl index 77b43cd..49a16a9 100644 --- a/src/ec_semver.erl +++ b/src/ec_semver.erl @@ -20,11 +20,13 @@ %%%=================================================================== -type semvar() :: string(). --type parsed_semvar() :: {MajorVsn::string(), - MinorVsn::string(), - PatchVsn::string(), +-type parsed_semvar() :: {MajorVsn::integer(), + MinorVsn::integer(), + PatchVsn::integer(), PathString::string()}. +-type semver_tokens() :: {string(), string(), string(), string()}. + %%%=================================================================== %%% API %%%=================================================================== @@ -41,7 +43,7 @@ compare(VsnA, VsnB) -> %%% Internal Functions %%%=================================================================== --spec tokens(semvar()) -> parsed_semvar(). +-spec tokens(semvar()) -> semver_tokens(). tokens(Vsn) -> [MajorVsn, MinorVsn, RawPatch] = string:tokens(Vsn, "."), {PatchVsn, PatchString} = split_patch(RawPatch), @@ -62,7 +64,7 @@ split_patch([Dig|T], {PatchVsn, PatchStr}) when Dig >= $0 andalso Dig =< $9 -> split_patch(PatchStr, {PatchVsn, ""}) -> {PatchVsn, PatchStr}. --spec compare_toks(parsed_semvar(), parsed_semvar()) -> boolean(). +-spec compare_toks(semver_tokens(), semver_tokens()) -> boolean(). compare_toks({MajA, MinA, PVA, PSA}, {MajB, MinB, PVB, PSB}) -> compare_toks2({to_int(MajA), to_int(MinA), to_int(PVA), PSA}, {to_int(MajB), to_int(MinB), to_int(PVB), PSB}). diff --git a/src/ec_talk.erl b/src/ec_talk.erl index 0823169..4a82d1b 100644 --- a/src/ec_talk.erl +++ b/src/ec_talk.erl @@ -49,7 +49,7 @@ %%============================================================================ -type prompt() :: string(). -type type() :: boolean | number | string. --type supported() :: string() | boolean() | number(). +-type supported() :: boolean() | number() | string(). %%============================================================================ %% API @@ -100,8 +100,11 @@ ask_default(Prompt, string, Default) -> %% between min and max. -spec ask(prompt(), number(), number()) -> number(). ask(Prompt, Min, Max) - when is_list(Prompt), is_number(Min), is_number(Max) -> - Res = ask(Prompt, fun get_integer/1, none), + when erlang:is_list(Prompt), + erlang:is_number(Min), + erlang:is_number(Max), + Min =< Max -> + Res = ask_convert(Prompt, fun get_integer/1, number, none), case (Res >= Min andalso Res =< Max) of true -> Res; @@ -115,14 +118,16 @@ ask(Prompt, Min, Max) %% ============================================================================ %% @doc Actually does the work of asking, checking result and %% translating result into the requested format. --spec ask_convert(prompt(), fun(), type(), supported()) -> supported(). +-spec ask_convert(prompt(), fun((any()) -> any()), type(), supported() | none) -> supported(). ask_convert(Prompt, TransFun, Type, Default) -> - NewPrompt = Prompt ++ case Default of - none -> - []; - Default -> - " (" ++ sin_utils:term_to_list(Default) ++ ")" - end ++ "> ", + NewPrompt = + erlang:binary_to_list(erlang:iolist_to_binary([Prompt, + case Default of + none -> + []; + Default -> + [" (", io_lib:format("~p", [Default]) , ")"] + end, "> "])), Data = string:strip(string:strip(io:get_line(NewPrompt)), both, $\n), Ret = TransFun(Data), case Ret of