Ruby勉強会@関西 #21に参加

してきました。
初Matzにちょっと興奮しました。気付いてみれば世界のMatzですもんね。あのノリでRubyを新しい方向に導いたりしているわけなんですね。突然、SymbolがStringのサブクラスになっちゃったりして驚かされたりするわけですが、何となく納得できました。はい。

cuzicさんの初心者レッスン。資料・題材とも良くできていたかと思います。ただ、何か「ネタ」な印象の方が強かったのはなぜなんでしょう?(^^;

久しぶりに初心者レッスンの課題をやってみました。結局時間内には書ききれず、帰りの電車までお持ち帰りしましたが、概ね書き終えましたので、整形したものを晒しておきます。
ぎゃくっく(Date#>>(n))がnヶ月先のDateオブジェクトを返すことは知っていたのですが、loopの課題だったので、cuzicさん同様、day=1になるまでインクリメントする戦略を採用しています。
表示ロジックが汚すぎたので、メソッドでバラバラにしてみましたが、まだイマイチです。
インタフェースとしては、引数の数に合わせて、「0:今月」「1:年指定」「2:年・月指定」を用意していますが、その他のオプションは用意していません。
nヶ月分のカレンダーを水平方向に並べるためには、大きめの変更が必要となってしまったのが、心残りです。

require 'date'
require 'enumerator'

class Cal
  MONTH_NAMES = %w(January Febrary March April May June July August September Octover November December )
  WDAY_NAMES = %w(Su Mo Tu We Th Fr Sa)
  N_WDAY = WDAY_NAMES.size
  WIDTH_ONE_DAY = 3

  def self.display(year=nil, month=nil)
    year = Date.today unless year
    if year.kind_of? Date
      month = year.month
      year = year.year
      self.display_year_and_month(year, month)
    elsif month
      self.display_year_and_month(year, month)
    else
      self.display_year(year)
    end
  end
  
  def self.display_year(year)
    1.upto(MONTH_NAMES.size) do |m|
      cal = self.new(year, m)
      cal.display
    end
  end
  
  def self.display_year_and_month(year, month)
    cal = self.new(year, month)
    cal.display
  end

  def initialize( year, month )
    @body = Date.new(year, month, 1)
  end

  def display
    first_wday = find_first_wday
    puts year_line
    puts month_line
    puts wday_names_line
    
    puts all_weeks_lines(first_wday)
  end
  
  def find_first_wday
    @body.wday
  end
  
  def last_day?(date)
    if (date + 1).day == 1
      true
    else
      false
    end
  end
  
  def find_last_day
    last_day = @body.dup
    loop do 
      last_day += 1
      break if last_day? last_day
    end
    last_day
  end
  
  def year_line
    (" " * ((WIDTH_ONE_DAY * N_WDAY - @body.year.to_s.length )/ 2)) << @body.year.to_s
  end
  
  def month_line
    nmonth = MONTH_NAMES[@body.month - 1]
    (" " * ((WIDTH_ONE_DAY * N_WDAY - nmonth.length) / 2)) << nmonth
  end
  
  def wday_names_line
    ret = ("%2s " * N_WDAY) % WDAY_NAMES
    ret.chop
  end
  
  def before_first_day(first_wday)
    ret = " " * (WIDTH_ONE_DAY * first_wday)
  end
  
  def first_week_line(first_wday)
    ret = before_first_day(first_wday)
    nokori_first_week = N_WDAY - first_wday
    ret << "%2s " * (nokori_first_week) % (1..(nokori_first_week)).to_a
    ret.chop!
  end
  
  def nokori_week_line(nokori_first_week)
    ret = ""
    (nokori_first_week..find_last_day.day).each_slice(N_WDAY) do |days|
      ret << "%2s " * (days.size) % days
      ret.chop! << "\n"
    end
    ret
  end
  
  def all_weeks_lines(first_wday)
    nokori_first_day_week = N_WDAY - first_wday + 1    
    first_week_line(first_wday) << "\n" << nokori_week_line(nokori_first_day_week)
  end
  
end

def main0
  puts "test case"
  today = Date.today
  puts "Display Calendar of current month"
  Cal.display; puts
  puts "Display Calendars in 2007"
  Cal.display(2007); puts
  puts "Display Calendar of 30 days ago"
  Cal.display(today - 30)
end

def main1
  params = [ARGV.shift, ARGV.shift]
  params.map!{|x| x.to_i if x }
  Cal.display(*params)
end

if $0 == __FILE__
  main1
end