RotationMaker を作った

最近は iCal づいています。

/lang/ruby/misc/rotation-maker – CodeRepos::Share – Trac

これは何か?

README より抜粋

  • 例えば毎週月曜に何かやります
  • メンバーが 5人いて担当は 2人ずつとします
  • いつ誰が担当するのか先々の予定を算出したい
  • ハッピーマンデーがあるので、その場合は火曜にスライド

みたいなときに便利かもしれないツールです。

使い方

オプションを与えずに起動するとなんとなく分かります。たぶん。

$ ruby rotation-maker.rb
Usage: rotation-maker [options]
    -x, --exclude DATE
        --exclude-from-ical ICS
        --exclude-from-file FILE
        --exmethod [METHOD]
    -s, --dtstart DATE
    -e, --dtend DATE
    -i, --interval INTERVAL
    -d, --date EVENT DATE
        --date-from-ical ICS
        --date-from-file FILE
    -m, --member MEMBER
        --member-from-file FILE
    -a, --atonce NUMBER
    -y, --yaml FILE

最低限必要なものは

  • date
  • member

です。-d や -m を複数書いてもいいですが、それぞれ1行1アイテム形式のファイルから読み込ませることもできます。

また、date ではなく -s START, -e END, -i INTERVAL でくり返しの予定を記述することもできます。INTERVAL は基本的に整数ですが、activesupport をインストールしてあれば week, month, year も指定できます。

exclude で除外する日付を指定します。デフォルトでは除外日に予定が当たったらその日はスキップします。exmethod オプションに backload を与えていたら次の日にずらします。次の日も除外日だったら除外日でなくなるまでスライドします。1

あ、今気づいたけど slide オプションは YAML からしか与えられないじゃないか。後で直します。

YAML で設定を書く場合はこんな感じで書きます。

dtstart: '2008-12-01'
dtend: '2009-03-31'
interval: week
atonce: 2
exmethod: backload
members:
  - abc
  - def
  - ghi
  - jkl
  - mno
  - pqr
  - stu
excludes:
  # PATH or URI
  ical: http://www.google.com/calendar/ical/japanese%40holiday.calendar.google.com/public/basic.ics

出力部分は自分で書いてください^^;

例えばこんな感じのものを用意すると iCal 形式で予定を吐き出せます。

#! /usr/bin/env ruby
# -*- coding: utf-8 -*-

require File.dirname( __FILE__ ) + '/rotation-maker'
require 'erb'
require 'nkf'

def main
  rot = RotationMaker.new.run
  puts NKF::nkf( '-w -Lw', ERB.new( template, nil, '-' ).result( binding ) )
end

def serialized_time( time )
  return time.gsub( /-/, '' )
end

def template
  return <<EOD
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Asia/Tokyo
X-LIC-LOCATION:Asia/Tokyo
BEGIN:STANDARD
TZOFFSETFROM:+0900
TZOFFSETTO:+0900
TZNAME:JST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
<%- rot.each do |r| -%>
BEGIN:VEVENT
SUMMARY:社内勉強会
DESCRIPTION:発表 <%= r['member'].join( ', ' ) %>
DTSTART;TZID=Asia/Tokyo:<%= serialized_time( r['date'] ) %>T180000
DTEND;TZID=Asia/Tokyo:<%= serialized_time( r['date'] ) %>T190000
END:VEVENT
<%- end -%>
END:VCALENDAR
EOD
end

main

結果はこんな感じ。

ハッピーマンデーを除けてスケジューリングできた様子

あ。あれ? Google Calendar にある Japanese Holidays の成人の日の情報が

DTSTART;VALUE=DATE:20090112
DTEND;VALUE=DATE:20090113
DTSTAMP:20081203T115909Z

になってますね。見た目は 12日だけに見えるんだけど。えーまぁ、これはデータの問題ということで。

問題というか

iCal の Rrule 2って、くり返しの終了が指定されていない場合、無限に続いてしまいますよね? これをどう扱ったらいいのかが全然分かっていません。今回、除外日を設定できるようにしたため、除外日を Array にして Array#include? でチェックしているのですが、Array で無限なんて扱えないですよね。

実際には Vpim::Icalendar がイベントの日時情報を DateTime ではなく Time で扱っているため、2037年問題に引っかかって有限の配列を取得することができているのですが、本当に無限のものを扱いたい場合は全部を計算で扱う Array 以外の何かが必要になるんじゃないかと思っています。とにかく動くものを作りたかったのでその辺突っ込んで調べてませんが。

またこのため Time の ArgumentError を rescue してそのまま知らん顔するという暴挙に出ています。こんなんじゃいかんよなぁ。limit を設けるようにした方がいいのか、Icalendar に戻した方がいいのか。Icalendar は DateTime で扱っているので少なくとも 2037年問題には引っかからなそうなのですが。Icalendar にこの include?( date ) みたいな便利メソッドがあれば Array に展開することなく処理を続けられるのかな。ただ、実際にはどこかで区切らないと処理が終わらないのでどっちみち limit は要るのか。

Icalendar は Icalendar で to_ical がマルチバイト文字列をぶった切る問題があるしなぁ。ふーむ悩ましい。

何かご存知の方はツッコミください。

TODO とか

  • slide オプションをコマンドラインからも与えられるようにする
  • slide オプションで予定の前倒しもできるようにする
  • 土日を除外するのはもっと簡単にできてもいいような気がする

げ。

*atonce をコマンドラインから与えられるようにする><

参考

2008-12-04 追記

