Skip to content

Commit

Permalink
Improve specs and update dialyzer config
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Sep 5, 2024
1 parent b06d225 commit 7fb7c7b
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 68 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

**Note** `ex_money` 5.17.0 and later is supported on Elixir 1.12 and later versions only.

## Money v5.17.1

This is the changelog for Money v5.17.1 released on September 6th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)

### Bug Fixes

* Update `poison` optional dependency to allow `~> 6.0`

* Update `stream_data` test dependency to `~> 1.0`

## Money v5.17.0

This is the changelog for Money v5.17.0 released on May 28th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)
Expand Down
34 changes: 19 additions & 15 deletions lib/money.ex
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ defmodule Money do
"""
@spec to_string(Money.t(), Keyword.t() | Cldr.Number.Format.Options.t()) ::
{:ok, String.t()} | {:error, {atom, String.t()}}
{:ok, String.t()} | {:error, {module, String.t()}}

def to_string(money, options \\ [])

Expand Down Expand Up @@ -1595,7 +1595,7 @@ defmodule Money do
Money.new(:JPY, "124")
"""
@spec round(Money.t(), Keyword.t()) :: Money.t()
@spec round(Money.t(), Keyword.t()) :: Money.t() | {:error, {module(), binary()}}
def round(money, opts \\ [])

# Digital tokens don't have rounding
Expand Down Expand Up @@ -2164,32 +2164,36 @@ defmodule Money do
defp digits_from_options(currency_data, options) when is_list(options) do
{fractional_digits, options} = Keyword.pop(options, :fractional_digits)

with {:ok, digits} <- digits_from_options(currency_data, fractional_digits) do
with {:ok, digits} <- do_digits_from_options(currency_data, fractional_digits) do
{:ok, -digits, options}
else
:error -> {:error, invalid_digits_error(fractional_digits)}
other -> other
end
end

defp digits_from_options(currency_data, :iso), do: Map.fetch(currency_data, :iso_digits)
defp digits_from_options(currency_data, nil), do: Map.fetch(currency_data, :iso_digits)
defp digits_from_options(currency_data, :cash), do: Map.fetch(currency_data, :cash_digits)
defp digits_from_options(currency_data, :accounting), do: Map.fetch(currency_data, :digits)
defp do_digits_from_options(currency_data, :iso), do: Map.fetch(currency_data, :iso_digits)
defp do_digits_from_options(currency_data, nil), do: Map.fetch(currency_data, :iso_digits)
defp do_digits_from_options(currency_data, :cash), do: Map.fetch(currency_data, :cash_digits)
defp do_digits_from_options(currency_data, :accounting), do: Map.fetch(currency_data, :digits)

defp digits_from_options(_currency_data, integer) when is_integer(integer) and integer >= 0,
defp do_digits_from_options(_currency_data, integer) when is_integer(integer) and integer >= 0,
do: {:ok, integer}

defp digits_from_options(_currency_data, other),
do:
{:error,
{Money.InvalidDigitsError,
"Unknown or invalid :fractional_digits option found: #{inspect(other)}"}}
defp do_digits_from_options(_currency_data, other),
do: {:error, invalid_digits_error(other)}

defp invalid_digits_error(other), do:
{Money.InvalidDigitsError,
"Unknown or invalid :fractional_digits option found: #{inspect(other)}"}

@doc """
Return a zero amount `t:Money.t/0` in the given currency.
## Arguments
* `money_or_currency` is either a `t:Money.t/0` or
a currency code
a currency code.
* `options` is a keyword list of options passed
to `Money.new/3`. The default is `[]`.
Expand All @@ -2207,7 +2211,7 @@ defmodule Money do
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
"""
@spec zero(currency_code | Money.t()) :: Money.t()
@spec zero(currency_code | Money.t()) :: Money.t() | {:error, {module(), binary()}}

def zero(money_or_currency, options \\ [])

Expand Down
56 changes: 29 additions & 27 deletions lib/money/backend.ex
Original file line number Diff line number Diff line change
Expand Up @@ -539,13 +539,13 @@ defmodule Money.Backend do
## Options
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
* `{:ok, money}` or
* `{:error, reason}`
* `{:error, reason}`.
## Example
Expand All @@ -568,7 +568,7 @@ defmodule Money.Backend do
## Arguments
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
Expand Down Expand Up @@ -598,9 +598,9 @@ defmodule Money.Backend do
## Arguments
* `money` is any valid `t:Money.t/0` type returned
by `Money.new/2`
by `Money.new/2`.
* `number` is an integer, float or `t:Decimal.t/0`
* `number` is an integer, float or `t:Decimal.t/0`.
> Note that multipling one `t:Money.t/0` by another is not supported.
Expand Down Expand Up @@ -632,7 +632,7 @@ defmodule Money.Backend do
## Arguments
* `money` is any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
* `number` is an integer, float or `Decimal.t`
Expand Down Expand Up @@ -662,10 +662,10 @@ defmodule Money.Backend do
## Arguments
* `money` is any valid `t:Money.t/0` types returned
* `money` is any valid `t:Money.t/0` types returned.
by `Money.new/2`
* `number` is an integer, float or `t:Decimal.t/0`
* `number` is an integer, float or `t:Decimal.t/0`.
> Note that dividing one `t:Money.t/0` by another is not supported.
Expand Down Expand Up @@ -699,7 +699,7 @@ defmodule Money.Backend do
* `money` is any valid `t:Money.t/0` types returned
by `Money.new/2`
* `number` is an integer, float or `Decimal.t`
* `number` is an integer, float or `t:Decimal.t/0`
## Returns
Expand Down Expand Up @@ -754,13 +754,13 @@ defmodule Money.Backend do
## Arguments
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
* `:gt` | `:eq` | `:lt` or
* `{:error, {module(), String.t}}`
* `{:error, {module(), String.t}}`.
## Examples
Expand Down Expand Up @@ -791,13 +791,13 @@ defmodule Money.Backend do
## Arguments
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
* `:gt` | `:eq` | `:lt` or
* raises an exception
* raises an exception.
## Examples
Expand All @@ -817,7 +817,7 @@ defmodule Money.Backend do
## Arguments
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
Expand Down Expand Up @@ -854,13 +854,13 @@ defmodule Money.Backend do
## Arguments
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
by `Money.new/2`
by `Money.new/2`.
## Returns
* `-1` | `0` | `1` or
* raises an exception
* raises an exception.
## Examples
Expand All @@ -887,12 +887,12 @@ defmodule Money.Backend do
derived as follows:
1. Round the money amount to the required currency precision using
`Money.round/1`
`Money.round/1`.
2. Divide the result of step 1 by the integer divisor
2. Divide the result of step 1 by the integer divisor.
3. Round the result of the division to the precision of the currency
using `Money.round/1`
using `Money.round/1`.
4. Return two numbers: the result of the division and any remainder
that could not be applied given the precision of the currency.
Expand Down Expand Up @@ -921,15 +921,15 @@ defmodule Money.Backend do
## Arguments
* `money` is a ``t:Money.t/0`` struct
* `money` is a `t:Money.t/0` struct.
* `opts` is a keyword list of options
* `options` is a keyword list of options.
## Options
* `:rounding_mode` that defines how the number will be rounded. See
`Decimal.Context`. The default is `:half_even` which is also known
as "banker's rounding"
as "banker's rounding".
* `:currency_digits` which determines the rounding increment.
The valid options are `:cash`, `:accounting` and `:iso` or
Expand All @@ -940,13 +940,13 @@ defmodule Money.Backend do
There are two kinds of rounding applied:
1. Round to the appropriate number of fractional digits
1. Round to the appropriate number of fractional digits.
3. Apply an appropriate rounding increment. Most currencies
round to the same precision as the number of decimal digits, but some
such as `:CHF` round to a minimum such as `0.05` when its a cash
amount. The rounding increment is applied when the option
`:currency_digits` is set to `:cash`
`:currency_digits` is set to `:cash`.
## Examples
Expand All @@ -963,7 +963,9 @@ defmodule Money.Backend do
Money.new(:JPY, "124")
"""
@spec round(Elixir.Money.t(), Keyword.t()) :: Elixir.Money.t()
@spec round(Elixir.Money.t(), Keyword.t()) ::
Elixir.Money.t() | {:error, {module(), binary()}}

def round(%Elixir.Money{} = money, options \\ []) do
Elixir.Money.round(money, options)
end
Expand Down Expand Up @@ -1266,7 +1268,7 @@ defmodule Money.Backend do
"""
@spec from_integer(integer, Elixir.Money.currency_code(), Keyword.t()) ::
Elixir.Money.t() | {:error, module(), String.t()}
Elixir.Money.t() | {:error, {module(), String.t()}}

