Skip to content

Commit 7fb7c7b

Browse files
committed
Improve specs and update dialyzer config
1 parent b06d225 commit 7fb7c7b

8 files changed

Lines changed: 92 additions & 68 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

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

5+
## Money v5.17.1
6+
7+
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)
8+
9+
### Bug Fixes
10+
11+
* Update `poison` optional dependency to allow `~> 6.0`
12+
13+
* Update `stream_data` test dependency to `~> 1.0`
14+
515
## Money v5.17.0
616

717
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)

lib/money.ex

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ defmodule Money do
760760
761761
"""
762762
@spec to_string(Money.t(), Keyword.t() | Cldr.Number.Format.Options.t()) ::
763-
{:ok, String.t()} | {:error, {atom, String.t()}}
763+
{:ok, String.t()} | {:error, {module, String.t()}}
764764

765765
def to_string(money, options \\ [])
766766

@@ -1595,7 +1595,7 @@ defmodule Money do
15951595
Money.new(:JPY, "124")
15961596
15971597
"""
1598-
@spec round(Money.t(), Keyword.t()) :: Money.t()
1598+
@spec round(Money.t(), Keyword.t()) :: Money.t() | {:error, {module(), binary()}}
15991599
def round(money, opts \\ [])
16001600

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

2167-
with {:ok, digits} <- digits_from_options(currency_data, fractional_digits) do
2167+
with {:ok, digits} <- do_digits_from_options(currency_data, fractional_digits) do
21682168
{:ok, -digits, options}
2169+
else
2170+
:error -> {:error, invalid_digits_error(fractional_digits)}
2171+
other -> other
21692172
end
21702173
end
21712174

2172-
defp digits_from_options(currency_data, :iso), do: Map.fetch(currency_data, :iso_digits)
2173-
defp digits_from_options(currency_data, nil), do: Map.fetch(currency_data, :iso_digits)
2174-
defp digits_from_options(currency_data, :cash), do: Map.fetch(currency_data, :cash_digits)
2175-
defp digits_from_options(currency_data, :accounting), do: Map.fetch(currency_data, :digits)
2175+
defp do_digits_from_options(currency_data, :iso), do: Map.fetch(currency_data, :iso_digits)
2176+
defp do_digits_from_options(currency_data, nil), do: Map.fetch(currency_data, :iso_digits)
2177+
defp do_digits_from_options(currency_data, :cash), do: Map.fetch(currency_data, :cash_digits)
2178+
defp do_digits_from_options(currency_data, :accounting), do: Map.fetch(currency_data, :digits)
21762179

2177-
defp digits_from_options(_currency_data, integer) when is_integer(integer) and integer >= 0,
2180+
defp do_digits_from_options(_currency_data, integer) when is_integer(integer) and integer >= 0,
21782181
do: {:ok, integer}
21792182

2180-
defp digits_from_options(_currency_data, other),
2181-
do:
2182-
{:error,
2183-
{Money.InvalidDigitsError,
2184-
"Unknown or invalid :fractional_digits option found: #{inspect(other)}"}}
2183+
defp do_digits_from_options(_currency_data, other),
2184+
do: {:error, invalid_digits_error(other)}
2185+
2186+
defp invalid_digits_error(other), do:
2187+
{Money.InvalidDigitsError,
2188+
"Unknown or invalid :fractional_digits option found: #{inspect(other)}"}
21852189

21862190
@doc """
21872191
Return a zero amount `t:Money.t/0` in the given currency.
21882192
21892193
## Arguments
21902194
21912195
* `money_or_currency` is either a `t:Money.t/0` or
2192-
a currency code
2196+
a currency code.
21932197
21942198
* `options` is a keyword list of options passed
21952199
to `Money.new/3`. The default is `[]`.
@@ -2207,7 +2211,7 @@ defmodule Money do
22072211
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
22082212
22092213
"""
2210-
@spec zero(currency_code | Money.t()) :: Money.t()
2214+
@spec zero(currency_code | Money.t()) :: Money.t() | {:error, {module(), binary()}}
22112215

