Never been to TextSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

About this user

Guido Sohne http://sohne.net

« Newer Snippets
Older Snippets »
3 total  XML / RSS feed 

Convert numbers to words

Ugly code. But it works. If you have something better, then post it.

This code is probably (definitely :-) buggy, so if you want to get real work done, just use the Linguistics gem instead.

class Number
  
  def self.to_words(number)
    Number.new.to_s(number)
  end
  
  def self.commify(number)
    (s=number.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(/(\d)(?=\d{3}+(\.\d*)?$)/,'\1,')
  end
    
  def initialize
    @unit = %w[zero one two three four five six seven eight nine]
    @teen = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen]
    @tens = %w[zero ten twenty thirty fourty fifty sixty seventy eighty ninety]
    @qtys = %w[hundred thousand million billion trillion quadrillion quintillion]
    @zero = ["zero"]
    @hundred = "hundred"
    @sepr = "and"
  end
    
  def to_s(number)
    out = quantify(number).flatten
    for x in 0 .. out.length - 1
      out[x] = nil if out[x] == @sepr && out[x+1] == @sepr
    end
    out.compact!
    out = @zero if out.length == 1 && out[0] == @sepr
    out.pop while out.last == @sepr
    out.shift while out.first == @sepr    
    out.join(' ').gsub(/ ,/,',')
  end
        
  private 
  
  def padded_groups(v)
    out = []
    padded = (s=v.to_s;x=s.length;s).rjust(x+(3-(x%3))).gsub(//,'0')
    padded.scan(/.{3}/)
  end
  
  def wordify(v)
    out = []
    zero = '0'[0]
    h, t, u = v[0] - zero, v[1] - zero, v[2] - zero
    if h != 0
      out << @unit[h]
      out << @hundred
    end
    out << @sepr if h != 0 && (t != 0 || u != 0)
    out << @sepr if h == 0 && t == 0 && u != 0
    if t == 1
      out << @teen[u]
    else
      out << @tens[t] if t != 0
      out << @unit[u] if u != 0
    end
    return out
  end
  
  def quantify(v)
    v = padded_groups(v).reverse
    pos = v.length - 1
    out = []
    while pos >= 0
      word = wordify(v[pos])
      if word[0] != nil
        out << word
        out << @qtys[pos] if pos != 0                
      else
        out << @sepr
      end
      pos -= 1
    end
    return out
  end

end

# for number in [
#     0, 
#     1, 
#     3, 
#     11, 
#     100,
#     1000, 
#     1001, 
#     1100, 
#     1101, 
#     1_000_001, 
#     8_000_000_000, 
#     8_000_000_001, 
#     4_567_890_923, 
#     6_804_567_890_903, 
#     5_006_804_567_890_903
#   ]
#   print "#{Number.commify(number)}: #{Number.to_words(number)}\n"
# end

Format an integer with commas to make it more readable

More information or better ways of doing this welcome ...

def commify(number)
    c = { :value => "", :length => 0 }
    r = number.to_s.reverse.split("").inject(c) do |t, e|  
      iv, il = t[:value], t[:length]
      iv += ',' if il % 3 == 0 && il != 0    
      { :value => iv + e, :length => il + 1 }
    end
    r[:value].reverse!
  end


Alex Young suggested

def commify(v)
 (s=v.to_s;x=s.length;s).rjust(x+(3-(x%3))).scan(/.{3}/).join(',').strip
end


and there's always

number_with_delimiter(number, delimiter)


from NumberHelper in the Rails API ... which is implemented as follows:-

def number_with_delimiter(number, delimiter=",")
  number.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
end


They don't always work too well when the number has a decimal point in it (and more than two or so digits after the decimal point), so there's room for an improved version ...

JV suggested the following snippet from http://pleac.sourceforge.net/pleac_ruby/numbers.html which appears to be able to handle commas and decimal places as well.

def commify(n)
    n.to_s =~ /([^\.]*)(\..*)?/
    int, dec = $1.reverse, $2 ? $2 : ""
    while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
    end
    int.reverse + dec
end

Rake task to load fixtures in a specific order

The default task for loading fixtures, rake load_fixtures, appears to load the fixture data in alphabetical order. If you have foreign key or other constraints, it may be impossible to load the fixtures into the database.

The rake task below searches for a file called test/ordered_fixtures.rb and loads that file. The file contains code that sets an environment variable specifying the load order for fixtures.

ENV["FIXTURE_ORDER"] = 
  %w( entities interaction_sources interaction_devices payments 
      interactions accounts employments enrollments payables 
      receivables tenures wards ).join(' ')


The lib/tasks/fixtures.rake (rake load_fixtures_ordered) task first loads all fixtures specified via ordered_fixtures, and then loads all other fixtures not specified as being ordered so it should work for you even if you do not create an ordered_fixtures file.

require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
require File.expand_path(File.dirname(__FILE__) + "/../../test/ordered_fixtures")

ENV["FIXTURE_ORDER"] ||= ""

desc "Load fixtures into #{ENV['RAILS_ENV']} database"
task :load_fixtures_ordered => :environment do
  require 'active_record/fixtures'  
  ordered_fixtures = Hash.new
  ENV["FIXTURE_ORDER"].split.each { |fx| ordered_fixtures[fx] = nil }
  other_fixtures = Dir.glob(File.join(RAILS_ROOT, 'test', 'fixtures', '*.{yml,csv}')).collect { |file| File.basename(file, '.*') }.reject {|fx| ordered_fixtures.key? fx }
  ActiveRecord::Base.establish_connection(ENV['RAILS_ENV'])
  (ordered_fixtures.keys + other_fixtures).each do |fixture|
    Fixtures.create_fixtures('test/fixtures',  fixture)
  end unless :environment == 'production' 
  # You really don't want to load your *fixtures* 
  # into your production database, do you?  
end


The code may not be the best but it Works For Me.
« Newer Snippets
Older Snippets »
3 total  XML / RSS feed