🗓️Day 16
Tuesday, 23 August 2022 - Day 16 of Exhort August 2022 - Exercism (My Elixir Journey)
Exercises
Newsletter
Exercise on Exercism | View my solution
Solution
Expand to see code (spoiler alert)
defmodule Newsletter do
@spec read_emails(path :: String.t()) :: list(String.t())
def read_emails(path) do
{:ok, contents} = File.read(path)
String.split(contents, "\n", trim: true)
end
@spec open_log(path :: String.t()) :: pid()
def open_log(path) do
File.open!(path, [:write])
end
@spec log_sent_email(pid(), email :: String.t()) :: :ok
def log_sent_email(pid, email) do
IO.puts(pid, email)
end
@spec close_log(pid()) :: :ok
def close_log(pid) do
File.close(pid)
end
@spec send_newsletter(String.t(), String.t(), fun()) :: :ok
def send_newsletter(emails_path, log_path, send_fun) do
pid = open_log(log_path)
read_emails(emails_path)
|> Enum.each(fn email -> if :ok == send_fun.(email), do: log_sent_email(pid, email) end)
close_log(pid)
end
end
View gist on GitHub
Notes
I had to use File.open!
and I could have used IO.puts
to avoid having to concatenate a \n
.
Chessboard
Exercise on Exercism | View my solution
Solution
Expand to see code (spoiler alert)
defmodule Chessboard do
@spec rank_range :: Range.t()
def rank_range, do: 1..8
@spec file_range :: Range.t()
def file_range, do: ?A..?H
@spec ranks :: list(integer())
def ranks, do: Enum.to_list(rank_range())
@spec files :: list(String.t())
def files, do: Enum.map(file_range(), &<<&1>>)
end
View gist on GitHub
Notes
I really love the shorthand: Enum.map(file_range(), &<<&1>>)
Remote Control Car
Exercise on Exercism | View my solution
Solution
Expand to see code (spoiler alert)
defmodule RemoteControlCar do
@enforce_keys [:nickname]
defstruct [:nickname, battery_percentage: 100, distance_driven_in_meters: 0]
@spec new(String.t()) :: struct()
def new(nickname \\ "none") do
%RemoteControlCar{nickname: nickname}
end
@spec display_distance(remote_car :: struct()) :: String.t()
def display_distance(%RemoteControlCar{} = remote_car) do
"#{remote_car.distance_driven_in_meters} meters"
end
@spec display_battery(remote_car :: struct()) :: String.t()
def display_battery(%RemoteControlCar{battery_percentage: 0}), do: "Battery empty"
def display_battery(%RemoteControlCar{} = remote_car),
do: "Battery at #{remote_car.battery_percentage}%"
@spec drive(remote_car :: struct()) :: struct()
def drive(%RemoteControlCar{battery_percentage: 0} = remote_car), do: remote_car
def drive(%RemoteControlCar{} = remote_car) do
%{
remote_car
| battery_percentage: remote_car.battery_percentage - 1,
distance_driven_in_meters: remote_car.distance_driven_in_meters + 20
}
end
end
View gist on GitHub
Notes
I didn't know about the @enforce_keys
module attribute.
Overall progress