Skip to content

Add ability to nest Money.with_rounding_mode blocks#1128

Merged
yukideluxe merged 11 commits intoRubyMoney:mainfrom
pawelma:main
Jul 14, 2025
Merged

Add ability to nest Money.with_rounding_mode blocks#1128
yukideluxe merged 11 commits intoRubyMoney:mainfrom
pawelma:main

Conversation

@pawelma
Copy link
Contributor

@pawelma pawelma commented May 9, 2025

WHAT

Allow .with_rounding_mode blocks nesting

WHY

So, that we can safely use the block and not rely on global rounding_mode.

Relates to the comment in PR which introduced the feature #343 (comment)

pawelma and others added 7 commits May 9, 2025 14:30
so that it can emphasize it's behaviour better
So that it won't return to the global value in case if someone will
modify down in the stack.

For example we might have:
```ruby
	- initializers/money.rb
	Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN

	- controllers/test.rb
	Money.with_rounding_mode(BigDecimal::ROUND_UP) do
	  object.amount = Money.from_amount(1.234)
	  object.save
	  other_object.amount = object.amount * different_rate
	end

	- models/object.rb
	def save
	  Money.with_rounding_mode(BigDecimal::ROUND_DOWN) do
	    self.tax = object.amount * tax_rate
	  end
	  ...
	end
```

Above example prior the change would cause other_object to use
`ROUND_HALF_EVEN`, despite it's explicitly defined in a `with_rounding_mode`
block which sets `ROUND_UP`.

The small rounding errors might be tricky to debug,
and in worst case scenarios can cumulate to a bigger differences when
code operates on multiple amounts that might be incorrectly rounded.

Co-Authored-By: Łukasz Wójcik <lukasz.wojcik@simplybusiness.co.uk>
@pawelma
Copy link
Contributor Author

pawelma commented Jul 8, 2025

Hey @semmons99. Any chance this could be considered in the next release?

Copy link
Member

@yukideluxe yukideluxe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

context "with a block" do
it "respects the rounding_mode" do
expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
expect(Money.with_rounding_mode(BigDecimal::ROUND_DOWN) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for changing this to use the non-deprecated method! 😍

expect(Money.from_amount(2.137).to_d).to eq 2.14
end

it 'safely handles concurrent usage in different threads' do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, I always find it very difficult to test these scenarios and you made it so easy. I'll keep this in mind for my future self 👏🏻

@yukideluxe yukideluxe merged commit 20fba2a into RubyMoney:main Jul 14, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants