diff --git a/CHANGELOG.md b/CHANGELOG.md index f2c5d99..595274e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Cldr_Currencies v2.11.1 + +This is the changelog for Cldr_Currencies v2.11.1 released on August 4th, 2021. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_currencies/tags) + +### Bug Fixes + +* Add missing docs and specs. Thanks to @tcitworld for the report. Closes #5. + ## Cldr_Currencies v2.11.0 This is the changelog for Cldr_Currencies v2.11.0 released on July 1st, 2021. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_currencies/tags) diff --git a/lib/cldr/currency.ex b/lib/cldr/currency.ex index 52087fc..c0338c1 100644 --- a/lib/cldr/currency.ex +++ b/lib/cldr/currency.ex @@ -21,6 +21,8 @@ defmodule Cldr.Currency do @type filter :: list(currency_status | code) | currency_status | code + @type territory :: atom() | String.t() + @type t :: %__MODULE__{ code: code, alt_code: code, @@ -53,8 +55,6 @@ defmodule Cldr.Currency do from: nil, to: nil - alias Cldr.LanguageTag - @table_options [:set, {:read_concurrency, true}] @default_options [quiet: true] @@ -636,6 +636,37 @@ defmodule Cldr.Currency do @territory_currencies end + @doc """ + Returns a list of currencies associated with + a given territory. + + ## Arguments + + * `territory` is any valid ISO 3166 Alpha-2 territory code. + See `Cldr.validate_territory/1`. + + ## Returns + + * `{:ok, map}` where `map` has as its key a `t:Cldr.Currency` + struct and the value is a map of validity dates for that + currency; or + + * `{:error, {exception, reason}}` + + ## Example + + iex> Cldr.Currency.territory_currencies(:LT) + {:ok, %{ + EUR: %{from: ~D[2015-01-01], to: nil}, + LTL: %{from: nil, to: ~D[2014-12-31]}, + LTT: %{from: nil, to: ~D[1993-06-25]}, + SUR: %{from: nil, to: ~D[1992-10-01]} + }} + + """ + @spec territory_currencies(territory()) :: + {:ok, map()} | {:error, {module(), String.t()}} + def territory_currencies(territory) do with {:ok, territory} <- Cldr.validate_territory(territory), {:ok, currencies} <- Map.fetch(territory_currencies(), territory) do @@ -650,6 +681,36 @@ defmodule Cldr.Currency do end end + @doc """ + Returns a list of currencies associated with + a given territory. + + ## Arguments + + * `territory` is any valid ISO 3166 Alpha-2 territory code. + See `Cldr.validate_territory/1`. + + ## Returns + + * `map` where `map` has as its key a `t:Cldr.Currency` + struct and the value is a map of validity dates for that + currency; or + + * raises an exception + + ## Example + + iex> Cldr.Currency.territory_currencies!(:LT) + %{ + EUR: %{from: ~D[2015-01-01], to: nil}, + LTL: %{from: nil, to: ~D[2014-12-31]}, + LTT: %{from: nil, to: ~D[1993-06-25]}, + SUR: %{from: nil, to: ~D[1992-10-01]} + } + + """ + @spec territory_currencies!(territory()) :: map() | no_return() + def territory_currencies!(territory) do case territory_currencies(territory) do {:ok, currencies} -> currencies @@ -776,7 +837,7 @@ defmodule Cldr.Currency do ## Arguments * `currency_or_currency_code` is a `binary` or `atom` representation - of an ISO 4217 currency code, or a `%Cldr.Currency{}` struct. + of an ISO 4217 currency code, or a `t:Cldr.Currency` struct. * `backend` is any module that includes `use Cldr` and therefore is a `Cldr` backend module @@ -1092,7 +1153,7 @@ defmodule Cldr.Currency do """ @spec currency_strings!( - Cldr.LanguageTag.t() | Cldr.Locale.locale_name(), + LanguageTag.t() | Locale.locale_name(), only :: filter(), except :: filter() ) :: @@ -1137,6 +1198,9 @@ defmodule Cldr.Currency do ["au$", "aud", "澳大利亚元"] """ + @spec strings_for_currency(t(), LanguageTag.t | Locale.locale_name, Cldr.backend) :: + [String.t()] + def strings_for_currency(currency, locale, backend) do module = Module.concat(backend, Currency) @@ -1153,7 +1217,7 @@ defmodule Cldr.Currency do ## Arguments - * `currency` is a `Cldr.Currency.t`, a list of `Cldr.Currency.t` or a + * `currency` is a `t:Cldr.Currency`, a list of `t:Cldr.Currency` or a map where the values of each item is a `Cldr.Currency.t` * `only` is `:all`, `:current`, `:historic`, `:tender` @@ -1166,7 +1230,7 @@ defmodule Cldr.Currency do ## Currency Status - A currency may be in current use, of historic interest only. It + A currency may be in current use or of historic interest only. It may or may not be legal tender. And it may mostly be used as a financial instrument. To help return the most useful currencies the currency status code acts as follows: @@ -1185,11 +1249,7 @@ defmodule Cldr.Currency do financial instruments. """ - @spec currency_filter( - Cldr.Currency.t() | [Cldr.Currency.t()] | map(), - Cldr.Currency.currency_status() - ) :: list(Cldr.Currency.t()) - + @spec currency_filter(t() | [t()] | map(), currency_status()) :: list(t()) def currency_filter(currencies, only \\ :all, except \\ nil) def currency_filter(currencies, :all, nil) do @@ -1219,15 +1279,15 @@ defmodule Cldr.Currency do expand_filter(currencies, :only, only) -- expand_filter(currencies, :except, except) end - def expand_filter(currencies, :only, [:all]) do + defp expand_filter(currencies, :only, [:all]) do currencies end - def expand_filter(_currencies, :except, [nil]) do + defp expand_filter(_currencies, :except, [nil]) do [] end - def expand_filter(currencies, _, filter_list) do + defp expand_filter(currencies, _, filter_list) do Enum.flat_map(filter_list, fn filter -> case filter do :historic -> @@ -1264,29 +1324,120 @@ defmodule Cldr.Currency do |> Enum.uniq() end + @doc """ + Returns a boolean indicating if a given + currency is historic. + + Historic means that the currency is no longer + in use. + + ## Arguments + + * `currency` is a `t:Cldr.Currency` + + ## Returns + + * `true` or `false` + + """ + @spec historic?(currency :: t()) :: boolean() def historic?(%Cldr.Currency{} = currency) do is_nil(currency.iso_digits) || (is_integer(currency.to) && currency.to < Date.utc_today().year) end + @doc """ + Returns a boolean indicating if a given + currency is legal tender. + + Legal tender is anything recognized by law + as a means to settle a public or private debt or + meet a financial obligation. + + ## Arguments + + * `currency` is a `t:Cldr.Currency` + + ## Returns + + * `true` or `false` + + """ + @spec tender?(currency :: t()) :: boolean() def tender?(%Cldr.Currency{} = currency) do !!currency.tender end + @doc """ + Returns a boolean indicating if a given + currency is current. + + Current means that the currency is in current + use. + + ## Arguments + + * `currency` is a `t:Cldr.Currency` + + ## Returns + + * `true` or `false` + + """ + @spec current?(currency :: t()) :: boolean() def current?(%Cldr.Currency{} = currency) do !is_nil(currency.iso_digits) && is_nil(currency.to) end + @doc """ + Returns a boolean indicating if a given + currency is annotated. + + Annotated means that the currency description + has annotations (comments inside parenthesis). + This is mostly found in currency codes used as + financial instruments (not legal tender). + + ## Arguments + + * `currency` is a `t:Cldr.Currency` + + ## Returns + + * `true` or `false` + + """ + @spec annotated?(currency :: t()) :: boolean() def annotated?(%Cldr.Currency{} = currency) do String.contains?(currency.name, "(") end + @doc """ + Returns a boolean indicating if a given + currency is unannotated. + + Annotated means that the currency description + has annotations (comments inside parenthesis). + This is mostly found in currency codes used as + financial instruments (not legal tender). + + ## Arguments + + * `currency` is a `t:Cldr.Currency` + + ## Returns + + * `true` or `false` + + """ + @spec unannotated?(currency :: t()) :: boolean() def unannotated?(%Cldr.Currency{} = currency) do - !String.contains?(currency.name, "(") + !annotated?(currency) end # Sort the list by string. If the string is the same # then sort historic currencies after the current one + @doc false def string_comparator({k, v1}, {k, v2}, currencies) do cond do @@ -1313,6 +1464,7 @@ defmodule Cldr.Currency do # The strategy is to remove the duplicate string from the # currency that is historic. + @doc false def remove_duplicate_strings(strings, currencies) do strings diff --git a/lib/cldr/eternal.ex b/lib/cldr/eternal.ex index 9d74875..af52f3e 100644 --- a/lib/cldr/eternal.ex +++ b/lib/cldr/eternal.ex @@ -26,6 +26,8 @@ defmodule Cldr.Eternal do alias Cldr.Eternal.Table alias Cldr.Eternal.Supervisor, as: Sup + @type table :: number | atom + # Return values of `start_link` functions @type on_start :: {:ok, pid} | :ignore | {:error, {:already_started, pid} | {:shutdown, term} | term} @@ -93,7 +95,7 @@ defmodule Cldr.Eternal do iex> Cldr.Eternal.heir(:my_table) """ - @spec heir(table :: Table.t()) :: any() + @spec heir(table :: table()) :: any() def heir(table) when is_table(table), do: :ets.info(table, :heir) @@ -105,7 +107,7 @@ defmodule Cldr.Eternal do iex> Cldr.Eternal.owner(:my_table) """ - @spec owner(table :: Table.t()) :: any() + @spec owner(table :: table()) :: any() def owner(table) when is_table(table), do: :ets.info(table, :owner) @@ -120,7 +122,7 @@ defmodule Cldr.Eternal do :ok """ - @spec stop(table :: Table.t()) :: :ok + @spec stop(table :: table()) :: :ok def stop(table) when is_table(table) do name = Table.to_name(table) proc = GenServer.whereis(name) diff --git a/lib/cldr/eternal/table.ex b/lib/cldr/eternal/table.ex index 0f7871f..a195d4c 100644 --- a/lib/cldr/eternal/table.ex +++ b/lib/cldr/eternal/table.ex @@ -8,11 +8,11 @@ defmodule Cldr.Eternal.Table do @type t :: number | atom @doc """ - Converts a table name to a valid Supervisor name. - - Because tables can be integer references, we convert this to an atom only if - the `create` flag is set to true. Otherwise, we attempt to convert to an existing - name (as it should have already been created). + Converts a table name to a valid Supervisor name. + + Because tables can be integer references, we convert this to an atom only if + the `create` flag is set to true. Otherwise, we attempt to convert to an existing + name (as it should have already been created). """ @spec to_name(name :: number | atom, create :: true | false) :: name :: atom | nil def to_name(name, create \\ false) @@ -35,8 +35,8 @@ defmodule Cldr.Eternal.Table do end @doc """ - Determines whether a value is a table or not. Tables can be either atoms or - integer values. + Determines whether a value is a table or not. Tables can be either atoms or + integer values. """ defmacro is_table(val) do quote do diff --git a/mix.exs b/mix.exs index c9dbfe2..4967c8b 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Cldr.Currencies.MixProject do use Mix.Project - @version "2.11.0" + @version "2.11.1" def project do [ diff --git a/mix.lock b/mix.lock index e48b97b..9f05324 100644 --- a/mix.lock +++ b/mix.lock @@ -5,11 +5,11 @@ "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "earmark": {:hex, :earmark, "1.4.9", "837e4c1c5302b3135e9955f2bbf52c6c52e950c383983942b68b03909356c0d9", [:mix], [{:earmark_parser, ">= 1.4.9", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "0d72df7d13a3dc8422882bed5263fdec5a773f56f7baeb02379361cb9e5b0d8e"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, "ex_cldr": {:hex, :ex_cldr, "2.23.0", "16aa883c3388a0b27485a810ae2a60d815968a473b5315454ebe2b5264e92a80", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c9dad3115e2622a4902390591d9c4a2f7c5333bd73f02a02f7b4190394c7347"}, - "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"}, + "ex_doc": {:hex, :ex_doc, "0.25.1", "4b736fa38dc76488a937e5ef2944f5474f3eff921de771b25371345a8dc810bc", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3200b0a69ddb2028365281fbef3753ea9e728683863d8cdaa96580925c891f67"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"},