Language Ruby
(Using continuations, singleton classes)
| Date: | 09/15/06 |
| Author: | Victor Borja |
| URL: | n/a |
| Comments: | 9 |
| Info: | http://www.ruby-lang.org |
| Score: |
# 99 Bottles of beer, in Ruby
# By Victor Borja, Sep 14, 2006
# This one shows my favorite Ruby features:
# continuations, open classes, singleton classes, blocks and being funny!
class Integer # The bottles
def drink; self - 1; end
end
class << song = nil
attr_accessor :wall
def bottles
(@bottles.zero? ? "no more" : @bottles).to_s <<
" bottle" << ("s" unless @bottles == 1).to_s
end
def of(bottles)
@bottles = bottles
(class << self; self; end).module_eval do
define_method(:buy) { bottles }
end
self
end
def sing(&step)
puts "#{bottles.capitalize} of beer on the wall, #{bottles} of beer."
if @bottles.zero?
print "Go to the store buy some more, "
step = method :buy
else
print "Take one down and pass it around, "
end
@bottles = step[@bottles]
puts "#{bottles} of beer on the wall."
puts "" or wall.call unless step.kind_of? Method
end
end
callcc { |song.wall| song.of(99) }.sing { |beer| beer.drink }
Download Source | Write Comment
Alternative Versions
| Version | Author | Date | Comments | Rate |
|---|---|---|---|---|
| minimal version | Anonymous | 05/18/05 | 3 | |
| shows inheritance, iterators, yield, etc | Kian Wright | 06/10/05 | 0 | |
| alternative version | Greg T. | 05/18/05 | 10 | |
| In words | Daniel Straight | 07/10/06 | 1 | |
| object-oriented version | Mike Gertz | 04/20/05 | 2 | |
| wall-based OO version | Kevin Baird | 07/07/05 | 2 | |
| monkeypatch and anonymous procs | J. B. Rainsberger | 04/04/07 | 0 | |
| Readably re-opening Integer, teetotaller | Eric Budd | 01/06/08 | 0 |
Download Source | Write Comment
Add Comment
Please provide a value for the fields Name,
Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.
Please don't post large portions of code here! Use the form to submit new examples or updates instead!
Comments
The part I liked the more was the last line, especially "}.sing {", that makes use of a not commonly known behavior of ruby continuations. When the continuation is called the first time, the #sing message is sent to the value resulting from the body of callcc, however subsequent calls to the continuation (by means of wall.call) always send the #sing message to the nil object. I proved this by changing "song = nil" to "song = Object.new", now I understand why Victor used nil as the song, a very cleaver choice !.
I actually think I'll submit it.
(1..99).to_a.reverse.each do |bottle|
if bottle > 1
puts "#{bottle} bottles of beer on the wall, #{bottle} bottles of beer."
suffix = bottle > 2 ? "#{bottle -1} bottles of beer on the wall" : "1 bottle of beer on the wall"
elsif bottle == 1
puts "1 bottle of beer on the wall, 1 bottle of beer."
suffix = "no more beer on the wall!"
end
puts "Take one down, pass it around #{suffix}"
puts "--"
end
Nice codes.
num_bot = proc { |n| "#{n} bottle#{n == 1 ? '' : 's'}" }
99.downto(2) do |num|
puts "#{num_bot[num]} of beer on the wall, #{num_bot[num]} of beer!"
puts "Take one down, pass it around, #{num_bot[num-1]} of beer on the wall!"
end
puts "#{num_bot[1]} of beer on the wall, #{num_bot[1]} of beer!"
puts "Take one down, pass it around, no more bottles of beer on the wall!"
bob = proc { |num| "#{num == 0 ? "no more" : num} bottle#{"s" if num != 1} of beer" }
bob_on_wall = proc { |num| "#{bob[num]} on the wall" }
99.downto(1) {|f| print "#{bob_on_wall[f]}, #{bob[f]}!\nTake one down, pass it around, #{bob_on_wall[f-1]}!\n\n" }
puts <<END
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.
END
# I prefer clear ruby code thought
def b i,w=nil;"#{i==0&&"no more"||i} bottle#{"s"if i!=1} of beer#{" on the wall"if w}"end
99.downto(1){|i|puts"#{b i,1}, #{b i}.\nTake one down, pass it around, #{b i-1,1}.\n\n"}
puts b(0,1).capitalize+", #{b 0}.\nGo to the store and buy some more, #{b 99,1}."