Matthias Reitinger wrote:
> Michael Morin wrote:
>> I did something slightly different, which works on multiple levels, not
>> just two.  For example, it can go all the way up to 999 without any
>> extra code.
>>
>> [...]
> 
> Unfortunately your implemention fails with multiples of 100.
> 
> Being the lazy guy I just used the excellent [Ruby Lingustics 
> Framework][1] to deduce English numerals.  The following program 
> produces the [full 99 Bottles of Beer lyrics][2] with numerals:
> 
> ---
> require 'Linguistics'
> Linguistics::use(:en)
> 
> class Fixnum
>   def bottles
>     case self
>       when 0: "no more bottles"
>       when 1: "one bottle"
>       else    "#{self.en.numwords} bottles"
>     end
>   end
> end
> 
> 99.downto(0) do |n|
>   puts "#{n.bottles.capitalize} of beer on the wall, #{n.bottles} of 
> beer."
>   if n > 0
>     puts "Take one down and pass it around, #{(n-1).bottles} of beer on 
> the wall."
>     puts
>   else
>     puts "Go to the store and buy some more, #{99.bottles} of beer on 
> the wall."
>   end
> end
> ---
> 
> Regards,
> Matthias
> 
> [1]: http://www.deveiate.org/projects/Linguistics/
> [2]: http://99-bottles-of-beer.net/lyrics.html

So it does.  Just drop the "and" from the strings and it's still 
technically correct.  Things could be better if I had special cases for 
things like that, but I didn't want to complicate the code.

Nothing lazy about using libraries.  Linguistics takes a different 
approach though.  They have three different procs stored in an array for 
the number of digits in the number.

# A collection of functions for transforming digits into word
# phrases. Indexed by the number of digits being transformed; e.g.,
# <tt>NumberToWordsFunctions[2]</tt> is the function for transforming
# double-digit numbers.
NumberToWordsFunctions = [
	proc {|*args| raise "No digits (#{args.inspect})"},

	# Single-digits
	proc {|zero,x|
		(x.nonzero? ? to_units(x) : "#{zero} ")
	},

	# Double-digits
	proc {|zero,x,y|
		if x.nonzero?
			to_tens( x, y )
		elsif y.nonzero?
			"#{zero} " + NumberToWordsFunctions[1].call( zero, y )
		else
			([zero] * 2).join(" ")
		end
	},

	# Triple-digits
	proc {|zero,x,y,z|
		NumberToWordsFunctions[1].call(zero,x) +
		NumberToWordsFunctions[2].call(zero,y,z)
	}
]

That's quite clever.  Each proc calls the previous proc.  Mine relied on 
recursion and subtraction instead of separating the digits.  Doing it 
this way gives you an easy way to implement the special cases.

-- 
Michael Morin
Guide to Ruby
http://ruby.about.com/
Become an About.com Guide:  beaguide.about.com
About.com is part of the New York Times Company