Skip to content

Commit 52b15e9

Browse files
committed
Add Money#to_nearest_cash_value to return a rounded Money instance to the smallest denomination
This new method allows you to get a new Money instance rounded to the smallest denomination. Closes RubyMoney#1131
1 parent 20fba2a commit 52b15e9

File tree

6 files changed

+59
-12
lines changed

6 files changed

+59
-12
lines changed

AUTHORS

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Abhay Kumar
22
Adrian Longley
3+
Alex Speller
34
Alexander Donkin
45
Alexander Ross
5-
Alex Speller
66
Andreas Loupasakis
77
Andrei
88
Andrew White
@@ -49,8 +49,8 @@ Greg Byrne
4949
Hakan Ensari
5050
Hongli Lai
5151
Ilia Lobsanov
52-
Ivan Shamatov
5352
Ingo Wichmann
53+
Ivan Shamatov
5454
Jack Spiva
5555
Jacob Atzen
5656
James Cotterill
@@ -83,8 +83,8 @@ Marco Otte-Witte
8383
Mateus Gomes
8484
Mateusz Wolsza
8585
Matias Korhonen
86-
Matthew McEachen
8786
Matt Jankowski
87+
Matthew McEachen
8888
Max Melentiev
8989
Michael Irwin
9090
Michael J. Cohen
@@ -96,14 +96,15 @@ Mike Połétyn
9696
Musannif Zahir
9797
Neil Middleton
9898
Nick Lozon
99+
Nicolay Hvidsten
99100
Nihad Abbasov
100101
Olek Janiszewski
101102
Orien Madgwick
102-
Paweł Madejski
103103
Paul McMahon
104104
Paulo Diniz
105105
Pavan Sudarshan
106106
Pavel Gabriel
107+
Paweł Madejski
107108
pconnor
108109
Pedro Nascimento
109110
Pelle Braendgaard
@@ -119,9 +120,11 @@ sankaranarayanan
119120
Scott Pierce
120121
Semyon Perepelitsa
121122
Shane Emmons
123+
Simon Neutert
122124
Simone Carletti
123125
Spencer Rinehart
124126
Steve Morris
127+
Sunny Ripert
125128
Thomas E Enebo
126129
Thomas Weymuth
127130
Ticean Bennett
@@ -142,5 +145,3 @@ Yuri Sidorov
142145
Yuusuke Takizawa
143146
Zubin Henner
144147
Бродяной Александр
145-
Nicolay Hvidsten
146-
Simon Neutert

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
- Add Zimbabwe Gold (ZWG) currency
1414
- Update thousands_separator for CHF
1515
- Add Caribbean Guilder (XCG) as replacement for Netherlands Antillean Gulden (ANG)
16-
- Add `Currency#cents_based?` to check if currency is cents-based
16+
- Add `Money#to_nearest_cash_value` to return a rounded Money instance to the smallest denomination
17+
- Add `Money::Currency#cents_based?` to check if currency is cents-based
1718
- Add ability to nest `Money.with_rounding_mode` blocks
1819
- Allow `nil` to be used as a default_currency
1920

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
3. Make sure everything is working: `bundle exec rake spec`
88
4. Make your changes
99
5. Test your changes
10-
5. Create a Pull Request
11-
6. Celebrate!!!!!
10+
6. Create a Pull Request
11+
7. Celebrate! 🎉
1212

1313
## Notes
1414

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ Money.from_amount(2.34567).format #=> "$2.34567"
472472

473473
To round to the nearest cent (or anything more precise), you can use the `round` method. However, note that the `round` method on a `Money` object does not work the same way as a normal Ruby `Float` object. Money's `round` method accepts different arguments. The first argument to the round method is the rounding mode, while the second argument is the level of precision relative to the cent.
474474

