I am reading the money gem source code and I can't seem to understand the constructor:
def initialize(obj, currency = Money.default_currency, bank = Money.default_bank)
@fractional = obj.respond_to?(:fractional) ? obj.fractional : as_d(obj)
@currency = obj.respond_to?(:currency) ? obj.currency : Currency.wrap(currency)
@currency ||= Money.default_currency
@bank = obj.respond_to?(:bank) ? obj.bank : bank
end
Why are we testing if obj
has a "fractional"
method? When does that return true and when does it return false? Same questions for currency in the next line.
Thanks
These checks are to allow passing various kinds of things as the obj
and act intelligently. It's an example of using "duck typing"--we don't care what it actually is, but if it quacks like a duck, treat it like one for quacking purposes. From the source comments:
# @param [Object] obj Either the fractional value of the money,
# a Money object, or a currency. (If passed a currency as the first
# argument, a Money will be created in that currency with fractional value
# = 0.
# @param [Currency, String, Symbol] currency The currency format.
# @param [Money::Bank::*] bank The exchange bank to use.
#
# @example
# Money.new(100) #=> #<Money @fractional=100 @currency="USD">
# Money.new(100, "USD") #=> #<Money @fractional=100 @currency="USD">
# Money.new(100, "EUR") #=> #<Money @fractional=100 @currency="EUR">
The intent seems to be that you may want to pass a Money object: if so, you want to use the same fractional
and currency
. If it doesn't have those methods, treat it like a number.