As Sloth As Possible

可能な限りナマケモノでありたい

カテゴリ: プログラミング

ここんとこMacPortsをメインに使ってたので気付いてなかったのだけど、GHCをインストールしたくなって、でも確かあれは「ソースからコンパイルはしてはいけない」って言われてたよな、MacPortsじゃない方法で入れたいな、と思って見に行ったらFinkのLeopard対応始まってた

まだバイナリのダウンロードはできないみたいだけど、どのみちいつもソースから入れてるのであんまり関係ない。何かと便利なので入れておこう。

といった調子でコードを書いております。もりもりと。それはもうもりもりと。

ここ数日ちょっとばかし個人的な理由で気分が晴れず、なんかもうイライラしてきたのでとりあえずコードを書かねば、とそういう思いに駆られてひたすらにコードを書きまくっている。事情を知っている人がこれ聞いたら即座に「いや、そんなことしてる場合じゃないだろ」ってツッコミが入りそうだけど。何かしてないと落ち付かないが何もする気にならない、そんなときに癒してくれるのは愛しのMacBookだけなんだ。哀しい。哀しすぎる。まぁいいや。

そんなわけで先週末からあれこれ(ニコニコ動画のflvダウンロードスクリプト書いたりとか)やってたのだけど、ふと思いたってどう書く?orgのお題に挑戦してみることにした。ふと思いたってというか、「とりあえず、初学者はコードを晒せ!」とか「どう書く?orgのperl全コンプ」辺りでそのキーワードを見かけてついカッとなって手を出してましまいました。今も反省してません。近所のKさんによると「(faultierがそんなことをするなんて)信じられません…普段はおとなしい普通の子だったんですけど…」だそうです。って何の話だ。

で。脳味噌が大分Ruby色に染まりつつあるfaultierとしては、本当ならRubyで書きたいところではあるんだけど、Rubyは流石にカバレッジが高い。ほとんど全てのお題に解答が出てるし、それにRubyでばっかり書いてたらあんまり勉強にならない。じゃあ今勉強しなきゃいけないのは…いや、Perlは全コンプされてるんだった。これはこれで見てると勉強にはなるけど。あとはPython、Smalltalk、Haskell、Java、Common Lispあたりが多いのか。というかSmalltalk凄いな。なんかこの上位陣の中で一際異彩を放ってる気が。

そういえばObjective-Cはどうだろう…大分人気が低いな。Objective-Cファンとしては寂しいのだけど、この少なさなら、今なら目立てるかも。まぁそれはそれとして、なんだかんだでずっとサボってたら、気が付いたらObjective-C 2.0とかになってるし来年の始めにはiPod&iPhoneのSDKも出るし、そろそろ真面目に勉強しておかなきゃな。

と、いうことでひとまずObjective-Cで書くことにしました。さくさくObjective-Cの未解決問題を減らしていきたい所存であります。あとは誰かが罵しつっこんでくれると嬉しいなぁ。

以前iPod touchをJailbreakした際にRubyをインストールしたものの、irbは起動しないし添付ライブラリを読みこんだだけで落ちてしまって、全く使いものにならなかった。その原因が気になっていたので今日はそいつを追っかけてみた。てっきりarm-darwin版のRubyが何かバグを抱えているもんだとばかり思って愚痴ってたのだけども、結論から先に言うとどうもそうではないようだ。で、タイトルのようなことになるのだけども。

とりあえずエラーを吐いてる箇所を探す

エラーを吐いてる、と言うのは正しくない。どのライブラリでも関係なく、requireした時点で[BUG]とだけ言ってAbort trapしてしまうツンツンぶりで、まったくとりあってもらえないというのが現状。数は多くないけど、日本でもarm-darwin版rubyに泣かされてる人は何人かいるみたいだ。

っても、インタープリタのコードもライブラリのコードも読んだことないし、arm-darwinのバイナリを作る開発環境もないしで、インタープリタのバグだったりしたらお手上げだったりするんだけど。まぁ、とりあえず小さそうなところで、URIライブラリを選んでみる。

bash-2.3# ruby -e "require 'uri'"
/opt/iphone/lib/ruby/1.8/uri/generic.rb:1121 : [BUG] terminated node (0x21294c)
ruby 1.8.6 (2007-03-13) [arm-darwin]

Abort trap

ぐ。ここまでは既に何度も経験したので、この程度のツンツン加減じゃへこたれないからね。しかしgeneric.rbの時点で落ちるとはどういうことだ。1121行目に一体何があるのか見てみるべくuri/generic.rbを開いてみる。

1106     def inspect
1107       sprintf("#<%s:%#0x URL:%s>", self.class.to_s, self.object_id, self.to_s)
1108     end
1109 
1110     def coerce(oth)
1111       case oth
1112       when String
1113         oth = URI.parse(oth)
1114       else
1115         super
1116       end
1117 
1118       return oth, self
1119     end
1120   end
1121 end

endやん。さらっと見てみたけど当然のことながらおかしなところは何もない。他のRubyライブラリか、あるいはもっとローレベルな機能に依存してるとこはないかとも思ったけど、どう見てもごく普通のRubyコード。一応、まさかsprintfが?とか裏切りのcase式か?とか一通り自分で書いて試してみたけど、別に問題なく通る。というか、ここModuleやClassの定義の箇所だし、そもそも実行すらされてないはず。何なんだ一体。

行けるとこまで行かせてみる

何箇所かコメントアウトしてみたりしたら、一応generic.rbは読み込めたりするんだけど、今度は他のライブラリで止まるし、ひっかかる箇所を見比べても共通点が見えてこない。仕方ないのでライブラリのソースにdebug printを仕掛けつつ、上から順番に地道に読みすすめていくことにする。

まずはuri.rbからrequireしてるものをgeneric.rb以外全部コメントアウトして、generic.rbの方では__END__で後ろの処理を無効にして実行してみると、その段階では問題なく読み込める。徐々に読み込む範囲を広げていったら、ついに「そこから先は必ずAbort trapする」行を見つけた。

 914     def route_from(oth)
 915       # you can modify `rel', but can not `oth'.
 916       begin
 917         oth, rel = route_from0(oth)
 918       rescue
 919         raise $!.class, $!.message
 920       end
 921       if oth == rel
 922         return rel
 923       end
 924       
 925       rel.set_path(route_from_path(oth.path, self.path))
 926       if rel.path == './' && self.query
 927         # "./?foo" -> "?foo"
 928         rel.set_path('')
 929       end
 930 
 931       return rel
 932     end
 933         
 934     alias - route_from

これの925行目の後、return relより前に何かの式を入れるとそこで必ずAbort trapする。ついに、ついに見つけたぜこの野郎。

…待て。うん、この箇所も全然おかしくない。何の変哲もないif文。試しに色々なif文を書いてみる。全部ダメ。unlessもwhileもbegin-rescueもダメ。putsは…ダメ。じゃあ、1。あ、これは通るのか。1+1は…な、なんだって、これも通らないだと?…なんか、すごく嫌な予感がする。手に負えないバグを見つけるよりもよっぽど嫌な予感が。

さて。どうも926行目に書いてあることが原因じゃないようだ。ふむ。じゃあ、コードの順番を入れかえてみたり、前後のコードを減らしたり増やしたりしてみたらどうだろう。

…あはは。コードを減らすと通るんだ。それも、どの箇所かに関係なく。

vim*1を閉じて、おもむろにtop、と打ちこんでみた。うふふふふふ。そういうこと。そういうことなんだ。

メモリが全然なかった。なんでか知らんがhttpd*2起動してるし。誰だそんなふざけたものをiPodに入れたやつは。俺か。俺だよなぁ。

100MBのメモリでできること

結局、iPod touchがあまりに貧弱なため、インタープリタがrequireしたコードを解析中にメモリを使い切ってしまい、どうしようもなくなって[BUG]と断末魔を残して死んでたんだろう、ということだった。だから、コードをあれこれいじってたときに、条件分岐が複雑なコードやオブジェクトを余計に生成するコードが即座に息の根を止めてたんだな。ちょっと考えればわかりそうなもんで、多分携帯電話とかで開発してる人だったら、そんなリソース馬鹿食いしそうなRubyなんかがモバイル端末でまともに動くわけないじゃん、って言いそうだ。あるいは、いやいや、数年落ちのビンテージ環境でもRuby自体は動くわい、それはiPod touchが貧弱なんじゃい、っていう声も違う方から聞こえてきそう。

でもさ。iPhone/iPod touchが携帯電話とも骨董PCとも違うのは、あれは高機能なGUI環境なんだってことなんだよな。サブセットとは言えdarwinが、いやMacOSXが載ってるわけで、だからこそモバイル端末にあるまじき過剰な期待をしてしまうし、(皮肉にも)それが故に骨董PCでもできるようなことが出来なかったりする。確かにiPod touchのインターフェースレベルの層を排してdarwinだけにすれば、Rubyくらいは平気で動くと思うけど、それって何の意味があるんだろう。かと言ってあんなにスムーズに動くUIがあって、音楽・動画が再生できて、ネットワークにも繋がるのに、ハードの制約でいじれる部分が少ないというのも切ない話。

やっぱりObjective-Cで書いて最適化しまくってなんぼって世界か、あるいはWidget程度の小さなアプリがせいぜいってところなのか。Cocoaは好きなんでそれはそれでいいんだけどさ。折角RubyやPerl*3があるのにまともに使えないのは残念過ぎる。まぁ、最初からAppleが言うようにWebアプリで作ればいいじゃんって話だが*4

*1:最初vimがあることに気付かなくて、しばらくviを使ってた。いや、だって入ってないと思ってたし。会社のサーバだってviしか入ってないんだぜ。

*2:以前ネタで入れたApacheがlauchd経由で自動起動するように設定されてたらしい。使いみちもないし、即座に消した。

*3:もしかしたらPerlならRubyよりまともに動くかもしれないけど、CPANフル活用してバリバリ、というわけにもいかないだろうからどっちみち期待はできない

*4:しかしSafariのJSはそれはそれでなんだかなって代物だけど。未だに。

表題通り。恵比寿にあるドリコム東京本社に行ってRails勉強会に参加してきました。体調不良でえらい豪華なメンバーのランチには参加できなかったし、それどころか恵比寿についてから迷って遅刻ギリギリになるし、まぁいろいろとアレだったけども。うん、そう、ここのところ頭痛いなぁとか思ってたら、体が熱っぽいくて意識が遠くなって、そうかこれ風邪ひいてんじゃね?とか気が付いたのは帰り道。馬鹿は風邪ひかないんじゃなくてひいたことに気が付かないとは名言だなーとか思いながらよれよれと帰ってきました。それはそれとして、勉強会は非常に楽しかったです。以下、自分で後で見返すためにも軽くまとめ。

Rails 2.0は案外普通だな

前半のセッションでは「Rails 2.0を読む」と題してRails 1.2から2.0になって変わったところをざっとさらい、該当箇所のソースを読んで、どんなことやってんだろうなどと話した。Rails 2.0。Railsの仕事から離れてからRails周辺の話題を追いきれてなくて、実はまだ試してなかったんだけど、ちょっと面白そうなことになってるみたい。これは後で試してみないとなぁ。

相違点をざっと。

RESTfulなRails

SOAP関連のサポートが省かれてREST関連の機能が強化されてるよ、って話。これは前々から聞いてたのでふむふむなるほどと言った程度。RESTfulなクライアントサイドを書くための仕組みだけでなく、RESTfulなサーバサイドのAPIも作りやすくなってるらしい。

MultiView

respond_toを拡張。面白いなぁと思ったのは、従来ならviewの拡張子がhoge.rhtmlとなるところがhoge.html.erbとかになる話。一個目の拡張子(変な言い方だ)でファイルの種類を、二個目の拡張子で何で処理するかを判別するらしい。

セキュリティの強化

デフォルト設定だとURLに自動的にトークンが入ってCSRF攻撃対策を取るとか。えーとこれなんだっけと思いながらメモ見たら「あとで調べる」とだけ書いてある。コラ。しっかりしてくれ自分。

Record identification

URLの規約をより簡素にして、モデルからURLを特定する仕組み。redirect_toやlink_to、form_forなどで使う。具体的にどういうことかというと、例えばRubyistモデルの情報を参照するページのURLが /[モデル名(複数形)]/:idという規約に従っていれば、userがRubyistクラスだったとしてlink_to(user)とかやると"/rubyists/#{rubyist.id}"なURLが自動生成されるということらしい。

HTTP Loving

Basic認証がデフォルトでサポートされるらしい。ところでなんでLoveなんだろう。

Queryキャッシュ

ARがQueryキャッシュするらしい。肥大化してものすごいメモリ食うんじゃねってとこを不安視する声が上がって、ソース読みながらキャッシュの生成・破棄のタイミングを調べたりしたのだけれど、どうもそんなに本格的なものではない様子。メモリリソースが気になるような状況では使わない、本格的にDB負荷や速度を考えるならどのみち違う方法でのキャッシングを考える。要検証。

Sexy Migration

マイグレーションの見栄えがよくなるよという話。

create_table :rubyists do |t|
  t.column :full_name, :string
  t.column :handle_name, :string
  t.column :age, :integer
  t.column :created_at, :timestamp
  t.column :updated_at, :timestamp
end

とかだったのが、

create_table :rubyists do |t|
  t.string    :full_name, :handle_name
  t.integer  :age
  t.timestamps
end

と書けるようになると。誰かが言ってたけど「Cの変数宣言みたい」。なるほどねぇ。ちなみに1.2系でもプラグインで同等の機能があるらしい。belongs_toとかもMigrationで書けるんだって話だったか。この変聞き逃してて記憶が定かでない。

あと、「(上のコードの)tはいらない」という情報がでて、それって凄いんじゃない?てかどうやって実装してるの?という話になって、終盤はMigrationまわりのソースを読んだ。結局それらしいコードは見つからず、もしかしてガセだったんじゃないかというところでに落ちついた。

Railsのプロファイリングあれこれ

後半のセッションはRailsアプリのプロファイリングノウハウについて。これ、凄く聞きたかった。Railsの欠点でもあり俺個人の弱点でもあるパフォーマンスとそのチューニング、そのためにもまず上手なプロファイリングが必要だよねと。

Railsのprofiler

Seattle.rbがいろいろと面白いものを作ってるらしく、いくつかのProfilerをセッションオーナーの瀧内さんが紹介してくれた。

中でも面白かったのがProduction Log Analyzer。これは実行中のプログラム自体の動作を測定するのではなく、ログを解析してRailsのパフォーマンスを測定するというもの。プログラムに組みこまないので「測定することによる影響」が無くてすむし、動作も重くならないし、既に稼働中のシステムを測定することもできる。これはなかなか素敵だった。

ただ、SyslogLoggerで吐いたログじゃなきゃダメらしい。なんでだろう。とりあえずSeattle.rbはSyslog大好き?ってことにしておいた。

Rubyレベルのprofiler

RubyProfは必須だそうです。標準のprofilerより速いのか。実際にRailsに仕込んでプロファイルさせてみるところまで実演。ちなみにRails 2.0を使用。試行錯誤してる内にRailsのここが変わった、RubyProfの最新版はここが違う、なんて話も出たりして、苦労してプロファイル結果を表示したときには拍手が上がった。うん、大変だった。なんか凄く大変だった。

ついでにdebugger

プロファイリングしたらデバッグしてみよう、ということで、2.0の新機能のdebuggerも試してみることに。script/serverのdebuggerオプションというのがあって、これを付けるとdebuggerが有効になるらしい。Ruby本体のバグ修正にともなって使えなくなったことで有名なbreakpointに変わって、ruby-debugを使ったものになっているとか。が、やってみたところlighttpdでは無視され、WEBrickでは何らかのエラーで起動できず、結局試してみることができなかった。流石にpreview版、まだまだ不安定というところか。ちなみにscript/profilerは全然メンテされてないらしく、一応2.0にも標準添付されてるくせに全く使えなかった。

作ってみるのがいい

後半のセッションはとにかく作ってみて試してみてあれこれ話しあったのだけど、これが非常に勉強になったし楽しかった。聞くところによると他のセッションでも掲示板作ったり、初心者セッションではScaffoldでとりあえず組んでみたりしてたらしい。まさにRailsならではだよなぁ。

まとめ

ようと思ったけどいい具合に意識が遠のいて来たのでとりあえずここまで。薬飲んで寝る。明日に備えて。そう明日もAkasaka.rbのJRuby勉強会に行くんだった。RubyばっかりじゃなくてPerlとかJavascriptも勉強してこいって言われそうだなぁ。

今の子供達にどうやってプログラミングの楽しさを教えたらいいのか?がちょっと気になったので、いい加減自分のことを「子」と表現するのは躊躇われるけど、一応現代っ子的な環境に育ってプログラマへの道を歩みだしてるfaultierが考えてみるよ。

与えてみるとよさそうな素材なら、はてブのコメントでも言われてるように今だったらFlashとかHTMLあたりかな。これで遊ばせてみて、凝り始めたところで「プログラミングすると、もっと色んなことができるようになる」とほのめかしてみる。あるいは、ロボット工作キットみたいのを一緒に作ってみるとか。重要なのは「自分が言ったとおりにパソコンやロボットが動いてくれる」ことを実感してもらうことで、アルゴリズムだのコンピュータの仕組みだのを教えることじゃない。そんなのは進んで行く内に自然に興味が出てくることだろうし、自分でそこに至らなければ壁にぶつかる日が遠からず来るので、そのときに教えてやればいい話。

そうだな、今の俺なら「黒い画面に文字だけでてくるおもちゃ」を喜々として一日中いじり倒しているだろうが、パソコンはゲームやネットやお絵描きや作文に使うものと認識してた子供の頃の俺はおそらくそんなのに何の興味も湧かなかったと思う。とりあえず最上位のレイヤーから、簡単でかつ興味を引くものからでいいんじゃない?って意見に激しく同意する。そう、増田さんの当時CUIでBASICなりCなりを書くのが最上位レイヤーだったかも知れないが、今ではCUIもプログラミング言語も普通にパソコンを使うだけなら意識する必要のない下位のレイヤー。そこまで潜る楽しさを教えるために、最初からそれに触れさせる必要が必ずしもあるわけじゃない。磯の生き物を採集する楽しさを知ってから、深海の生物を研究し始めてもいいじゃない。

お子様の主張

さて。それはそれでいいんだけど、それよりも何か結構な抵抗感を感じたんだよな、この増田さんに。昨日はついカッとなって全否定エントリを書こうと思ってたんだけど、一晩明けてちょっと冷静になったので、この増田さんの温和なほのぼのエントリのどこが俺の気に障ったのか考えてみることにする。多分、こんな風に思ったんだろう。

  • 子供の興味関心を親が決められる、あるいは決めてやるもんだと思ってるんじゃないか?
  • 「プログラミングの楽しさ」と「BASICのコードを打ち込んだあの日の楽しかった記憶」を混同してるんじゃないか?

この辺に抵抗してしまいたくなるあたりまだ自分は「子供」側の意識でいるんだなと気が付いて苦笑しちゃったけど。で、こう思う親の気持ちはわかんないでもないけど、多分どっちも考え直したほうがいい種類の発想だなぁ。親がこういう発想でいると子供にとっては迷惑だし、多分余計に思いどおりにならないだろうし。それに、スポーツだとか楽器の演奏だとか伝統芸能ならまだしも、プログラミングって幼少時に教え込まないといけないものじゃないしなぁ。

「BASICの~」に関しては特に言うことはなくて、自分でも言っているように、ゲームやらネットやらが溢れてる時代にその当時の感動を再現させるのは無理でしょう。ベーマガとやらがないというけど、どっかからソースコードを拾ってきてそれを自分の環境で動かしてみるってだけなら、むしろオープンソースだなんだとか言ってる今の方が容易。でもそれが今と当時じゃ同じ意味じゃないのは誰にだってわかる。そこに拘ると、「プログラミングの楽しさ」を見失うと思う。

プログラミングは何で楽しいのか

教える必要があるのは「プログラミングは楽しい」ではなくて、もっと本質的な「考えることは楽しい」や「創り出すことは楽しい」の方だと思う。さらに言えばそれも教えるよりやらせてみる方が適切。で、増田さんはプログラミングを「やってみる」ことを通してそれを知ったのかもしれないけど、別にそれにはプログラミングが「最適」なわけじゃないし、むしろ今はいきなり「プログラミングを通して」それを教えるのは難しいんじゃないかな。逆に、「考えること」や「創ること」を楽しいと思える子供が、パソコンに触れる環境にあり、楽しそうにプログラミングしてる親父の姿を見てたら、プログラミングをやりたがる日はそんなに遠くないように思う*1。そんでもって、やりはじめてしまえば自分で勝手にサイトなり書籍なりを探してくると思う。今はそんなものそれこそ溢れてるし。だから、増田さんが「プログラミングの楽しさ」を教えるためにすることは何もない。ただ考えさせ、創らせてやればいいと思う、どんな形でもいいから。

しまった、これは親父の罠だ!

そんなことを考えてて、見事に俺は親父の戦略にはまったんじゃないかと思えてきた。思えば親父は俺に何かをしろと言ってくることはそんなになかった。暇さえあれば本を読んであれこれ考える生意気なガキになったのは、ただそこに本が沢山にあったから。工作やお絵描きに熱中して、ものをつくるって楽しいと知ったのは、そこにただ工作道具や筆記具があったから。それからパソコンをいじるようになったのも、ただそこにあって、親父がいつも面白そうにガチャガチャいじってたからだ。唯一やれと言ってきたキャッチボールには、全く興味を示さなくて、親父ががっかりしてたのは覚えてる。

で、そんな俺がどうなったかというと、今親父と同じプログラマになろうとしてるわけで。親父は何もせず、ただそうなる可能性のある環境を作った*2だけで、息子をプログラマに仕立て上げてしまったんだから、大した策士だ。まぁ、もっともプログラマにしたかったかどうかも定かではないが。

そしてきっと、俺に自分の子供ができたときも、そんなことを繰り返すのかなぁと漠然と思う。子供に俺みたいになって欲しいとはあんまり思わないけども。

*1:それでもプログラミングしないのなら多分向いてないのだろう。そんときは教えても仕方がない。

*2:本も工具もパソコンも親父が趣味で持ってたものなので、意図して作った環境なのかはわからない

今仕事でRailsアプリケーションを組むときに、test/unitじゃなくてRSpecを使ってる。mock周りの使い勝手がいいとか、語彙が馴染みやすいとかいろいろ魅力があるんだけど、その「可読性」を保つにはなかなかコツがいると思う。

言うまでもなくRSpecはRubyのコードを「英語の表現として自然に見える」ようにすることを意図して語彙や書き方を決めている。これは英語圏のエンジニアには非常に素敵なことではあるんだけど、英語が苦手で英作文なんて始めて数分で泣きたくなるようなへたれ外国語学部生にとっては正直やっかいだし、周りの人達の大半は英語に慣れていない人達*1だったりするので、せっかく可読性が高い綺麗な表記でさえむしろ意図を理解する妨げになったりする。いっそドイツ語で書いて「お勉強」に活用してやろうかという衝動に駆られたけども、誰一人として読めない上に一週間後の俺ですら理解に苦しみそうなのでそんな暴走は妄想の中だけにしておく。

ということで、やっぱりSpecやらコメントやらといったものは、とっつきやすくするためにもできるだけ日本語で書きたいところ。ところが、英語の語順を前提にしているのでちょっと工夫しないとコードとして見たときかspecコマンドの出力かどっちかが不自然になるんだよなぁ。

Lesson1:I study english編

まず、RSpecの記述はどういうふうに書くかというと、

describe ClassName, 'context' do
end

となる。で、その条件下にあるときの挙動について、

it 'should ...' do
end

で列挙していく。例えば、最近各方面で名前を聞くことの多いあの先生の仕様を書くなら、

describe Teacher, 'when introduce himself' do

  it 'should tell own name' do
    momoiro = Teacher.new('糸色 望')
    momoiro.name.should be_eql('糸色望') #桃色係長の名前をつなげて書いちゃだめですよ。
  end

end

こんな感じ。describe〜やit〜もさることながら、仕様確認の処理の記述も'momoiro('s) name should be equal "糸色望".'とちゃんと読めていい感じ。で、これを実行すると、

'Teacher when introduce himself should tell his own name' FAILED
expected "絶 望", got "糸色 望"

という出力をしてくれる。この'Teacher when introduce himself should tell his own name'が綺麗に文章になっていて*2「RSpecは軸がぶれてない 素敵」と口ずさみたくなる感じ。いや、軸関係ないけど。人として。でもこれは英語が'Something when ...'で一つの主語になるから綺麗に'it'に繋がるのであって、日本語で単純に置き換えるとちょっと不自然になる。

Lesson2:仕様なんぞ箇条書きで十分なんです編

最初はもういっそ英語的な部分は無視して、

  • 先生が自己紹介をするケース
    • 自分の名前を言う
    • 横書きにされると絶望する
    • 命名権には数十円から数百円/日必要

という箇条書きのイメージで、contextには条件を、'should ...'の部分には説明を書いてしまえと

describe Teacher, '先生が自己紹介をするケース' do
  it '自分の名前を言う' do
    ...
  end
  it '横書にされると絶望する' do
    ...
  end
end

と書いてみたところ、

'Teacher 先生が自己紹介をするケース 自分の名前を言う' FAILED

となってしまった。ぬうん。なんか、文章にならないのが気持ち悪い。最初のTeacherもちょっと気持ち悪い。どうせなら、出力も日本語として違和感無く読める物@ITの記事より)であるといいなあと思うんだよなぁ。

Lesson3:specコマンドは日本語で喋り始めました編

じゃあ、ということで、さっきの画像にならって、出力の文章が繋がるようにしてみる。

describe Teacher, '先生が自己紹介をするという状況では' do
  it '先生は自分の名前を言うんだ' do
    ...
  end
  it '先生は横書にされると絶望するんだ' do
    ...
  end
end
'Teacher 先生が自己紹介をするという状況では 先生は自分の名前を言うんだ' FAILED

…出力はいいんだけど、肝心のSpecの記述、日本語が浮いちゃっててなんだかな。Teacherやitが完全に無視されてるのも可哀想スマートでない。

Lesson4:俺は妥協しないぜ!編

で、大腸のしくみについてよく考えた*3結果、「が〜〜するとき」と「は〜〜すること」というふうにすると不自然さが若干緩和されるなぁというところに至る。

describe Teacher, 'が自己紹介をするとき' do
  it 'は、自分の名前を言うこと' do
    ...
  end
  it 'は、名前を横書きにされると絶望すること' do
    ...
  end
end
'Teacher が自己紹介をするとき は、自分の名前を言うこと' FAILED

やった。これならSpecの方では「それ(it)は、〜〜なこと」と読めるし、出力は「〜〜するときは、〜〜なこと」と読めてどちらも自然。俺ってば軸がぶれてない、素敵。…結局それが言いたいだけか。

*1:以前ある人がRailsの書籍の情報が若干古くてハマってたので、「ググって調べて」って言ったらさらに古いバージョンの日本語APIリファレンス読んでて、なんで一次資料見ないのって突っ込んだら「英語だから…」って言われたときは泣けた。気持ちはわかるけど、勘弁してよ…。

*2:「つーか英文間違ってるじゃねーかこのゆとり世代が!」って思ったら激しく指摘してください。「っるっせーわこのダラズが、そんぐらい知っとるわい!!ネタに決まってんじゃろがボケが!!」と感謝の言葉を述べながら即座に修正します。

*3:ネタ古いなぁ。なんでこんなの唐突に思い出したんだろう

Lightweight Language Spiritに行ってきました。想像以上に面白かった!!ふんふんふん!!(←興奮しすぎ)

書きたいことは山程あるんだけど、うん、たぶん後で書く。メモ大量に取ったせいで整理できてない。

  • Perl 6.0 はポロロッカ星人によって作られる
  • とかちつくちて
  • Matzサンタさん!
  • Xtalはゲーム制作用として発売しています
  • むしゃくしゃしてやった。今は(ry
  • でもエフェクトはS式
  • 対策:PHPは避ける

…ちょっと待て。俺は一体何を聞いてきたんだ。おい。

さっきは興奮しすぎて書けなかった*1、LL魂の感想の続きを。

基調講演

HHKの和田先生、素敵な方ですね。講演内容の「hackとはplayfulな行為」「好きだからやる」というのが端々から伝わってきて大変面白かった。なんだか楽しくなった。

Language Update

弾さんの小ネタやMatzさん&笹田さんのペアプレにはかなりやられた。ていうかMatzさんびっくりだよもう。Ruby 2.0って!?ええ、1.9は!?と普通に騙されかけた。Lazy Collection欲しいよw

個人的に興味をひかれたのはIo。プロトタイプベースのオブジェクト指向言語ということで、全く知らなかったんだけど中々面白そう。なんでもオブジェクト、なんでもメッセージの特性を利用して、演算子*2の定義と「Rubyでいうところのmethod_missingのような機構」だけで、まるでWiki記法のようなプレゼン用DSLを実現しちゃうのにかなり驚かされた。

というわけで早速Ioをいじってしまいましたぜ。

昼休み

LL魂とは微塵も関係ないんだけど、ファミマのおにぎりが美味かった。地獄の沙汰もヨメ次第ってどんなドラマ?

オレ様言語の作りかた

Xtalの石橋さんのプレゼンが面白過ぎて会場大爆笑。終始飛ばしまくり。…よし。

集められた「オレ様言語*3」の中でも特に異彩を放ってたのはやっぱりなでしこ。まぁ、前々から面白いなとは思ってたんだけど、あまりいじってみたくはならなかった。けど、実際コードを見てみたら…あれは、凄いな。どう見ても日本語です。可読性、特に非プログラマに見せたときの理解可能性は圧倒的というか、他の言語やフォーマットでは実現できないものだよね。

質疑も全てなでしこに集中してた。その中でもっと日本語っぽくできそうじゃない?とか形態素解析とかと組み合わせて表記のブレも吸収できるようにしない?とかって提案も出てたけど、なでしこはあれでいいんじゃないかと思う。自然言語でコンピュータを制御する研究はこれから色んな方面で進むと思うしそれはそれで興味深いと思うのだけども、なでしこの「バッチ処理を手軽に記述する」とか「非プログラマに事務処理を自動化してもらう」とか、そういった用途を考えるとあまり柔軟であるよりは簡潔で簡易なものの方がいい。くじら飛行机さん自身が言ってたけど、プログラミング言語というよりはコマンドの塊、シェルスクリプトのようなイメージなんだよね。だったらあれは十分に現実的な解だと思う。

あと他に、簡潔さと非プログラマにも読みやすいって特徴が生きそうなところと言えば、TDDやBDDにおける仕様記述だろうか*4。CLRやJVM上で動かしてテスト/仕様記述向きのシンタックスを組み込んだらなかなか面白いことになりそうな気がする。

VM魂

どれも中々興味深いんだけど、参加者のみなさんかなり興味津々だったみたいなんだけど、残念ながら俺個人的には最近あんまりJavaも.NET触れてないのでそんなに思うところはなかったんだよね…。でも、DLRの話が面白かった。Silverlight上でPythonのモジュールを読みこんでそれにJSでイベントハンドラ付けてやってアプリケーションとして動かすってデモを見て、Microsoftすごいことになってるんじゃん、と思いました。DLRは注目しとこう。

あと、荒井さんの発表がさりげなくVistaのデモにもなってるように見えた。全然関係ないけど、高井さんのスライドが本当に次々と横方向にスライドしまくるので酔った。

プレゼン魂(キミならどう書く?)

これは非常に面白かった。

まず、「一般人に使えるプレゼンソフト」っていう要件定義が無視されてたのに笑った。独自のXMLフォーマットで記述とか、HTMLにScriptタグでエフェクト指定とか、無理でしょ普通に。結局「オーサリングツールが要るよね」って話に落ちついたけど、小黒さんのR-Slideの「ドキュメント作成機能は思いきって切り捨てて表示に特化させる」ってアプローチは案外ありかなと思う。何故かは知らないけど、非プログラマの人って意外とドローツールとか使えたりするし。いや、俺の周囲の人がそういう傾向なだけかもしれないけど。でも、独自記法とか新しいソフトの使いかたとかを覚えるよりは一般人には楽そうだ。それでいて逸般人にも素敵なソフトだったし、R-Slide。

amachangさんのJSプレゼンツールは本当に綺麗で使いたくなったし(あのインデックスは素敵すぎる!!感動した!)、下田さんのプレゼンで高橋メソッドはやっぱり素敵だと再認識できた。小黒さんはプレゼン自体が面白い&前述のアプローチが興味深いのはもちろんのこと、チャット連動機能でニコニコ動画化しかけた*5ことで相当盛りあがった。使いどころは難しそうだけど、あれは上手くすればとてつもなく面白いものができそう。

Lightning Talk

この辺は流石にメモれなかっただけど、大爆笑させてもらいました。ネタに走りまくってたのも普通なのもどれも面白かったんだけど、書ききれないや。

来年は

と、こんな感じでお腹いっぱいになったLL魂。実は初めてこの手のイベントに参加したのだけど、今まで行かなかったのが悔やまれるくらいに大満足でした。ところで、来年は定員1300名でやるそうですよ。…なんだその規模!おおお!?

*1:自分で書いた奇怪なメモを整理できなかったからとも言う

*2:というか、予約語じゃないからあれもメッセージなんだよね

*3:このセッションでは、なでしこ、Xtal、Sukuna、crowbar/Diksamの作者の方々の発表があった

*4:なでしこのソースだけで、顧客や営業に見せる仕様書と、テストと、開発者向けのドキュメントを全て兼ねさせられるなぁ

*5:自重しろ、との返しも含めてw

また新しいのが出てたので、こないだTigerを入れ直したばかりのMac miniをまっさらにして入れてみる。なんだか最近OSのセットアップが週末の習慣になってる気がする。なにかあったらすぐOS再セットアップ。気分転換にOS再セットアップ。なんだその変な趣味。おかげでMacOSXの再セットアップには大分手慣れてしまったよ。

で、Leopardの最新Preview版。すごい。興奮して鼻血出そう。新インターフェースはWWDCとかで発表されてる通りなんだけど、なかなかにインパクトあるよ。まだ最適化が足りないのか、1.83GHz Core Duoでメモリ512MBのMac miniでは若干重かったけども。あと、半透明のメニューバーは視認性悪いな。

具体的なことは多分ここには書けない*1のが残念なのだけども、もう発売間近なので皆さんお楽しみにということで。アプリの互換性とか検証してみよう。あとObjective-C 2.0だなぁ。あとでADCのリファレンス読んでみよう。

*1:ってかどこまで書いていいのかわかんない。規約確認しないと。

PHP版Ruby on Rails? - DB操作クラスを自動生成する”PHP Object Generator”

POG

なかなか面白いし、便利そう。まぁ、最近PHPで書くことは滅多に無いので多分使わないけど。あーでもこの記事の

POGはもともと、データベースにアクセスするコードを自動生成することで開発時間を削減することを目的として開発された。データベースにアクセスするためのコードはアプリケーションごとに異なるが、結局似たようなコードになることが多い。こういったソースコードの生成を自動化することで開発時間を短縮しようとアプローチしている。POGで採用しているアプローチはRuby on Railsで採用されているアプローチと似ている。

PHP版Ruby on Rails? - DB操作クラスを自動生成する"PHP Object Generator"

って、えーと、これで「PHP版Ruby on Rails」は流石にちょっと。

これは見たとこ便利なコードジェネレータって感じで、フルスタックのWebアプリケーションフレームワークであるRoRとはそもそも用途が違う気がするし、RoRのジェネレータの部分だけ見て「そういうアプローチ」ってのも乱暴かと。DRY原則、MVCモデル、O/Rマッパー、マイグレーション…とか、それらの要素をとっぱらって script/generate model だけあっても全然RoRじゃないと思うんだけどなぁ。

新宿の紀伊国屋にはあったけど近所の本屋には置いてなかった(まぁ、当然か)ので、今日は大宮に行って買ってきた。

うん。すごく良い。HMDTのサイト上と同じライトな語り口で読みやすいし、ちゃんとOSXやCocoaの基礎を説明してるけどあちこちに深入りしないバランス感覚が丁度いい。読み進めると何気なくXMLのパースとかPackageMakerの使いかたまで書いてくれてるのも嬉しい。なんか作りたくなってくるなぁ。

これからプログラミングをはじめてみようと思いたってこの本を手にするという、なんともチャレンジャーな人がどれだけいるのかはわからないけど、あまりにも情報が少ないMacでのアプリ開発をしてみたい人にとっては価値ある一冊ですね。

今度はXcode上でアプリケーションを作るときに使えるかやってみる。

アプリケーションで使うクラスを全部フレームワークとしてビルドして、RubyからOSX#requiew_frameworkすれば自作のObjective-CクラスをRSpecにかけられることは前回まででわかったのだけど、流石にそれはダルい。プロジェクト内にmyclass_spec.rbってファイルを置いといてSpecターゲットをビルドするとそれらを自動で検証してくれたりするのが理想なわけです。

そんなわけで、こういう手順でやってみた。

  1. 普通にCocoa Applicationのプロジェクトを作る
  2. プロジェクトにRubyCocoa Applicationを作るビルドターゲットを追加する
    1. RubyCocoa Applicationを起動すると、'_spec.rb'のファイルを読み込んでSpec Runnerで実行するようにする
  3. xxx_spec.rbを書く
  4. xxx.m (Objective-Cのクラス)を実装する
  5. RubyCocoaのビルドターゲットの方で「ビルドして実行」

ビルドターゲットを最初Shell Toolで作ろうとしたんだけど、それだとリソースとしてRubyスクリプトを含められないので外部から読み込んだりといろいろ面倒くさい。その辺はまた後で考えるとして、とりあえずRubyCocoa Applicationにしてmain内でアプリケーションループを開始しないでスクリプトだけ実行して終了するようにした。これならクラスやスクリプトは自動で読み込まれるしGUIは表示されない。

Specターゲットの方のmain.mとrb_main.rbはこんな感じ。

#import <Cocoa/Cocoa.h>
#import <RubyCocoa/RBRuntime.h>

int main(int argc, const char *argv[])
{
    return RBApplicationMain("rb_main.rb", argc, argv);
}
require 'osx/cocoa'
require 'rubygems'
require 'spec'

def rb_main_init
  path = OSX::NSBundle.mainBundle.resourcePath.fileSystemRepresentation
  specs = []
  rbfiles = Dir.entries(path).select {|x| /?.rb?z/ =? x}
  rbfiles -= [ File.basename(__FILE__) ]
  rbfiles.each do |path|
    if path =? /_spec/
      specs << File.join(File.dirname(__FILE__), File.basename(path))
    else
      require( File.basename(path) )
    end
    ::Spec::Runner::CommandLine.run(specs, STDERR, STDOUT, true, true) unless specs.empty?
  end
end
if $0 == __FILE__ then
  rb_main_init
  #OSX.NSApplicationMain(0, nil)
end

これでResource内のxxx_spec.rbを全部読み込んでSpecRunnerにかけてくれる。試しに実装してみる。

Namakemono.h

#import <Cocoa/Cocoa.h>

@interface Namakemono : NSObject
{
	NSString * name;
}
- (id)initWithName:(NSString *)aName;
- (NSString *)name;
- (void)setName:(NSString *)aName;
- (NSString *)greetingMessage;
@end

namakemono_spec.rb

include OSX

describe Namakemono do
  before :each do
    @faul = Namakemono.alloc.initWithName(NSString.stringWithString('faultier'))
  end
  
  it 'should be Namakemono' do
    @faul.should be_kind_of(Namakemono)
  end
  
  it 'should have name' do
    @faul.name.to_s.should eql('faultier')
    @faul.greetingMessage.to_s.should match(/Hello, my name is #{@faul.name}/)
  end
end

「ビルドして実行」

[Session started at 2007-07-23 02:07:18 +0900.]
..

Finished in 0.014898 seconds

2 examples, 0 failures

Spec はステータス 0 で終了しました。

ばっちりだー!そうそう。そういうの、俺が望んでたのは。視覚的に面白いかどうかはともかく(C#のNUnitみたいなGUIツール作るのがいいかなぁ)、SpecをRubyで書けるようになったことで飛躍的に可読性と柔軟性が上がる。あと、個人的な趣味と会社でも使ってて慣れてるからRSpecにしたけど、別にTest::Unitを使ってもいいよな。ていうかRuby test classってテンプレートあるんだけど、もしかしてもう俺がやろうとしてるような機構がRubyCocoaに組込まれてるんだろうか。…なんか段々車輪の再発明じゃないかと不安になってきた。faulって馬鹿だなーと思った方は是非つっこんで下さい。

まぁでも、マインドセットとしてはTDDよりBDDの方が良いと思うし、テスティングフレームワークであるTest::Unitより仕様記述用のDSLっぽく実装されてるRSpecの方がより可読性は高いと思うし、だから敢えて使うんだ、と、いうことで。と、いうことで。

さてここまで来たわけだけども、歓喜の踊りを踊るのはにはまだ早い。毎回無意味にビルドターゲットにRubyCocoa Applicationを入れて一から実装するのはかなり嫌なので、Specを読み込んで実行するツールだけ別に作っておいて、RSpecのスクリプトとObjective-Cのクラスを含んだローダブルバンドルをビルドターゲットにして、そいつをビルドフェーズの最後でツールに読み込ませて実行するようにしたい。できればunit test bundleみたいにテンプレにしてしまえればいいんだけど。Xcodeのテンプレって自分でも作れるんだよね、多分。知らないけど。

うーん。眠くなってきたので今日はここまで。

今日はちょっと別なことに興味を引かれたので、一旦Cocoa&RSpecでBDD大作戦のほうはお休み。

さて、Dashboad Widgetなら開発もCUI上で完結できるんじゃね?なんて言ってしまったのでTerminalから手動でバンドルをビルドする方法を探してみることにした、のはいいんだけど何だかえらい面倒なことになりそうだ。

バンドルの実態

OSX上で実行可能なモノとして扱われるアプリケーションバンドル(拡張子が.appのやつら)にしろ、ウィジェット(.wdgt)にしろ、実態は単なるディレクトリで、中に決まった構成でファイルを配置して特別な拡張子を付けたものにすぎない*1。フレームワーク(.framework)やローダブルバンドル(.bundle)も同様。その証拠にターミナルでcd /Application/Safari.appとかやるとSafariの中に入れるし、Finderからでも「パッケージの内容を表示」で中身を見ることができて、そこでいろいろいじくることでアイコンを変えたりローカライズしたりアプリケーションそのものの挙動を変えてしまったりも簡単にできる。

で、あるならばそれを自力で作ってしまえばいいわけで、rakeとかmakeとかで自動化してしまえばCUIでサクサク開発も夢じゃない。と、ここまでは知ってはいた。けども、実際何が必要でどんな手順でやればいいのかはわかんない。さて、どうしたもんかね。

とりあえず本職に聞いてみる

不可解なことでも実際誰かがやっていることであるはずなので、そいつの仕事ぶりを見て技を盗めばいい。つまり、Xcodeの様子を観察してみればいいのだ。Xcodeの仕事はと言えばまさにgccでソースをコンパイルして、バンドル用のディレクトリを作り、必要なファイルをそこにコピーすることに他ならないので、要は見様見真似でそれをやってのければいいのです。多分。

というわけで、早速Xcode上でCocoa Bundleプロジェクトを作成してそれをビルドさせてみる。動作としてはこんな感じだった。

  1. Test.bundle/Contentsを作ってそこにInfo.plistをぶち込む
  2. Test.bundle/Contents/Resourcesを作ってそこにローカライズ可能なリソースたち(デフォルトのプロジェクトだとEnglish.lprojにInfoPlist.stringsがあるだけ)をぶち込む
  3. プリコンパイル済みプレフィックスヘッダとやらを生成、または処理する
    1. '-arch ppc'で
    2. '-arch i386'で
  4. ソースをコンパイル
    1. '-arch ppc'で
    2. '-arch i386'で
  5. リンク
    1. ppc用のやつをppc用のフォルダに入れとく
    2. i386用のやつをi386用のフォルダに入れとく
  6. ppc用バイナリとi386用バイナリをくっつけてUniversal Binaryを生成、Test.bundle/Contents/MacOSにぶち込む

これで出来上がり。うん、大体予想してた通りだ。このうちプリコンパイル済みヘッダとやらは多分なくてもいい。あと最初のInfo.plist、com.apple.tools.info-plist-utilityとかいうので処理してるんだけど、それがどこにある何のことなのかよくわからない。出来たバンドルの中見たけど単に元のInfo.plistのコピーが入ってるだけに見えるんだけどな。

で、それぞれの段階で二回ずつ処理してるのがちょっと面白い。Universal Binaryって本当に二つのアーキテクチャ用にコンパイルしたバイナリを一纏めにしてるだけなのか。ふぅん。何だか面倒なので差しあたって手を出したくないところなんだけど、大した機能があるわけでもないのにIntel Mac専用なウィジェットとか作ったところで面白くもないので、これもちゃんと覚えておこう。多分同じことを二回やってくっつけるだけだ。きっと。おそらく。

ということで、こんなRakefileを作ってみた。Rakefileの書きかたちゃんと調べてないけどまぁ失敗したら後で直せばいいか。(こら)

task :default => :build
desc 'Build loadable bundle'
task :build => ['Hello'] do |t|
  bundle_name = 'build/Hello.bundle'
  Dir.mkdir bundle_name
  Dir.mkdir "#{bundle_name}/Contents"
  Dir.mkdir "#{bundle_name}/Contents/Resources"
  Dir.mkdir "#{bundle_name}/Contents/MacOS"
  sh "cp Info.plist #{bundle_name}/Contents"
  sh "cp -R English.lproj #{bundle_name}/Contents/Resources"
  sh "cp Hello #{bundle_name}/Contents/MacOS"
end

file 'Hello' => ['Hello.ppc', 'Hello.i386'] do |t|
  sh "/usr/bin/lipo -create #{t.prerequisites} -output #{t}"
end

file 'Hello.ppc' => ['Hello.ppc.o'] do |t|
  sh "/usr/bin/gcc-4.0 -o #{t} -framework Cocoa -arch ppc -filelist #{t}.LinkFileList -bundle -mmacosx-version-min=10.4"
end

file 'Hello.i386' => ['Hello.i386.o'] do |t|
  sh "/usr/bin/gcc-4.0 -o #{t} -framework Cocoa -arch i386 -filelist #{t}.LinkFileList -bundle -mmacosx-version-min=10.4"
end

file 'Hello.ppc.o' => ['Hello.m'] do |t|
  sh "/usr/bin/gcc-4.0 -x objective-c -arch ppc -o #{t} -c #{t.prerequisites}"
  File.open('Hello.ppc.LinkFileList', 'w') { |f| f.write('Hello.ppc.o') }
end

file 'Hello.i386.o' => ['Hello.m'] do |t|
  sh "/usr/bin/gcc-4.0 -x objective-c -arch i386 -o #{t} -c #{t.prerequisites}"
  File.open('Hello.i386.LinkFileList', 'w') { |f| f.write('Hello.i386.o') }
end

お。ちゃんとビルドできた。class-dumpしてみる。

$ class-dump build/Hello.bundle/Contents/MacOS/Hello
/*
 *     Generated by class-dump 3.1.1.
 *
 *     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2006 by Steve Nygard.
 */
This file does not contain any Objective-C runtime information.

クラスがない。思いっきり失敗しとるやんけ。 orz

念のため普通にXcodeでビルドしたやつもclass-dumpしてみるとちゃんとクラスの情報取れる。他のCocoaアプリからロードしてみても、自分で構成したやつはprincipalClassがnilになる。…うー。よくわからないまま適当にコンパイラのオプション省略するからいけないんだよね…。もうちょいいじってみよう。

追記

ちゃんとビルドできました。リンクのタイミングでXcodeは-filelistってのを使ってるんだけど、それやめて引数でファイル名与えたら通った。ってかやっぱり上のRakefile手順間違ってる?

*1:と、書いてあるっぽい。多分。

BDDでCocoa開発をするのにRSpecを使ってみるの続き。

なんだか意外と簡単に使えそうだったのでこんどはCocoa組込みじゃないフレームワークで試してみよう、ということでOgreKit。こちらは事前にコンパイルして/Library/Frameworks以下に配置済。と、ここでそもそもどうやってフレームワークを呼び出すのかわからなくて一思案。本家サイトでなんか書いてないかなーと探してみるも、どこに書いてあるんだかわからん。ActiveRecordSupportとか興味深いことが書いてあるのも見つけたけどとりあえず後回し。

サンプルのソースを見てたらOSX.require_frameworkを使うらしいというのはわかったんだけど、読み込んだフレームワークのクラスがどこにあるのかわからずしばらく悩んだ。OgreKit::OGRegularExpressionとかやってみてそんなもん無いと怒られたり。冷静に考えれば、Objective-CだったらRubyみたいにモジュールがネストしてないのでOSX::OGRegularExpressionがでよかったんだけど、それを見つけるまでGoogle先生を質問攻めにしてしまった。さてそんなわけでできたのがこんな感じ。

require 'osx/cocoa'
include OSX
require_framework 'OgreKit'

describe OGRegularExpression do
  before :each do
    @match_string   = 'Ich liebe dich, aber du liebst ihn. Ich liebe dich...'
    @unmatch_string = 'Ich mag nicht nur Ruby, sondern Objective-C.'
    @expression     = 'dich'
    @ogregex        = OGRegularExpression.regularExpressionWithString(@expression)
  end
  
  before :all do
    @result         = []
  end
  
  after :all do
    p @result
  end 
  
  it "should replace matches" do
    # Rubyのメソッド呼び出しっぽいスタイル
    replaced = @ogregex.replaceAllMatchesInString_withString(@match_string, 'mich')
    replaced.to_s.should_not include(@expression)
    @result << replaced.to_s 
  end
  
  it 'should replace nothing when no matches in string' do
    # こっちはObjective-Cのメッセージパッシングっぽいスタイル
    not_replaced = @ogregex.objc_send(:replaceAllMatchesInString, @unmatch_string, :withString, 'mich')
    not_replaced.to_s.should eql(@unmatch_string)
    @result << not_replaced.to_s
  end
end
$ spec ogrekit_spec.rb
..["Ich liebe mich, aber du liebst ihn. Ich liebe mich...", "Ich mag nicht nur Ruby, sondern Objective-C."]


Finished in 0.018822 seconds

2 examples, 0 failures

でけたでけた。変換の例に使ってる文章が何なのかは気にしない方向で。OgreKitのSpecなのに正規表現使ってないのも気にしたら負けかなと思ってる。で、OgreKitは既に有効なロードパスの中にあったのでフレームワーク名で呼び出せたけど、OSX#require_frameworkは引数にフレームワークのフルパスも与えられるので、フレームワーク化してしまえば自分で作った任意のObjective-Cクラスも簡単に扱える。まだ試してないけどバンドルをロードする機能もある。思ったんだけど、gemのパッケージを自動生成するやつみたいにwigetのファイル構成とかビルドするRakefileとかのジェネレータを作ったら便利かもしれない。wdigetならインターフェースもバンドルの開発もCUI上で完結できるし、RSpecで確認しながら作るスタイルは向いてるかも。Dashcodeが出ようってご時世に何を言ってるんだか…でもvimのが楽なんだもん、Xcodeでいろいろやるより。

あと、初めてRubyCocoaを見たときにも思ったんだけど、Objective-Cはメソッド名が長いなぁやっぱり。CamelCaseもRubyの中にあるとどうしても違和感が拭えない。慣れるっきゃないかな。Objective-Cで書いてるとそんなに気にならないんだけど。何でだろ。

さて、なんだかRubyCocoaを触ってみよう、なノリになってきたけど、目的はRSpecでもRubyCocoaでもなくて「CocoaでBDD」。これをどうにかしてCocoaアプリの開発に取り入れてみたいと思う。いちいちアプリをフレームワーク化してビルドしてterminalからspec実行して、とかやりはじめたら本末転倒。Xcodeで上手く自動実行させる方法を考えよう、と。

前々からCocoaで開発してるときにTDDがいまひとつやりにくいのが気になってた。Xcodeにも組み込まれててデファクトになってるOCUnit、あれが結構使いにくい。単に使いかたを理解してないだけだという気もするけど、それを差し引いてもTDDのツールとしてはそんなに洗練されてないと思う。実行結果が視覚的に面白くないし(これはモチベーション下るので結構重要)、エラーの通知もあんまり解析しやすくない。そういえばアサーションの実態がCのマクロなのでObjective-Cの文法じゃないのも気になるし、あんまり柔軟じゃない。他にもいろいろな実装はあるらしいけど、ただでさえ情報の少ないCocoaのそれもTDDのしかも代替フレームワークともなると、日本語で読める最新の詳細な情報など皆無。ここでぬぬぬぬ、となるわけですよ。

なきゃ作れという話

ということで、最初は自分で作ることを試みた。もっとわかりやすいのがいいし、せっかくObjective-Cみたいな動的な言語なんだからリフレクションとか使って柔軟にやって欲しいし、ああどうせならBDDっぽい語彙で書きたいよなー、とか妄想を膨らます。イメージとしては

- (void) before {
  // 俺を作る
  faul = [[Namakemono alloc] initWithName:@"faultier"];
}

- (void) after {
  // 俺を逃がしてやる
  [faul release];
}

- (void) whenIntroduce {
  [faul shouldKindOf:Animal];
  [faul shouldKindOf:Namakemono];
  [[faul name] shouldEqual:@"faultier"];
  [[faul capitarizedName] shouldEqual:@"Faultier"];
}

- (void) whenStudy {
  // 来週はテストだ
  id study = [[Task alloc] initWithName:@"English Study"];
  [faul setTask:study key:@"study"];

  [[faul task:@"study"] shuldEqual:study];
  [faul shouldThrow:NullYarukiException message:@selector(reportProgress:) arguments:@"study"];

  // studyタスクを開放し忘れるとテスト直前にメモリリークしてることに気付く…
  [study release];
}

こんな感じ。あとモックも欲しいなぁ、CUI版とXcode組み込み版のRunnerはそれぞれいるよなぁ、とか言ってたら手に負えなくなってきた。あは。

じゃあRubyで書けばいいんじゃね?

RubyにはRSpecという素敵な代物が既にある。スクリプトなら拡張も容易だし、Rubyの表現力なら好き放題書ける。RubyCocoaはLeopardでは標準で入るらしいから環境整える手間もいらないし、それを使えばサクっとBDDできるんじゃない?と思い立ってやってみることにした。

まずはCocoaのクラスのSpecをどんなふうに書けばいいのか試してみる。

require 'osx/cocoa'
include OSX

describe NSString do
  before :each do
    @expected_string = 'Cocoa BDD with RSpec'
    @str = NSString.stringWithString(@expected_string)
  end

  it 'should be allocated from String' do
    @str.should be_kind_of(NSString)
    @str.to_s.should be_eql(@expected_string)
  end

  it 'should not be editable' do
    @str.to_s.should be_eql(@expected_string)
    lambda { @str << 'append' }.should raise_error(OCException)
  end

  it 'should be editable' do # わざと間違えてみる
   @str << 'append'
   @str.to_s.should be_eql("#{@expected_string}append")
  end
end

実行結果

$ spec nsstring_spec.rb
..F

1)
OSX::OCException in 'OSX::NSString should be editable'
NSInvalidArgumentException - Attempt to mutate immutable object with setString:
/Library/Frameworks/RubyCocoa.framework/Versions/A/Resources/ruby/osx/objc/oc_attachments.rb:57:in `setString'
/Library/Frameworks/RubyCocoa.framework/Versions/A/Resources/ruby/osx/objc/oc_attachments.rb:57:in `method_missing'
./nsstring_spec.rb:20:

Finished in 0.013094 seconds

3 examples, 1 failure

普通だ。なんらの違和感もない。これはまごうことなきRubyだ。素敵素敵。

あとは自作のクラスを検証するやりかたと、Cocoaアプリの開発サイクルにどう組込むかだねー。あとでやります。


実際に使ってもらうのに勝ることはないとは知ってはいたけど、本当にやってみると…ああ、全く正しいね。うん。 orz


作り手は自分の埋めた地雷など踏まない。使い手は作り手の予想など軽々越えられる。




木下さんの新しいCocoa本が出るということを今知った。あわわわ。プレゼント企画ももう終わってるじゃないか。しまったー乗り遅れたー。

今度は初心者向けの入門書らしい。そういえば俺がCocoaで遊んでみようと思ったときにはHMDT本を買ったけど、「Macってどうやっていじくるの?」「Objective-Cって何やのん?」ってレベルだった当時、率直に言って若干敷居が高かったし(いきなりCocoaバインディングやCoreDataを理解しようというのは無謀だったなぁ)、かと言って他の本はと言えばXcodeの使い方みたいな表面的なとこをなでる程度で物足りなかったし、数少ないCocoa関連書籍の中でも良書と言われていたものたちも、その当時(PantherからTigerへの移行期ぐらいだったかな)でさえもはや時代遅れになってしまっていた。

で、今、せっかくLeopardやらBootCampやらSafariやらiPhoneなんかで注目が集まってるというのに、Macでプログラミングしてみようと思ってる人の足掛りになりそうなドキュメントがほとんど無い。…まぁ、ADCのリファレンス読めって話だけどさ。でもそろそろまたこの手の本が必要な頃合いでしょう。

そんなわけでたのしいCocoaには期待。つか俺もそろそろなんかCocoaアプリでも作ろう。RubyCocoaも試したいし。

あと、プログラミング初心者じゃなくてCocoaをちゃんと知りたい人にはObjective-C Mac OS Xプログラミングが断然オススメ。Objective-CとCocoaについて体系的にかつ網羅的に知りたいと思ったら、現時点で発行されてる日本語書籍でこれに勝るものは無いと思う。

追記

ここまで書いた時点でもう発売してるってことに気が付いた。よく読め俺。あほう。なんだかすごく恥しくなりつつ、早速明日たのしいCocoa買ってきます。

暇つぶしのつもりが…

サークルも引退し、新しいバイト先も決まって、なんとなく心に余裕を持って迎えた3連休。折角だからなんかしようと思い立って、RSSリーダー、といかRSSティッカーの開発を始めた。Cocoaの勉強は随分サボってたし、RSSを扱うプログラムを書くのは仕事(Webシステム開発)の役にも立つだろうし。ってことで数ヶ月ぶりにXcodeを起動させてみる。おおう。どうやって使うんだっけ。

経験はハウツー本より強し

1年前趣味で始めた頃は数週間で熱が冷めて、Objective-Cの独特の文法と情報量の少なさの前に早々に挫折したCocoaアプリ開発だけど、久々に手をつけてみると意外とわかるわかる。アルバイトとしてシステム開発の仕事に携わり始めて、半年。社内体制もプロジェクトの進め方もむっちゃくちゃで、仕事と言えばPHPやJSPで書かれたぐちゃぐちゃなコードの保守ばかりで、はっきりいって何のプラスにもならなかったと思ってた今の会社での仕事もしっかり経験になってたんだなぁ。データベースやXMLなんて、趣味でやってた頃は申し訳程度に弄ってただけだったもんな。…ほとんど自力で勉強してた気もするけど。ていうかベタ書きのPHPとObjective-Cじゃほとんど共通点無いけど。まぁいいや。

高僧と門前の小僧しかいない世界

てな感じでXcodeで遊んでたら、面白くなってきた。奥が深いなぁ、Objective-C。独特の構文も見慣れてくると味があるように見えてくる。言語の優劣を語れるほどいろいろ知ってるわけではないので余計なことは言わないようにしますけど、良いですよ、Objective-C。Cocoaも素敵だし。

…もう少しドキュメントが整備されると、尚良いんですが。MacOSXになってから以前より注目度が上がったとは言え、ユーザの母体数がWindowsやLinuxに比べると圧倒的に少なくて、その中でも開発者人口ともなると微小な数に過ぎなくて、さらに日本語で情報を発信してるサイトなんかGoogle先生でも数えるほどしか見つけて来れないレベル。その見つけたドキュメントにしても書籍にしても、凄い高度な内容か入門程度の表面的な内容かしかなくて、ちょっと弄ってみるって所から脱して自分で考えたアプリケーションを組み上げてみる、っていう2ステップ目に踏み出す助けには、あまりならない。しかも、MacOSXもCocoaもXcodeもガンガン進化してる最中なので、1年前の情報が半分くらい役に立たない始末。ぬーん。英語を、英語を読めと言うのね。仕方ないから読みますよ。読みますけど。MacOSX向けのフリーソフトがなかなか増えないわけだよなぁ。

↑このページのトップヘ