def from_integer(amount, currency, options \\ []) when is_integer(amount) do
Elixir.Money.from_integer(amount, currency, options)
Expand Down Expand Up @@ -1297,7 +1299,7 @@ defmodule Money.Backend do
"""
@spec zero(Elixir.Money.currency_code() | Elixir.Money.t(), Keyword.t()) ::
Elixir.Money.t()
Elixir.Money.t() | {:error, {module(), binary()}}

def zero(money, options \\ [])

Expand Down
7 changes: 3 additions & 4 deletions lib/money/financial.ex
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,12 @@ defmodule Money.Financial do
Money.new(:USD, "7731.466833737959119743127888")
"""
@spec net_present_value(Money.t(), number, number) :: Money.t()

@spec net_present_value(Money.t(), float, number) :: Money.t()
def net_present_value(%Money{currency: currency} = future_value, interest_rate, periods) do
net_present_value(future_value, interest_rate, periods, Money.new(currency, 0))
end

@spec net_present_value(Money.t(), number, number, Money.t()) :: Money.t()
@spec net_present_value(Money.t(), float, number, Money.t()) :: Money.t()
def net_present_value(%Money{} = future_value, interest_rate, periods, %Money{} = investment) do
present_value(future_value, interest_rate, periods)
|> Money.sub!(investment)
Expand All @@ -228,7 +227,7 @@ defmodule Money.Financial do
represented as a tuple of the form `{period, %Money{}}`
"""
@spec internal_rate_of_return(list({integer, Money.t()})) :: number()
@spec internal_rate_of_return(list({integer, Money.t()})) :: float()
def internal_rate_of_return([{_period, %Money{}} | _other_flows] = flows) do
# estimate_m = sum_of_inflows(flows)
# |> Kernel./(abs(Math.to_float(amount)))
Expand Down
2 changes: 1 addition & 1 deletion lib/money/sigil.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule Money.Sigil do
Money.new(:USD, "1000.34")
"""
@spec sigil_M(binary, list) :: Money.t() | {:error, {Exception.t(), String.t()}}
@spec sigil_M(binary, list(char)) :: Money.t() | {:error, {module(), String.t()}}
def sigil_M(amount, [_, _, _] = currency) do
Money.new(to_decimal(amount), atomize(currency))
end
Expand Down
4 changes: 3 additions & 1 deletion lib/money/subscription.ex
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ defmodule Money.Subscription do
"""
# @doc since: "2.3.0"
@spec current_plan(Subscription.t() | map, Keyword.t()) :: Plan.t() | nil
@spec current_plan(Subscription.t() | map, Keyword.t()) ::
Plan.t() | {Change.t(), Plan.t()} | nil

def current_plan(subscription, options \\ [])

Expand Down Expand Up @@ -988,6 +989,7 @@ defmodule Money.Subscription do
end
end

@dialyzer {:nowarn_function, raise_change_plan_options_error: 1}
defp raise_change_plan_options_error(opt) do
raise ArgumentError, "change_plan requires the the option #{inspect(opt)}"
end
Expand Down
17 changes: 12 additions & 5 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Money.Mixfile do
use Mix.Project

@version "5.17.0"
@version "5.17.1"

def project do
[
Expand All @@ -21,7 +21,14 @@ defmodule Money.Mixfile do
elixirc_paths: elixirc_paths(Mix.env()),
dialyzer: [
ignore_warnings: ".dialyzer_ignore_warnings",
plt_add_apps: ~w(inets jason mix phoenix_html gringotts)a
plt_add_apps: ~w(inets jason mix phoenix_html gringotts)a,
flags: [
:error_handling,
:unknown,
:underspecs,
:extra_return,
:missing_return
]
],
compilers: Mix.compilers()
]
Expand Down Expand Up @@ -88,14 +95,14 @@ defmodule Money.Mixfile do
{:ex_cldr_numbers, "~> 2.33"},
{:nimble_parsec, "~> 0.5 or ~> 1.0"},
{:decimal, "~> 1.6 or ~> 2.0"},
{:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", optional: true},
{:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", optional: true},
{:phoenix_html, "~> 2.0 or ~> 3.0 or ~> 4.0", optional: true},
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
{:jason, "~> 1.0", optional: true},
{:stream_data, "~> 0.4", only: [:dev, :test]},
{:stream_data, "~> 1.0", only: [:dev, :test]},
{:benchee, "~> 1.0", optional: true, only: :dev},
{:exprof, "~> 0.2", only: :dev, runtime: false},
{:ex_doc, "0.30.9", only: [:dev, :release]},
{:ex_doc, "~> 0.31", only: [:dev, :release]},

{:gringotts, "~> 1.1", optional: true}
]
Expand Down
Loading

0 comments on commit 7fb7c7b

Please sign in to comment.