changed CHANGELOG.md
 
@@ -2,6 2,14 @@
2
2
3
3
**Note** `ex_money` 5.17.0 and later is supported on Elixir 1.12 and later versions only.
4
4
5
## Money v5.18.0
6
7
This is the changelog for Money v5.18.0 released on September 18th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)
8
9
### Enhancements
10
11
* Adds `min/2`, `max/2`, `min!/2`, `max!/2`, `clamp/3`, `clamp!/3`, `negate/1`, `negate!/1` and `within?/3`.
12
5
13
## Money v5.17.2
6
14
7
15
This is the changelog for Money v5.17.2 released on September 18th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/kipcole9/money/tags)
changed hex_metadata.config
 
@@ -1,11 1,11 @@
1
1
{<<"links">>,
2
2
[{<<"Changelog">>,
3
- <<"https://github.com/kipcole9/money/blob/v5.17.2/CHANGELOG.md">>},
3
<<"https://github.com/kipcole9/money/blob/v5.18.0/CHANGELOG.md">>},
4
4
{<<"GitHub">>,<<"https://github.com/kipcole9/money">>},
5
5
{<<"Readme">>,
6
- <<"https://github.com/kipcole9/money/blob/v5.17.2/README.md">>}]}.
6
<<"https://github.com/kipcole9/money/blob/v5.18.0/README.md">>}]}.
7
7
{<<"name">>,<<"ex_money">>}.
8
- {<<"version">>,<<"5.17.2">>}.
8
{<<"version">>,<<"5.18.0">>}.
9
9
{<<"description">>,
10
10
<<"Money functions for operations on and localization of a money data type with support\nfor ISO 4217 currencies and ISO 24165 digial tokens (crypto currencies).">>}.
11
11
{<<"elixir">>,<<"~> 1.12">>}.
changed lib/money.ex
 
@@ -604,7 604,7 @@ defmodule Money do
604
604
{:error,
605
605
{Money.Invalid,
606
606
"A currency code, symbol or description must be specified but " <>
607
- "was not found in #{inspect(string)}"}}
607
"was not found in #{inspect(string)}"}}
608
608
end
609
609
610
610
# No currency was in the string so we'll derive it from
 
@@ -906,7 906,7 @@ defmodule Money do
906
906
end
907
907
908
908
@doc """
909
- The absolute value of a `Money` amount.
909
The absolute value of a `t:Money.t/0` amount.
910
910
Returns a `t:Money.t/0` type with a positive sign for the amount.
911
911
912
912
## Arguments
 
@@ -936,7 936,7 @@ defmodule Money do
936
936
## Arguments
937
937
938
938
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
939
- by `Money.new/2`
939
by `Money.new/2`.
940
940
941
941
## Returns
942
942
 
@@ -976,12 976,12 @@ defmodule Money do
976
976
end
977
977
978
978
@doc """
979
- Add two `Money` values and raise on error.
979
Add two `t:Money.t/0` values or raise on error.
980
980
981
981
## Arguments
982
982
983
983
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
984
- by `Money.new/2`
984
by `Money.new/2`.
985
985
986
986
## Returns
987
987
 
@@ -1008,18 1008,18 @@ defmodule Money do
1008
1008
end
1009
1009
1010
1010
@doc """
1011
- Subtract one `Money` value struct from another.
1011
Subtract one `t:Money.t/0` value struct from another.
1012
1012
1013
1013
## Options
1014
1014
1015
1015
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1016
- by `Money.new/2`
1016
by `Money.new/2`.
1017
1017
1018
1018
## Returns
1019
1019
1020
1020
* `{:ok, money}` or
1021
1021
1022
- * `{:error, reason}`
1022
* `{:error, reason}`.
1023
1023
1024
1024
## Example
1025
1025
 
@@ -1052,13 1052,13 @@ defmodule Money do
1052
1052
## Arguments
1053
1053
1054
1054
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1055
- by `Money.new/2`
1055
by `Money.new/2`.
1056
1056
1057
1057
## Returns
1058
1058
1059
1059
* a `t:Money.t/0` struct or
1060
1060
1061
- * raises an exception
1061
* raises an exception.
1062
1062
1063
1063
## Examples
1064
1064
 
@@ -1084,11 1084,11 @@ defmodule Money do
1084
1084
## Arguments
1085
1085
1086
1086
* `money` is any valid `t:Money.t/0` type returned
1087
- by `Money.new/2`
1087
by `Money.new/2`.
1088
1088
1089
- * `number` is an integer, float or `Decimal.t`
1089
* `number` is an integer, float or `t:Decimal.t/0`.
1090
1090
1091
- > Note that multipling one %Money{} by another is not supported.
1091
> Note that multipling one `t:Money.t/0` by another is not supported.
1092
1092
1093
1093
## Returns
1094
1094
 
@@ -1129,10 1129,10 @@ defmodule Money do
1129
1129
1130
1130
## Arguments
1131
1131
1132
- * `money` is any valid `t:Money.t/0` types returned
1133
- by `Money.new/2`
1132
* `money` is any valid `t:Money.t/0` type returned
1133
by `Money.new/2`.
1134
1134
1135
- * `number` is an integer, float or `Decimal.t`
1135
* `number` is an integer, float or `t:Decimal.t/0`.
1136
1136
1137
1137
## Returns
1138
1138
 
@@ -1238,6 1238,409 @@ defmodule Money do
1238
1238
end
1239
1239
end
1240
1240
1241
@doc """
1242
Return the minimum of two `t:Money.t/0` amounts.
1243
1244
## Arguments
1245
1246
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1247
by `Money.new/2`. `money_1` and `money_2` should be of the same
1248
currency.
1249
1250
## Returns
1251
1252
* `{:ok, minimum_money}` or
1253
1254
* `{:error, reason}`
1255
1256
## Example
1257
1258
iex> Money.min(Money.new(:USD, 200), Money.new(:USD, 300))
1259
{:ok, Money.new(:USD, 200)}
1260
1261
iex> Money.min(Money.new(:USD, 200), Money.new(:AUD, 200))
1262
{:error,
1263
{ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}
1264
1265
"""
1266
@doc since: "5.18.0"
1267
1268
@spec min(money_1 :: Money.t(), money_2 :: Money.t()) ::
1269
{:ok, Money.t()} | {:error, {module(), String.t()}}
1270
1271
def min(%Money{currency: same_currency} = money_1, %Money{currency: same_currency} = money_2) do
1272
case compare(money_1, money_2) do
1273
:gt -> {:ok, money_2}
1274
:eq -> {:ok, money_2}
1275
:lt -> {:ok, money_1}
1276
{:error, reason} -> {:error, reason}
1277
end
1278
end
1279
1280
def min(%Money{currency: code_a}, %Money{currency: code_b}) do
1281
{:error, compare_error(code_a, code_b)}
1282
end
1283
1284
@doc """
1285
Return the maximum of two `t:Money.t/0` amounts.
1286
1287
## Arguments
1288
1289
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1290
by `Money.new/2`. `money_1` and `money_2` should be of the same
1291
currency.
1292
1293
## Returns
1294
1295
* `{:ok, maximum_money}` or
1296
1297
* `{:error, reason}`.
1298
1299
## Example
1300
1301
iex> Money.max(Money.new(:USD, 200), Money.new(:USD, 300))
1302
{:ok, Money.new(:USD, 300)}
1303
1304
iex> Money.max(Money.new(:USD, 200), Money.new(:AUD, 200))
1305
{:error,
1306
{ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}
1307
1308
"""
1309
@doc since: "5.18.0"
1310
1311
@spec max(money_1 :: Money.t(), money_2 :: Money.t()) ::
1312
{:ok, Money.t()} | {:error, {module(), String.t()}}
1313
1314
def max(%Money{currency: same_currency} = money_1, %Money{currency: same_currency} = money_2) do
1315
case compare(money_1, money_2) do
1316
:lt -> {:ok, money_2}
1317
:eq -> {:ok, money_2}
1318
:gt -> {:ok, money_1}
1319
{:error, reason} -> {:error, reason}
1320
end
1321
end
1322
1323
def max(%Money{currency: code_a}, %Money{currency: code_b}) do
1324
{:error, compare_error(code_a, code_b)}
1325
end
1326
1327
@doc """
1328
Return the minimum of two `t:Money.t/0` amounts or
1329
raises an exception.
1330
1331
## Arguments
1332
1333
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1334
by `Money.new/2`. `money_1` and `money_2` should be of the same
1335
currency.
1336
1337
## Returns
1338
1339
* `minimum_money` or
1340
1341
* raises an exception.
1342
1343
## Example
1344
1345
iex> Money.min!(Money.new(:USD, 200), Money.new(:USD, 300))
1346
Money.new(:USD, 200)
1347
1348
iex> Money.min!(Money.new(:USD, 200), Money.new(:AUD, 200))
1349
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.
1350
1351
"""
1352
@doc since: "5.18.0"
1353
1354
@spec min!(money_1 :: Money.t(), money_2 :: Money.t()) ::
1355
Money.t() | no_return()
1356
1357
def min!(%Money{currency: same_currency} = money_1, %Money{currency: same_currency} = money_2) do
1358
case compare(money_1, money_2) do
1359
:gt -> money_2
1360
:eq -> money_2
1361
:lt -> money_1
1362
{:error, {exception, reason}} -> raise exception, reason
1363
end
1364
end
1365
1366
def min!(%Money{currency: code_a}, %Money{currency: code_b}) do
1367
{exception, reason} = compare_error(code_a, code_b)
1368
raise exception, reason
1369
end
1370
1371
@doc """
1372
Return the maximum of two `t:Money.t/0` amounts or
1373
raises an exception.
1374
1375
## Arguments
1376
1377
* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
1378
by `Money.new/2`. `money_1` and `money_2` should be of the same
1379
currency.
1380
1381
## Returns
1382
1383
* `maximum_money` or
1384
1385
* raises an exception.
1386
1387
## Example
1388
1389
iex> Money.max!(Money.new(:USD, 200), Money.new(:USD, 300))
1390
Money.new(:USD, 300)
1391
1392
iex> Money.max!(Money.new(:USD, 200), Money.new(:AUD, 200))
1393
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.
1394
1395
"""
1396
@doc since: "5.18.0"
1397
1398
@spec max!(money_1 :: Money.t(), money_2 :: Money.t()) ::
1399
Money.t() | no_return()
1400
1401
def max!(%Money{currency: same_currency} = money_1, %Money{currency: same_currency} = money_2) do
1402
case compare(money_1, money_2) do
1403
:lt -> money_2
1404
:eq -> money_2
1405
:gt -> money_1
1406
{:error, {exception, reason}} -> raise exception, reason
1407
end
1408
end
1409
1410
def max!(%Money{currency: code_a}, %Money{currency: code_b}) do
1411
{exception, reason} = compare_error(code_a, code_b)
1412
raise exception, reason
1413
end
1414
1415
@doc """
1416
Clamps a `t:Money.t/0` to be in the range of `minimum`
1417
to `maximum`.
1418
1419
### Arguments
1420
1421
* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
1422
by `Money.new/2`. They should be of the same currency.
1423
1424
### Returns
1425
1426
* `{:ok, money]` where `money` is clamped to the `minimum` or `maximum` if required.
1427
* If `money` is within the range `minimum..maximum` then `money` is returned unchanged.
1428
* If `money` is less than `minimum` then `minimum` is returned.
1429
* If `money` is greater than `maximum` then `maximum` is returned.
1430
1431
* or `{:error, reason}`.
1432
1433
### Examples
1434
1435
iex> Money.clamp(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
1436
{:ok, Money.new(:USD, 100)}
1437
1438
iex> Money.clamp(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
1439
{:ok, Money.new(:USD, 200)}
1440
1441
iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
1442
{:ok, Money.new(:USD, 50)}
1443
1444
iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
1445
{:error,
1446
{ArgumentError,
1447
"Minimum must be less than maximum. Found Money.new(:USD, \\"300\\") and Money.new(:USD, \\"200\\")"}}
1448
1449
iex> Money.clamp(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
1450
{:error, {ArgumentError, "Cannot compare monies with different currencies. Received :USD, :AUD and :EUR"}}
1451
1452
"""
1453
@doc since: "5.18.0"
1454
1455
@spec clamp(money :: Money.t(), minimum :: Money.t(), maximum :: Money.t()) ::
1456
{:ok, Money.t()} | {:error, {module(), String.t()}}
1457
1458
def clamp(
1459
%__MODULE__{currency: same_currency} = money,
1460
%__MODULE__{currency: same_currency} = minimum,
1461
%__MODULE__{currency: same_currency} = maximum
1462
) do
1463
if compare(minimum, maximum) == :lt do
1464
Money.max(minimum, Money.min!(maximum, money))
1465
else
1466
{:error,
1467
{ArgumentError,
1468
"Minimum must be less than maximum. Found #{inspect(minimum)} and #{inspect(maximum)}"}}
1469
end
1470
end
1471
1472
def clamp(%Money{currency: code_a}, %Money{currency: code_b}, %Money{currency: code_c}) do
1473
{:error, compare_error(code_a, code_b, code_c)}
1474
end
1475
1476
@doc """
1477
Clamps a `t:Money.t/0` to be in the range of `minimum`
1478
to `maximum` or raises an exception.
1479
1480
### Arguments
1481
1482
* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
1483
by `Money.new/2`. They should be of the same currency.
1484
1485
### Returns
1486
1487
* `money` where `money` is clamped to the `minimum` or `maximum` if required.
1488
* If `money` is within the range `minimum..maximum` then `money` is returned unchanged.
1489
* If `money` is less than `minimum` then `minimum` is returned.
1490
* If `money` is greater than `maximum` then `maximum` is returned.
1491
1492
* or `{:error, reason}`.
1493
1494
### Examples
1495
1496
iex> Money.clamp!(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
1497
Money.new(:USD, 100)
1498
1499
iex> Money.clamp!(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
1500
Money.new(:USD, 200)
1501
1502
iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
1503
Money.new(:USD, 50)
1504
1505
iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
1506
** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")
1507
1508
iex> Money.clamp!(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
1509
** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR
1510
1511
"""
1512
@doc since: "5.18.0"
1513
1514
@spec clamp!(money :: Money.t(), minimum :: Money.t(), maximum :: Money.t()) ::
1515
Money.t() | no_return()
1516
1517
def clamp!(
1518
%__MODULE__{currency: same_currency} = money,
1519
%__MODULE__{currency: same_currency} = minimum,
1520
%__MODULE__{currency: same_currency} = maximum
1521
) do
1522
if compare(minimum, maximum) == :lt do
1523
Money.max!(minimum, Money.min!(maximum, money))
1524
else
1525
raise ArgumentError,
1526
"Minimum must be less than maximum. Found #{inspect(minimum)} and #{inspect(maximum)}"
1527
end
1528
end
1529
1530
def clamp!(%Money{currency: code_a}, %Money{currency: code_b}, %Money{currency: code_c}) do
1531
{exception, reason} = compare_error(code_a, code_b, code_c)
1532
raise exception, reason
1533
end
1534
1535
@doc """
1536
Returns a boolean indicating if the `t:Money.t/0` is in the
1537
range `minimum..maximum`.
1538
1539
### Arguments
1540
1541
* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
1542
by `Money.new/2`. They should be of the same currency.
1543
1544
### Returns
1545
1546
* `true` or `false`.
1547
1548
### Examples
1549
1550
iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
1551
true
1552
1553
iex> Money.within?(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
1554
false
1555
1556
iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 300), Money.new(:USD, 200))
1557
** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")
1558
1559
iex> Money.within?(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
1560
** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR
1561
1562
"""
1563
@doc since: "5.18.0"
1564
1565
@spec within?(money :: Money.t(), minimum :: Money.t(), maximum :: Money.t()) :: boolean()
1566
1567
def within?(
1568
%__MODULE__{currency: same_currency} = money,
1569
%__MODULE__{currency: same_currency} = minimum,
1570
%__MODULE__{currency: same_currency} = maximum
1571
) do
1572
if compare(minimum, maximum) == :lt do
1573
compare(money, minimum) in [:gt, :eq] && compare(money, maximum) in [:lt, :eq]
1574
else
1575
raise ArgumentError,
1576
"Minimum must be less than maximum. Found #{inspect(minimum)} and #{inspect(maximum)}"
1577
end
1578
end
1579
1580
def within?(%Money{currency: code_a}, %Money{currency: code_b}, %Money{currency: code_c}) do
1581
{exception, reason} = compare_error(code_a, code_b, code_c)
1582
raise exception, reason
1583
end
1584
1585
@doc """
1586
Negate a `t:Money.t/0` value.
1587
1588
### Argument
1589
1590
* `money_1` is any valid `t:Money.t/0` type.
1591
1592
### Returns
1593
1863
* `{:ok, negated_money}` with the amount negated.
1595
1596
### Example
1597
1598
iex> Money.negate(Money.new(:USD, 200))
1599
{:ok, Money.new(:USD, -200)}
1600
1601
iex> Money.negate(Money.new(:USD, -200))
1602
{:ok, Money.new(:USD, 200)}
1603
1604
"""
1605
@doc since: "5.18.0"
1606
1607
@spec negate(money :: Money.t()) :: {:ok, Money.t()}
1608
1609
def negate(%__MODULE__{amount: amount} = money) do
1610
{:ok, Map.put(money, :amount, Decimal.negate(amount))}
1611
end
1612
1613
@doc """
1614
Negate a `t:Money.t/0` value or raises an
1615
exception.
1616
1617
### Argument
1618
1619
* `money_1` is any valid `t:Money.t/0` type.
1620
1621
### Returns
1622
1623
* `negated_money` with the amount negated or
1624
1625
* raises an exception.
1626
1627
### Example
1628
1629
iex> Money.negate!(Money.new(:USD, 200))
1630
Money.new(:USD, -200)
1631
1632
iex> Money.negate!(Money.new(:USD, -200))
1633
Money.new(:USD, 200)
1634
1635
"""
1636
@doc since: "5.18.0"
1637
1638
@spec negate!(money :: Money.t()) :: Money.t() | no_return()
1639
1640
def negate!(%__MODULE__{amount: amount} = money) do
1641
Map.put(money, :amount, Decimal.negate(amount))
1642
end
1643
1241
1644
@doc """
1242
1645
Returns a boolean indicating if two `Money` values are equal
1243
1646
 
@@ -1309,8 1712,11 @@ defmodule Money do
1309
1712
1310
1713
"""
1311
1714
@doc since: "5.3.0"
1312
- @spec sum([t(), ...], ExchangeRates.t() | {:ok, ExchangeRates.t()} | {:error, {module(), String.t()}}) ::
1313
- {:ok, t} | {:error, {module(), String.t()}}
1715
@spec sum(
1716
[t(), ...],
1717
ExchangeRates.t() | {:ok, ExchangeRates.t()} | {:error, {module(), String.t()}}
1718
) ::
1719
{:ok, t} | {:error, {module(), String.t()}}
1314
1720
1315
1721
def sum(money_list, rates \\ latest_rates_or_empty_map())
1316
1722
 
@@ -1384,10 1790,19 @@ defmodule Money do
1384
1790
end
1385
1791
1386
1792
def compare(%Money{currency: code_a}, %Money{currency: code_b}) do
1387
- {:error,
1388
- {ArgumentError,
1389
- "Cannot compare monies with different currencies. " <>
1390
- "Received #{inspect(code_a)} and #{inspect(code_b)}."}}
1793
{:error, compare_error(code_a, code_b)}
1794
end
1795
1796
defp compare_error(code_a, code_b) do
1797
{ArgumentError,
1798
"Cannot compare monies with different currencies. " <>
1799
"Received #{inspect(code_a)} and #{inspect(code_b)}."}
1800
end
1801
1802
defp compare_error(code_a, code_b, code_c) do
1803
{ArgumentError,
1804
"Cannot compare monies with different currencies. " <>
1805
"Received #{inspect(code_a)}, #{inspect(code_b)} and #{inspect(code_c)}"}
1391
1806
end
1392
1807
1393
1808
@doc """
 
@@ -1833,9 2248,9 @@ defmodule Money do
1833
2248
end
1834
2249
1835
2250
def to_currency(%Money{currency: from_currency, amount: amount} = money, to_currency, rates)
1836
- when is_atom(to_currency) or is_digital_token(to_currency) and is_map(rates) do
2251
when is_atom(to_currency) or (is_digital_token(to_currency) and is_map(rates)) do
1837
2252
with {:ok, to_currency_code} <- validate_currency(to_currency),
1838
- {:ok, cross_rate} <- cross_rate(from_currency, to_currency_code, rates) do
2253
{:ok, cross_rate} <- cross_rate(from_currency, to_currency_code, rates) do
1839
2254
converted_amount = Decimal.mult(amount, cross_rate)
1840
2255
{:ok, %{money | currency: to_currency, amount: converted_amount}}
1841
2256
end
 
@@ -2183,9 2598,10 @@ defmodule Money do
2183
2598
defp do_digits_from_options(_currency_data, other),
2184
2599
do: {:error, invalid_digits_error(other)}
2185
2600
2186
- defp invalid_digits_error(other), do:
2187
- {Money.InvalidDigitsError,
2188
- "Unknown or invalid :fractional_digits option found: #{inspect(other)}"}
2601
defp invalid_digits_error(other),
2602
do:
2603
{Money.InvalidDigitsError,
2604
"Unknown or invalid :fractional_digits option found: #{inspect(other)}"}
2189
2605
2190
2606
@doc """
2191
2607
Return a zero amount `t:Money.t/0` in the given currency.
 
@@ -2285,7 2701,9 @@ defmodule Money do
2285
2701
else
2286
2702
def integer?(%{amount: �cimal{coef: :NaN}}), do: false
2287
2703
def integer?(%{amount: �cimal{coef: :inf}}), do: false
2288
- def integer?(%{amount: �cimal{coef: coef, exp: exp}}), do: exp >= 0 or zero_after_dot?(coef, exp)
2704
2705
def integer?(%{amount: �cimal{coef: coef, exp: exp}}),
2706
do: exp >= 0 or zero_after_dot?(coef, exp)
2289
2707
2290
2708
defp zero_after_dot?(coef, exp) when coef >= 10 and exp < 0,
2291
2709
do: Kernel.rem(coef, 10) == 0 and zero_after_dot?(Kernel.div(coef, 10), exp 1)
 
@@ -2456,7 2874,7 @@ defmodule Money do
2456
2874
end
2457
2875
2458
2876
defp get_rate(currency, rates) do
2459
- keys = is_atom(currency) && [currency, Atom.to_string(currency)] || [currency]
2877
keys = (is_atom(currency) && [currency, Atom.to_string(currency)]) || [currency]
2460
2878
2461
2879
rates
2462
2880
|> Map.take(keys)
changed lib/money/backend.ex
 
@@ -964,7 964,7 @@ defmodule Money.Backend do
964
964
965
965
"""
966
966
@spec round(Elixir.Money.t(), Keyword.t()) ::
967
- Elixir.Money.t() | {:error, {module(), binary()}}
967
Elixir.Money.t() | {:error, {module(), binary()}}
968
968
969
969
def round(%Elixir.Money{} = money, options \\ []) do
970
970
Elixir.Money.round(money, options)
changed lib/money/exchange_rates/exchange_rates_retriever.ex
 
@@ -213,7 213,7 @@ defmodule Money.ExchangeRates.Retriever do
213
213
end
214
214
215
215
defp process_response({:error, reason}, _url, _config) do
216
- {:error, {Money.ExchangeRateError, "#{inspect reason}"}}
216
{:error, {Money.ExchangeRateError, "#{inspect(reason)}"}}
217
217
end
218
218
219
219
defp if_none_match_header(url) do
 
@@ -473,7 473,9 @@ defmodule Money.ExchangeRates.Retriever do
473
473
defp seconds(milliseconds) do
474
474
seconds = div(milliseconds, 1000)
475
475
plural = if seconds == 1, do: "second", else: "seconds"
476
- {:ok, formatted_seconds} = Cldr.Number.to_string(seconds, backend: Money.get_env(:default_cldr_backend))
476
477
{:ok, formatted_seconds} =
478
Cldr.Number.to_string(seconds, backend: Money.get_env(:default_cldr_backend))
477
479
478
480
{formatted_seconds, plural}
479
481
end
 
@@ -481,5 483,4 @@ defmodule Money.ExchangeRates.Retriever do
481
483
defp exchange_rate_service_error do
482
484
{Money.ExchangeRateError, "Exchange rate service does not appear to be running"}
483
485
end
484
-
485
486
end
changed lib/money/exchange_rates/exchange_rates_supervisor.ex
 
@@ -193,7 193,7 @@ defmodule Money.ExchangeRates.Supervisor do
193
193
defp start_retriever! do
194
194
case ExchangeRates.Retriever.start() do
195
195
{:ok, _pid} -> :ok
196
- {:error, reason} -> raise "Unhandled error starting retriever; #{inspect reason}"
196
{:error, reason} -> raise "Unhandled error starting retriever; #{inspect(reason)}"
197
197
end
198
198
end
199
199
end
changed lib/money/protocol/inspect.ex
 
@@ -14,7 14,7 @@ defimpl Inspect, for: Money do
14
14
end
15
15
16
16
def do_inspect(%Money{format_options: []} = money, _opts) do
17
- "Money.new(#{inspect(money.currency)}, #{inspect Decimal.to_string(money.amount)})"
17
"Money.new(#{inspect(money.currency)}, #{inspect(Decimal.to_string(money.amount))})"
18
18
end
19
19
20
20
def do_inspect(money, _opts) do
 
@@ -24,6 24,6 @@ defimpl Inspect, for: Money do
24
24
|> String.trim_leading("[")
25
25
|> String.trim_trailing("]")
26
26
27
- "Money.new(#{inspect money.currency}, #{inspect Decimal.to_string(money.amount)}, #{format_options})"
27
"Money.new(#{inspect(money.currency)}, #{inspect(Decimal.to_string(money.amount))}, #{format_options})"
28
28
end
29
- end
\ No newline at end of file
29
end
changed lib/money/protocol/phoenix_html_safe.ex
 
@@ -5,4 5,4 @@ if Cldr.Config.ensure_compiled?(Phoenix.HTML.Safe) &&
5
5
Phoenix.HTML.Safe.to_iodata(Money.to_string!(money))
6
6
end
7
7
end
8
- end
\ No newline at end of file
8
end
changed lib/money/subscription.ex
 
@@ -264,7 264,7 @@ defmodule Money.Subscription do
264
264
"""
265
265
# @doc since: "2.3.0"
266
266
@spec current_plan(Subscription.t() | map, Keyword.t()) ::
267
- Plan.t() | {Change.t(), Plan.t()} | nil
267
Plan.t() | {Change.t(), Plan.t()} | nil
268
268
269
269
def current_plan(subscription, options \\ [])
changed mix.exs
 
@@ -1,7 1,7 @@
1
1
defmodule Money.Mixfile do
2
2
use Mix.Project
3
3
4
- @version "5.17.2"
4
@version "5.18.0"
5
5
6
6
def project do
7
7
[
 
@@ -103,7 103,6 @@ defmodule Money.Mixfile do
103
103
{:benchee, "~> 1.0", optional: true, only: :dev},
104
104
{:exprof, "~> 0.2", only: :dev, runtime: false},
105
105
{:ex_doc, "~> 0.31", only: [:dev, :release]},
106
-
107
106
{:gringotts, "~> 1.1", optional: true}
108
107
]
109
108
|> Enum.reject(&is_nil/1)