475-
```
475+
```ruby
476476
# Float
477477
2.34567.round #=> 2
478478
2.34567.round(2) #=> 2.35
@@ -485,10 +485,18 @@ Money.from_cents(2.34567).round(BigDecimal::ROUND_HALF_UP, 2).format #=> "$0.023
485485
```
486486

487487
You can set the default rounding mode by passing one of the `BigDecimal` mode enumerables like so:
488+
488489
```ruby
489490
Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
490491
```
491-
See [BigDecimal::ROUND_MODE](https://ruby-doc.org/stdlib-2.5.1/libdoc/bigdecimal/rdoc/BigDecimal.html#ROUND_MODE) for more information
492+
493+
See [BigDecimal::ROUND_MODE](https://ruby-doc.org/stdlib-2.5.1/libdoc/bigdecimal/rdoc/BigDecimal.html#ROUND_MODE) for more information.
494+
495+
To round to the nearest cash value in currencies without small denominations:
496+
497+
```ruby
498+
Money.from_cents(11_11, "CHF").to_nearest_cash_value.format # => "CHF 11.10"
499+
```
492500

493501
## Ruby on Rails
494502

@@ -528,7 +536,7 @@ This will work seamlessly with [rails-i18n](https://github.com/svenfuchs/rails-i
528536

529537
If you wish to disable this feature and use defaults instead:
530538

531-
``` ruby
539+
```ruby
532540
Money.locale_backend = nil
533541
```
534542

lib/money/money.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ def round_to_nearest_cash_value
8080
return_value(rounded_value)
8181
end
8282

83+
# Round a given amount of money to the nearest possible money in cash value.
84+
#
85+
# @return [Money]
86+
def to_nearest_cash_value
87+
dup_with(fractional: round_to_nearest_cash_value)
88+
end
89+
8390
# @!attribute [r] currency
8491
# @return [Currency] The money's currency.
8592
# @!attribute [r] bank

spec/money_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,36 @@ def expectation.fractional
527527
end
528528
end
529529

530+
describe "#to_nearest_cash_value" do
531+
it "rounds to the nearest possible cash value" do
532+
expect(Money.new(23_50, "AED").to_nearest_cash_value).to eq(Money.new(23_50, "AED"))
533+
expect(Money.new(-23_50, "AED").to_nearest_cash_value).to eq(Money.new(-23_50, "AED"))
534+
expect(Money.new(22_13, "AED").to_nearest_cash_value).to eq(Money.new(22_25, "AED"))
535+
expect(Money.new(-22_13, "AED").to_nearest_cash_value).to eq(Money.new(-22_25, "AED"))
536+
expect(Money.new(22_12, "AED").to_nearest_cash_value).to eq(Money.new(22_00, "AED"))
537+
expect(Money.new(-22_12, "AED").to_nearest_cash_value).to eq(Money.new(-22_00, "AED"))
538+
539+
expect(Money.new(1_78, "CHF").to_nearest_cash_value).to eq(Money.new(1_80, "CHF"))
540+
expect(Money.new(-1_78, "CHF").to_nearest_cash_value).to eq(Money.new(-1_80, "CHF"))
541+
expect(Money.new(1_77, "CHF").to_nearest_cash_value).to eq(Money.new(1_75, "CHF"))
542+
expect(Money.new(-1_77, "CHF").to_nearest_cash_value).to eq(Money.new(-1_75, "CHF"))
543+
expect(Money.new(1_75, "CHF").to_nearest_cash_value).to eq(Money.new(1_75, "CHF"))
544+
expect(Money.new(-1_75, "CHF").to_nearest_cash_value).to eq(Money.new(-1_75, "CHF"))
545+
546+
expect(Money.new(2_99, "USD").to_nearest_cash_value).to eq(Money.new(2_99, "USD"))
547+
expect(Money.new(-2_99, "USD").to_nearest_cash_value).to eq(Money.new(-2_99, "USD"))
548+
expect(Money.new(3_00, "USD").to_nearest_cash_value).to eq(Money.new(3_00, "USD"))
549+
expect(Money.new(-3_00, "USD").to_nearest_cash_value).to eq(Money.new(-3_00, "USD"))
550+
expect(Money.new( 3_01, "USD").to_nearest_cash_value).to eq(Money.new(3_01, "USD"))
551+
expect(Money.new(-3_01, "USD").to_nearest_cash_value).to eq(Money.new(-3_01, "USD"))
552+
end
553+
554+
it "raises an error if smallest denomination is not defined" do
555+
expect {Money.new(1_00, "XAG").to_nearest_cash_value}
556+
.to raise_error(Money::UndefinedSmallestDenomination)
557+
end
558+
end
559+
530560
describe "#amount" do
531561
it "returns the amount of cents as dollars" do
532562
expect(Money.new(1_00).amount).to eq 1

0 commit comments

Comments
 (0)