|
defmodule CountryList do |
|
def start_link(initial \\ []), do: Task.start_link(fn -> loop(initial) end) |
|
|
|
defp loop(list) do |
|
receive do |
|
{:get, caller} -> |
|
send caller, {:get, list} |
|
loop list |
|
{:get, caller, :by_name, name} -> |
|
send caller, {:get, :by_name, Enum.filter(list, &(&1.country == name))} |
|
loop list |
|
{:add, entry} -> |
|
loop [entry | list] |
|
end |
|
end |
|
end |
|
|
|
defmodule Util do |
|
defp make_list(binary) do |
|
String.split(binary, "\n") |
|
|> Enum.map(&String.split(String.strip(&1), ",")) |
|
|> Enum.map(fn |
|
([cn, cp, pop]) -> %{country: cn, capital: cp, population: elem(Integer.parse(pop), 0)} |
|
([""]) -> nil |
|
end) |
|
|> Enum.reject(&is_nil/1) |
|
end |
|
|
|
@doc """ |
|
Creates a CountryList process from file |
|
""" |
|
def country_list_from_file (path \\ "crapitals.csv") do |
|
case File.read(path) do |
|
{:ok, content} -> CountryList.start_link make_list(content) |
|
{:error, posix} -> {:error, :file, posix} |
|
end |
|
end |
|
end |
|
|
|
defmodule Crapitals do |
|
def main() do |
|
{:ok, pid} = Util.country_list_from_file |
|
main :next, pid |
|
end |
|
|
|
defp main(:next, list) do |
|
case get_command() do |
|
{:error, :bad_command} -> |
|
IO.puts "Sorry, unrecognised command" |
|
main :next, list |
|
{:error, :bad_value, msg} -> |
|
IO.puts "Sorry, you entered a bad value. #{msg}" |
|
main :next, list |
|
{:by_name, name} -> |
|
send list, {:get, self(), :by_name, name} |
|
receive do |
|
{:get, :by_name, [data | _]} -> |
|
%{country: cn, capital: cp, population: pop} = data |
|
IO.puts "Found #{cn} (#{cp}) (#{pop} people)" |
|
{:get, :by_name, []} -> |
|
IO.puts "Country not found" |
|
end |
|
main :next, list |
|
:exit -> |
|
IO.puts "Bye then" |
|
end |
|
end |
|
|
|
defp get_command() do |
|
case String.split(IO.gets("> "), ~r/\s+/, trim: true) do |
|
["exit"] -> :exit |
|
["by_name", name] -> {:by_name, name} |
|
_ -> {:error, :bad_command} |
|
end |
|
end |
|
end |