🗓️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

Last updated