Current section

Files

Jump to
tz_extra lib file_parser zone_parser.ex
Raw

lib/file_parser/zone_parser.ex

defmodule TzExtra.FileParser.ZoneParser do
@moduledoc false
def parse(file_path, countries) do
File.stream!(file_path)
|> strip_comments()
|> strip_empty()
|> trim()
|> Enum.to_list()
|> parse_strings_into_maps()
|> add_country_names(countries)
end
defp strip_comments(stream) do
stream
|> Stream.filter(&(!Regex.match?(~r/^[\s]*#/, &1)))
|> Stream.map(&Regex.replace(~r/[\s]*#.+/, &1, ""))
end
defp strip_empty(stream) do
Stream.filter(stream, &(!Regex.match?(~r/^[\s]*\n$/, &1)))
end
defp trim(stream) do
Stream.map(stream, &String.trim(&1))
end
defp parse_strings_into_maps([]), do: []
defp parse_strings_into_maps([string | tail]) do
maps =
Enum.zip([
[:country_codes, :coordinates, :name, :_],
String.split(string, ~r{\s}, trim: true, parts: 4)
|> Enum.map(& String.trim(&1))
])
|> Enum.into(%{})
|> Map.delete(:_)
|> denormalize_entry()
maps ++ parse_strings_into_maps(tail)
end
defp denormalize_entry(%{} = entry) do
country_codes = String.split(entry.country_codes, ",", trim: true)
for country_code <- country_codes do
%{
country_code: country_code,
coordinates: entry.coordinates,
name: entry.name,
short_name: String.split(entry.name, "/") |> List.last()
}
end
end
defp add_country_names(list, countries) do
Enum.map(list, fn map ->
{country_code, map} = pop_in(map, [:country_code])
country = Enum.find(countries, & &1.code == country_code)
Map.put(map, :country, country)
end)
end
end