22122216
def zero(money_or_currency, options \\ [])
22132217

lib/money/backend.ex

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -539,13 +539,13 @@ defmodule Money.Backend do
539539
## Options
540540
541541
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
542-
by `Money.new/2`
542+
by `Money.new/2`.
543543
544544
## Returns
545545
546546
* `{:ok, money}` or
547547
548-
* `{:error, reason}`
548+
* `{:error, reason}`.
549549
550550
## Example
551551
@@ -568,7 +568,7 @@ defmodule Money.Backend do
568568
## Arguments
569569
570570
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
571-
by `Money.new/2`
571+
by `Money.new/2`.
572572
573573
## Returns
574574
@@ -598,9 +598,9 @@ defmodule Money.Backend do
598598
## Arguments
599599
600600
* `money` is any valid `t:Money.t/0` type returned
601-
by `Money.new/2`
601+
by `Money.new/2`.
602602
603-
* `number` is an integer, float or `t:Decimal.t/0`
603+
* `number` is an integer, float or `t:Decimal.t/0`.
604604
605605
> Note that multipling one `t:Money.t/0` by another is not supported.
606606
@@ -632,7 +632,7 @@ defmodule Money.Backend do
632632
## Arguments
633633
634634
* `money` is any valid `t:Money.t/0` types returned
635-
by `Money.new/2`
635+
by `Money.new/2`.
636636
637637
* `number` is an integer, float or `Decimal.t`
638638
@@ -662,10 +662,10 @@ defmodule Money.Backend do
662662
663663
## Arguments
664664
665-
* `money` is any valid `t:Money.t/0` types returned
665+
* `money` is any valid `t:Money.t/0` types returned.
666666
by `Money.new/2`
667667
668-
* `number` is an integer, float or `t:Decimal.t/0`
668+
* `number` is an integer, float or `t:Decimal.t/0`.
669669
670670
> Note that dividing one `t:Money.t/0` by another is not supported.
671671
@@ -699,7 +699,7 @@ defmodule Money.Backend do
699699
* `money` is any valid `t:Money.t/0` types returned
700700
by `Money.new/2`
701701
702-
* `number` is an integer, float or `Decimal.t`
702+
* `number` is an integer, float or `t:Decimal.t/0`
703703
704704
## Returns
705705
@@ -754,13 +754,13 @@ defmodule Money.Backend do
754754
## Arguments
755755
756756
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
757-
by `Money.new/2`
757+
by `Money.new/2`.
758758
759759
## Returns
760760
761761
* `:gt` | `:eq` | `:lt` or
762762
763-
* `{:error, {module(), String.t}}`
763+
* `{:error, {module(), String.t}}`.
764764
765765
## Examples
766766
@@ -791,13 +791,13 @@ defmodule Money.Backend do
791791
## Arguments
792792
793793
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
794-
by `Money.new/2`
794+
by `Money.new/2`.
795795
796796
## Returns
797797
798798
* `:gt` | `:eq` | `:lt` or
799799
800-
* raises an exception
800+
* raises an exception.
801801
802802
## Examples
803803
@@ -817,7 +817,7 @@ defmodule Money.Backend do
817817
## Arguments
818818
819819
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
820-
by `Money.new/2`
820+
by `Money.new/2`.
821821
822822
## Returns
823823
@@ -854,13 +854,13 @@ defmodule Money.Backend do
854854
## Arguments
855855
856856
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
857-
by `Money.new/2`
857+
by `Money.new/2`.
858858
859859
## Returns
860860
861861
* `-1` | `0` | `1` or
862862
863-
* raises an exception
863+
* raises an exception.
864864
865865
## Examples
866866
@@ -887,12 +887,12 @@ defmodule Money.Backend do
887887
derived as follows:
888888
889889
1. Round the money amount to the required currency precision using
890-
`Money.round/1`
890+
`Money.round/1`.
891891
892-
2. Divide the result of step 1 by the integer divisor
892+
2. Divide the result of step 1 by the integer divisor.
893893
894894
3. Round the result of the division to the precision of the currency
895-
using `Money.round/1`
895+
using `Money.round/1`.
896896
897897
4. Return two numbers: the result of the division and any remainder
898898
that could not be applied given the precision of the currency.
@@ -921,15 +921,15 @@ defmodule Money.Backend do
921921
922922
## Arguments
923923
924-
* `money` is a ``t:Money.t/0`` struct
924+
* `money` is a `t:Money.t/0` struct.
925925
926-
* `opts` is a keyword list of options
926+
* `options` is a keyword list of options.
927927
928928
## Options
929929
930930
* `:rounding_mode` that defines how the number will be rounded. See
931931
`Decimal.Context`. The default is `:half_even` which is also known
932-
as "banker's rounding"
932+
as "banker's rounding".
933933
934934
* `:currency_digits` which determines the rounding increment.
935935
The valid options are `:cash`, `:accounting` and `:iso` or
@@ -940,13 +940,13 @@ defmodule Money.Backend do
940940
941941
There are two kinds of rounding applied:
942942
943-
1. Round to the appropriate number of fractional digits
943+
1. Round to the appropriate number of fractional digits.
944944
945945
3. Apply an appropriate rounding increment. Most currencies
946946
round to the same precision as the number of decimal digits, but some
947947
such as `:CHF` round to a minimum such as `0.05` when its a cash
948948
amount. The rounding increment is applied when the option
949-
`:currency_digits` is set to `:cash`
949+
`:currency_digits` is set to `:cash`.
950950
951951
## Examples
952952
@@ -963,7 +963,9 @@ defmodule Money.Backend do
963963
Money.new(:JPY, "124")
964964
965965
"""
966-
@spec round(Elixir.Money.t(), Keyword.t()) :: Elixir.Money.t()
966+
@spec round(Elixir.Money.t(), Keyword.t()) ::
967+
Elixir.Money.t() | {:error, {module(), binary()}}
968+
967969
def round(%Elixir.Money{} = money, options \\ []) do
968970
Elixir.Money.round(money, options)
969971
end
@@ -1266,7 +1268,7 @@ defmodule Money.Backend do
12661268
12671269
"""
12681270
@spec from_integer(integer, Elixir.Money.currency_code(), Keyword.t()) ::
1269-
Elixir.Money.t() | {:error, module(), String.t()}
1271+
Elixir.Money.t() | {:error, {module(), String.t()}}
12701272

12711273
def from_integer(amount, currency, options \\ []) when is_integer(amount) do
12721274
Elixir.Money.from_integer(amount, currency, options)
@@ -1297,7 +1299,7 @@ defmodule Money.Backend do
12971299
12981300
"""
12991301
@spec zero(Elixir.Money.currency_code() | Elixir.Money.t(), Keyword.t()) ::
1300-
Elixir.Money.t()
1302+
Elixir.Money.t() | {:error, {module(), binary()}}
13011303

13021304
def zero(money, options \\ [])
13031305

lib/money/financial.ex

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,12 @@ defmodule Money.Financial do
209209
Money.new(:USD, "7731.466833737959119743127888")
210210
211211
"""
212-
@spec net_present_value(Money.t(), number, number) :: Money.t()
213-
212+
@spec net_present_value(Money.t(), float, number) :: Money.t()
214213
def net_present_value(%Money{currency: currency} = future_value, interest_rate, periods) do
215214
net_present_value(future_value, interest_rate, periods, Money.new(currency, 0))
216215
end
217216

218-
@spec net_present_value(Money.t(), number, number, Money.t()) :: Money.t()
217+
@spec net_present_value(Money.t(), float, number, Money.t()) :: Money.t()
219218
def net_present_value(%Money{} = future_value, interest_rate, periods, %Money{} = investment) do
220219
present_value(future_value, interest_rate, periods)
221220
|> Money.sub!(investment)
@@ -228,7 +227,7 @@ defmodule Money.Financial do
228227
represented as a tuple of the form `{period, %Money{}}`
229228
230229
"""
231-
@spec internal_rate_of_return(list({integer, Money.t()})) :: number()
230+
@spec internal_rate_of_return(list({integer, Money.t()})) :: float()
232231
def internal_rate_of_return([{_period, %Money{}} | _other_flows] = flows) do
233232
# estimate_m = sum_of_inflows(flows)
234233
# |> Kernel./(abs(Math.to_float(amount)))

lib/money/sigil.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ defmodule Money.Sigil do
1414
Money.new(:USD, "1000.34")
1515
1616
"""
17-
@spec sigil_M(binary, list) :: Money.t() | {:error, {Exception.t(), String.t()}}
17+
@spec sigil_M(binary, list(char)) :: Money.t() | {:error, {module(), String.t()}}
1818
def sigil_M(amount, [_, _, _] = currency) do
1919
Money.new(to_decimal(amount), atomize(currency))
2020
end

lib/money/subscription.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ defmodule Money.Subscription do
263263
264264
"""
265265
# @doc since: "2.3.0"
266-
@spec current_plan(Subscription.t() | map, Keyword.t()) :: Plan.t() | nil
266+
@spec current_plan(Subscription.t() | map, Keyword.t()) ::
267+
Plan.t() | {Change.t(), Plan.t()} | nil
267268

268269
def current_plan(subscription, options \\ [])
269270

@@ -988,6 +989,7 @@ defmodule Money.Subscription do
988989
end
989990
end
990991

992+
@dialyzer {:nowarn_function, raise_change_plan_options_error: 1}
991993
defp raise_change_plan_options_error(opt) do
992994
raise ArgumentError, "change_plan requires the the option #{inspect(opt)}"
993995
end

mix.exs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Money.Mixfile do
22
use Mix.Project
33

4-
@version "5.17.0"
4+
@version "5.17.1"
55

66
def project do
77
[
@@ -21,7 +21,14 @@ defmodule Money.Mixfile do
2121
elixirc_paths: elixirc_paths(Mix.env()),
2222
dialyzer: [
2323
ignore_warnings: ".dialyzer_ignore_warnings",
24-
plt_add_apps: ~w(inets jason mix phoenix_html gringotts)a
24+
plt_add_apps: ~w(inets jason mix phoenix_html gringotts)a,
25+
flags: [
26+
:error_handling,
27+
:unknown,
28+
:underspecs,
29+
:extra_return,
30+
:missing_return
31+
]
2532
],
2633
compilers: Mix.compilers()
2734
]
@@ -88,14 +95,14 @@ defmodule Money.Mixfile do
8895
{:ex_cldr_numbers, "~> 2.33"},
8996
{:nimble_parsec, "~> 0.5 or ~> 1.0"},
9097
{:decimal, "~> 1.6 or ~> 2.0"},
91-
{:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", optional: true},
98+
{:poison, "~> 3.0 or ~> 4.0 or ~> 5.0 or ~> 6.0", optional: true},
9299
{:phoenix_html, "~> 2.0 or ~> 3.0 or ~> 4.0", optional: true},
93100
{:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false},
94101
{:jason, "~> 1.0", optional: true},
95-
{:stream_data, "~> 0.4", only: [:dev, :test]},
102+
{:stream_data, "~> 1.0", only: [:dev, :test]},
96103
{:benchee, "~> 1.0", optional: true, only: :dev},
97104
{:exprof, "~> 0.2", only: :dev, runtime: false},
98-
{:ex_doc, "0.30.9", only: [:dev, :release]},
105+
{:ex_doc, "~> 0.31", only: [:dev, :release]},
99106

100107
{:gringotts, "~> 1.1", optional: true}
101108
]

0 commit comments

Comments
 (0)