├── .gitignore ├── rebar.config ├── test ├── tut6_tests.erl ├── tut7_tests.erl ├── tut8_tests.erl ├── tut9_tests.erl ├── mess_server_tests.erl ├── string_tests.erl ├── tut2_tests.erl ├── debug_tests.erl ├── tut5_tests.erl ├── stdlib_io_tests.erl ├── unicode_tests.erl ├── stdlib_base64_tests.erl ├── tut3_tests.erl ├── tut4_tests.erl ├── stdlib_array_tests.erl ├── tut1_tests.erl ├── stdlib_file_tests.erl ├── function_tests.erl ├── stdlib_math_tests.erl └── stdlib_binary_tests.erl ├── include ├── mess_config.hrl └── mess_interface.hrl ├── src ├── tut2.erl ├── tut3.erl ├── tut5.erl ├── tutorial.app.src ├── tut1.erl ├── tut7.erl ├── tut6.erl ├── tut8.erl ├── tut9.erl ├── mess_client.erl ├── user_interface.erl ├── tut4.erl ├── mess_server.erl └── messenger.erl └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | ebin/ 2 | *.beam 3 | .eunit/ 4 | logs/ -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | 2 | {cover_enabled, true}. 3 | 4 | {eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}. 5 | -------------------------------------------------------------------------------- /test/tut6_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut6_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | start_test() -> 6 | ?debugVal(tut6:start()). 7 | -------------------------------------------------------------------------------- /test/tut7_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut7_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | start_test() -> 6 | ?debugVal(tut7:start()). 7 | -------------------------------------------------------------------------------- /test/tut8_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut8_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | start_test() -> 6 | ?debugVal(tut8:start(node())). 7 | -------------------------------------------------------------------------------- /test/tut9_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut9_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | start_test() -> 6 | ?debugVal(tut9:start(node())). 7 | -------------------------------------------------------------------------------- /include/mess_config.hrl: -------------------------------------------------------------------------------- 1 | %%%----FILE mess_config.hrl---- 2 | 3 | %%% Configure the location of the server node, 4 | -define(server_node, messenger@super). 5 | 6 | %%%----END FILE---- -------------------------------------------------------------------------------- /test/mess_server_tests.erl: -------------------------------------------------------------------------------- 1 | -module(mess_server_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | start_server_test() -> 6 | mess_server:start_server(). 7 | -------------------------------------------------------------------------------- /test/string_tests.erl: -------------------------------------------------------------------------------- 1 | -module(string_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | scan_string_test() -> 6 | erl_scan:string("\"X\"."), 7 | erl_scan:string("\"\x{400}\"."). 8 | -------------------------------------------------------------------------------- /test/tut2_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut2_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | fac_test() -> 6 | ?assertEqual(24, tut2:fac(4)). 7 | 8 | fib_test() -> 9 | ?assertEqual(8, tut2:fib(5)). 10 | -------------------------------------------------------------------------------- /test/debug_tests.erl: -------------------------------------------------------------------------------- 1 | -module(debug_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | debugmsg_test() -> 6 | ?debugMsg('hello hello\n'). 7 | 8 | debugfmt_test() -> 9 | ?debugFmt('~p', [1024]). 10 | -------------------------------------------------------------------------------- /test/tut5_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut5_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | say_something_test() -> 6 | ?debugTime("say_something", tut5:say_something(hello, 3)). 7 | 8 | start_test() -> 9 | ?debugVal(tut5:start()). 10 | -------------------------------------------------------------------------------- /src/tut2.erl: -------------------------------------------------------------------------------- 1 | -module(tut2). 2 | -export([fac/1, fib/1]). 3 | 4 | %% Description: description of test_fac 5 | 6 | fac(1) -> 7 | 1; 8 | fac(N) -> 9 | N * fac(N-1). 10 | 11 | fib(0) -> 12 | 1; 13 | fib(1) -> 14 | 1; 15 | fib(N) 16 | when N > 1 -> 17 | fib(N-1) + fib(N-2). -------------------------------------------------------------------------------- /src/tut3.erl: -------------------------------------------------------------------------------- 1 | -module(tut3). 2 | -export([sum/1,product/1,odds/1]). 3 | 4 | sum([X|R]) -> X + sum(R); 5 | sum([]) -> 0. 6 | 7 | product([X|R]) -> X * product(R); 8 | product([]) -> 1. 9 | 10 | odds(List) -> odds(List,1). 11 | odds([X|R],N) when N rem 2 == 1 -> [X | odds(R,N+1)]; 12 | odds([_|R],N) -> odds(R,N+1); 13 | odds([],_) -> []. -------------------------------------------------------------------------------- /src/tut5.erl: -------------------------------------------------------------------------------- 1 | -module(tut5). 2 | 3 | -export([start/0, say_something/2]). 4 | 5 | say_something(What, 0) -> 6 | done; 7 | say_something(What, Times) -> 8 | io:format("~p~n", [What]), 9 | say_something(What, Times - 1). 10 | 11 | start() -> 12 | spawn(tut5, say_something, [hello, 3]), 13 | spawn(tut5, say_something, [goodbye, 3]). -------------------------------------------------------------------------------- /src/tutorial.app.src: -------------------------------------------------------------------------------- 1 | {application, tutorial, 2 | [ 3 | {description, "erlang tutorial"}, 4 | {vsn, "0.1"}, 5 | {modules, [ 6 | mess_client, 7 | mess_server, 8 | user_interface 9 | ]}, 10 | {registered, []}, 11 | {applications, [ 12 | kernel, 13 | stdlib 14 | ]}, 15 | {env, []} 16 | ]}. -------------------------------------------------------------------------------- /test/stdlib_io_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_io_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | io_format_test() -> 6 | io:format("hello hello\n"). 7 | 8 | io_format_p_test() -> 9 | io:format("~p", [1024]). 10 | 11 | io_format_w_test() -> 12 | io:format("~w", [1024]). 13 | 14 | io_format_s_test() -> 15 | io:format("~s~n",[<<"åäö"/utf8>>]). 16 | 17 | io_format_ts_test() -> 18 | io:format("~ts~n",[<<"åäö"/utf8>>]). 19 | -------------------------------------------------------------------------------- /test/unicode_tests.erl: -------------------------------------------------------------------------------- 1 | -module(unicode_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | encoding_to_bom_test() -> 6 | % latin1, unicode, utf8, utf16, utf32, {utf16, big | little}, {utf32, big | little} 7 | % io:format("~w", [unicode:encoding_to_bom(utf8)]). 8 | io:format("~w", [unicode:encoding_to_bom( {utf16, big} )]). 9 | 10 | bom_to_encoding_test() -> 11 | io:format("~p", [unicode:bom_to_encoding(<<239,187,191>>)]). 12 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | A tutorial on erlang. 2 | 3 | Get start 4 | 5 | rebar compile 6 | rebar eunit 7 | rebar eunit suite=stdlib_array_test 8 | 9 | # Thanks: 10 | 11 | + [erlang](http://www.erlang.org/doc/index.html) 12 | + [rebar](http://github.com/basho/rebar) 13 | + [eunit](http://github.com/richcarl/eunit) 14 | + [erlang-eunit-introduction](http://erlcode.wordpress.+ com/2010/08/30/erlang-eunit-introduction/)+ 15 | + [erlang build tool](http://blog.linezing.com/2011/04/rebar%EF%BC%9A+ erlang%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7) -------------------------------------------------------------------------------- /test/stdlib_base64_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_base64_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | base64_encode_test() -> 6 | S = "hello base64", 7 | A1 = base64:encode(S), 8 | ?assertEqual(<<"aGVsbG8gYmFzZTY0">>, A1), 9 | A2 = base64:encode_to_string(S), 10 | ?assertEqual("aGVsbG8gYmFzZTY0", A2). 11 | 12 | base64_decode_test() -> 13 | S = "aGVsbG8gYmFzZTY0", 14 | A1 = base64:decode(S), 15 | ?assertEqual(<<"hello base64">>, A1), 16 | A2 = base64:mime_decode_to_string(S), 17 | ?assertEqual("hello base64", A2). -------------------------------------------------------------------------------- /test/tut3_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut3_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | 4 | sum_test() -> 5 | ?assertEqual(0, tut3:sum([])), 6 | ?assertEqual(0, tut3:sum([0])), 7 | ?assertEqual(6, tut3:sum([1,2,3,4,-4])). 8 | 9 | product_test() -> 10 | ?assertEqual(1, tut3:product([])), 11 | ?assertEqual(2, tut3:product([2])), 12 | ?assertEqual(36, tut3:product([2,3,2,3])). 13 | 14 | odds_test() -> 15 | ?assertEqual([], tut3:odds([])), 16 | ?assertEqual([1], tut3:odds([1])), 17 | ?assertEqual([1,3,5], tut3:odds([1,2,3,4,5])). -------------------------------------------------------------------------------- /test/tut4_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut4_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | if_A5_test() -> 6 | ?assertEqual(a_equals_5, tut4:test_if(5,3)). 7 | 8 | if_A1B7_test() -> 9 | ?assertEqual(a_equals_1_or_b_equals_7, tut4:test_if(1,7)). 10 | 11 | convert_length_centimeter_test() -> 12 | ?assertEqual({inch, 5.0}, tut4:convert_length({centimeter,12.7})). 13 | 14 | convert_length_inch_test() -> 15 | ?assertEqual({centimeter,12.7}, tut4:convert_length({inch, 5})). 16 | 17 | month_length_test() -> 18 | ?assertEqual(28, tut4:month_length(3000, feb)). 19 | -------------------------------------------------------------------------------- /src/tut1.erl: -------------------------------------------------------------------------------- 1 | -module(tut1). 2 | -export([double/1, mult/2, convert/2, convert_length/1, list_length/1]). 3 | 4 | % Modules and Functions 5 | 6 | double(X) -> 7 | 2 * X. 8 | 9 | mult(X, Y) -> 10 | X * Y. 11 | 12 | %% Atoms 13 | 14 | convert(M, inch) -> 15 | M / 2.54; 16 | convert(N, centimeter) -> 17 | N * 2.54. 18 | 19 | % Tuples 20 | 21 | convert_length({centimeter, X}) -> 22 | {inch, X / 2.54}; 23 | convert_length({inch, Y}) -> 24 | {centimeter, Y * 2.54}. 25 | 26 | % Lists 27 | 28 | list_length([]) -> 29 | 0; 30 | list_length([First | Rest]) -> 31 | 1 + list_length(Rest). -------------------------------------------------------------------------------- /src/tut7.erl: -------------------------------------------------------------------------------- 1 | -module(tut7). 2 | 3 | -export([start/0, ping/1, pong/0]). 4 | 5 | ping(0) -> 6 | pong ! finished, 7 | io:format("ping finished~n", []); 8 | 9 | ping(N) -> 10 | pong ! {ping, self()}, 11 | receive 12 | pong -> 13 | io:format("Ping received pong~n", []) 14 | end, 15 | ping(N - 1). 16 | 17 | pong() -> 18 | receive 19 | finished -> 20 | io:format("Pong finished~n", []); 21 | {ping, Ping_PID} -> 22 | io:format("Pong received ping~n", []), 23 | Ping_PID ! pong, 24 | pong() 25 | end. 26 | 27 | start() -> 28 | register(pong, spawn(tut7, pong, [])), 29 | spawn(tut7, ping, [3]). -------------------------------------------------------------------------------- /test/stdlib_array_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_array_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | array_set_test() -> 6 | A1 = array:set(17, true, array:new()), 7 | ?assertEqual(18, array:size(A1)), 8 | ?assertEqual(true, array:get(17, A1)), 9 | ?assertEqual(undefined, array:get(3, A1)). 10 | 11 | array_sparse_test() -> 12 | A1 = array:set(17, true, array:new()), 13 | A2 = array:set(4, false, A1), 14 | ?assertEqual([{4, false}, {17, true}], array:sparse_to_orddict(A2)). 15 | 16 | array_fix_test() -> 17 | A3 = array:fix(array:new([{size,10},{fixed,false},{default,-1}])), 18 | {'EXIT',{badarg,_}} = (catch array:set(18, true, A3)), 19 | ?debugMsg("array_fix_test done."). -------------------------------------------------------------------------------- /src/tut6.erl: -------------------------------------------------------------------------------- 1 | -module(tut6). 2 | 3 | -export([start/0, ping/2, pong/0]). 4 | 5 | ping(0, Pong_PID) -> 6 | Pong_PID ! finished, 7 | io:format("ping finished~n", []); 8 | 9 | ping(N, Pong_PID) -> 10 | Pong_PID ! {ping, self()}, 11 | receive 12 | pong -> 13 | io:format("Ping received pong~n", []) 14 | end, 15 | ping(N - 1, Pong_PID). 16 | 17 | pong() -> 18 | receive 19 | finished -> 20 | io:format("Pong finished~n", []); 21 | {ping, Ping_PID} -> 22 | io:format("Pong received ping~n", []), 23 | Ping_PID ! pong, 24 | pong() 25 | end. 26 | 27 | start() -> 28 | Pong_PID = spawn(tut6, pong, []), 29 | spawn(tut6, ping, [3, Pong_PID]). -------------------------------------------------------------------------------- /src/tut8.erl: -------------------------------------------------------------------------------- 1 | -module(tut8). 2 | 3 | -export([start/1, ping/2, pong/0]). 4 | 5 | ping(0, Pong_Node) -> 6 | {pong, Pong_Node} ! finished, 7 | io:format("ping finished~n", []); 8 | 9 | ping(N, Pong_Node) -> 10 | {pong, Pong_Node} ! {ping, self()}, 11 | receive 12 | pong -> 13 | io:format("Ping received pong~n", []) 14 | end, 15 | ping(N - 1, Pong_Node). 16 | 17 | pong() -> 18 | receive 19 | {ping, Ping_PID} -> 20 | io:format("Pong received ping~n", []), 21 | Ping_PID ! pong, 22 | pong() 23 | after 5000 -> 24 | io:format("Pong timed out~n", []) 25 | end. 26 | 27 | start(Ping_Node) -> 28 | register(pong, spawn(tut8, pong, [])), 29 | spawn(Ping_Node, tut8, ping, [3, node()]). 30 | -------------------------------------------------------------------------------- /test/tut1_tests.erl: -------------------------------------------------------------------------------- 1 | -module(tut1_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | double_test() -> 6 | ?assertEqual(2, tut1:double(1)). 7 | 8 | mult_test() -> 9 | ?assertEqual(15, tut1:mult(3, 5)). 10 | 11 | convert_inch_test() -> 12 | ?assertEqual(1.1811023622047243, tut1:convert(3, inch)). 13 | 14 | convert_centimeter_test() -> 15 | ?assertEqual(17.78, tut1:convert(7, centimeter)). 16 | 17 | convert_length_centimeter_test() -> 18 | ?assertEqual({inch, 5.0}, tut1:convert_length({centimeter,12.7})). 19 | 20 | convert_length_inch_test() -> 21 | ?assertEqual({centimeter,12.7}, tut1:convert_length({inch, 5})). 22 | 23 | list_length_test() -> 24 | ?assertEqual(7, tut1:list_length([1,2,3,4,5,6,7])). 25 | 26 | list_test() -> 27 | ?assertEqual("abc", [97,98,99]). 28 | -------------------------------------------------------------------------------- /src/tut9.erl: -------------------------------------------------------------------------------- 1 | -module(tut9). 2 | 3 | -export([start/1, ping/2, pong/0]). 4 | 5 | ping(N, Pong_Pid) -> 6 | link(Pong_Pid), 7 | ping1(N, Pong_Pid). 8 | 9 | ping1(0, _) -> 10 | exit(ping); 11 | 12 | ping1(N, Pong_Pid) -> 13 | Pong_Pid ! {ping, self()}, 14 | receive 15 | pong -> 16 | io:format("Ping received pong~n", []) 17 | end, 18 | ping1(N - 1, Pong_Pid). 19 | 20 | pong() -> 21 | process_flag(trap_exit, true), 22 | pong1(). 23 | 24 | pong1() -> 25 | receive 26 | {ping, Ping_PID} -> 27 | io:format("Pong received ping~n", []), 28 | Ping_PID ! pong, 29 | pong1(); 30 | {'EXIT', From, Reason} -> 31 | io:format("pong exiting, got ~p~n", [{'EXIT', From, Reason}]) 32 | end. 33 | 34 | start(Ping_Node) -> 35 | PongPID = spawn(tut9, pong, []), 36 | spawn(Ping_Node, tut9, ping, [3, PongPID]). 37 | -------------------------------------------------------------------------------- /test/stdlib_file_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_file_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | -ifndef(FN). 6 | -define(FN, '/tmp/output.txt'). 7 | -endif. 8 | 9 | io_write_test() -> 10 | case file:open(?FN, [write]) of 11 | {ok,S} -> 12 | io:format(S, "~s~n", ["Hello readers"]), 13 | file:close(S); 14 | {error, Reason} -> 15 | ?debugFmt("open error reason:~s~n", [Reason]), 16 | ng 17 | end, 18 | ?debugMsg("io write done~n"). 19 | 20 | io_read_test() -> 21 | case file:open(?FN, [read]) of 22 | {ok, S} -> 23 | read_text(S), 24 | file:close(S); 25 | {error, Reason} -> 26 | ?debugFmt("open error reason:~s~n", [Reason]), 27 | ng 28 | end, 29 | ?debugMsg("io read done~n"). 30 | 31 | read_text(IoDevice) -> 32 | case file:read_line(IoDevice) of 33 | {ok, Line} -> 34 | ?debugFmt("read: ~s", [Line]), 35 | io:format("~s", [Line]), read_text(IoDevice); 36 | eof -> 37 | ok 38 | end. -------------------------------------------------------------------------------- /test/function_tests.erl: -------------------------------------------------------------------------------- 1 | -module(function_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | bif_test() -> 6 | ?debugFmt("rem:~w round:~w trunc:~w float:~w length:~w~n", 7 | [2004 rem 4, round(5.6), trunc(5.01), float(5), length([a,b,c,d])]), 8 | ?debugFmt("is_atom:~w ~w is_tuple:~w ~w~n", 9 | [is_atom(hello), is_atom("hello"), 10 | is_tuple({pairs, {c,30}}), 11 | is_tuple([pairs, {c,30}])]), 12 | ?debugFmt("atom_to_list:~w list_to_atom:~w integer_to_list:~w~n", 13 | [atom_to_list(hello), 14 | list_to_atom("goodbye"), 15 | integer_to_list(22)]). 16 | 17 | hof_test()-> 18 | Double = fun(X)->X*2 end, 19 | ?debugFmt("Double func: ~w", [Double(5)] ), 20 | ?debugFmt("lists map: ~w", [lists:map(Double, [1,2,3])]), 21 | Print_City = fun({City, {X, Temp}}) -> ?debugFmt("~-15w ~w ~w~n", [City, X, Temp]) end, 22 | Cities = [{moscow, {c, 10}}, {paris, {f, -28}}], 23 | lists:foreach(Print_City, Cities), 24 | Compare = fun({_, {_, Temp1}}, {_, {_, Temp2}}) -> Temp1 < Temp2 end, 25 | lists:foreach(Print_City, lists:sort(Compare, Cities)). 26 | -------------------------------------------------------------------------------- /include/mess_interface.hrl: -------------------------------------------------------------------------------- 1 | %%%----FILE mess_interface.hrl---- 2 | 3 | %%% Message interface between client and server and client shell for 4 | %%% messenger program 5 | 6 | %%%Messages from Client to server received in server/1 function. 7 | -record(logon,{client_pid, username}). 8 | -record(message,{client_pid, to_name, message}). 9 | %%% {'EXIT', ClientPid, Reason} (client terminated or unreachable. 10 | 11 | %%% Messages from Server to Client, received in await_result/0 function 12 | -record(abort_client,{message}). 13 | %%% Messages are: user_exists_at_other_node, 14 | %%% you_are_not_logged_on 15 | -record(server_reply,{message}). 16 | %%% Messages are: logged_on 17 | %%% receiver_not_found 18 | %%% sent (Message has been sent (no guarantee) 19 | %%% Messages from Server to Client received in client/1 function 20 | -record(message_from,{from_name, message}). 21 | 22 | %%% Messages from shell to Client received in client/1 function 23 | %%% spawn(mess_client, client, [server_node(), Name]) 24 | -record(message_to,{to_name, message}). 25 | %%% logoff 26 | 27 | %%%----END FILE---- -------------------------------------------------------------------------------- /src/mess_client.erl: -------------------------------------------------------------------------------- 1 | %%%----FILE mess_client.erl---- 2 | 3 | %%% The client process which runs on each user node 4 | 5 | -module(mess_client). 6 | -export([client/2]). 7 | -include("mess_interface.hrl"). 8 | 9 | client(Server_Node, Name) -> 10 | {messenger, Server_Node} ! #logon{client_pid=self(), username=Name}, 11 | await_result(), 12 | client(Server_Node). 13 | 14 | client(Server_Node) -> 15 | receive 16 | logoff -> 17 | exit(normal); 18 | #message_to{to_name=ToName, message=Message} -> 19 | {messenger, Server_Node} ! 20 | #message{client_pid=self(), to_name=ToName, message=Message}, 21 | await_result(); 22 | {message_from, FromName, Message} -> 23 | io:format("Message from ~p: ~p~n", [FromName, Message]) 24 | end, 25 | client(Server_Node). 26 | 27 | %%% wait for a response from the server 28 | await_result() -> 29 | receive 30 | #abort_client{message=Why} -> 31 | io:format("~p~n", [Why]), 32 | exit(normal); 33 | #server_reply{message=What} -> 34 | io:format("~p~n", [What]) 35 | after 5000 -> 36 | io:format("No response from server~n", []), 37 | exit(timeout) 38 | end. 39 | 40 | %%%----END FILE--- -------------------------------------------------------------------------------- /test/stdlib_math_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_math_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | math_pi_test() -> 6 | ?debugFmt("pi(): ~p", [math:pi()]). 7 | 8 | math_sincos_test() -> 9 | ?debugFmt("sin(60): ~w", [math:sin(60)]), 10 | ?debugFmt("cos(90): ~w", [math:cos(90)]), 11 | ?debugFmt("tan(90): ~w", [math:tan(90)]), 12 | ?debugFmt("asin(1): ~w", [math:asin(1)]), 13 | ?debugFmt("acos(1): ~w", [math:acos(1)]), 14 | ?debugFmt("atan(1): ~w", [math:atan(1)]), 15 | ?debugFmt("atan2(0, 1): ~w", [math:atan2(0, 1)]), 16 | ?debugFmt("sinh(90): ~w", [math:sinh(90)]), 17 | ?debugFmt("cosh(90): ~w", [math:cosh(90)]), 18 | ?debugFmt("tanh(90): ~w", [math:tanh(90)]), 19 | ?debugFmt("asinh(90): ~w", [math:asinh(90)]), 20 | ?debugFmt("acosh(90): ~w", [math:acosh(90)]), 21 | ?debugFmt("atanh(0): ~w", [math:atanh(0)]). 22 | 23 | math_exp_test() -> 24 | ?debugFmt("exp(4): ~w", [math:exp(4)]), 25 | ?debugFmt("log(100): ~w", [math:log(100)]), 26 | ?debugFmt("log10(100): ~w", [math:log10(100)]), 27 | ?debugFmt("pow(4,3): ~w", [math:pow(4,3)]), 28 | ?debugFmt("sqrt(81): ~w", [math:sqrt(81)]). 29 | 30 | math_erf_test() -> 31 | % erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt. 32 | ?debugFmt("erf(4): ~w", [math:erf(4)]), 33 | ?debugFmt("erfc(4): ~w", [math:erfc(4)]). -------------------------------------------------------------------------------- /src/user_interface.erl: -------------------------------------------------------------------------------- 1 | %%%----FILE user_interface.erl---- 2 | 3 | %%% User interface to the messenger program 4 | %%% login(Name) 5 | %%% One user at a time can log in from each Erlang node in the 6 | %%% system messenger: and choose a suitable Name. If the Name 7 | %%% is already logged in at another node or if someone else is 8 | %%% already logged in at the same node, login will be rejected 9 | %%% with a suitable error message. 10 | 11 | %%% logoff() 12 | %%% Logs off anybody at at node 13 | 14 | %%% message(ToName, Message) 15 | %%% sends Message to ToName. Error messages if the user of this 16 | %%% function is not logged on or if ToName is not logged on at 17 | %%% any node. 18 | 19 | -module(user_interface). 20 | -export([logon/1, logoff/0, message/2]). 21 | -include("mess_interface.hrl"). 22 | -include("mess_config.hrl"). 23 | 24 | logon(Name) -> 25 | case whereis(mess_client) of 26 | undefined -> 27 | register(mess_client, 28 | spawn(mess_client, client, [?server_node, Name])); 29 | _ -> already_logged_on 30 | end. 31 | 32 | logoff() -> 33 | mess_client ! logoff. 34 | 35 | message(ToName, Message) -> 36 | case whereis(mess_client) of % Test if the client is running 37 | undefined -> 38 | not_logged_on; 39 | _ -> mess_client ! #message_to{to_name=ToName, message=Message}, 40 | ok 41 | end. 42 | 43 | %%%----END FILE---- -------------------------------------------------------------------------------- /src/tut4.erl: -------------------------------------------------------------------------------- 1 | -module(tut4). 2 | -export([test_if/2, convert_length/1, month_length/2]). 3 | 4 | test_if(A, B) -> 5 | if 6 | A == 5 -> 7 | io:format("A == 5~n", []), 8 | a_equals_5; 9 | B == 6 -> 10 | io:format("B == 6~n", []), 11 | b_equals_6; 12 | A == 2, B == 3 -> %i.e. A equals 2 and B equals 3 13 | io:format("A == 2, B == 3~n", []), 14 | a_equals_2_b_equals_3; 15 | A == 1 ; B == 7 -> %i.e. A equals 1 or B equals 7 16 | io:format("A == 1 ; B == 7~n", []), 17 | a_equals_1_or_b_equals_7 18 | end. 19 | 20 | convert_length(Length) -> 21 | case Length of 22 | {centimeter, X} -> 23 | {inch, X / 2.54}; 24 | {inch, Y} -> 25 | {centimeter, Y * 2.54} 26 | end. 27 | 28 | 29 | month_length(Year, Month) -> 30 | %% All years divisible by 400 are leap 31 | %% Years divisible by 100 are not leap (except the 400 rule above) 32 | %% Years divisible by 4 are leap (except the 100 rule above) 33 | Leap = if 34 | trunc(Year / 400) * 400 == Year -> 35 | leap; 36 | trunc(Year / 100) * 100 == Year -> 37 | not_leap; 38 | trunc(Year / 4) * 4 == Year -> 39 | leap; 40 | true -> 41 | not_leap 42 | end, 43 | case Month of 44 | sep -> 30; 45 | apr -> 30; 46 | jun -> 30; 47 | nov -> 30; 48 | feb when Leap == leap -> 29; 49 | feb -> 28; 50 | jan -> 31; 51 | mar -> 31; 52 | may -> 31; 53 | jul -> 31; 54 | aug -> 31; 55 | oct -> 31; 56 | dec -> 31 57 | end. -------------------------------------------------------------------------------- /test/stdlib_binary_tests.erl: -------------------------------------------------------------------------------- 1 | -module(stdlib_binary_tests). 2 | -include_lib("eunit/include/eunit.hrl"). 3 | -export([]). 4 | 5 | binary_to_list_test() -> 6 | A = binary:bin_to_list(<<"erlang">>,{1,3}), 7 | ?debugFmt("~p", [A]). 8 | 9 | binary_list_to_test() -> 10 | A = binary:list_to_bin("hello"), 11 | ?debugFmt("~p", [A]). 12 | 13 | binary_decode_test() -> 14 | A = binary:decode_unsigned(<<169,138,199>>,big), 15 | ?debugFmt("~p", [A]). 16 | 17 | binary_encode_test() -> 18 | A = binary:encode_unsigned(11111111,big), 19 | ?debugFmt("~p", [A]). 20 | 21 | binary_prefix_test() -> 22 | A = binary:longest_common_prefix([<<"erlang">>,<<"ergonomy">>]), 23 | B = binary:longest_common_prefix([<<"erlang">>,<<"perl">>]), 24 | ?debugFmt("~p ~p", [A, B]). 25 | 26 | binary_suffix_test() -> 27 | A = binary:longest_common_suffix([<<"erlang">>,<<"fang">>]), 28 | B = binary:longest_common_suffix([<<"erlang">>,<<"perl">>]), 29 | ?debugFmt("~p ~p", [A, B]). 30 | 31 | binary_match_test() -> 32 | A = binary:match(<<"abcde">>, [<<"bcde">>,<<"cd">>],[]), 33 | B = binary:matches(<<"abcde">>,[<<"bcde">>,<<"bc">>,<<"de">>],[]), 34 | ?debugFmt("~p ~p", [A, B]). 35 | 36 | binary_part_test() -> 37 | Bin = <<1,2,3,4,5,6,7,8,9,10>>, 38 | A = binary:part(Bin,{byte_size(Bin), -5}), 39 | ?debugFmt("~p", [A]). 40 | 41 | binary_byte_size_test() -> 42 | A = binary:copy(<<1>>,100), 43 | S1 = byte_size(A), 44 | S2 = binary:referenced_byte_size(A), 45 | <<_:10/binary,B:10/binary,_/binary>> = A, 46 | S3 = byte_size(B), 47 | S4 = binary:referenced_byte_size(B), 48 | ?debugFmt("~p ~p ~p ~p", [S1, S2, S3, S4]). 49 | 50 | binary_replace_test() -> 51 | A = binary:replace(<<"abcde">>,<<"b">>,<<"[]">>,[{insert_replaced,1}]), 52 | B = binary:replace(<<"abcde">>,[<<"b">>,<<"d">>],<<"[]">>,[global,{insert_replaced,1}]), 53 | C = binary:replace(<<"abcde">>,[<<"b">>,<<"d">>],<<"[]">>,[global,{insert_replaced,[1,1]}]), 54 | D = binary:replace(<<"abcde">>,[<<"b">>,<<"d">>],<<"[-]">>,[global,{insert_replaced,[1,2]}]), 55 | ?debugFmt("~p ~p ~p ~p", [A, B, C, D]). 56 | 57 | binary_split_test() -> 58 | A = binary:split(<<"banana">>,[<<"a">>],[{scope,{2,3}}]), 59 | B = binary:split(binary:part(<<"banana">>,{2,3}),[<<"a">>],[]), 60 | ?debugFmt("~p ~p", [A, B]), 61 | C = binary:split(<<0,1,0,0,4,255,255,9>>, [<<0,0>>, <<255,255>>],[global]), 62 | D = binary:split(<<1,255,4,0,0,0,2,3>>, [<<0,0,0>>,<<2>>],[]), 63 | ?debugFmt("~p ~p", [C, D]). 64 | 65 | -------------------------------------------------------------------------------- /src/mess_server.erl: -------------------------------------------------------------------------------- 1 | %%%----FILE mess_server.erl---- 2 | 3 | %%% This is the server process of the messenger service 4 | 5 | -module(mess_server). 6 | -export([start_server/0, server/0]). 7 | -include("mess_interface.hrl"). 8 | 9 | server() -> 10 | process_flag(trap_exit, true), 11 | server([]). 12 | 13 | %%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] 14 | server(User_List) -> 15 | io:format("User list = ~p~n", [User_List]), 16 | receive 17 | #logon{client_pid=From, username=Name} -> 18 | New_User_List = server_logon(From, Name, User_List), 19 | server(New_User_List); 20 | {'EXIT', From, _} -> 21 | New_User_List = server_logoff(From, User_List), 22 | server(New_User_List); 23 | #message{client_pid=From, to_name=To, message=Message} -> 24 | server_transfer(From, To, Message, User_List), 25 | server(User_List) 26 | end. 27 | 28 | %%% Start the server 29 | start_server() -> 30 | register(messenger, spawn(?MODULE, server, [])). 31 | 32 | %%% Server adds a new user to the user list 33 | server_logon(From, Name, User_List) -> 34 | %% check if logged on anywhere else 35 | case lists:keymember(Name, 2, User_List) of 36 | true -> 37 | From ! #abort_client{message=user_exists_at_other_node}, 38 | User_List; 39 | false -> 40 | From ! #server_reply{message=logged_on}, 41 | link(From), 42 | [{From, Name} | User_List] %add user to the list 43 | end. 44 | 45 | %%% Server deletes a user from the user list 46 | server_logoff(From, User_List) -> 47 | lists:keydelete(From, 1, User_List). 48 | 49 | %%% Server transfers a message between user 50 | server_transfer(From, To, Message, User_List) -> 51 | %% check that the user is logged on and who he is 52 | case lists:keysearch(From, 1, User_List) of 53 | false -> 54 | From ! #abort_client{message=you_are_not_logged_on}; 55 | {value, {_, Name}} -> 56 | server_transfer(From, Name, To, Message, User_List) 57 | end. 58 | %%% If the user exists, send the message 59 | server_transfer(From, Name, To, Message, User_List) -> 60 | %% Find the receiver and send the message 61 | case lists:keysearch(To, 2, User_List) of 62 | false -> 63 | From ! #server_reply{message=receiver_not_found}; 64 | {value, {ToPid, To}} -> 65 | ToPid ! #message_from{from_name=Name, message=Message}, 66 | From ! #server_reply{message=sent} 67 | end. 68 | 69 | %%%----END FILE--- -------------------------------------------------------------------------------- /src/messenger.erl: -------------------------------------------------------------------------------- 1 | %%% Message passing utility. 2 | %%% User interface: 3 | %%% login(Name) 4 | %%% One user at a time can log in from each Erlang node in the 5 | %%% system messenger: and choose a suitable Name. If the Name 6 | %%% is already logged in at another node or if someone else is 7 | %%% already logged in at the same node, login will be rejected 8 | %%% with a suitable error message. 9 | %%% logoff() 10 | %%% Logs off anybody at at node 11 | %%% message(ToName, Message) 12 | %%% sends Message to ToName. Error messages if the user of this 13 | %%% function is not logged on or if ToName is not logged on at 14 | %%% any node. 15 | %%% 16 | %%% One node in the network of Erlang nodes runs a server which maintains 17 | %%% data about the logged on users. The server is registered as "messenger" 18 | %%% Each node where there is a user logged on runs a client process registered 19 | %%% as "mess_client" 20 | %%% 21 | %%% Protocol between the client processes and the server 22 | %%% ---------------------------------------------------- 23 | %%% 24 | %%% To server: {ClientPid, logon, UserName} 25 | %%% Reply {messenger, stop, user_exists_at_other_node} stops the client 26 | %%% Reply {messenger, logged_on} logon was successful 27 | %%% 28 | %%% When the client terminates for some reason 29 | %%% To server: {'EXIT', ClientPid, Reason} 30 | %%% 31 | %%% To server: {ClientPid, message_to, ToName, Message} send a message 32 | %%% Reply: {messenger, stop, you_are_not_logged_on} stops the client 33 | %%% Reply: {messenger, receiver_not_found} no user with this name logged on 34 | %%% Reply: {messenger, sent} Message has been sent (but no guarantee) 35 | %%% 36 | %%% To client: {message_from, Name, Message}, 37 | %%% 38 | %%% Protocol between the "commands" and the client 39 | %%% ---------------------------------------------- 40 | %%% 41 | %%% Started: messenger:client(Server_Node, Name) 42 | %%% To client: logoff 43 | %%% To client: {message_to, ToName, Message} 44 | %%% 45 | %%% Configuration: change the server_node() function to return the 46 | %%% name of the node where the messenger server runs 47 | 48 | % (messenger@super)1> messenger:start_server(). 49 | % (c1@bilbo)1> messenger:logon(peter). 50 | % (c2@kosken)1> messenger:logon(james). 51 | % (c3@gollum)1> messenger:logon(fred). 52 | % (c1@bilbo)2> messenger:message(fred, "hello"). 53 | % (c3@gollum)2> messenger:message(peter, "go away, I'm busy"). 54 | % (c3@gollum)3> messenger:logoff(). 55 | % (c2@kosken)2> messenger:message(fred, "peter doesn't like you"). 56 | 57 | -module(messenger). 58 | -export([start_server/0, server/0, 59 | logon/1, logoff/0, message/2, client/2]). 60 | 61 | %%% Change the function below to return the name of the node where the 62 | %%% messenger server runs 63 | server_node() -> 64 | messenger@super. 65 | 66 | %%% This is the server process for the "messenger" 67 | %%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...] 68 | server() -> 69 | process_flag(trap_exit, true), 70 | server([]). 71 | 72 | server(User_List) -> 73 | receive 74 | {From, logon, Name} -> 75 | New_User_List = server_logon(From, Name, User_List), 76 | server(New_User_List); 77 | {'EXIT', From, _} -> 78 | New_User_List = server_logoff(From, User_List), 79 | server(New_User_List); 80 | {From, message_to, To, Message} -> 81 | server_transfer(From, To, Message, User_List), 82 | io:format("list is now: ~p~n", [User_List]), 83 | server(User_List) 84 | end. 85 | 86 | %%% Start the server 87 | start_server() -> 88 | register(messenger, spawn(messenger, server, [])). 89 | 90 | %%% Server adds a new user to the user list 91 | server_logon(From, Name, User_List) -> 92 | %% check if logged on anywhere else 93 | case lists:keymember(Name, 2, User_List) of 94 | true -> 95 | From ! {messenger, stop, user_exists_at_other_node}, %reject logon 96 | User_List; 97 | false -> 98 | From ! {messenger, logged_on}, 99 | link(From), 100 | [{From, Name} | User_List] %add user to the list 101 | end. 102 | 103 | %%% Server deletes a user from the user list 104 | server_logoff(From, User_List) -> 105 | lists:keydelete(From, 1, User_List). 106 | 107 | 108 | %%% Server transfers a message between user 109 | server_transfer(From, To, Message, User_List) -> 110 | %% check that the user is logged on and who he is 111 | case lists:keysearch(From, 1, User_List) of 112 | false -> 113 | From ! {messenger, stop, you_are_not_logged_on}; 114 | {value, {_, Name}} -> 115 | server_transfer(From, Name, To, Message, User_List) 116 | end. 117 | 118 | %%% If the user exists, send the message 119 | server_transfer(From, Name, To, Message, User_List) -> 120 | %% Find the receiver and send the message 121 | case lists:keysearch(To, 2, User_List) of 122 | false -> 123 | From ! {messenger, receiver_not_found}; 124 | {value, {ToPid, To}} -> 125 | ToPid ! {message_from, Name, Message}, 126 | From ! {messenger, sent} 127 | end. 128 | 129 | %%% User Commands 130 | logon(Name) -> 131 | case whereis(mess_client) of 132 | undefined -> 133 | register(mess_client, 134 | spawn(messenger, client, [server_node(), Name])); 135 | _ -> already_logged_on 136 | end. 137 | 138 | logoff() -> 139 | mess_client ! logoff. 140 | 141 | message(ToName, Message) -> 142 | case whereis(mess_client) of % Test if the client is running 143 | undefined -> 144 | not_logged_on; 145 | _ -> mess_client ! {message_to, ToName, Message}, 146 | ok 147 | end. 148 | 149 | %%% The client process which runs on each user node 150 | client(Server_Node, Name) -> 151 | {messenger, Server_Node} ! {self(), logon, Name}, 152 | await_result(), 153 | client(Server_Node). 154 | 155 | client(Server_Node) -> 156 | receive 157 | logoff -> 158 | exit(normal); 159 | {message_to, ToName, Message} -> 160 | {messenger, Server_Node} ! {self(), message_to, ToName, Message}, 161 | await_result(); 162 | {message_from, FromName, Message} -> 163 | io:format("Message from ~p: ~p~n", [FromName, Message]) 164 | end, 165 | client(Server_Node). 166 | 167 | %%% wait for a response from the server 168 | await_result() -> 169 | receive 170 | {messenger, stop, Why} -> % Stop the client 171 | io:format("~p~n", [Why]), 172 | exit(normal); 173 | {messenger, What} -> % Normal response 174 | io:format("~p~n", [What]) 175 | after 5000 -> 176 | io:format("No response from server~n", []), 177 | exit(timeout) 178 | end. --------------------------------------------------------------------------------