# encoding: utf-8
require "papla/version"
module Papla
# Converts a number to Polish words, capitalizing
# the first letter of the whole phrase.
#
# Currently numbers from 0 up to 999 999 999
# are supported. If you pass a bigger number,
# an ArgumentError is raised.
#
# To convert a number, simply call:
#
# Papla[your_number]
#
# Examples:
#
# Papla[0] # => "Zero"
# Papla[22] # => "Dwadzieścia dwa"
# Papla[150] # => "Sto pięćdziesiąt"
# Papla[999] # => "Dziewięćset dziewięćdziesiąt dziewięć"
# Papla[12345] # => "Dwanaście tysięcy trzysta czterdzieści pięć"
# Papla[1_000_001] # => "Jeden milion jeden"
#
# When given a Float, Papla will assume that
# the decimal part represents cents. It will then
# round the number using Float#round to
# two decimal places, and append the number
# of cents divided by hundred to the resulting string.
#
# Example:
#
# Papla[1.0] # => "Jeden 00/100"
# Papla[87.654321] # => "Osiemdziesiąt siedem 65/100"
# Papla[2.999] # => "Trzy 00/100"
#
# @param [Fixnum] number the number to convert
# @return [String] the phrase in Polish
def self.[](number)
validate!(number)
number = prepare(number)
basic_number = number.to_i
basic_phrase = build_basic_phrase(basic_number)
case number
when Float; append_cents(basic_phrase, number)
else basic_phrase
end
end
private
ZERO = 'zero'
ONES = [nil] + %w[
jeden dwa trzy cztery pięć
sześć siedem osiem dziewięć dziesięć
jedenaście dwanaście trzynaście czternaście piętnaście
szesnaście siedemnaście osiemnaście dziewiętnaście
].freeze
TENS = [nil, nil] + %w[
dwadzieścia trzydzieści czterdzieści pięćdziesiąt
sześćdziesiąt siedemdziesiąt osiemdziesiąt dziewięćdziesiąt
].freeze
HUNDREDS = [nil] + %w[
sto dwieście trzysta czterysta pięćset
sześćset siedemset osiemset dziewięćset
].freeze
RANKS = [
[],
['tysięcy', 'tysiąc', 'tysiące'].freeze,
['milionów', 'milion', 'miliony'].freeze,
['miliardów', 'miliard', 'miliardy'].freeze
].freeze
def self.prepare(number)
case number
when Float; number.round(2)
else number
end
end
def self.build_basic_phrase(basic_number)
if basic_number.zero?
ZERO
else
groups = group(basic_number)
groups_as_words = convert_groups(groups)
groups_as_words.flatten.join(' ')
end.capitalize
end
def self.group(number)
groups = []
while number > 0
number, group = number.divmod(1000)
groups.unshift(group)
end
groups
end
def self.convert_groups(groups)
bound = groups.count - 1
result = []
groups.each_with_index do |group, i|
if group > 0
result << convert_small_number(group)
result << rank(bound - i, group) if i < bound
end
end
result
end
def self.convert_small_number(number)
if number.zero?
[]
elsif number < 20
[ONES[number]]
elsif number < 100
tens, remainder = number.divmod(10)
[TENS[tens], convert_small_number(remainder)]
else
hundreds, remainder = number.divmod(100)
[HUNDREDS[hundreds], convert_small_number(remainder)]
end
end
def self.rank(rank, number)
RANKS[rank][declination_index(number)]
end
def self.declination_index(number)
return 1 if number == 1
remainder = number - number / 100 * 100
case remainder
when 12..14 then 0
else
ones = number - number / 10 * 10
case ones
when 2..4 then 2
else 0
end
end
end
def self.validate!(number)
max = 999_999_999
raise ArgumentError, "#{number} is too big, only numbers up to #{max} are supported" if number > max
end
def self.append_cents(basic_phrase, number)
cents = 100 * (number - number.to_i)
"%s %02d/100" % [basic_phrase, cents]
end
end