Last active
July 26, 2023 03:30
-
-
Save defndaines/2098a1b2e749f5da620f9de37e1990e5 to your computer and use it in GitHub Desktop.
Functions for Title Case
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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