トップ 最新の日記 ユーザー登録 ログイン ヘルプ

のびのびなRuby日記 このページをアンテナに追加 RSSフィード

2007-07-01

99 Bottles of Beer  99 Bottles of Beer - のびのびなRuby日記 を含むブックマーク はてなブックマーク -  99 Bottles of Beer - のびのびなRuby日記  99 Bottles of Beer - のびのびなRuby日記 のブックマークコメント

Code Golfに掲載されていた99 Bottles Of Beer問題をRubyを使い、尚かつテストファーストで書いてみました。

まだリファクタリング出来るところが残っていると思いますが、一旦載せておいて、リファクタリング前後の変化を自分へのメモとして残しておきたいと思います。

#もっと短く書けるんでしょうね(^^;

ファイルの配置場所

|-- lib
|   `-- ninety_nine_bottle_of_beer.rb
`-- test
    `-- ninty_nine_bottle_of_beer_test.rb

リファクタリング

#ninty_nine_bottle_of_beer_test.rb
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
require 'test/unit'
require 'ninety_nine_bottle_of_beer'

class NinetyNineBottlesOfBeerTest < Test::Unit::TestCase
  def setup
    @target = NinetyNineBottlesOfBeer.new
  end

  def test_sing
    result = @target.sing
    expected_lyrics_at_index_zero = create_lyrics_for(99)
    expected_lyrics_at_index_ninety_six  = create_lyrics_for(3)
    expected_lyrics_at_index_ninety_seven  = create_lyrics_for(2)
    expected_lyrics_at_index_ninety_eight  = "1 bottle of beer on the wall, 1 bottle of beer.\n"
    expected_lyrics_at_index_ninety_eight  += "Go to the store and buy some more, 99 bottles of beer on the wall.\n"
    
    assert_equal(expected_lyrics_at_index_zero , result[0])
    assert_equal(expected_lyrics_at_index_ninety_six , result[96])
    assert_equal(expected_lyrics_at_index_ninety_seven , result[97])
    assert_equal(expected_lyrics_at_index_ninety_eight , result[98])
    assert_equal(99, result.size)
  end

  private
  def create_lyrics_for(i)
    result = "#{i} bottles of beer on the wall, #{i} bottles of beer.\n"
    if i == 2
      result += "Take one down and pass it around, 1 bottle of beer on the wall.\n"
    else
      result += "Take one down and pass it around, #{i - 1} bottles of beer on the wall.\n"
    end
  end
end
#ninety_nine_bottle_of_beer.rb
class NinetyNineBottlesOfBeer
  def sing
    result = []
    99.downto(1) do |count|
      if (count == 1)
        lyrics = "1 bottle of beer on the wall, 1 bottle of beer.\n"
        lyrics += "Go to the store and buy some more, 99 bottles of beer on the wall.\n"
      else
        lyrics = "#{count} bottles of beer on the wall, #{count} bottles of beer.\n"
        lyrics += "Take one down and pass it around, "
        if count == 2
          lyrics += "1 bottle of beer on the wall.\n"
        else
          lyrics += "#{count - 1} bottles of beer on the wall.\n"
        end
      end
      result << lyrics
    end
    return result
  end
end

str = NinetyNineBottlesOfBeer.new.sing 
File.open("99bottle.txt","w") do |file|
 file << str
end

リファクタリング

テストコードはプロダクトコードのメソッド名を変更したので、それに伴いテストコード内のメソッド名を変更しました。変更はそれだけです。

$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
require 'test/unit'
require 'ninety_nine_bottle_of_beer'

class NinetyNineBottlesOfBeerTest < Test::Unit::TestCase
  def setup
    @target = NinetyNineBottlesOfBeer.new
  end

  def test_make_lyrics
    result = @target.make_lyrics
    expected_lyrics_at_index_zero = create_lyrics_for(99)
    expected_lyrics_at_index_ninety_six  = create_lyrics_for(3)
    expected_lyrics_at_index_ninety_seven  = create_lyrics_for(2)
    expected_lyrics_at_index_ninety_eight  = "1 bottle of beer on the wall, 1 bottle of beer.\n"
    expected_lyrics_at_index_ninety_eight  += "Go to the store and buy some more, 99 bottles of beer on the wall.\n"
    
    assert_equal(expected_lyrics_at_index_zero , result[0])
    assert_equal(expected_lyrics_at_index_ninety_six , result[96])
    assert_equal(expected_lyrics_at_index_ninety_seven , result[97])
    assert_equal(expected_lyrics_at_index_ninety_eight , result[98])
    assert_equal(99, result.size)
  end

  private
  def create_lyrics_for(i)
    result = "#{i} bottles of beer on the wall, #{i} bottles of beer.\n"
    if i == 2
      result += "Take one down and pass it around, 1 bottle of beer on the wall.\n"
    else
      result += "Take one down and pass it around, #{i - 1} bottles of beer on the wall.\n"
    end
  end
end
class NinetyNineBottlesOfBeer
  def make_lyrics
    result = []
    99.downto(1) do |i|
      lyrics = "#{i} bottle#{"s" if i > 1} of beer on the wall, #{i} bottle#{"s" if i > 1} of beer.\n"
      if (i == 1)
        lyrics += "Go to the store and buy some more, 99 bottles of beer on the wall.\n"
      else
        lyrics += "Take one down and pass it around, #{i - 1} bottle#{"s" if i > 2} of beer on the wall.\n" 
      end
      result << lyrics
    end
    return result
  end
end

lyrics = NinetyNineBottlesOfBeer.new.make_lyrics
File.open("99bottle.txt","w") do |file|
 file << lyrics
end

感想

もっと短く出来るのかなあと考えてみましたが、良い案が浮かびませんでした(^^;

そもそもクラスを作る必要かあるのかも疑問なところです。

今回NinetyNineBottlesOfBeerというクラスを作りましたがクラス名がしっくりきません。

またPoetというクラスを作成しsingメソッドを実装して生成したNinetyNineBottlesOfBeerの詩を渡してPoetに99bottles of beerを歌ってもらうのも面白いかなと思いましたが、そこまで複雑にする必要はないなと思いやめました。

因に99 Bottles of Beerというサイトでは1103種類の異なる言語バリエーションで99 Bottles of Beerのコードを紹介しています。

JoyceJoyce2011/09/08 11:56Okay I'm convinced. Let's put it to aitcon.

bkixldibotpbkixldibotp2011/09/09 00:267PJ9qE <a href="http://dgwfqdyyqqqm.com/">dgwfqdyyqqqm</a>

bgfqywracbgfqywrac2011/09/09 20:4950ykLW , [url=http://pxyavitoqudk.com/]pxyavitoqudk[/url], [link=http://sbysmbdavknc.com/]sbysmbdavknc[/link], http://bfpqukafzeud.com/

zbzbeawjqpzbzbeawjqp2011/09/10 18:26537XoC <a href="http://gtcdcctqzqpu.com/">gtcdcctqzqpu</a>

zdqgxulzdqgxul2011/09/12 19:14DGx0PY , [url=http://synexmpphtlm.com/]synexmpphtlm[/url], [link=http://mfqvmontfsjy.com/]mfqvmontfsjy[/link], http://vhwwuaheevtl.com/