Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'minitest/autorun'
- require 'humanize'
- class NumberConverter
- DICTIONARY = {
- 0 => 'zero',
- 1 => 'one',
- 2 => 'two',
- 3 => 'three',
- 4 => 'four',
- 5 => 'five',
- 6 => 'six',
- 7 => 'seven',
- 8 => 'eight',
- 9 => 'nine',
- 10 => 'ten',
- 11 => 'eleven',
- 12 => 'twelve',
- 13 => 'thirteen',
- 14 => 'fourteen',
- 15 => 'fifteen',
- 16 => 'sixteen',
- 17 => 'seventeen',
- 18 => 'eighteen',
- 19 => 'nineteen',
- 20 => 'twenty',
- 30 => 'thirty',
- 40 => 'fourty',
- 50 => 'fifty',
- 60 => 'sixty',
- 70 => 'seventy',
- 80 => 'eighty',
- 90 => 'ninety',
- 10**2 => 'hundred',
- 10**3 => 'thousand',
- 10**6 => 'million',
- 10**9 => 'billion',
- 10**12 => 'trillion',
- 10**15 => 'quadrillion',
- 10**18 => 'quintillion',
- 10**21 => 'sextillion',
- }
- def self.validate(number)
- raise("Sorry, I only know how to handle integers") unless number.is_a?(Integer)
- raise("Sorry, that's too big") if number > 10**21
- raise("Sorry, no negative numbers") if number < 0
- end
- def self.spacer(number)
- if number < 100
- ' and '
- else
- ', '
- end
- end
- def self.convert(number)
- validate(number)
- case
- when number < 20
- DICTIONARY[number]
- when number < 100
- digit = number / 10 * 10
- remainder = number % 10
- if remainder == 0
- "#{DICTIONARY[digit]}"
- else
- "#{DICTIONARY[digit]}-#{DICTIONARY[remainder]}"
- end
- else
- power = Math.log10(number).to_i
- if power > 2
- # Every third power of 10, break the number up to call convert
- # on its component parts. e.g. 23,432 --> "Twenty three thousand..."
- power -= power % 3
- end
- digit = number / 10**power
- remainder = number % 10**power
- if remainder != 0
- remainder_text = "#{spacer(remainder)}#{convert(remainder)}"
- end
- "#{convert(digit)} #{DICTIONARY[10**power]}#{remainder_text}"
- end
- end
- end
- class TestNumberConverter < Minitest::Test
- describe NumberConverter do
- def check_number(number)
- output = NumberConverter.convert(number)
- assert_equal(number.humanize, output)
- end
- describe "invalid numbers" do
- it "can't handle floats" do
- assert_raises RuntimeError do
- NumberConverter.convert(4.3)
- end
- end
- it "can't handle more than a sextillion" do
- assert_raises RuntimeError do
- NumberConverter.convert(10**22)
- end
- end
- it "can't handle negative numbers" do
- assert_raises RuntimeError do
- NumberConverter.convert(-50)
- end
- end
- end
- describe "valid integers" do
- it "knows 0" do
- check_number(0)
- end
- it "knows 3" do
- check_number(3)
- end
- it "knows 10" do
- check_number(10)
- end
- it "knows 13" do
- check_number(13)
- end
- it "knows 23" do
- check_number(23)
- end
- it "knows 70" do
- check_number(70)
- end
- it "knows 300" do
- check_number(300)
- end
- it "knows 429" do
- check_number(429)
- end
- it "knows 3000" do
- check_number(3000)
- end
- it "knows 3429" do
- check_number(3429)
- end
- it "knows 10,009" do
- check_number(10009)
- end
- it "knows 67,009" do
- check_number(67009)
- end
- it "knows 403,209" do
- check_number(403229)
- end
- it "knows 1,403,209" do
- check_number(1403229)
- end
- it "knows 10,403,219" do
- check_number(10403219)
- end
- it "knows 400,003,219,001" do
- check_number(400003219001)
- end
- it "knows 10,400,403,219,321" do
- check_number(10400403219321)
- end
- it "knows 10,000,400,403,219,321" do
- check_number(10000400403219321)
- end
- it "knows 10**21" do
- check_number(10**21)
- end
- end
- end
- end
Add Comment
Please, Sign In to add comment