Skip to content

Commit

Permalink
Add tests for :only and :except and bump version for release
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Dec 26, 2021
1 parent 4c8812b commit 99a9a30
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 2 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Cldr_Units v3.10.0

This is the changelog for Cldr_units v3.10.0 released on December 27th, 2021. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_units/tags)

### Bug Fixes

* Further refinement to `Cldr.Unit.unit_category/1` to return a result in a broader range of cases.

### Enhancements

* Adds `:only` and `:except` options to `Cldr.Unit.parse/2`. These options provide a mechanism to disambiguate the unit when a unit string could refer to more than one unit. For example, "2w" could refer to either "2 weeks" or "2 watts". If neither option is provided then the result is the same as in prior releases: the unit with the lexically shorter and alphabetically earlier unit is returned.

## Cldr_Units v3.9.2

This is the changelog for Cldr_units v3.9.2 released on December 26th, 2021. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_units/tags)
Expand Down
41 changes: 39 additions & 2 deletions lib/cldr/unit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -440,17 +440,38 @@ defmodule Cldr.Unit do
* `:backend` is any module that includes `use Cldr` and therefore
is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
* `:only` is a unit category or list of unit categories. The parsed
unit must match one of the categories in order to be valid. This is
helpful when disambiguating parsed units. For example, parsing "2w"
could be either "2 watts" or "2 weeks". Specifying `only: :duration`
would return "2 weeks". Specifiying `only: :power` would return
"2 watts"
* `:except` is the oppostte of `:only`. The parsed unit must *not*
match the specified unit category or unit categories.
## Returns
* `{:ok, unit}` or
* `{:error, {exception, reason}}`
## Notes
When both `:only` and `:except` options are passed, both
conditions must be true in order to return a parsed result.
## Examples
iex> Cldr.Unit.parse "1kg"
Cldr.Unit.new(1, :kilogram)
iex> Cldr.Unit.parse "1w"
Cldr.Unit.new(1, :watt)
iex> Cldr.Unit.parse "1w", only: :duration
Cldr.Unit.new(1, :week)
iex> Cldr.Unit.parse "1 tages", locale: "de"
Cldr.Unit.new(1, :day)
Expand Down Expand Up @@ -511,7 +532,7 @@ defmodule Cldr.Unit do
defp unit_matching_filter(_unit, units, [] = _only, [] = _except) do
units
|> Enum.map(&Kernel.to_string/1)
|> Enum.sort(&(String.length(&1) <= String.length(&2)))
|> Enum.sort(&(String.length(&1) <= String.length(&2) && &1 < &2))
|> hd
|> wrap(:ok)
end
Expand Down Expand Up @@ -2519,10 +2540,26 @@ defmodule Cldr.Unit do
end

@doc false
defp category_unit_match_error(unit, only, []) do
{
Cldr.Unit.CategoryMatchError,
"None of the units #{inspect Enum.sort(unit)} belong to a unit category matching " <>
"only: #{inspect only}"
}
end

defp category_unit_match_error(unit, [], except) do
{
Cldr.Unit.CategoryMatchError,
"None of the units #{inspect Enum.sort(unit)} belong to a unit category matching " <>
"except: #{inspect except}"
}
end

defp category_unit_match_error(unit, only, except) do
{
Cldr.Unit.CategoryMatchError,
"None of the units #{inspect unit} belong to a unit category matching " <>
"None of the units #{inspect Enum.sort(unit)} belong to a unit category matching " <>
"only: #{inspect only} except: #{inspect except}"
}
end
Expand Down
53 changes: 53 additions & 0 deletions test/unit_parse_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule Cldr.Unit.Parse.Test do
use ExUnit.Case, async: true

test "Parse a simple unit" do
assert MyApp.Cldr.Unit.parse("1 week") == Cldr.Unit.new(1, :week)
assert MyApp.Cldr.Unit.parse("2 weeks") == Cldr.Unit.new(2, :week)
end

test "Parse an ambiguous unit with no filter" do
assert MyApp.Cldr.Unit.parse("2 w") == Cldr.Unit.new(2, :watt)
end

test "Parse an ambiguous unit with :only filter" do
assert MyApp.Cldr.Unit.parse("2 w", only: :duration) == Cldr.Unit.new(2, :week)
assert MyApp.Cldr.Unit.parse("2 w", only: [:duration, :length]) == Cldr.Unit.new(2, :week)
assert MyApp.Cldr.Unit.parse("2 w", only: :power) == Cldr.Unit.new(2, :watt)
end

test "Parse an ambiguous unit with :except filter" do
assert MyApp.Cldr.Unit.parse("2 w", except: :duration) == Cldr.Unit.new(2, :watt)
assert MyApp.Cldr.Unit.parse("2 w", except: :power) == Cldr.Unit.new(2, :week)
end

test "Parse with a filter that doesn't match" do
assert MyApp.Cldr.Unit.parse("2 w", only: :energy) ==
{:error,
{Cldr.Unit.CategoryMatchError,
"None of the units [:watt, :week] belong to a unit category matching only: [:energy]"}}
end

test "Parse with an invalid :only or :except" do
assert MyApp.Cldr.Unit.parse("2w", only: :invalid) ==
{:error,
{Cldr.Unit.UnknownUnitCategoryError,
"The unit category :invalid is not known."}}

assert MyApp.Cldr.Unit.parse("2w", only: [:invalid, :also_invalid]) ==
{:error,
{Cldr.Unit.UnknownUnitCategoryError,
"The unit categories [:invalid, :also_invalid] are not known."}}

assert MyApp.Cldr.Unit.parse("2w", except: :invalid) ==
{:error,
{Cldr.Unit.UnknownUnitCategoryError,
"The unit category :invalid is not known."}}

assert MyApp.Cldr.Unit.parse("2w", except: [:invalid, :also_invalid]) ==
{:error,
{Cldr.Unit.UnknownUnitCategoryError,
"The unit categories [:invalid, :also_invalid] are not known."}}
end

end

0 comments on commit 99a9a30

Please sign in to comment.