Skip to content

Instantly share code, notes, and snippets.

@FLamparski
Created July 4, 2016 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FLamparski/287004321761f7206e66dbead55ab328 to your computer and use it in GitHub Desktop.
Save FLamparski/287004321761f7206e66dbead55ab328 to your computer and use it in GitHub Desktop.
Learning Elixir: A shitty program that does things with data

Crapitals

Filip Learns Elixir, Day 1

Basically, it's a thing which reads data from a CSV file, keeps it in memory using a stateful process CountryList, and lets you query said list. I tried using several of Elixir's features here such as processes, messaging, pattern-matching, and the pipe operator.

UK London 35000000
Whatever Whenever 454264
Thingy Thangy 54253435
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment