Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
defmodule CountdownSong do
def song(%{upper: upper, lower: lower}, verse_template) do
verses(upper, lower, verse_template)
end
def verses(upper, lower, verse_template) do
upper..lower
|> Enum.map(fn n -> verse(n, verse_template) end)
|> Enum.join("\n")
end
def verse(num, verse_template) do
verse_template.lyrics(num)
end
end
defmodule Bottles do
defstruct upper: 99, lower: 0
end
defmodule VerseTemplate do
@callback lyrics(integer) :: String.t()
end
defmodule BottleVerse do
@behaviour VerseTemplate
@impl VerseTemplate
def lyrics(num) do
"#{bottle_number(num) |> String.capitalize()} of beer on the wall, " <>
"#{bottle_number(num)} of beer.\n" <>
"#{action(num)}, " <>
"#{successor(num) |> bottle_number()} of beer on the wall.\n"
end
def bottle_number(num) do
"#{amount(num)} #{container(num)}"
end
defp container(6), do: "six-pack"
defp container(1), do: "bottle"
defp container(_), do: "bottles"
defp pronoun(1), do: "it"
defp pronoun(_), do: "one"
defp amount(6), do: "1"
defp amount(0), do: "no more"
defp amount(num), do: "#{num}"
defp action(0), do: "Go to the store and buy some more"
defp action(num), do: "Take #{pronoun(num)} down and pass it around"
defp successor(0), do: 99
defp successor(num), do: num - 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment