第4回勉強会@minami.rb に参加してきた。
http://qwik.jp/minamirb/57.html
その中での1セッション 『TDD テスト駆動開発入門』(by yalabさん)での課題が時間内に終わらなかったので復習をかねて最後までやり遂げる事に。ruby はそんなに書きなれていない事もあり、なかなか手間取ったがやっと課題の要件はみたす事ができたので、ここに晒しておく。
ruby ではそうじゃないよとか、普通はこうだよね。的なツッコミを入れていただけると有難いです。
時間がかかったポイントとしては ruby の実装不足。慣れてないのが大きいのかなと。
ただコーディングするだけならすぐかもしれないが、いかにrubyっぽく綺麗に書けるのだろうかと考えながらだったからのような気がします。実際このコードが rubyの暗黙の美的センスに乗っ取っているかどうかはわからないのですが、極力そうしたつもり。
for とか while とかでぐるぐるまわして if で条件分岐してどうたらとかいうのは、なるべくしたくないですし。
こういう積み重ねが大切ですね。
まぁ、とりあえずこんな感じで一旦アップしておきます。
ちょっと思うところがあるので、これに手を入れてすぐに第2版をアップしたいと思います。
課題
http://www.slideshare.net/yalab/ss-6749458
・月末を返す last_day メソッドを作ってください。
・第一週の日曜日 (先月の最後の日曜日かもしれない)を返すメソッドを作ってください。
・最終週の土曜日(次月の最初の土曜日かもしれない)を返すメソッドを作ってください。
・各週と各日を操作するeach_weekとeach_dayを作ってください。
・月曜始まりと日曜始まりの両方を使えるようにしてください。
calendar.rb
カレンダー
calendarTest.rb
カレンダーのテストクラス
これが重要。これのおかげで一旦完成した後も躊躇なくリファクタリングを進める事ができる。
常々思っている事なのだが、テストコードは人の為と云うよりも自分の安心の為に書くものだと思う。
実行結果
$ ruby calendarTest.rb
Loaded suite calendarTest
Started
................
Finished in 0.02391 seconds.
16 tests, 16 assertions, 0 failures, 0 errors
Calendar.rb
class Calendar
attr_reader :first_day
attr_reader :last_day
attr_reader :base_cwday</p>
<p>def initialize(year, month, base_cwday = "Sun")
@first_day = Date.new(year, month, 1)</p>
<h1>@last_day = (Date.new(year, month, 1) >> 1) - 1</h1>
<pre><code>@last_day = (Date.new(year, month, -1))
@base_cwday = Date::ABBR_DAYNAMES.index(base_cwday)
</code></pre>
<p>end</p>
<p># カレンダー表示上の最初の日を返す
def display_first_day
return @first_day - @first_day.cwday + @base_cwday
end</p>
<p># カレンダー表示上の最後の日を返す
def display_last_day
return @last_day + (6 - @last_day.cwday + @base_cwday)
end</p>
<p># 当月すべての日を週ごとに配列にして返す
def each_week
weeks = Array.new()
display_first_day.step(display_last_day, 7) {|wd|
week = Array.new()
wd.step(wd + 6, 1) {|d|
week < < d if first_day.month == d.month
}
weeks << week
}
return weeks
end</p>
<p># 当月すべての日を配列にして返す
def each_day
days = Array.new()
@first_day.step(@last_day, 1) {|date|
days << date
}
return days
end
end
CalendarTest
require 'test/unit'
require 'date'
require './calendar'</p>
<p>class CalendarTest < Test::Unit::TestCase</p>
<p># 基本パターン
def test_first_day_201101
actual = Calendar.new(2011, 1)
assert_equal Date.new(2011, 1, 1), actual.first_day
end</p>
<p># 固定値で返してないか別の月で確認
def test_first_day_201102
actual = Calendar.new(2011, 2)
assert_equal Date.new(2011, 2, 1), actual.first_day
end</p>
<p># 日数 31日
def test_last_day_201101
actual = Calendar.new(2011, 1)
assert_equal Date.new(2011, 1, 31), actual.last_day<br />
end</p>
<p># 日数 28日
def test_last_day_201102
actual = Calendar.new(2011, 2)
assert_equal Date.new(2011, 2, 28), actual.last_day<br />
end</p>
<p># 日数 29日
def test_last_day_201002
actual = Calendar.new(2012, 2)
assert_equal Date.new(2012, 2, 29), actual.last_day<br />
end</p>
<p># 日数 30日
def test_last_day_201004
actual = Calendar.new(2010, 4)
assert_equal Date.new(2010, 4, 30), actual.last_day
end</p>
<p>## display_first_sunday
# カレンダー上の最初日曜が前月にあるパターン
def test_display_first_day_feb
feb = Calendar.new(2011, 2)
assert_equal Date.new(2011, 1, 30), feb.display_first_day
end</p>
<p># カレンダー上の最初日曜が前月にあるパターン(月曜始まり)
def test_display_first_day_feb_Mon
feb = Calendar.new(2011, 2, "Mon")
assert_equal Date.new(2011, 1, 31), feb.display_first_day
puts feb.base_cwday
end</p>
<p># カレンダー上の最初日曜が前年前月にあるパターン
def test_display_first_day_jan
feb = Calendar.new(2011, 1)
assert_equal Date.new(2010, 12, 26), feb.display_first_day
end</p>
<p>## display_last_saturday
# カレンダー上の最終土曜が翌月にあるパターン2
def test_display_last_day_201101
actual = Calendar.new(2011, 1)
assert_equal Date.new(2011, 2, 5), actual.display_last_day
end</p>
<p># カレンダー上の最終土曜が翌年翌月にあるパターン
def test_display_last_day_201012
actual = Calendar.new(2010, 12)
assert_equal Date.new(2011, 1, 1), actual.display_last_day
end</p>
<p># カレンダー上の最終土曜が翌年翌月にあるパターン(月曜始まり)
def test_display_last_day_201012_mon
actual = Calendar.new(2010, 12, "Mon")
assert_equal Date.new(2011, 1, 2), actual.display_last_day
end</p>
<p># カレンダー上の最終日が当月にあるパターン
def test_display_last_day_201104
actual = Calendar.new(2011, 4)
assert_equal Date.new(2011, 4, 30), actual.display_last_day
end</p>
<p># カレンダー上の最終日が当月にあるパターン(月曜始まり)
def test_display_last_day_201107_mon
actual = Calendar.new(2011, 7, "Mon")
assert_equal Date.new(2011, 7, 31), actual.display_last_day
end</p>
<p>def test_each_week
actual = Calendar.new(2011, 1)
expect = [
Array.new(1) { |i| i+1 },
Array.new(7) { |i| i+2 },
Array.new(7) { |i| i+9 },
Array.new(7) { |i| i+16 },
Array.new(7) { |i| i+23 },
Array.new(2) { |i| i+30 },
]
weeks = Array.new()
expect.each { |e|
week = Array.new()
e.each { |d|
week << Date.new(2011,1,d)
}
weeks << week
}
assert actual.each_week == weeks
end</p>
<p>def test_each_day
actual = Calendar.new(2011, 1)</p>
<pre><code>array = Array.new([])
(1..31).each { |day|
array << Date.new(2011,1,day)
}
assert actual.each_day == array
</code></pre>
<p>end</p>
<p>end