1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
require 'bigdecimal'
require_relative './humanize/locales'
module Humanize
SPACE = ' '.freeze
EMPTY = ''.freeze
# Big numbers are big: http://wiki.answers.com/Q/What_number_is_after_vigintillion&src=ansTT
def humanize(locale: Humanize.config.default_locale,
decimals_as: Humanize.config.decimals_as)
locale_class, spacer = Humanize.for_locale(locale)
return locale_class::SUB_ONE_GROUPING[0] if zero?
infinity = to_f.infinite?
if infinity
infinity_word = locale_class::INFINITY
return infinity == 1 ? infinity_word : "#{locale_class::NEGATIVE}#{spacer}#{infinity_word}"
elsif is_a?(Float) && nan?
return locale_class::UNDEFINED
end
sign = locale_class::NEGATIVE if negative?
parts = locale_class.new.humanize(abs)
process_decimals(locale_class, locale, parts, decimals_as, spacer)
Humanize.stringify(parts, sign, spacer)
end
def self.for_locale(locale)
case locale.to_sym
# NOTE: add locales here in ealphabetical order
when :az, :de, :en, :es, :fr, :id, :ms, :pt, :ru, :vi
[Object.const_get("Humanize::#{locale.capitalize}"), SPACE]
when :th
[Humanize::Th, EMPTY]
when :tr
[Humanize::Tr, SPACE]
when :jp
[Humanize::Jp, EMPTY]
else
raise "Unsupported humanize locale: #{locale}"
end
end
def self.stringify(parts, sign, spacer)
output = parts.reverse.join(spacer).squeeze(spacer)
if locale_is?(:es) && sign
"#{output}#{spacer}#{sign}"
elsif sign
"#{sign}#{spacer}#{output}"
else
output
end
end
def self.locale_is?(locale)
Humanize.config.default_locale == locale
end
def process_decimals(locale_class, locale, parts, decimals_as, spacer)
return unless is_a?(Float) || is_a?(BigDecimal)
# Why 15?
# (byebug) BigDecimal.new(number, 15)
# 0.8000015e1
# (byebug) BigDecimal.new(number, 16)
# 0.8000014999999999e1
decimal = BigDecimal(self, 15) - BigDecimal(to_i)
_sign, significant_digits, _base, exponent = decimal.split
return if significant_digits == "0"
grouping = locale_class::SUB_ONE_GROUPING
leading_zeroes = [grouping[0]] * exponent.abs
decimals_as = :digits if leading_zeroes.any?
decimals_as_words =
case decimals_as
when :digits
digits = significant_digits.chars.map do |num|
grouping[num.to_i]
end
(leading_zeroes + digits).join(spacer)
when :number
significant_digits.to_i.humanize(locale: locale)
end
parts.insert(0, decimals_as_words, locale_class::POINT)
end
class << self
attr_writer :config
end
def self.config
@config ||= Configuration.new
end
def self.reset_config
@config = Configuration.new
end
def self.configure
yield(config)
end
class Configuration
attr_accessor :default_locale, :decimals_as
def initialize
@default_locale = :en
@decimals_as = :digits
end
end
end
class Integer
include Humanize
end
class Float
include Humanize
end
class BigDecimal
include Humanize
end
|