Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

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: (3.65 in 247 votes)
# 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

VersionAuthorDateCommentsRate
In wordsDaniel Straight07/10/061
alternative versionGreg T.05/18/0510
minimal versionAnonymous05/18/053
shows inheritance, iterators, yield, etcKian Wright06/10/050
object-oriented versionMike Gertz04/20/052
wall-based OO versionKevin Baird07/07/052
monkeypatch and anonymous procsJ. B. Rainsberger04/04/070
Readably re-opening Integer, teetotallerEric Budd01/06/080

Comments

>>  Pepe said on 01/19/07 20:33:48

Pepe Yeah men, keep doing the good work. How Deep is this men, it moves me to tears.

>>  rafa said on 01/25/07 18:49:34

rafa I really like this over the other versions, I think it shows more the ruby way.

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 !.

>>  Hesenrre said on 01/26/07 02:05:15

Hesenrre Jejejejeje, like your coding friend :D, ruby rules!!!!

>>  Namagem said on 12/31/08 16:33:56

Namagem It's absolutely possible to make a slightly less polished version in only 4 lines.
I actually think I'll submit it.

>>  similar to python one said on 02/19/09 16:23:05

similar to python one A friend said the python version looked cleaner. So I wrote that one in Ruby.

(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

>>  jeff said on 03/24/09 05:53:56

jeff As noted by the first comment, this entry stands out not for being the shortest, but because it shows some neat language features, and how they are combined in the last line, that looks almost like a DSL. I think many rubyists would agree, in that ruby makes programming so easy, that the focus is more in expression and artistic value. :)

Nice codes.

>>  Billy said on 12/16/09 02:33:42

Billy I really like this one!

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!"

>>  regeya said on 04/12/10 21:54:54

regeya #Not very ruby-ish, but it works

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

>>  D. Rose said on 04/27/10 19:06:58

D. Rose # 99 Bottles of Beer in 258 chars for ruby 1.9 and exactly the SAME as http://99-bottles-of-beer.net/lyrics.html
# 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}."

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!

Name:

eMail:

URL:

Security Code:
  
Comment: