Skip to content

Commit

Permalink
Improve error handling when no format is resolved
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Jul 7, 2024
1 parent 6683356 commit 9f9f156
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 20 deletions.
4 changes: 2 additions & 2 deletions lib/cldr/backend/date_time.ex
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ defmodule Cldr.DateAndTime.Backend do
# CLDR defined format.
iex> #{inspect(__MODULE__)}.to_string(%{year: 2024, day: 3}, locale: "fr")
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \\"dy\\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :dy"}}
"""
@spec to_string(Cldr.Calendar.any_date_time(), Keyword.t()) ::
Expand Down Expand Up @@ -408,7 +408,7 @@ defmodule Cldr.DateAndTime.Backend do
# CLDR defined format.
iex> #{inspect(__MODULE__)}.to_string(%{minute: 11})
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \\"m\\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :m"}}
"""
@spec to_string(Cldr.Calendar.any_date_time(), Keyword.t()) ::
Expand Down
20 changes: 16 additions & 4 deletions lib/cldr/date.ex
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ defmodule Cldr.Date do
# CLDR-defined format.
iex> Cldr.Date.to_string(%{year: 2024, day: 3}, MyApp.Cldr, locale: "fr")
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \\"dy\\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :dy"}}
"""
@spec to_string(Cldr.Calendar.any_date_time(), Cldr.backend() | Keyword.t(), Keyword.t()) ::
Expand Down Expand Up @@ -464,9 +464,7 @@ defmodule Cldr.Date do
if Map.has_key?(available_formats, format) do
Map.fetch(available_formats, format)
else
with {:ok, match} <- Cldr.DateTime.Format.best_match(format, locale, calendar, backend) do
{:ok, Map.fetch!(available_formats, match)}
end
resolve_format(format, available_formats, locale, calendar, backend)
end
end

Expand All @@ -478,6 +476,20 @@ defmodule Cldr.Date do
{:ok, format_string}
end

@doc false
def resolve_format(format, available_formats, locale, calendar, backend) do
with {:ok, match} <- Cldr.DateTime.Format.best_match(format, locale, calendar, backend),
{:ok, format} <- Map.fetch(available_formats, match) do
{:ok, format}
else
:error ->
{:error, Cldr.DateTime.Format.no_format_resolved_error(format)}

other ->
other
end
end

defp error_return(map, requirements) do
requirements =
requirements
Expand Down
21 changes: 14 additions & 7 deletions lib/cldr/format/date_time_format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -632,13 +632,13 @@ defmodule Cldr.DateTime.Format do
) :: {:ok, format_id()} | {:error, {module(), String.t()}}

def best_match(
skeleton,
original_skeleton,
locale \\ Cldr.get_locale(),
calendar \\ Cldr.Calendar.default_cldr_calendar(),
backend \\ Cldr.Date.default_backend()
) do
with {:ok, locale} <- Cldr.validate_locale(locale, backend),
skeleton = to_string(skeleton),
skeleton = to_string(original_skeleton),
{:ok, skeleton} <- put_preferred_time_symbols(skeleton, locale),
{:ok, skeleton_tokens} <- Compiler.tokenize_skeleton(skeleton) do
# match_with_day_periods? =
Expand All @@ -663,18 +663,22 @@ defmodule Cldr.DateTime.Format do

case candidates do
[] ->
{:error,
{
Cldr.DateTime.UnresolvedFormat,
"No available format resolved for #{inspect(skeleton)}"
}}
{:error, no_format_resolved_error(original_skeleton)}

[{format_id, _} | _rest] ->
{:ok, format_id}
end
end
end

@doc false
def no_format_resolved_error(skeleton) do
{
Cldr.DateTime.UnresolvedFormat,
"No available format resolved for #{inspect(skeleton)}"
}
end

# https://www.unicode.org/reports/tr35/tr35-dates.html#Matching_Skeletons
# For skeleton and id fields with symbols representing the same type (year, month, day, etc):
# Most symbols have a small distance from each other.
Expand Down Expand Up @@ -785,6 +789,9 @@ defmodule Cldr.DateTime.Format do
when different_but_compatible({symbol_a, count_a}, {symbol_b, count_b}) and
different_types({symbol_a, count_a}, {symbol_b, count_b}) ->
acc + abs(count_a - count_b) + 10

_other_a, _other_b, acc ->
acc + 10
end)

{token_id, distance}
Expand Down
9 changes: 5 additions & 4 deletions lib/cldr/time.ex
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ defmodule Cldr.Time do
# CLDR-defined format.
iex> Cldr.Time.to_string(%{minute: 11})
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \\"m\\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :m"}}
"""
@spec to_string(map, Cldr.backend() | Keyword.t(), Keyword.t()) ::
Expand Down Expand Up @@ -347,9 +347,7 @@ defmodule Cldr.Time do
if Map.has_key?(available_formats, format) do
Map.fetch(available_formats, format)
else
with {:ok, match} <- Cldr.DateTime.Format.best_match(format, locale, calendar, backend) do
{:ok, Map.fetch!(available_formats, match)}
end
resolve_format(format, available_formats, locale, calendar, backend)
end
end

Expand All @@ -361,6 +359,9 @@ defmodule Cldr.Time do
{:ok, format_string}
end

@doc false
defdelegate resolve_format(format, available_formats, locale, calendar, backend), to: Cldr.Date

@doc """
Returns a map of the standard time formats for a given
locale and calendar.
Expand Down
6 changes: 3 additions & 3 deletions test/partial_date_times_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ defmodule Cldr.DateTime.PartialTest do

assert Cldr.Date.to_string(%{year: 3, day: 5}) ==
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \"dy\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :dy"}}
end

test "Partial Times" do
Expand Down Expand Up @@ -43,7 +43,7 @@ defmodule Cldr.DateTime.PartialTest do

assert Cldr.Time.to_string(%{hour: 23, second: 45}) ==
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \"sh\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :sh"}}

assert Cldr.Time.to_string(%{hour: 23, second: 45}, format: "h:m:s") ==
{:error,
Expand All @@ -58,7 +58,7 @@ defmodule Cldr.DateTime.PartialTest do

assert Cldr.DateTime.to_string(%{year: 2024, minute: 10}) ==
{:error,
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for \"m\""}}
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :m"}}

end

Expand Down

0 comments on commit 9f9f156

Please sign in to comment.