前のエントリのツールも一緒に checkout できるようにしました。手軽に cat できるなら月水金カレンダーとかでも割とすぐ作れるので、こっちで頑張りすぎる必要ないかなぁという気がしてきました。

  1. 年末年始分、丸ごとスライドさせることもできます。 

  2. 例えば毎週月曜といった形で設定されたイベント 

先読みと後読みの間

ときどきの雑記帖 リターンズ 2006年12月

連続だ。

dereference を日本語にしようとすると悩みませんか? referece は「参照」で固まっちゃってますが、dereferece を日本語の名詞で表そうとするとぴったり来るものがないと思うのですが。

自分が悩むのは正規表現の lookahead と lookbehind ですね。まぁ自分で訳してて悩むってわけじゃなくて、日本語のページを読んでいても意味が分からなくて英語の方を読んだら分かった、ということなんですが。

ちなみにサンプルを書くとこういうやつね。

先読み lookahead
RE(?=re)
RE(?!re)
後読み lookbehind
(?<=re)RE
(?<!re)RE

先読みは比較的多くの実装で使えるけど、後読みは使えないものが結構多くて困る。個人的に困ったのは Ecma262 3rd で使えなかったとき。

で、なんで悩んだかっていうと、この先と後がどうも時間軸のことを言っているように読めてしまったから。違うんですね。マッチさせたい正規表現の前方にどのような文字列がくるか、あるいはこないか、後方にどのような文字列がくるか、あるいはこないか、ということなんですな。before, after のことではないと。

たぶん前方後方って書いちゃうと後方参照(backreference)と紛らわしいから先読み後読みになったんだろうなぁ。この辺の表現てどうも日本語は弱いですな。

NFS と uid, gid

最近になってようやく NFS の便利さを実感しているわけですが、ここでちょっといやな感じの発見が。それは

各システムで uid, gid が合ってない

って辺り。まぁユーザーが手作業でいじるデータについてはそんなに影響がないんですが(まだ大人数管理とかしてないし)、デーモンがアクセスするファイルになるとちょっと勝手が変わってきますね、これ。

例えば Web サーバの権限で生成、更新を行っているファイルを NFS でマウントした領域に置くとすると、NFS クライアントが思っている owner の意味と NFS サーバが思っている owner の意味が食い違ってくるわけです。NFS サーバがそれ以外何も仕事をしていないならいいですけど、例えば予備機として、自分のローカルのディスクにあるデータを活かしてそのままサービスを提供できるようにしときたいじゃないですか。でも uid, gid が合ってないとそれができないわけです。また、NFS サーバはそのままで、NFS クライアント側をリプレイスする際も、uid, gid が一致しているかどうかを気にしておく必要があります。

chown, chgrp し直せばいいだけの話っちゃ話なんですが、できるだけダウンタイムを短くしようと思うなら、これは統一しておいた方がよさげですね。気づかずにハマりそう。

ちらっと見た限りでは、個人的には FreeBSD の一部のデーモン用の id の振り方が好きですね。例えば www は 80, bind は 53, sshd は 22 など、デフォルトの port と一致しているのですぐに把握できます。今後はこれを参考にしていこうっと。

あ。Linux の exports には uid, gip の map 機能があるのか。これは使える。FreeBSD は maproot と mapall しかないんだよな。これでも本当は十分なのかもしれないけど。

勉強することが多すぎるよね

embrace the conflict – 葛藤を楽しもう

なるほどなぁ、と。整然としていて参考になります。

自分の中で葛藤というのは非常にイメージの悪い言葉なのでできるだけ使いたくはないんだけど、これが衝突であればすっきりと飲み込めます。タイミング的に、社会そのものの多様化とオープンシステムの文化がソフトウェアにまで浸透した時期1がある程度一致しているように見えるのは偶然なんですかね?

しかしこうなって思うのは、「従前の学校文化」での学習はなんて楽ちんだったんだ、ってことですな。まぁ向き不向きがあるので「従前の学校文化」の学習が楽だった人とそうでない人がいるのは承知のうえですが、それでも何を学ぶかは自分で探したり考えたりする必要はなかったので、その分の負担は減るわけです。同じようにいわゆる伝統的な職人芸的世界も、基本的に学習というか習熟パスに大きな変化や断絶や複線化なんつーのはないわけです。ところが今は学習対象について習熟していくと同時に、その学習対象を取り巻く環境も学ばなければならない。面倒くさいけどやらなしゃーない。

自分はこの部分を学ぶときにこそ、コミュニケーションが大事なんじゃないかと思います。だから自分はテーマが絞られてしまったコミュニティにはあまり興味がないのですな。例えばソフト畑においてある特定の言語、ある特定のプラットフォームに関してのみ扱うコミュニティではその外の文化とのギャップがよく分からなくなってしまう。これはちょっと避けたい。2

しかし実際にはこの異文化をそのまま並存(共存とは限らない)させるコミュニティというのはとても運営が難しい。そこに参加するのも難しい。ある程度は、軸を絞ることで実現できると思うけど、その軸を設定できる分野とできない分野、論理的に設定はできるけど心情的に設定できない分野があるでしょうね。かといって本当に雑然としたままとりあえず並立させちゃう 2ch 式コミュニティはノイズが多すぎてコストが大きい。適切なサイズで、適切なコストで参加できるコミュニティ。「ないものは作れ」精神もときに必要になるのでしょう。

  1. いわゆるオープンソースに対してこの説明は不十分なんだけど 

  2. もちろん他のコミュニティのやりとりを ROM るという手はあるだろうけど、ROM だけで得られる情報には限界がある。 

About

例によって個人のなんちゃらです