history

青木日記 RSS

<前月 | 最新 | 次月>

2006-09-01

:

バカ逝くで出てきた、sh の「:」(ヌルコマンド) について。 ああ、そんなのあったなあと思いつつも、 何に使うのか思い出せなかったので、調べました。 『入門UNIXシェルプログラミング』で。 これはまじでいい本です。

この本には次のような使い道が書いてあった。

  • if や while の条件式で、常に true になる式として使う。
  • if の then 節や else 節で、何もしないときに使う。
  • コマンドの引数だけ評価するときに使う (例えば : ${var ? "var is not set"} とか)。
  • リダイレクトと組み合わせて touch や truncate の効果を出す。

ところで、Linux だと /bin/sh がフツー bash なのでわりとなんでも通っちゃうけど、 商用 UNIX をさわってみると制限ありまくりで泣けるよね。 そのてん『入門 UNIX シェルプログラミング』 は各種商用 UNIX でもちゃんと通じる書きかたが書いてあるので非常に助かりました。 なにしろ原題は "Portable Shell Programming" だし。

(05:26)


2006-09-04

(12)

Ruby リファレンスマニュアル刷新計画は 元々 ruby-reference-manual ML でやってることなので、 参加したい人はまずそっちに入っといてください。 この日記にも進捗は書きますけど、あくまで ML がメインなので。

参加方法

To: ruby-reference-manual@ml.fdiary.net
Cc: aamine@loveruby.net
Subject: 参加希望

で、本文には

  • Rubyリファレンスマニュアルの便利な点
  • Rubyリファレンスマニュアルの不便な点
  • その他リファレンスマニュアルについて思うこと

を書いてください。ML のログはこちら。

http://www.fdiary.net/ml/ruby-reference-manual/

(21:16)

『GNU 開発ツール』

『GNU 開発ツール』届く。

うわ、これは……装丁がカッコイイ! でもこれは卑怯でしょ。 タイトルが日本語なら表紙にも日本語で書けえええ!

しかも紙が厚いし二色刷り。金かかりそー! でもフォントは明朝のがよかったなあ。

(21:23)


2006-09-09

Development Environment Conference

開発環境カンファレンスで発表してきました。 聞いてくださったみなさん、ありがとうございました。

他の人達がすげーまっとうにツールとかの紹介をしてたのに対して、 わたしは old type バリバリのプレゼンをやってきました。

PowerPoint のファイルもあげときますが、 台本のほうが本文があって読みやすいと思うので、 そちらを以下にダラダラとつなげます。

DEC/1: イントロ

こんにちは、日本 Ruby の会の青木と言います。 今日は「オレポータビリティ」というテーマで 開発環境について話したいと思います。

自己紹介

まず簡単に自己紹介をしておきます。

自己紹介 (1)
* 学生
* 専門は……哲学?

ふだんは大学生をやっております。 専門は強いて言うと哲学で、 プログラムは全然関係ありません。

ということは、

開発と言えば自宅

わたしにとって開発と言えば自宅でやるものです。

自己紹介 (2)
* Ruby 関係者
* 標準添付ライブラリ メンテナ
* 著書いろいろ

それから、普段は Ruby 方面で活動しています。 標準添付ライブラリをいくつか自分で書いて メンテしていますし、レポジトリのコミット権も持ってます。 その他にアプリケーション、ライブラリもいろいろと書きました。

それから本もいろいろ書きました。 具体的には、

著作
『ふつうのHaskellプログラミング』
『ふつうのLinuxプログラミング』
『Javaを独習する前に読む本』
『Rubyレシピブック』
『Rubyソースコード完全解説』
『Rubyを256倍使うための本  無道編』

ふつうのHaskellプログラミング や、 ふつうのLinuxプログラミング などです。

で、まあ、なにぶん Ruby 関係者ですので、

言語は
ほぼ確実に
RubyかC

プログラミングするときはほぼすべて Ruby か C です。

本当は Ruby だけいじって済ませたいんですが、 人が調子よくコマンドラインをたたいてるときに限って、

./lib/bitchannel/syntax.rb:398:
[BUG] Segmentation Fault
ruby 1.9.0 (2005-10-22) [x86_64-linux]

「……あれっ?」 なんてことが、起きるわけです。 こういうときはしょうがないので C プログラマになって ruby 本体をいじります。

DEC/2: 「開発環境」の定義

さて、今日は開発環境カンファレンスってことですが、 開発環境ってのもけっこう曖昧な言葉ですよね。 依頼されたときに何をしゃべろうか迷いました。

そこで、わたしはこの「環境」という単語を できるだけ広くとらえることにしました。

部屋

まず部屋。 これは当然開発環境でしょうね。

ハードウェア

それからハードウェア。

ソフトウェア

最後にソフトウェア。

この部屋、ハードウェア、ソフトウェアを 全部ひっくるめて開発環境と考えて、 この順番で話していきたいと思います。

DEC/3: 部屋の様子

そこで まず わたしの部屋から始めたいと思います。

こんな感じです。

わたしには 「ヒューマンインターフェイスには金をかける」 という信条があるので、 モニタと椅子だけは高いのを使ってます。

もっとも、そんなこと言いながらマウスは 1500 円です。

(あとで高林さん (だったかな) から質問があったので追記: 椅子はコンテッサ。ついでにモニタは EIZO FlexScan L665)

ちなみに後ろはこんな感じで、

本棚で埋めつくされてます。

で、またデスクトップに戻ります。

キーボードをよく見てもらうと、 これ、右側が切断されてます。

テンキーなんてぜんぜん使わないくせに 場所を食って邪魔だったので、 のこぎりで切り落としてしまいました。 こうするとナチュラルキーボードも コンパクトになって便利です。

DEC/4: ハードウェア

ところで、さきほどの写真では机の右側のほうを わざと写さなかったんですが、 ここに何があるかと言うと……

こういうものがあります。 これ全部コンピュータです。 写真に映っていないものも含めて すべて合わせると 20 台くらいあります。

しかもこれ、普通のパソコンばっかりじゃありません。 中には Alpha とか SPARC とか POWER が混じってます。 具体的には、

5 つのアーキテクチャ
x86, AMD64, Alpha, SPARC, POWER

アーキテクチャ 5 つ

7 つの OS
Linux, FreeBSD, NetBSD, Windows,
Solaris, Tru64UNIX, AIX

オペレーティングシステムが 7 つ。 組み合わせだと、

9 つのプラットフォーム
Linux/x86
Linux/AMD64
Linux/Alpha
FreeBSD/Alpha
NetBSD/Alpha
Tru64UNIX/Alpha
Solaris/SPARC
AIX/POWER
Windows/x86

9 つのプラットフォームがあります。

(注釈: 実は、 Development Environment Conference なので、DEC つながりで AlphaStation 500 の実物を持ってくる予定だった。 しかし出発の 30 分前に挫折)

「こんなに たくさんあって どうすんの?」

さて、マシンが 20 台くらいあるぜー、 と言うと、たいてい 「こんなにたくさんあって何に使うんだ」 と聞かれるんですけど、 主な役割は

愛でるため

愛でることです! なでて、

紺匡体
萌え〜

紺匡体萌えー と叫ぶためにあるんです。

まあ、そんなわけで、 マシンたちは なでるためにあるんですが、 せっかくマシンがたくさんあるわけですから、

ついでに
Ruby のテストも
している

ついでに Ruby のテストもしているわけです。

DEC/4: テーマ解説

ようやく今日のテーマにたどりつきました。

前提:
マシン台数も
プラットフォームも
多すぎる

わたしの開発環境は アーキテクチャも OS も多すぎます。 そのような状況だからこそ、

オレポータビリティ

今日のテーマである 「俺 - portability」の話になるのです。 この オレ ポータビリティ というのは、

俺 (の) portability

……の、ことです。 つまり、自分自身の portability のことです。 「ポータブルなプログラム」と言えば いろいろな環境において 動作するプログラムのことですね。 「俺がポータブルである」というのは、 いろいろな環境でも同じように開発できる、 ということです。

どんな環境でも
同じように開発できる
 
→ オレポータビリティが高い!

今日はオレポータビリティを高める 戦略について話そうと思います。

DEC/5: 戦略 (1) 必須ソフトウェアを限界まで削る

オレポータビリティを高める戦略、その 1 は、 どうしてもこれでなきゃだめ、 ないと死んじゃう、 というソフトウェアを減らすことです。

なぜかと言えば、

どこでも使える
ソフトウェアが
そもそも少ない

プラットフォームの種類が多い場合、 どこでも動くソフトウェアは限られます。 例えば IDE なんて絶望的です。

たくさんソフトウェアを
使うとインストールがめんどくさい

しかも、たくさんインストールしないといけないと インストールだけでバカみたいに手間がかかります。 パッケージシステムがどこにでもあるわけでは ないですから。

実例を見てみます。 例えばこれはメインマシンのデスクトップです。

old type な人にありがちな、 味も素気もないデスクトップですね。 端末を 2 枚ひらいて、 右の端末でコード書いて、 左の端末でコマンドを打ちます。

このキャプチャに映ってる端末は rxvt なんですが、 別に rxvt でなければまずいわけではありません。 ちゃんと使えれば何でも使います。

ウィンドウマネージャは sawfish ですが、 これもやっぱりこだわってません。 単に Debian デフォルトだったから使ってるだけです。 だいたい何を使ってもそのうち慣れます。

画面は Linux ですが、別に Windows でもいいんです。 実際、このノートパソコンには Windows XP が入ってます。 Linux についても、 GNOME や KDE を使おうが使うまいがどっちでもいいんです。 どっちを使ってようと慣れれば大丈夫です。

で、端末やウィンドウマネージャは何でもいいとして、 必ずこれを使う、というものもあるわけです。 必ず使うのはこういうプログラムです。

必ず使うソフトウェア
* Ruby
* C コンパイラなど
* zsh
* CVS or Subversion
* vi
* 独自の開発ツール

順番に詳しく見ていきます。

使うプラグラム (1)
Ruby
開発版 + 安定版ぜんぶ

まず当然 Ruby。 Ruby プログラムを書くのに Ruby がないと話になりません。

わたしは Ruby は開発版の最新を使うことに しているので、OS をインストールしたら まず CVS trunk HEAD を自分でコンパイルします。

さらに、安定版をねこそぎ入れます。 いまは 1.8 系列が安定版なので、 1.8.0 から 1.8.5 まで全部入れるわけです。 これは動作の検証用です。

ただ、たくさんあると各バージョンで 比較するのも面倒なので、

forall-rubyコマンド
横断テストの自動化

forall-ruby コマンドという自作コマンドを使います。 このコマンドは、システムにあるすべての ruby に 対して同じオプションをつけて実行するコマンドです。

例えば次のコマンドを実行すると、

~ % forall-ruby -e 'p Object.superclass'                  aamine@core
ruby 1.8.2 (2004-12-25) [i386-cygwin]
nil
ruby 1.8.3 (2005-09-21) [i386-cygwin]
nil
ruby 1.8.4 (2005-12-24) [i386-cygwin]
nil
ruby 1.8.5 (2006-08-25) [i386-cygwin]
nil
ruby 1.9.0 (2006-08-23) [i386-cygwin]
BasicObject

ああ Ruby 1.9 では Object の上に BasicObject てのが 追加されたんだなあとわかります。

使うもの (2)
C コンパイラなど
gcc, bison, flex, autoconf, make, ...

次に C コンパイラとか autoconf。 こいつらは Ruby をコンパイルするのに 必要なので否応なく入れます。

使うもの (3)
zsh

それから zsh です。実は zsh は インストールするのが結構大変なんですが、 もう bash では生きていけない身体に なってしまったので やむなく使います。

使うもの (4)
vi

それから vi。 UNIX 系の OS ならフツー入ってるので楽です。 Windows でも Cygwin を入れればついてきますし。

また、これは vim とかではなく vi であるところも重要です。 わたしはシンタックスハイライティングだとか オートコンプリートだのは 一切使わないことにしているので、 素の vi で大丈夫です。

ちなみに、素の vi はマルチバッファではないので 複数ファイルが編集できません。 そこで、複数ファイルをいじるときは シェルのジョブ制御機能を使います。

複数ファイルを編集するときは
シェルのジョブ制御を使う
Ctrl-z でサスペンド、
fg コマンドで復帰

もはやジョブ制御なんて知らない人もいそうですが、 こういう機能もあるんです。

使うもの (5)
バージョン管理システム
(CVS か Subversion)

それからバージョン管理システム。 種類はなんでもいいんですが、 わたしは CVS をメインに使ってます。

※ 追記: id:naoya さんの発表によれば CVS を使っていいのは小学生までらしい。

使うもの (6)
独自の開発ツール
* ReFe
* rdefs

その他、いくつか自作のツールがあります。 Ruby に特化していますが、 アイデア自体は他の言語でも変わらないでしょう。

具体的に見ますと、

ReFe
Rubyのリファレンスマニュアルを
検索するツール

まず ReFe というツールです。 これは Ruby のリファレンスマニュアルを検索するツールです。

例えば String クラスの each_with_index メソッドを調べたい! というときには

~ % refe string each_with_index                           aamine@core
String < Enumerable#each_with_index
--- each_with_index {|item,index| ... }
 
    要素とインデックスを両方与えるイテレータ。
 
    self を返します。

と指定すればいいわけです。

ちなみに、この場合は each_with_index メソッドは Enumerable モジュールから継承したメソッドなんですが、 そういうメソッドもちゃんと検索できます。

rdefsコマンド
定義されてるクラスとメソッドをリスト

それから rdefs コマンド。 これは、ファイルに定義されてる クラスとかメソッドをリストするコマンドです。

例えばこの locale.rb というファイルに どんなメソッドが定義されてるかなーと思ったら、

~ % rdefs locale.rb
module BitChannel
  class Locale
    def Locale.declare_locale(key, loc)
    def Locale.get(key)
    def Locale.key?(key)
    def Locale.keys
    def initialize
    def rc_table
    private :rc_table
    def [](key)
    alias text []
    def []=(key, str)
    def inspect

と、いうふうに調べればいいわけです。

独自ツールのポイント
* Ruby だけを使って書く
* インストーラを付ける

まずツールはポータビリティを考えて すべて pure Ruby で書きます。 例えば、なぜかツールを Python で書いちゃったりしたら また Python 入れなきゃいけませんから、 とうぜんここは Ruby を使うわけです。

それからインストーラを付けること。 マシンが 20 台あるってことは、 OS のインストールも最低 20 回やるわけです。 それだけあると、ツールにもインストーラが ついていたほうが楽です。

DEC/6: 戦略 (2) カスタマイズしない

オレポータビリティを高める戦略の 2 つめは、 ソフトウェアをカスタマイズしないことです。

なにしろマシンが 20 台からあるので、

いちいち
カスタマイズ
してられるか!

いちいちカスタマイズするのも面倒です。 じゃあ設定を共有するか、とか言い出すと、 今度はそっちのインフラ整備が面倒です。

ということで、ソフトウェアを細かく カスタマイズするのをあきらめます。

これも、本当にまったく カスタマイズしないわけではなくて、 「できるだけ」カスタマイズしないということです。 さすがにわたしも zsh はちょっといじりたいですし。

これを逆に言うと、

カスタマイズしなくても
使う気になるソフトだけ使う!

カスタマイズしなくても使う気になる ソフトウェアだけ使うということです。 「〜〜をインストールして設定すれば使える」 なんてのは使えないのと同じだと思いましょう。

英語で言うと、

No configuration is good configuration.

No configuration is good configuration です。 設定しないで使えるのが一番いいってことですね。

さらに日本語で言い直すなら、

ノウハウを作らないのがノウハウ

ノウハウを作らないのがノウハウです。

DEC/7: 戦略 (3) ホームディレクトリ構造の共通化

オレポータビリティを高める戦略の 3 つめは、 すべてのマシンでホームディレクトリの構造を統一することです。 これはまあ、あたりまえと言えばあたりまえでしょう。

各種設定を減らすためにも
共通化が重要

ホームディレクトリの構造が同じなら、 その構造を前提にしてツールが書けます。 そうすると設定が減って楽になると。

また英語で言うと、

Convention over configuration.

Convention over configuration、ということです。 日本語で言うなら「慣習じゅーよー」。

具体的にどういう構造にするかはいろいろあると思いますが、 わたしは UNIX の /usr 以下と同じ構造にしています。

UNIX の /usr 以下を真似
bin, etc, lib, share, src, var

ちなみに、src はもちろんソースコードですが、 ここには自分が作ったもの以外をまとめます。 で、

自分で作ったものは ~/c に置く

自分で作ったものは すべて ~/c に置きます。 ソースコードもツールも、すべてです。

DEC/8: 戦略 (4) バージョン管理

オレポータビリティを高める戦略その 4 は、 徹底的にバージョン管理システムを使うことです。

共有するため

バージョン管理システムを使う目的は、 この場合、マシン間でファイルを共有することです。

~/c 以下は例外なく
バージョン管理システムに入れる

~/c 以下、つまり自分で作ったものは すべてバージョン管理システムで管理します。 具体的には、

ソースコード

プログラムのソースコードやドキュメント。

開発ツール

さっき言ったような、独自の開発ツール。

大学のレポート

それに大学のレポートもですね。

とにかく自分が作ったものはすべてここに入れて、 バージョン管理システムで管理します。

ちなみに C は working Copy の C から取りました。

DEC/9: まとめ

では、まとめます。 オレポータビリティを高めるための 戦略は 4 つありました。

戦略 (1)
必須ソフトウェアを限界まで削る

一つめは、「これがないと死んじゃう」 ソフトウェアを限界まで減らすことです。 これによってインストールする手間を 減らすと同時に、ポータビリティを高めます。

戦略 (2)
カスタマイズしない

二つめは、ソフトウェアのカスタマイズを 半ばあきらめることです。 デフォルト設定が優秀なソフトだけ使いましょう。 No configuration is good configuration.

戦略 (3)
ホームディレクトリの共通化

三つめはホームディレクトリの構造を 共通化することです。 Convention over configuration.

戦略 (4)
徹底的にバージョン管理

四つめは、バージョン管理システムを 徹底的に使うことです。 バージョン管理システムを使うことで ファイルの共有も実現できます。

結論:
あたりまえのことを
徹底的にやるのが
ポイント

今日の話は、どれも けっこう あたりまえのことが多かったと思います。 バージョン管理するというのも、 ホームディレクトリを同じにするというのも、 まあ普通ですよね。 でも、それを徹底活用すると、 マシンが 20 台あっても OS が 7 種類あっても 生きていけるようになるわけです。 これが今日のポイントです。

以上でわたしの発表は終わりです。 ご静聴ありがとうございました。

(16:45)

本日のツッコミ (全2件) [ツッコミを入れる]

ひら [キーボードがSK6000だ!使ってました(^-^)
10年くらい前の名作キーボードだね。]

青木 [え、このキーボードって有名なんですか。
ロゴも入ってないし、確か 7000 円くらいで、
ナチュラルキーボードのくせに安いなあ〜
っていう印象しかなかったです……。
秋葉原の俺コンスポットで買った記憶があります。
タッチパッドのついてるのとついてないのがあった。]


2006-09-12

Development Environment Conference 感想

と、いうことで、いまさら DECon の感想を書く。

自分のセッションが最後だったので 「ぐはー緊張する死ぬもうだめぽ」 などと思いながら聞くのがきつかった。

一番印象深いのは……なんだろ。 今回はさすがにどれもうまくて没頭できたので、 印象も分散した感じ。

強いて言うと高林さんの Binary 2.0 話かな。 GDB でバイナリパッチを当てる話がおもしろかった。 でも「過去の経験から memcpy と memmove を間違えていると思われる」 って、そんなんソースコード見ないでわかるわけねー! (笑)

ちなみに小ネタ: objdump の出力が「memcpy@plt」となっていたと思うが、 その plt は Proceduce Linkage Table の略である。たしか。 i386/Linux では共有ライブラリの関数は 間接アクセスするようになってるんだけど、 その間接アクセスに使うテーブルが PLT。

しかし、前から思ってたんだけど、 strace は Binary 2.0 なんだろうか。 あれは /proc 見たり ptrace(2) 使ったりする話だから、 OS の話であって、バイナリとは関係なくない? いやまあ Binary 2.0って何だって言われると困るんだけど。

ここで話が突然変わるが、CVS は小学生までだ! しかし俺は小学生だから問題ない! (嘘つけ)

secondlife さんの vim 話は興味深かった。 俺は普段から vim 使ってるけど vi の範囲しか使わないので、 vim 特有のことはほとんど知らないんだよな。

そうだ、自分の話で一個書き忘れた。 「アプリケーションごとの設定方法を覚えるのがめんどくさい」 という理由を追加すべきだった。 どれくらいめんどくさがってるかと言えば、 人の考えた設定方法を覚えるくらいなら 自分でプログラム書いたほうが楽、というくらい。

はてなの開発環境はなかなかカッコイイ。 全員がノートパソコンだけど机に座ってるときはデュアルモニタにする、 というあたりが特にいいな。なんか軽快な感じがするよね。 俺も部屋の写真を入れたけど、 やっぱ部屋の写真があると見てるだけで楽しい。

宮川さんの飛行機ハック話。国際派でカッコイイ。 窓使いの憂鬱はわたしも使ってます。 日本語キーボードで英語配列にするとキーが増えて便利なんだよね (secondlife さんも同じことをやってて驚いた)。 わたしは「}」のキーを「|」、「半角」を ESC、「|」を「~/`」にしてます。 Linux でも同様に loadkeys/xmodmap で変換する (他のシステムにはシリアルか ssh で入るので変換の必要なし、 どうしょもないときは 101 キーボードをつなぐ)。

mala さんの話は、 ターンアラウンドを極限まで短くするという話が印象的。 とにかく試行回数を増やせればバグは潰せる、 試行回数を増やすほどバグは減る、 という話だったような気がする。 実に LLっぽい。

(08:35)

(13)

DECon のプレゼン作るために中断してたけど、 そろそろリファレンスマニュアルをやりますよ。

ところでなぜ締め切りが 20 日かと言うと、 21 日から 30 日まで俺が東京にいないからである。 だから 20 日までに俺の担当部分 (ウェブアプリ部分) は作ってしまう必要がある。 逆に言うと、その他の作業は 21 日以降でも大丈夫なのね。 ……いや、まあ、司令塔なしで作業してもらうというのもまた酷い話だけど。

(08:47)

(14) 愛称

えーと、いままでに出た案は

  • るりま
  • るりふぁ

か。うーむ。

  • Rubyの すごい リファレンスマニュアル

……という意味で 「すごいマニュアル」というのはどうかなッ! (なにがだ)

さらに略すと「凄マニュ」か。 どことなくサンスクリット語ぽい語感だな。

まだ続くよ

(09:26)

(15)

「すごレンスマニュアル」という略しかたを思いついて爆笑した

(09:29)

String#remove

ずーっと昔から考えてたことで、 いまさら言い出せないよなーと思って避けてたんだけど、 str.sub(/re/, '') と同じ働きをする str.remove(/re/) って欲しくない?

(00:38)

本日のツッコミ (全5件) [ツッコミを入れる]

ささだ [ふつうのマニュアルなんてどうか.]

yoosee [るファレンスマニュアル。さらに略してルファ。
小学生がワンピースと間違えて買うに違いない。]

shinh [はじめてコメントします。String#remove欲しいと思います。ついはじめてコメントするくらい欲しいです。]

shinh [全然はじめてじゃなかったようでした。はじめてじゃないのはじめてだと思うほど欲しいです。]

斎藤ただし [はじめまして。望ましいインターフェースってなんだろうとは自分も常々考えさせられる問題で、思わずコメントしたくなってしまいました。
String#delete!の引数にRegexpを許す方が保守的でいいんじゃないでしょうか。]


2006-09-13

(16)

えーっと何をしなきゃいけないんだっけ。

とりあえずは俺以外でも作業できる環境を作らないとだめだな。 ということは、まず、

  • サンプルファイルを作る
  • 動作を確認できるツールを用意する
  • 作業マニュアルを作る
  • 割り当てリストを作る

あたりか。

簡単なところで、割り当てリストから。 Subversion のレポジトリに ASSIGN てファイルを作っておいて、 アカウント名を書き込んでチェックインしたら OK ということにしよう。 えーと、*.rd と *.off を拡張子とってリストすれば終わりと。

次。依存関係を考えると、ツールかな。 パーサはだいたいできてるから、リストするツールを書けばいいだろう。

  • bc-list (定義されているエントリをリスト)
  • bc-convert (新フォーマットに変換)

うむ。こんなとこか。 bc-list はパースして pp するだけという手抜き実装だ。 bc-convert は ReFe のコードを持ってきてでっちあげた。

それからサンプルファイル。 Object, String, Enumerable, Comparable があればよかろう。 あと組み込み定数と組み込み関数は記法が特殊なので俺が引き取るっと。 メソッドを置き換えるライブラリも一つ欲しいな。jcode にしよう。

最後に作業マニュアル。 ざっと書いてメール → 完。

(10:56)

(17)

だって「Rubyリファレンスマニュアル刷新計画」って何回も書くのめんどくさいじゃん。

(10:56)

さむー

ちょ、ちょっと待って、なんでこんな寒いの? 夜は毛布二枚かけないともう寒くて寝られないよー。

ところで、「寒すぎ」と「サムスピ」は似てる。

(11:14)

Symbol と String (1)

もう Symbol が String に統合されるのは規定事項なのだろうか……。 やっぱ別物のほうがいいなあ。 Symbol を String のように扱いたい、というのはわかるけど、 それと継承関係を作ることは別の話だと思うんだよな。 どうせ破壊的メソッドは実装できないんだし、 いくつかメソッドを追加するだけで済ますわけにはいかないのだろうか。

やはりもう一発メールを投げてみよう。

(11:18)

Symbol と String (2)

ああ、そうか、ActiveSupport の件は Hash で同一視したいって話なのか。 ますます ActiveSupport が嫌いになってきた。

(11:27)

シェルスクリプトでユニットテスト

シェルスクリプトのユニットテストを書く必要が発生した。 …… shunitってあるのかな。ありそうだな。あるらしい。

うーむ。CVS HEAD 見てみたが、イマイチ好きになれない。特に関数名が。 これ使うなら「ふつりな」のときに自分で作ったやつのほうがいいや。 こんなやつ。

#!/bin/sh
 
. ./shunit.sh
 
assert_ok() {
    assert_stdout "OK" $1
    assert_status 0 $1
}
 
assert_out() {
    assert_stdout "$1" $2
    assert_status 0 $2
}
 
assert_out "Hello, World!" ./hello
assert_out "Hello, World!" ./hello2
assert_status 77 ./add
assert_out "ret=77" ./add2
assert_out "ret=77" ./sub
assert_out "ret=56" ./imul
assert_out "ret=2000" ./idiv
assert_out "i=0; i=1" ./lvar1
assert_ok ./if
assert_ok ./while1
assert_ok ./while2
assert_out "i=3; i=3; i=2; i=1; i=0" ./while3
assert_ok ./while-break
assert_ok ./while-continue
assert_out "i=3; i=2; i=1; i=0" ./for
assert_ok ./for-break
assert_ok ./for-continue
assert_ok ./immscope
 
test_finished

(13:25)

Symbol と String (3)

ぐはー。今度は Symbol と String がキーとして 同一視されなかったがためにバグが出た。 なんだこのタイミングのよさは。

(16:38)

Symbol と String (4)

ちなみに、こんなハッシュを作って演算子をメソッド名に変換してた。

OP = {
  '+'  => 'add',
  '-'  => 'sub',
  '*'  => 'mul',
  '/'  => 'div',
  '%'  => 'mod',
  '&'  => 'bitand',
  '|'  => 'bitor',
  '^'  => 'bitxor',
  '<<' => 'lshift',
  '>>' => 'rshift',
  '==' => 'eq',
  '!=' => 'neq',
  '>'  => 'gt',
  '<'  => 'lt',
  '>=' => 'gteq',
  '<=' => 'lteq',
  '&&' => 'logicaland',
  '||' => 'logicalor'
}

ハッシュ側のキーは文字列なんだけど、 検索するときは intern してあった罠。 世の中ままならねーんですよ。

(16:39)


2006-09-14

Subversion

そろそろ Subversion に移行してもいいかなあ。 ああ、でももうちょっと管理経験を積んでからにするか。 何か意図しない問題が出るかもしれないし。

(14:22)

(18)

そこらじゅうからコードをかき集めてきた甲斐あって、 もうそろそろウェブから見られそうな感じ。

いや表示は別にいいんだ。表示は今回簡単だから。 問題はこの複雑怪奇なオブジェクトグラフの永続化と インクリメンタルアップデートだ。 自分でも何がどこを参照してるのかわからなくなってきたし。

やっぱり、alias もさることながら、 メソッドの再定義と上書きがうぜー。 クラス名とメソッド名をキーにして完全一致検索しても まだエントリが複数あるというのが激しくウザい。

(18:23)

(19) データベースの論理構造

さてデータベース。こっからが問題だ。

ライブラリは特に問題ない。 ライブラリで定義されたクラスとメソッドのリストを持つ。 メソッドの追加や再定義に対応できるよう、 クラスの他にメソッドも持つのがポイント。

data Library = Library { name    :: String,
                         source  :: String,
                         classes :: [Class],
                         methods :: [Entry] }

クラスにはまず constant と singleton method と instance method があり、 それぞれにエントリベースのリストと名前ベースのリストがある。

data Class = Class { name          :: String,
                     source        :: String,
                     constant      :: NameSpace,
                     singleton     :: NameSpace,
                     instance      :: NameSpace }
 
data NameSpace = NameSpace { map   :: Map String MethodHolder,
                             list  :: [Entry] }

MethodHolder は「定義された Entry」「追加 Entry」「再定義 Entry」を持つ。

data NamedEntry = NamedEntry { defined   :: Entry,
                               added     :: [Entry],
                               redefined :: [Entry] }

で、最後にメソッドエントリは

class Entry
  def signatures :: [Signature]
  def source

いきなり Ruby に戻る罠。 だって抽象データにしたかったんだもん。

このように分析してみると、 Entry のアイデンティティが問題のような気がする。 Entry だけはライブラリとクラスから多重に参照されるうえ、 クラス名とメソッド名だけではユニークにならない。

解としてはライブラリ名も付ければよい。 一つのライブラリで一つのメソッドに 複数のドキュメントを提供することはさすがにないだろう。 ……ないよな?!

  • _builtin.String.new
  • _builtin.String#sub
  • jcode.String#sub

てな感じか。 どことなく selector namespace ぽい。

(20) データベースの物理構造

データベースはインクリメンタルに更新できるよう、 すべて遅延ロードする。

db/1.9.0/
    properties
    library/
        _builtin/
            source
            classes
            methods
        Env/
        English/
        abbrev/
           :
           :
    class/
        ARGF/
            source
            constant/
                map/
                list
            singleton/
                map/
                    file
                    filename
                    lineno
                    path
                    skip
                    to_s
                list
            instance/
                map/
                list
        ArgumentError/
        Array/
        Bitnum/
        Binding/
           :
           :
    method/
        _builtin.String.new
        _builtin.String-captalize
        _builtin.String-captalize!
        _builtin.String-casecmp
        _builtin.String-center
        _builtin.String-chomp
        _builtin.String-chomp!
        _builtin.String-chop
        _builtin.String-chop!
        _builtin.String-clear
                  :
                  :

method 以下は ライブラリ名で一回切ってもいいな。 何エントリあるのか調べてから考えよう。

case 無視のファイルシステムはあとで考える。 必要なら ReFe と同じ方法を使うと。

(19:04)

(21)

よく考えると、メソッドエントリに種類が入ってるから、 クラスが持つメソッドのリストは種類に分ける必要ないな。

String/
    properties
    source
    entries
    singleton/
    instance/
    contant/

さらに、list だけセーブして、ロードしたあとに Hash 作れば十分か。 これが本当に同じなら、だけど。

String/
    properties
    source
    entries

おお! めっちゃシンプルになった。

(19:43)

(22)

クラスが持つエントリの種類を整理しよう。

  • DEFINED entry: クラスを定義したライブラリで定義されるメソッド
  • ADDED entry: クラスを定義したライブラリ以外で定義されるメソッド
  • REDEFINED entry: クラス定義したライブラリ以外により再定義されるメソッド

……そうか。 これまでこの属性はクラスになければいけないような気がしていたけど、 メソッドエントリの属性にしてしまえばいいんじゃないか。 defined/added/redefined の区別はドキュメントに書いてあるんだから、 これをそのまま保存しておけば十分だ。

(21:54)

(23)

module_function なんて嫌いだ。

(00:34)

(24) 物理構造の 3? 4?

そうか。メソッドにライブラリが関係してくるのは クラスと別のライブラリで定義されたときだけだ。 んで、ライブラリ主導で検索するときは C.m で検索してから ライブラリ名でフィルタすればいいんだ。 ということは、やっぱりメソッドの ID は C.m で十分だ。

ということは、メソッドエントリは defined + added + redefined で 1 つか。

……ちょっと待てよ。 alias があるメソッドの片方だけを redefine したらどうなるんだ。

ええ? どうなんのこれ? ていうか、どうなるのが正しいんだよ。

ユースケースから考えよう。

ライブラリ主導の場合は、redefined エントリだけ。

クラス主導の場合は、defined + redefined。

メソッド名による検索の場合は、defined + redefined。

ライブラリのときは名前で検索したあと ライブラリでフィルタするから自動的に redefined だけになる。

よし、問題ない。たぶん。 メソッドの extent をロードしない限り変なことにはならないはず……。 ヤバいのはメソッドが減ったり増えたりする場合のクラス書き込みだけど、 これはあとで考えよう。

(01:12)

本日のツッコミ (全1件) [ツッコミを入れる]

ドし [Ruby is teh suck!!!!!!11]


2006-09-15

RHG 読書会

げっ、明日か! すっかり存在を忘れてた。どうしよう。 いまコード書きが調子いいから、 勢いで終わらせてしまいたいのだが……。

読書会に出て現場でコード書こうかな……。

(14:44)

凄マ! (25)

サブタイは気分によって毎回変わります。

もういっかいデータベースの物理構造をまとめてみよう。 まとめ、大切。

db/1.9.0/
    properties
    libraries/
        _builtin/
            properties
            source
            classes
            methods
        abbrev/
        base64/
        benchmark/
        bigdecimal/
    classes/
        ARGF/
            properties
            source
            methods/
                file/
                    s._builtin
                filename/
                lineno/
                path/
                skip/
                to_s/
        Abbrev/
        ArgumentError/
        Array/
        BasicSocket/
        BigDecimal/

これまでの考察を経て、method/ が消滅。 メソッドの位置は CLASSNAME/methods/METHODNAME/TYPECHAR.LIBRARYNAME に変えた。 TYPECHAR は singleton_method とか instance_method の種別を表すアルファベット 1 文字。

ライブラリからメソッドを得るときは CLASSNAME + METHODNAME で検索してから LIBRARYNAME でフィルタする。

あらためて考えると、TYPE と LIBRARYNAME の扱いが肝だな。 だいたいアレだ、module function がすべて悪い。 こんなものがあるから、 ドキュメントの実体をコピーしないで済ますには TYPE を最後にせざるをえなかったのだ。

(15:54)

スゴレンスマニュアル (26)

画面いろいろ出たー

(23:21)