Skip to content

Instantly share code, notes, and snippets.

@defndaines
Last active July 26, 2023 03:30
Show Gist options
  • Save defndaines/2098a1b2e749f5da620f9de37e1990e5 to your computer and use it in GitHub Desktop.
Save defndaines/2098a1b2e749f5da620f9de37e1990e5 to your computer and use it in GitHub Desktop.
Functions for Title Case
defmodule Title do
@moduledoc """
Build up a title-case function for ensuring that a line is properly cased.
"""
# Includes articles as well
@prepositions ~w(a aboard about above abreast absent across after against ago
along aloft alongside amid among an and apropos around as aslant astride at atop
before behind below beneath beside besides between beyond but by circa cum
despite during except for from in including inside into less like next
notwithstanding of off on onto or out over per pre sans since than the through
throughout to toward towards under underneath unlike until unto up upon versus
vs. v. via vis-à-vis with within without)
@complex [
"À La",
"According to",
"Ahead of",
"Apart from",
"as Regards",
"as Soon as",
"as Well as",
"Aside from",
"Away from",
"Back to",
"Because of",
"Close to",
"Counter to",
"Due to",
"Far from",
"in Case",
"Instead of",
"Near to",
"Opposite of",
"Other than",
"Outside of",
"Owing to",
"per Pro",
"Pertaining to",
"Prior to",
"Pursuant to",
"Rather than",
"Regardless of",
"Round about",
"Subsequent to",
"Such as"
]
@doc """
Format the provided string to title case. Title case capitalizes all important words, but
doesn't capitalize prepositions or articles unless they are in an important position..
"""
def title_case(string) do
string
|> String.split()
|> Enum.map_join(" ", &capitalize/1)
|> complex_prepositions()
|> capitalize_chunks()
end
defp capitalize(string) when string in @prepositions, do: string
defp capitalize(string) do
{char, rest} = String.Unicode.titlecase_once(string, :default)
char <> rest
end
defp complex_prepositions(string) do
if String.contains?(string, @complex) do
String.replace(string, @complex, &String.downcase/1)
else
string
end
end
defp capitalize_chunks(string) do
string
|> String.split(":")
|> Enum.map(&String.trim/1)
|> Enum.map_join(": ", &capitalize/1)
end
end
defmodule TitleTest do
use ExUnit.Case
test "with no prepositions" do
truth = [
"truth be told",
"Truth be told",
"Truth Be Told"
]
assert ["Truth Be Told"] == truth |> Enum.map(&Title.title_case/1) |> Enum.uniq()
end
test "with legitimate uppercasing mid-word" do
assert "Japan: OKs Divorce Bill" == Title.title_case("Japan: OKs divorce bill")
end
test "with emdash" do
assert "Korea—Not Just Delicious Food" == Title.title_case("Korea—Not just delicious food")
assert "U.S.—a Country in Turmoil" == Title.title_case("U.S.—a country in turmoil")
end
test "with is in it" do
assert "This Is It!" == Title.title_case("This is it!")
end
test "with non-ASCII in it" do
assert "Éowyn’s Résumé" == Title.title_case("éowyn’s résumé")
end
test "prepositions" do
assert "It's the End of the World as We Know It" ==
Title.title_case("it's the end of the world as we know it")
end
test "complex prepositions" do
assert "Life according to You Is outside of Material Goods" ==
Title.title_case("life according to you is outside of material goods")
end
test "preposition and articles at the beginning" do
assert "To Address the Problem" == Title.title_case("to address the problem")
assert "The Problem to Address" == Title.title_case("the problem to address")
end
test "capitalize after colons" do
assert "Empathy: An Answer to Hate?" == Title.title_case("empathy: an answer to hate?")
end
test "handles extra spaces" do
assert "Beneath the Planet of the Apes" == Title.title_case("beneath the planet of the apes")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment