「プログラミング」の概念を破壊するutil atnow
開発::util
atnow 3
atnowというプログラムはこれまでも存在した(しばらくGitHubからは消えていた)が、今回は少しコンセプトが違う。
これまでatnowはリアルタイムアクションを記録し、自信のそのときの行動を明らかにすることが主な目的であり、手動入力というのは補助的な位置づけであった。これを補完する存在としてDiary utilというものもあった。
atnow, Diary utilともに使い勝手がいまいちで、GitHubから取り下げていた。
コード概要
公開したバージョンは少し手の込んだものになっているが、当初はファイルロックなどもない、ほとんどyadが中心になったコードだった。つまり、公開バージョンでは紛れているが、もともとのバージョンでは「プログラミングとは」という概念を覆すようなコードだったのだ。
どういうことか。
普通、プログラミングというのはよく言われる様々な技法や技巧を用いて組まれるものであり、またプログラムは「あるべき形」に沿うものであるという考え方が普通である。 故に、複数のプログラミング言語を組み合わせること自体が、あまり一般に受け入れられるものとはいい難い。
だが、atnow3はRubyで書かれてはいるものの、Rubyである必然性はほとんどない。 Rubyで書いているのは、この手のグルーコードを簡潔に書けるから、に過ぎない。
どちらかといえば、シェルスクリプトで書くようなコードだが、実際にこのスクリプトはBashやZshなら書けはするが(Bashのほうがいくらか簡単だが)、シェルスクリプトで書くのはあまり適していない、と感じることになるだろう。
コード解説
atnowの主たる部分はYadが担っている。 これによって非常に簡単になっているのだが、一方で制約にもなっている。
単にYadでtweetするだけなら簡単だが、atnowは右クリックしたときのメニューからtweetsが見られるようになっている。
これをするためには、既に起動したYadを更新する必要がある。
--listen
オプションによって実現可能だが、そのためにはYadに対して標準入力で随時コマンドを与えなければならない。
シェルスクリプトでもFIFOを使うなどすれば可能だが、
exec 3<> $FIFO
のような非常に見慣れないコードを書くことになる。 そのため、シェルスクリプトよりもRubyを使うほうが楽なのだ。
RubyにおいてもFIFOを使うなどの方法はあるが、ここではパイプを使っている。
直接パイプを使う(IO.pipe
とKernel#fork
を使う)方法もあるが、ここでは1組あれば良いため、IO.popen
を使っている。IO#pid
はあまり使うことのない珍しいメソッドだ。
これにより、YadがSTDINで待機しているYadコマンドを、Rubyで任意に投げられるようになる。 といってももうひとつの問題が、tweetとタイムラインの更新はYadによって発動する、ということだ。
Yadはトリガーに対してコマンドを使うことができるようになっているが、これはあくまでコマンドを起動できるだけだ。bash -c
などのコマンドを使えば複合コマンドも打てるが、どうしてもYadのSTDINにつながっているRubyプロセスに渡らなくてはならない。
その最も簡単な方法がシグナルだ。 シグナルはOSに組み込まれたメカニズムで、簡単なプロセス間通信を可能にする。
Yadでtweetを行い、tweet後の更新をRubyで行う、と考えてしまうと複雑だが、その流れは不可分であると言えるし、単にそのフローに入ったことをRubyに伝えられればそれで十分だ。
そこで、atnowではYadはクリックされると親プロセス、つまりYadを起動したRubyプロセスに対してSIGHUP
を送信する。
atnow
RubyプロセスはSIGHUP
をトラップするようになっており、そのトラッピング関数の中でさらに別のYadを起動し、tweetとタイムラインの更新を行うようになっている。
つまり、このコードはプロセス、パイプ、シグナルといったOSレベルのメカニズムを積極的に活用することでシンプルに仕立てられており、「プログラミングの作法」というよりも、まずシステム、OSの基礎を理解しているかどうかが問われるコードで、そこを理解していれば簡単に書けるコードでもある。
このため、プログラミングの技巧に当てはめて優劣や難易を考えるのはとても難しい。 そういうコードだ。
だが、これが実用的なコードであるということを示されて、目からウロコという人もいるのではないだろうか。 Linuxer, Unicianであれば割と自然な感覚であり、シェルスクリプトの発展形としてPerl, Python, Rubyなどで書くことも多いコードではあるが、「プログラマ」であればあまり考えることのないコードだろう。
どうだろう、何か思うところはないだろうか?
なお、tweetといっているが、英語ではmurmurになっていて、このプログラムはTwitterクライアントではない。 もっとも、応用すればTwitterクライアントになるはずだが、RubyでアクティブなTwitterライブラリもないし、開発者キーを公開する気にもならないので、このプログラムはそういうものではない。
開発動機
就職してから、会社の中のコードの話は外ではできないので、色々思うことがあっても黙ってるしかなくて息苦しくなってしまったので、気軽に吐き出せる環境を作りたかったのと、 結構考えるべきことが多くて、作業中にもともとどういうコールスタックでここにきたのかわからなくなってしまうことが多かったので、辿れるようにしたくて書いた。
動機からして従来のatnowとは結構違う。
ただし、公開版ではちゃんとflockするようにしているし、要はatnowプロセスにSIGHUP
を送ればtweetできるので、プログラムから利用するのも結構簡単。