Class: Money::Formatter

Inherits:
Object
  • Object
show all
Defined in:
lib/money/money/formatter.rb,
sig/lib/money/money/formatter.rbs

Constant Summary collapse

DEFAULTS =

Returns:

  • (Hash[Symbol, string])
{
  thousands_separator: "",
  decimal_mark: ".",
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(money, *rules) ⇒ String

Creates a formatted price string according to several rules.

with the symbol (if present) and %n will be replaced with the number.

Note that the default rules can be defined through Money.default_formatting_rules hash.

Examples:

Money.us_dollar(0).format(display_free: true)     #=> "free"
Money.us_dollar(0).format(display_free: "gratis") #=> "gratis"
Money.us_dollar(0).format                            #=> "$0.00"
Money.ca_dollar(100).format #=> "$1.00"
Money.ca_dollar(100).format(with_currency: true) #=> "$1.00 CAD"
Money.us_dollar(85).format(with_currency: true)  #=> "$0.85 USD"
Money.us_dollar(100.1).format #=> "$1.001"
Money.us_dollar(100.1).format(rounded_infinite_precision: true) #=> "$1"
Money.us_dollar(100.9).format(rounded_infinite_precision: true) #=> "$1.01"
Money.ca_dollar(100).format(no_cents: true) #=> "$1"
Money.ca_dollar(599).format(no_cents: true) #=> "$5"
Money.ca_dollar(10000).format(no_cents_if_whole: true) #=> "$100"
Money.ca_dollar(10034).format(no_cents_if_whole: true) #=> "$100.34"
Money.new(100, "USD") #=> "$1.00"
Money.new(100, "GBP") #=> "£1.00"
Money.new(100, "EUR") #=> "€1.00"

# Same thing.
Money.new(100, "USD").format(symbol: true) #=> "$1.00"
Money.new(100, "GBP").format(symbol: true) #=> "£1.00"
Money.new(100, "EUR").format(symbol: true) #=> "€1.00"

# You can specify a false expression or an empty string to disable
# prepending a money symbol.§
Money.new(100, "USD").format(symbol: false) #=> "1.00"
Money.new(100, "GBP").format(symbol: nil)   #=> "1.00"
Money.new(100, "EUR").format(symbol: "")    #=> "1.00"

# If the symbol for the given currency isn't known, then it will default
# to "¤" as symbol.
Money.new(100, "AWG").format(symbol: true) #=> "¤1.00"

# You can specify a string as value to enforce using a particular symbol.
Money.new(100, "AWG").format(symbol: "ƒ") #=> "ƒ1.00"

# You can specify a indian currency format
Money.new(10000000, "INR").format(south_asian_number_formatting: true) #=> "1,00,000.00"
Money.new(10000000).format(south_asian_number_formatting: true) #=> "$1,00,000.00"
# If a string is specified, it's value is used.
Money.new(100, "USD").format(decimal_mark: ",") #=> "$1,00"

# If the decimal_mark for a given currency isn't known, then it will default
# to "." as decimal_mark.
Money.new(100, "FOO").format #=> "$1.00"
# If a falsey value is specified, no thousands_separator is used.
Money.new(100000, "USD").format(thousands_separator: false) #=> "1000.00"
Money.new(100000, "USD").format(thousands_separator: nil)   #=> "1000.00"
Money.new(100000, "USD").format(thousands_separator: "")    #=> "1000.00"

# If true is specified, the locale or default thousands_separator is used.
Money.new(100000, "USD").format(thousands_separator: true) #=> "1,000.00"

# If a string is specified, it's value is used.
Money.new(100000, "USD").format(thousands_separator: ".") #=> "$1.000.00"

# If the thousands_separator for a given currency isn't known, then it will
# default to "," as thousands_separator.
Money.new(100000, "FOO").format #=> "$1,000.00"
Money.ca_dollar(570).format(html_wrap: true, with_currency: true)
#=> "<span class=\"money-currency-symbol\">$</span><span class=\"money-whole\">5</span><span class=\"money-decimal-mark\">.</span><span class=\"money-decimal\">70</span> <span class=\"money-currency\">CAD</span>"
# You can specify to display the sign with positive numbers
Money.new(100, "GBP").format(sign_positive: true,  sign_before_symbol: true)  #=> "+£1.00"
Money.new(100, "GBP").format(sign_positive: true,  sign_before_symbol: false) #=> "£+1.00"
Money.new(100, "GBP").format(sign_positive: false, sign_before_symbol: true)  #=> "£1.00"
Money.new(100, "GBP").format(sign_positive: false, sign_before_symbol: false) #=> "£1.00"
Money.new(100, "GBP").format                               #=> "£+1.00"
Money.new(10000, "USD").format(disambiguate: false)   #=> "$100.00"
Money.new(10000, "CAD").format(disambiguate: false)   #=> "$100.00"
Money.new(10000, "USD").format(disambiguate: true)    #=> "US$100.00"
Money.new(10000, "CAD").format(disambiguate: true)    #=> "C$100.00"
# With the following entry in the translation files:
# en:
#   number:
#     currency:
#       symbol:
#         CAD: "CAD$"
Money.new(10000, "CAD").format(translate: true) #=> "CAD$100.00"
Money.new(89000, :btc).format(drop_trailing_zeros: true) #=> B⃦0.00089
Money.new(110, :usd).format(drop_trailing_zeros: true)   #=> $1.1
Money.new(89000, :btc).format(delimiter_pattern: /(\d)(?=\d)/) #=> B⃦8,9,0.00
Money.new(10000, "USD").format(format: '%u %n') #=> "$ 100.00"
Money.new(10000, "USD").format(format: '<span>%u%n</span>')  #=> "<span>$100.00</span>"

Parameters:

  • rules (Hash)

    The options used to format the string.

  • money (Object)

Options Hash (*rules):

  • :display_free (Boolean, String) — default: false

    Whether a zero amount of money should be formatted of "free" or as the supplied string.

  • :with_currency (Boolean) — default: false

    Whether the currency name should be appended to the result string.

  • :rounded_infinite_precision (Boolean) — default: false

    Whether the amount of money should be rounded when using infinite_precision

  • :no_cents (Boolean) — default: false

    Whether cents should be omitted.

  • :no_cents_if_whole (Boolean) — default: false

    Whether cents should be omitted if the cent value is zero

  • :symbol (Boolean, String, nil) — default: true

    Whether a money symbol should be prepended to the result string. The default is true. This method attempts to pick a symbol that's suitable for the given currency.

  • :decimal_mark (Boolean, String, nil) — default: true

    Whether the currency should be separated by the specified character or '.'

  • :thousands_separator (Boolean, String, nil) — default: true

    Whether the currency should be delimited by the specified character or ','

  • :html_wrap (Boolean) — default: false

    Whether all currency parts should be HTML-formatted.

  • :sign_positive (Boolean) — default: false

    Whether positive numbers should be signed, too.

  • :disambiguate (Boolean) — default: false

    Prevents the result from being ambiguous due to equal symbols for different currencies. Uses the disambiguate_symbol.

  • :translate (Boolean) — default: true

    true Checks for custom symbol definitions using I18n.

  • :drop_trailing_zeros (Boolean) — default: false

    Ignore trailing zeros after the decimal mark

  • :delimiter_pattern (Boolean) — default: /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/

    Regular expression to set the placement for the thousands delimiter

  • :format (String) — default: nil

    Provide a template for formatting. %u will be replaced

See Also:



190
191
192
193
194
# File 'lib/money/money/formatter.rb', line 190

def initialize(money, *rules)
  @money = money
  @currency = money.currency
  @rules = FormattingRules.new(@currency, *rules)
end

Instance Attribute Details

#currencyCurrency (readonly)

Returns the value of attribute currency.

Returns:



221
222
223
# File 'lib/money/money/formatter.rb', line 221

def currency
  @currency
end

#moneyMoney (readonly)

Returns the value of attribute money.

Returns:



221
222
223
# File 'lib/money/money/formatter.rb', line 221

def money
  @money
end

#rulesFormattingRules (readonly)

Returns the value of attribute rules.

Returns:



221
222
223
# File 'lib/money/money/formatter.rb', line 221

def rules
  @rules
end

Instance Method Details

#append_currency_symbol(formatted_number) ⇒ string

Parameters:

  • formatted_number (Object)

Returns:

  • (string)


273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/money/money/formatter.rb', line 273

def append_currency_symbol(formatted_number)
  if rules[:with_currency]
    currency_part =
      if rules[:html_wrap]
        html_wrap(currency.to_s, "currency")
      else
        currency.to_s
      end

    "#{formatted_number} #{currency_part}"
  else
    formatted_number
  end
end

#append_sign(formatted_number) ⇒ string

Parameters:

  • formatted_number (Object)

Returns:

  • (string)


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/money/money/formatter.rb', line 246

def append_sign(formatted_number)
  sign = money.negative? ? "-" : ""

  if rules[:sign_positive] == true && money.positive?
    sign = "+"
  end

  if rules[:sign_before_symbol] == true
    sign_before = sign
    sign = ""
  end

  symbol_value = symbol_value_from(rules)

  if symbol_value && !symbol_value.empty?
    if rules[:html_wrap]
      symbol_value = html_wrap(symbol_value, "currency-symbol")
    end

    rules[:format]
      .gsub("%u", [sign_before, symbol_value].join)
      .gsub("%n", [sign, formatted_number].join)
  else
    "#{sign_before}#{sign}#{formatted_number}"
  end
end

#decimal_markstring Also known as: separator

Returns:

  • (string)


212
213
214
# File 'lib/money/money/formatter.rb', line 212

def decimal_mark
  lookup :decimal_mark
end

#extract_whole_and_decimal_partsArray[string]

Returns:

  • (Array[string])


307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/money/money/formatter.rb', line 307

def extract_whole_and_decimal_parts
  fractional = money.fractional.abs

  # Round the infinite precision part if needed
  fractional = fractional.round if rules[:rounded_infinite_precision]

  # Translate subunits into units
  fractional_units = BigDecimal(fractional) / currency.subunit_to_unit

  # Split the result and return whole and decimal parts separately
  fractional_units.to_s("F").split(".")
end

#format_decimal_part(value) ⇒ nil, string

Parameters:

  • value (Object)

Returns:

  • (nil, string)


320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/money/money/formatter.rb', line 320

def format_decimal_part(value)
  return nil if currency.decimal_places == 0 && !Money.default_infinite_precision
  return nil if rules[:no_cents]
  return nil if rules[:no_cents_if_whole] && value.to_i == 0

  # Pad value, making up for missing zeroes at the end
  value = value.ljust(currency.decimal_places, "0")

  # Drop trailing zeros if needed
  value.gsub!(/0*$/, "") if rules[:drop_trailing_zeros]

  value.empty? ? nil : value
end

#format_numberstring

Returns:

  • (string)


223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/money/money/formatter.rb', line 223

def format_number
  whole_part, decimal_part = extract_whole_and_decimal_parts

  # Format whole and decimal parts separately
  decimal_part = format_decimal_part(decimal_part)
  whole_part = format_whole_part(whole_part)

  # Assemble the final formatted amount
  if rules[:html_wrap]
    if decimal_part.nil?
      html_wrap(whole_part, "whole")
    else
      [
        html_wrap(whole_part, "whole"),
        html_wrap(decimal_mark, "decimal-mark"),
        html_wrap(decimal_part, "decimal"),
      ].join
    end
  else
    [whole_part, decimal_part].compact.join(decimal_mark)
  end
end

#format_whole_part(value) ⇒ Object

Parameters:

  • value (Object)

Returns:

  • (Object)


300
301
302
303
304
305
# File 'lib/money/money/formatter.rb', line 300

def format_whole_part(value)
  # Apply thousands_separator
  value.gsub(rules[:delimiter_pattern]) do |digit_to_delimit|
    "#{digit_to_delimit}#{thousands_separator}"
  end
end

#free_textuntyped, "free"

Returns:

  • (untyped, "free")


296
297
298
# File 'lib/money/money/formatter.rb', line 296

def free_text
  rules[:display_free].respond_to?(:to_str) ? rules[:display_free] : "free"
end

#html_wrap(string, class_name) ⇒ ::String

Parameters:

  • string (string)
  • class_name (string)

Returns:

  • (::String)


292
293
294
# File 'lib/money/money/formatter.rb', line 292

def html_wrap(string, class_name)
  "<span class=\"money-#{class_name}\">#{string}</span>"
end

#lookup(key) ⇒ Object

Parameters:

  • key (Symbol)

Returns:

  • (Object)


334
335
336
337
338
# File 'lib/money/money/formatter.rb', line 334

def lookup(key)
  return rules[key] || DEFAULTS[key] if rules.has_key?(key)

  lookup_default key
end

#lookup_default(key) ⇒ Object

Parameters:

  • key (Symbol)

Returns:

  • (Object)


340
341
342
# File 'lib/money/money/formatter.rb', line 340

def lookup_default(key)
  (Money.locale_backend && Money.locale_backend.lookup(key, currency)) || DEFAULTS[key]
end

#show_free_text?Boolean

Returns:

  • (Boolean)


288
289
290
# File 'lib/money/money/formatter.rb', line 288

def show_free_text?
  money.zero? && rules[:display_free]
end

#symbol_value_from(rules) ⇒ untyped, ""

Parameters:

  • rules (Hash[Symbol, untyped])

Returns:

  • (untyped, untyped, "", untyped)


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/money/money/formatter.rb', line 344

def symbol_value_from(rules)
  if rules.has_key?(:symbol)
    if rules[:symbol] == true
      if rules[:disambiguate] && currency.disambiguate_symbol
        currency.disambiguate_symbol
      else
        money.symbol
      end
    elsif rules[:symbol]
      rules[:symbol]
    else
      ""
    end
  elsif rules[:html_wrap]
    currency.html_entity == "" ? currency.symbol : currency.html_entity
  elsif rules[:disambiguate] && currency.disambiguate_symbol
    currency.disambiguate_symbol
  else
    money.symbol
  end
end

#thousands_separatorstring Also known as: delimiter

Returns:

  • (string)


204
205
206
207
208
209
210
# File 'lib/money/money/formatter.rb', line 204

def thousands_separator
  val = lookup :thousands_separator

  return val unless val == true

  lookup_default :thousands_separator
end

#to_sstring

Returns:

  • (string)


196
197
198
199
200
201
202
# File 'lib/money/money/formatter.rb', line 196

def to_s
  return free_text if show_free_text?

  result = format_number
  formatted = append_sign(result)
  append_currency_symbol(formatted)
end