Packages

BeamLabCountries is a collection of all sorts of useful information for every country in the [ISO 3166](https://wikipedia.org/wiki/ISO_3166) standard. It includes country data, subdivisions (states/provinces), international organizations, language information, and country name translations.

Current section

Files

Jump to
beamlab_countries lib countries.ex
Raw

lib/countries.ex

defmodule BeamLabCountries do
@moduledoc """
Module for providing countries related functions.
"""
@doc """
Returns all countries.
"""
@spec all() :: [BeamLabCountries.Country.t()]
def all do
countries()
end
@doc """
Returns the total number of countries.
## Examples
iex> BeamLabCountries.count()
250
"""
@spec count() :: non_neg_integer()
def count do
length(countries())
end
@doc """
Returns one country given its alpha2 country code, or `nil` if not found.
## Examples
iex> %BeamLabCountries.Country{name: name} = BeamLabCountries.get("PL")
iex> name
"Poland"
iex> BeamLabCountries.get("INVALID")
nil
"""
@spec get(String.t()) :: BeamLabCountries.Country.t() | nil
def get(country_code) when is_binary(country_code) do
Map.get(countries_by_alpha2(), String.upcase(country_code))
end
@doc """
Returns one country given its alpha3 country code, or `nil` if not found.
## Examples
iex> %BeamLabCountries.Country{name: name} = BeamLabCountries.get_by_alpha3("POL")
iex> name
"Poland"
iex> BeamLabCountries.get_by_alpha3("INVALID")
nil
"""
@spec get_by_alpha3(String.t()) :: BeamLabCountries.Country.t() | nil
def get_by_alpha3(country_code) when is_binary(country_code) do
Map.get(countries_by_alpha3(), String.upcase(country_code))
end
@doc """
Returns one country given its alpha2 country code, or raises if not found.
## Examples
iex> %BeamLabCountries.Country{name: name} = BeamLabCountries.get!("PL")
iex> name
"Poland"
"""
@spec get!(String.t()) :: BeamLabCountries.Country.t()
def get!(country_code) do
case get(country_code) do
nil -> raise ArgumentError, "no country found for code: #{inspect(country_code)}"
country -> country
end
end
@doc """
Returns one country matching the given attribute and value, or `nil` if not found.
## Examples
iex> %BeamLabCountries.Country{alpha2: alpha2} = BeamLabCountries.get_by(:name, "Poland")
iex> alpha2
"PL"
iex> BeamLabCountries.get_by(:name, "Atlantis")
nil
"""
@spec get_by(atom(), term()) :: BeamLabCountries.Country.t() | nil
def get_by(attribute, value) do
Enum.find(countries(), fn country ->
country
|> Map.get(attribute)
|> equals_or_contains_in_list(value)
end)
end
@doc """
Filters countries by given attribute.
Returns a list of `BeamLabCountries.Country` structs
## Single attribute
iex> countries = BeamLabCountries.filter_by(:region, "Europe")
iex> Enum.count(countries)
51
iex> Enum.map(countries, &Map.get(&1, :alpha2)) |> Enum.take(5)
["AD", "AL", "AT", "AX", "BA"]
iex> countries = BeamLabCountries.filter_by(:unofficial_names, "Reino Unido")
iex> Enum.count(countries)
1
iex> Enum.map(countries, &Map.get(&1, :name)) |> List.first
"United Kingdom of Great Britain and Northern Ireland"
## Multiple attributes
iex> countries = BeamLabCountries.filter_by(region: "Europe", eu_member: true)
iex> length(countries)
26
iex> countries = BeamLabCountries.filter_by(region: "Europe", eea_member: true)
iex> length(countries)
30
"""
@spec filter_by(atom(), term()) :: [BeamLabCountries.Country.t()]
def filter_by(attribute, value) when is_atom(attribute) do
Enum.filter(countries(), fn country ->
country
|> Map.get(attribute)
|> equals_or_contains_in_list(value)
end)
end
@spec filter_by(keyword()) :: [BeamLabCountries.Country.t()]
def filter_by(criteria) when is_list(criteria) do
Enum.filter(countries(), fn country ->
Enum.all?(criteria, fn {attribute, value} ->
country
|> Map.get(attribute)
|> equals_or_contains_in_list(value)
end)
end)
end
defp equals_or_contains_in_list(nil, _), do: false
defp equals_or_contains_in_list([], _), do: false
defp equals_or_contains_in_list(list, value) when is_list(list) do
normalized_value = normalize(value)
Enum.any?(list, &(normalize(&1) == normalized_value))
end
defp equals_or_contains_in_list(attribute, value),
do: normalize(attribute) == normalize(value)
defp normalize(value) when is_integer(value),
do: value |> Integer.to_string() |> normalize()
defp normalize(value) when is_binary(value),
do: value |> String.downcase() |> String.replace(~r/\s+/, "")
defp normalize(value), do: value
@doc """
Returns all EU member countries.
## Examples
iex> eu = BeamLabCountries.eu_members()
iex> length(eu)
27
iex> Enum.map(eu, &Map.get(&1, :alpha2)) |> Enum.take(3)
["AT", "BE", "BG"]
"""
@spec eu_members() :: [BeamLabCountries.Country.t()]
def eu_members do
filter_by(:eu_member, true)
end
@doc """
Checks if country for specific attribute and value exists.
Returns boolean.
## Examples
iex> BeamLabCountries.exists?(:name, "Poland")
true
iex> BeamLabCountries.exists?(:name, "Polande")
false
"""
@spec exists?(atom(), term()) :: boolean()
def exists?(attribute, value) do
Enum.any?(countries(), fn country ->
country
|> Map.get(attribute)
|> equals_or_contains_in_list(value)
end)
end
# -- Load countries from yaml files once on compile time ---
@countries BeamLabCountries.Loader.load()
@countries_by_alpha2 Map.new(@countries, &{String.upcase(&1.alpha2), &1})
@countries_by_alpha3 Map.new(@countries, &{String.upcase(&1.alpha3), &1})
defp countries, do: @countries
defp countries_by_alpha2, do: @countries_by_alpha2
defp countries_by_alpha3, do: @countries_by_alpha3
end