Skip to content

Instantly share code, notes, and snippets.

@jmccartie
Created December 6, 2013 17:42
Show Gist options
  • Save jmccartie/7829015 to your computer and use it in GitHub Desktop.
Save jmccartie/7829015 to your computer and use it in GitHub Desktop.
class Beer
attr_accessor :bottle_count
def sing(first, last=0)
first.downto(last).inject("") do |memo, num|
memo << verse(num) + "\n"
end
end
def verse(num)
@bottle_count = num
[line1, line2, action, remaining_bottles].join()
end
private
def line1
pluralize_bottles(bottle_count).capitalize + " of beer on the wall, "
end
def line2
pluralize_bottles(bottle_count) + " of beer.\n"
end
def action
if bottle_count == 0
"Go to the store and buy some more, "
else
"Take #{humanize_bottles} down and pass it around, "
end
end
def remaining_bottles
reset_bottles if bottle_count == 0
"#{pluralize_bottles(bottle_count-1)} of beer on the wall.\n"
end
def reset_bottles
@bottle_count = 100
end
def humanize_bottles
bottle_count == 1 ? 'it' : 'one'
end
def pluralize_bottles(count)
if count == 0
"no more bottles"
elsif count == 1
"1 bottle"
else
"#{count} bottles"
end
end
end
@danielmurphy
Copy link

What's cool about the approach in https://gist.github.com/danielmurphy/7827772 is that it is easy to extend. To change verse 6 ("A 6 pack of beer on the wall..."), there is no code that has to change, you just create a new class (BeerSongVerse6).

Conceptually the goal is to find and use the correct object that with a very small scope, instead of one object that knows lots.

A code smell to look for is several if statements. That is a clue that there are probably multiple responsibilities stuffed into one object type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment