Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions lib/money/money.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Money
extend Forwardable

NULL_CURRENCY = NullCurrency.new.freeze
ZERO_MONEY = {} # cache of zero Money instances, keyed by iso_code
private_constant :ZERO_MONEY

attr_reader :value, :currency

Expand Down Expand Up @@ -75,8 +77,7 @@ def new(value = 0, currency = nil)
currency = Helpers.value_to_currency(currency)

if value.zero?
@@zero_money ||= {}
@@zero_money[currency.iso_code] ||= super(Helpers::DECIMAL_ZERO, currency)
ZERO_MONEY[currency.iso_code] ||= super(Helpers::DECIMAL_ZERO, currency)
else
super(value, currency)
end
Expand Down Expand Up @@ -107,6 +108,11 @@ def rational(money1, money2)
private

def new_from_money(amount, currency)
# Fast path: same ISO code string as the existing money's currency.
if currency.is_a?(String) && currency == amount.currency.iso_code && !amount.no_currency?
return amount
end

currency = Helpers.value_to_currency(currency)

if amount.no_currency?
Expand All @@ -125,11 +131,13 @@ def new_from_money(amount, currency)
end

def initialize(value, currency)
raise ArgumentError if value.nan?
raise ArgumentError if value.infinite?
raise ArgumentError unless value.finite?

@currency = currency
@value = BigDecimal(value.round(@currency.minor_units))
minor_units = currency.minor_units
# Avoid allocating via round when the value is already within precision.
# BigDecimal#round(0) returns an Integer, hence the BigDecimal() wrap.
@value = value.scale <= minor_units ? value : BigDecimal(value.round(minor_units))
freeze
end

Expand Down
Loading