lib/money/null_currency.rb
# frozen_string_literal: true class Money # A placeholder currency for instances where no actual currency is available, # as defined by ISO4217. You should rarely, if ever, need to use this # directly. It's here mostly for backwards compatibility and for that reason # behaves like a dollar, which is how this gem worked before the introduction # of currency. # # Here follows a list of preferred alternatives over using Money with # NullCurrency: # # For comparisons where you don't know the currency beforehand, you can use # Numeric predicate methods like #positive?/#negative?/#zero?/#nonzero?. # Comparison operators with Numeric (==, !=, <=, =>, <, >) work as well. # # @example # Money.new(1, 'CAD').positive? #=> true # Money.new(2, 'CAD') >= 0 #=> true # # Money with NullCurrency has behaviour that may surprise you, such as # database validations or GraphQL enum not allowing the string representation # of NullCurrency. Prefer using Money.new(0, currency) where possible, as # this sidesteps these issues and provides additional currency check # safeties. # # Unlike other currencies, it is allowed to calculate a Money object with # NullCurrency with another currency. The resulting Money object will have # the other currency. # # @example # Money.new(0, Money::NULL_CURRENCY) + Money.new(5, 'CAD') # #=> #<Money value:5.00 currency:CAD> # class NullCurrency attr_reader :iso_code, :iso_numeric, :name, :smallest_denomination, :subunit_symbol, :subunit_to_unit, :minor_units, :symbol, :disambiguate_symbol, :decimal_mark def initialize @symbol = '$' @disambiguate_symbol = nil @subunit_symbol = nil @iso_code = 'XXX' @iso_numeric = '999' @name = 'No Currency' @smallest_denomination = 1 @subunit_to_unit = 100 @minor_units = 2 @decimal_mark = '.' freeze end def compatible?(other) other.is_a?(Currency) || other.is_a?(NullCurrency) end def eql?(other) self.class == other.class && iso_code == other.iso_code end def to_s '' end alias_method :==, :eql? end end