Created
May 18, 2011 20:19
-
-
Save jlogsdon/979454 to your computer and use it in GitHub Desktop.
Converts a Double to Natural Language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Convert | |
def self.to_string(double) | |
split = double.to_s.split('.') | |
# Tack the tens on to cents if not present (.90 => .9 for example) | |
split[1] << "0" if split[1] and split[1].length == 1 | |
dollars = convert(split[0]) | |
cents = convert(split[1]) | |
dollars = plural(dollars, 'Dollar', split[0]) if dollars | |
cents = plural(cents, 'Cent', split[1]) if cents | |
return "Free" unless dollars or cents | |
return dollars unless cents | |
return cents unless dollars | |
return "#{dollars} and #{cents}" | |
end | |
private | |
def self.convert(digit) | |
return nil if !digit or digit == "0" | |
build = digitToWords(digit) | |
build = insertPlaceNames(build) | |
build = compileGroups(build) | |
build.join(', ').strip | |
end | |
def self.plural words, word, digit | |
word << "s" if digit.to_i > 1 | |
"#{words} #{word}" | |
end | |
def self.insertPlaceNames(build) | |
build.map! do |group| | |
if group.select { |digit| !!digit }.length == 0 | |
nil | |
else | |
group | |
end | |
end | |
build.each_index do |idx| | |
next unless build[idx] | |
# Handle the actual place name (for thousands and up) | |
build[idx] << "#{build[idx].pop} #{placeName(build.length - idx)}" unless (idx == build.length - 1) | |
# Handle the hundred spot for this group | |
build[idx].unshift "#{build[idx].shift} #{placeName(1)}" if build[idx].length == 3 | |
end | |
build | |
end | |
def self.placeName(place) | |
return nil if place == 0 | |
return "Hundred" if place == 1 | |
return "Thousand" if place == 2 | |
return "Million" if place == 3 | |
return "Billion" if place == 4 | |
return "Trillion" if place == 5 | |
end | |
def self.compileGroups(build) | |
build.select { |g| !!g }.map do |group| | |
group = group.select { |w| w } | |
if group.length > 1 | |
group << [group.pop, group.pop].reverse.join('-') | |
end | |
group.join(' and ') | |
end | |
end | |
def self.digitToWords(digit) | |
build = [] | |
groups = (digit.length / 3.0).ceil - 1 | |
groups.downto(0).each do |g| | |
words = [] | |
group = digit.reverse[g * 3, 3].reverse | |
# Shortcircuit single digits | |
if group.length == 1 | |
words << wordSingle(group) | |
build << words | |
next | |
end | |
# Handle the thousands | |
if group.length == 3 | |
words << wordSingle(group[0,1]) | |
group = group[1,2] | |
end | |
# Now we know we have a tens group left | |
if group.start_with? "1" | |
words << wordSingleTen(group) | |
else | |
words << wordTen(group[0,1]) | |
words << wordSingle(group[1,1]) | |
end | |
build << words | |
end | |
build | |
end | |
def self.wordSingle(digit) | |
return nil if digit == "0" | |
return "One" if digit == "1" | |
return "Two" if digit == "2" | |
return "Three" if digit == "3" | |
return "Four" if digit == "4" | |
return "Five" if digit == "5" | |
return "Six" if digit == "6" | |
return "Seven" if digit == "7" | |
return "Eight" if digit == "8" | |
return "Nine" if digit == "9" | |
end | |
def self.wordTen(digit) | |
return nil if digit == "0" | |
return "Ten" if digit == "1" | |
return "Twenty" if digit == "2" | |
return "Thirty" if digit == "3" | |
return "Fourty" if digit == "4" | |
return "Fifty" if digit == "5" | |
return "Sixty" if digit == "6" | |
return "Seventy" if digit == "7" | |
return "Eighty" if digit == "8" | |
return "Ninety" if digit == "9" | |
end | |
def self.wordSingleTen(digit) | |
return "Ten" if digit == "10" | |
return "Eleven" if digit == "11" | |
return "Twelve" if digit == "12" | |
return "Thirteen" if digit == "13" | |
return "Fourteen" if digit == "14" | |
return "Fifteen" if digit == "15" | |
return "Sixteen" if digit == "16" | |
return "Seventeen" if digit == "17" | |
return "Eighteen" if digit == "18" | |
return "Nineteen" if digit == "19" | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'convert' | |
describe Convert do | |
describe "to_string" do | |
it "should convert doubles to word form" do | |
Convert.to_string(10000).should == "Ten Thousand Dollars" | |
Convert.to_string(0.01).should == "One Cent" | |
Convert.to_string(0.12).should == "Twelve Cents" | |
Convert.to_string(1.23).should == "One Dollar and Twenty-Three Cents" | |
Convert.to_string(12.34).should == "Twelve Dollars and Thirty-Four Cents" | |
Convert.to_string(123.45).should == "One Hundred and Twenty-Three Dollars and Fourty-Five Cents" | |
Convert.to_string(1234.56).should == "One Thousand, Two Hundred and Thirty-Four Dollars and Fifty-Six Cents" | |
Convert.to_string(12345.67).should == "Twelve Thousand, Three Hundred and Fourty-Five Dollars and Sixty-Seven Cents" | |
Convert.to_string(123456.78).should == "One Hundred and Twenty-Three Thousand, Four Hundred and Fifty-Six Dollars and Seventy-Eight Cents" | |
Convert.to_string(1234567.89).should == "One Million, Two Hundred and Thirty-Four Thousand, Five Hundred and Sixty-Seven Dollars and Eighty-Nine Cents" | |
Convert.to_string(12345678.90).should == "Twelve Million, Three Hundred and Fourty-Five Thousand, Six Hundred and Seventy-Eight Dollars and Ninety Cents" | |
Convert.to_string(999999999999.99).should == "Nine Hundred and Ninety-Nine Billion, Nine Hundred and Ninety-Nine Million, Nine Hundred and Ninety-Nine Thousand, Nine Hundred and Ninety-Nine Dollars and Ninety-Nine Cents" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment