Ruby手習い(Dateクラス)
アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問) - give IT a try
上記記事のカレンダー作成問題。
出力結果
p-064% ruby calendar.rb May 2019 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
自分で書いたコード
require 'date' def main puts calendar end def calendar today = Date.today title = today.strftime("%B %Y").center(20) head = "Su Mo Tu We Th Fr Sa" last_day = Date.new(today.year, today.month + 1, -1).day wday = Date.new(today.year, today.month, 1).wday body = " " * wday d = 1 (1..last_day).each do body << d.to_s.rjust(2) d += 1 wday += 1 body << (wday % 7 == 0 ? "\n" : " ") end [title, head, body].join("\n") end if __FILE__ == $0 main end
出題者による回答例
require 'date' class CalendarRenderer DAY_LENGTH = 3 WEEK_LENGTH = DAY_LENGTH * 7 def initialize(year, month) @first_date = Date.new(year, month, 1) end def to_s (header_rows + body_rows).join("\n") end private def body_rows split_pattern = /.{#{DAY_LENGTH},#{WEEK_LENGTH}}/ body_text.scan(split_pattern) end def body_text first_week_offset + calendar_text end def first_week_offset ' ' * @first_date.wday * DAY_LENGTH end def calendar_text last_day = @first_date.next_month.prev_day.day rjust_all 1..last_day end def header_rows [month_year, sun_to_sat] end def month_year indent_length = 1 @first_date.strftime("%B %Y").center(WEEK_LENGTH + indent_length).rstrip end def sun_to_sat rjust_all %w(Su Mo Tu We Th Fr Sa) end def rjust_all(enum) enum.to_a.map{|e| e.to_s.rjust(DAY_LENGTH) }.join end end
- (ちょっと仕様=インターフェースがちがう)
- 1日当たりの幅を定数で指定できるようにしてる。
- 1日から最終日までの文字列をつくってから、カレンダーの幅でsplit → \nでjoin なるほど、これが最大の違い。まず材料をつくって、それを整形するというこっちの処理の方が拡張性高そう。発想できたかったな。