Skip to content

Commit a1ba9e7

Browse files
committed
Report suggestions under their CLDR name, and correct alias docs
1 parent c66648c commit a1ba9e7

5 files changed

Lines changed: 62 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
* `Unity.Aliases.resolve/1` returns `{:error, :unknown_unit}` instead of raising when given a non-string.
1414

15+
* `Unity.Aliases.suggest/2` reports each unit under its CLDR name rather than whichever spelling scored best, so a typo no longer suggests a derived plural such as `nights`. Every spelling is still scored, so a typo close to an abbreviation or plural finds the unit.
16+
17+
* `Unity.Aliases.all_known_names/0` documented that it returned aliases as well as CLDR names; it returns only CLDR base unit names.
18+
1519
## v1.0.0 (2026-07-31)
1620

1721
### Changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ See the [Exploring Unity](https://hexdocs.pm/unity/exploring_unity.html) guide f
8181

8282
See https://www.ibiblio.org/harris/500milemail.html.
8383

84+
`lightsecond` is one of the GNU Units definitions, so run
85+
`Unity.GnuUnitsImporter.import/0` first to make it available:
86+
8487
```
8588
> 3 millilightsecond to mile
8689
558.847191 miles

guides/exploring_unity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ Every unit also accepts its English plural, so `3 months`, `2 centuries` and `50
202202
| `L`, `mL`, `gal`, `cup` | liter, milliliter, gallon, cup |
203203
| `J`, `kJ`, `cal`, `kWh` | joule, kilojoule, calorie, kilowatt-hour |
204204
| `W`, `kW`, `hp` | watt, kilowatt, horsepower |
205-
| `Pa`, `atm`, `psi` | pascal, atmosphere, pound-per-square-inch |
205+
| `Pa`, `atm`, `psi` | pascal, atmosphere, pound-force-per-square-inch |
206206
| `Hz`, `kHz`, `MHz` | hertz, kilohertz, megahertz |
207207
| `N`, `lbf` | newton, pound-force |
208208

lib/unity/aliases.ex

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,14 +308,43 @@ defmodule Unity.Aliases do
308308
unit list, but not the spellings normalised at resolution time, which are not
309309
an enumerable set.
310310
311+
### Returns
312+
313+
* A list of alias names, each of which resolves via `resolve/1`.
314+
315+
### Examples
316+
317+
iex> "km" in Unity.Aliases.known_aliases()
318+
true
319+
320+
iex> "months" in Unity.Aliases.known_aliases()
321+
true
322+
311323
"""
312324
@spec known_aliases() :: [String.t()]
313325
def known_aliases do
314326
Map.keys(@aliases) ++ Map.keys(@derived_plurals)
315327
end
316328

317329
@doc """
318-
Returns all known unit names (both aliases and CLDR base names).
330+
Returns the CLDR base unit names.
331+
332+
These are the names `Localize.Unit` enumerates by category. Aliases, derived
333+
plurals and SI-prefixed forms such as `kilometer` are not among them; use
334+
`known_aliases/0` for the alias table, or `resolve/1` to resolve an arbitrary
335+
spelling.
336+
337+
### Returns
338+
339+
* A list of CLDR base unit names.
340+
341+
### Examples
342+
343+
iex> "meter" in Unity.Aliases.all_known_names()
344+
true
345+
346+
iex> "kilometer" in Unity.Aliases.all_known_names()
347+
false
319348
320349
"""
321350
@spec all_known_names() :: [String.t()]
@@ -341,7 +370,17 @@ defmodule Unity.Aliases do
341370
342371
### Returns
343372
344-
A list of `{cldr_name, distance}` tuples, sorted by distance descending.
373+
A list of `{cldr_name, distance}` tuples, sorted by distance descending and
374+
then by name. Each unit appears once, under its CLDR name, scored by its
375+
closest-matching spelling.
376+
377+
### Examples
378+
379+
iex> Unity.Aliases.suggest("metrs", max_results: 1)
380+
[{"meter", 0.9444444444444445}]
381+
382+
iex> Unity.Aliases.suggest("secnd", max_results: 2)
383+
[{"second", 0.9444444444444445}, {"decade", 0.7000000000000001}]
345384
346385
"""
347386
@spec suggest(String.t(), keyword()) :: [{String.t(), float()}]
@@ -351,11 +390,18 @@ defmodule Unity.Aliases do
351390

352391
all_names = known_aliases() ++ @all_known_names_list
353392

393+
# Every spelling of a unit is scored, so a typo close to an abbreviation or
394+
# a plural still finds it, but a unit is reported under its CLDR name.
395+
# Scoring the surface form and reporting it would suggest "nights" for
396+
# "millilightsecond" purely because the plural happens to score higher than
397+
# "night" does.
354398
all_names
355-
|> Enum.map(fn known -> {known, String.jaro_distance(name, known)} end)
356-
|> Enum.filter(fn {_known, distance} -> distance >= threshold end)
357-
|> Enum.sort_by(fn {_known, distance} -> distance end, :desc)
358-
|> Enum.uniq_by(fn {known, _distance} -> resolve_to_cldr(known) end)
399+
|> Enum.map(fn known -> {resolve_to_cldr(known), String.jaro_distance(name, known)} end)
400+
|> Enum.filter(fn {_cldr_name, distance} -> distance >= threshold end)
401+
|> Enum.reduce(%{}, fn {cldr_name, distance}, best ->
402+
Map.update(best, cldr_name, distance, &max(&1, distance))
403+
end)
404+
|> Enum.sort_by(fn {cldr_name, distance} -> {-distance, cldr_name} end)
359405
|> Enum.take(max_results)
360406
end
361407

test/unity/aliases_test.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
defmodule Unity.AliasesTest do
22
use ExUnit.Case, async: true
33

4-
doctest Unity.Aliases
4+
# `Unity.Aliases` is already doctested from `unity_test.exs`; declaring it
5+
# here too would run every one of its doctests twice.
56
doctest Unity.Aliases.Plural
67

78
alias Unity.Aliases

0 commit comments

Comments
 (0)