calendar_helperの頭の悪い携帯対応

vendor/plugins/calendar_helper/lib/calendar_helper.rb の、calendar メソッドの #TODO〜 からメソッドの最後までをこのように書き換えてみた…。

    # 自前テンプレートエンジンtmp。リクエストが携帯かどうかで切り替える。
    tmp = request.mobile? ? lambda do |tn|
      # 携帯の場合
      case tn
      when :table_start
        "<pre>"
      when :thtr
        ""
      when :pmt
        " %s " % options[:previous_month_text]
      when :month_name
        lambda do |colspan|
          "        %4s         " % Date::MONTHNAMES[options[:month]]
        end
      when :nmt
        " %s " % options[:next_month_text]
      when :h_to_dn
        "<br>"
      when :dn
        lambda do |d|
          " %s" % d[options[:abbrev]]
        end
      when :dn_to_b
        "<br>"
      when :td_om
        lambda do |d|
          " <font color='#999999'>%2d</font>" % d.day
        end
      when :td
        lambda do |cell_attrs, cell_text|
          " %2s" % cell_text
        end
      when :newline
        "<br>"
      when :table_end
        "</pre>"
      end
    end : lambda do |tn|
      # PCの場合
      case tn
      when :table_start
        %(<table class="#{options[:table_class]}" border="0" cellspacing="0" cellpadding="0">)
      when :thtr
        %(<thead><tr>)
      when :pmt
        %(<th colspan="2">#{options[:previous_month_text]}</th>)
      when :month_name
        lambda do |colspan|
          %(<th colspan="#{colspan}" class="#{options[:month_name_class]}">#{Date::MONTHNAMES[options[:month]]}</th>)
        end
      when :nmt
        %(<th colspan="2">#{options[:next_month_text]}</th>)
      when :h_to_dn
        %(</tr><tr class="#{ options[:day_name_class]}">)
      when :dn
        lambda do |d|
          unless d[options[:abbrev]].eql? d
            "<th scope='col'><abbr title='#{d}'>#{d[options[:abbrev]]}</abbr></th>"
          else
            "<th scope='col'>#{d[options[:abbrev]]}</th>"
          end
        end
      when :dn_to_b
        "</tr></thead><tbody><tr>"
      when :td_om
        lambda do |d|
          cls = options[:other_month_class] + (weekend?(d) ? " weekendDay" : "")
          "<td class=\"#{cls}\">#{d.day}%s</td>" %
            (options[:accessible] ? "<span class=\"hidden\"> #{Date::MONTHNAMES[d.month]}</span>" : "")
        end
      when :td
        lambda do |cell_attrs, cell_text|
          "<td #{cell_attrs}>#{cell_text}</td>"
        end
      when :newline
        "</tr><tr>"
      when :table_end
        "</tr></tbody></table>"
      end
    end

    # カレンダー構築
    cal = tmp.call(:table_start)
    cal << tmp.call(:thtr)
    if options[:previous_month_text] or options[:next_month_text]
      cal << tmp.call(:pmt)
      colspan=3
    else
      colspan=7
    end
     cal << tmp.call(:month_name).call(colspan)
    cal << tmp.call(:nmt) if options[:next_month_text]
    cal << tmp.call(:h_to_dn)
    day_names.each do |d|
      cal << tmp.call(:dn).call(d)
    end
    cal << tmp.call(:dn_to_b)
    beginning_of_week(first, first_weekday).upto(first - 1) do |d|
      cal << tmp.call(:td_om).call(d)
    end unless first.wday == first_weekday
    first.upto(last) do |cur|
      cell_text, cell_attrs = block.call(cur)
      cell_text  ||= cur.mday
      cell_attrs ||= {:class => options[:day_class]}
      cell_attrs[:class] += " weekendDay" if [0, 6].include?(cur.wday)
      cell_attrs[:class] += " today" if (cur == Date.today) and options[:show_today]
      cell_attrs = cell_attrs.map {|k, v| %(#{k}="#{v}") }.join(" ")
      cal << tmp.call(:td).call(cell_attrs, cell_text)
      cal << tmp.call(:newline) if cur.wday == last_weekday
    end
    (last + 1).upto(beginning_of_week(last + 7, first_weekday) - 1)  do |d|
      cal << tmp.call(:td_om).call(d)
     end unless last.wday == last_weekday
    cal << tmp.call(:table_end)

元のソースを切り貼りすることで携帯対応させることをテーマに、クロージャとしてのProcオブジェクトを最大限活用。コルーチンとか使ってみようとしたが、あくまで部分テンプレートを明示的に指定したかったので却下。RubyLISP的なとこってこういうとこなのだろうか。