Solution to Exercise 4, Chapter 2: Programming Erlang by Joe Armstrong

The problem: From page 37, Exercise 4, Chapter 2, Programming Erlang by Joe Armstrong

Run the file client and server code. Add a command called put_file. What messages do you need to add? Find out how to consult manual pages. Consult the manual pages for the file module.

Additional Specifications

  • We should be able to run “erl” from a directory of our choice other than where the .erl source files are located
  • We should be able to specify a directory of our choice in afile_server:start Dir argument
  • We should be able to put a file from a directory other than the current directory to the directory specified in Dir argument above

Solution

{Client, {put_file, File}} ->
  Source = filename:absname(File),
  Destination = filename:join(Dir, filename:basename(File)),
  Client ! {self(), file:copy(Source, Destination)}</pre>
  • We will use the file:copy function. copy/2 has a source and a destination
  • source = the absolute filename
  • destination = dir name + base filename

Testing the solution

1> c("../erlang/afile_server").
{ok,afile_server}
2> c("../erlang/afile_client").
{ok,afile_client}
3> FS = afile_server:start("../erlang").
<0.46.0>
4> afile_client:ls(FS).
{ok,[".idea","afile_client.beam","afile_client.erl",
     "afile_server.beam","afile_server.erl","erlang.iml","foo",
     "geometry.beam","geometry.erl","hello.beam","hello.erl",
     "shop.beam","shop.erl","shop1.beam","shop1.erl"]}
5> afile_client:put_file(FS, "../foo").
{ok,5}
6> afile_client:put_file(FS, "Test.java").
{ok,382}
7> afile_client:ls(FS).
{ok,[".idea","afile_client.beam","afile_client.erl",
     "afile_server.beam","afile_server.erl","erlang.iml","foo",
     "geometry.beam","geometry.erl","hello.beam","hello.erl",
     "shop.beam","shop.erl","shop1.beam","shop1.erl",
     "Test.java"]}

The files foo and Test.java are now showing up in the response from aflile_client:ls(FS) in line 7 above.

Full source code

afile_server.erl

-module(afile_server).
-export([start/1, loop/1]).

start(Dir) -> spawn(afile_server, loop, [Dir]).

loop(Dir) ->
  receive
    {Client, list_dir} ->
      Client ! {self(), file:list_dir(Dir)};
    {Client, {get_file, File}} ->
      Full = filename:join(Dir, File),
      Client ! {self(), file:read_file(Full)};
    {Client, {put_file, File}} ->
      Source = filename:absname(File),
      Destination = filename:join(Dir, filename:basename(File)),
      Client ! {self(), file:copy(Source, Destination)}
  end,
  loop(Dir).

afile_client.erl

-module(afile_client).
-export([ls/1, get_file/2, put_file/2]).

ls(Server) ->
  Server ! {self(), list_dir},
  receive
    {Server, FileList} ->
      FileList
  end.

get_file(Server, File) ->
  Server ! {self(), {get_file, File}},
  receive
    {Server, Content} ->
      Content
  end.

put_file(Server, File) ->
  Server ! {self(), {put_file, File}},
  receive
    {Server, Status} ->
      Status
  end.

Install Erlang on Mac OS X

Though erlang-solutions.com provides pre-built binaries for Mac OS X (among other OS), an alternate and easy way to install Erlang on Mac OS X is via brew. Simply type:

brew install erlang

Once installed, you can test it by typing “erl” in the Terminal to fire up the Erlang interactive shell:

Now that you have Erlang installed, what next? Highly recommend Joe Armstrong’s Programming Erlang (2nd Edition). It’s always nice to read programming books authored by language creator themselves. Joe Armstrong’s Github page also has some goodies related to the book and other information.

joe-armstrong-programming-erlang-2nd-edition-book-cover

For a little inspiration, here’s “Erlang the Movie”: