ここんとこMacPortsをメインに使ってたので気付いてなかったのだけど、GHCをインストールしたくなって、でも確かあれは「ソースからコンパイルはしてはいけない」って言われてたよな、MacPortsじゃない方法で入れたいな、と思って見に行ったらFinkのLeopard対応始まってた。
まだバイナリのダウンロードはできないみたいだけど、どのみちいつもソースから入れてるのであんまり関係ない。何かと便利なので入れておこう。
可能な限りナマケモノでありたい
ここんとこ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に入れたやつは。俺か。俺だよなぁ。
結局、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。
表題通り。恵比寿にあるドリコム東京本社に行ってRails勉強会に参加してきました。体調不良でえらい豪華なメンバーのランチには参加できなかったし、それどころか恵比寿についてから迷って遅刻ギリギリになるし、まぁいろいろとアレだったけども。うん、そう、ここのところ頭痛いなぁとか思ってたら、体が熱っぽいくて意識が遠くなって、そうかこれ風邪ひいてんじゃね?とか気が付いたのは帰り道。馬鹿は風邪ひかないんじゃなくてひいたことに気が付かないとは名言だなーとか思いながらよれよれと帰ってきました。それはそれとして、勉強会は非常に楽しかったです。以下、自分で後で見返すためにも軽くまとめ。
前半のセッションでは「Rails 2.0を読む」と題してRails 1.2から2.0になって変わったところをざっとさらい、該当箇所のソースを読んで、どんなことやってんだろうなどと話した。Rails 2.0。Railsの仕事から離れてからRails周辺の話題を追いきれてなくて、実はまだ試してなかったんだけど、ちょっと面白そうなことになってるみたい。これは後で試してみないとなぁ。
相違点をざっと。
SOAP関連のサポートが省かれてREST関連の機能が強化されてるよ、って話。これは前々から聞いてたのでふむふむなるほどと言った程度。RESTfulなクライアントサイドを書くための仕組みだけでなく、RESTfulなサーバサイドのAPIも作りやすくなってるらしい。
respond_toを拡張。面白いなぁと思ったのは、従来ならviewの拡張子がhoge.rhtmlとなるところがhoge.html.erbとかになる話。一個目の拡張子(変な言い方だ)でファイルの種類を、二個目の拡張子で何で処理するかを判別するらしい。
デフォルト設定だとURLに自動的にトークンが入ってCSRF攻撃対策を取るとか。えーとこれなんだっけと思いながらメモ見たら「あとで調べる」とだけ書いてある。コラ。しっかりしてくれ自分。
URLの規約をより簡素にして、モデルからURLを特定する仕組み。redirect_toやlink_to、form_forなどで使う。具体的にどういうことかというと、例えばRubyistモデルの情報を参照するページのURLが /[モデル名(複数形)]/:idという規約に従っていれば、userがRubyistクラスだったとしてlink_to(user)とかやると"/rubyists/#{rubyist.id}"なURLが自動生成されるということらしい。
Basic認証がデフォルトでサポートされるらしい。ところでなんでLoveなんだろう。
ARがQueryキャッシュするらしい。肥大化してものすごいメモリ食うんじゃねってとこを不安視する声が上がって、ソース読みながらキャッシュの生成・破棄のタイミングを調べたりしたのだけれど、どうもそんなに本格的なものではない様子。メモリリソースが気になるような状況では使わない、本格的にDB負荷や速度を考えるならどのみち違う方法でのキャッシングを考える。要検証。
マイグレーションの見栄えがよくなるよという話。
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の欠点でもあり俺個人の弱点でもあるパフォーマンスとそのチューニング、そのためにもまず上手なプロファイリングが必要だよねと。
Seattle.rbがいろいろと面白いものを作ってるらしく、いくつかのProfilerをセッションオーナーの瀧内さんが紹介してくれた。
中でも面白かったのがProduction Log Analyzer。これは実行中のプログラム自体の動作を測定するのではなく、ログを解析してRailsのパフォーマンスを測定するというもの。プログラムに組みこまないので「測定することによる影響」が無くてすむし、動作も重くならないし、既に稼働中のシステムを測定することもできる。これはなかなか素敵だった。
ただ、SyslogLoggerで吐いたログじゃなきゃダメらしい。なんでだろう。とりあえずSeattle.rbはSyslog大好き?ってことにしておいた。
RubyProfは必須だそうです。標準のprofilerより速いのか。実際にRailsに仕込んでプロファイルさせてみるところまで実演。ちなみにRails 2.0を使用。試行錯誤してる内にRailsのここが変わった、RubyProfの最新版はここが違う、なんて話も出たりして、苦労してプロファイル結果を表示したときには拍手が上がった。うん、大変だった。なんか凄く大変だった。
プロファイリングしたらデバッグしてみよう、ということで、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の~」に関しては特に言うことはなくて、自分でも言っているように、ゲームやらネットやらが溢れてる時代にその当時の感動を再現させるのは無理でしょう。ベーマガとやらがないというけど、どっかからソースコードを拾ってきてそれを自分の環境で動かしてみるってだけなら、むしろオープンソースだなんだとか言ってる今の方が容易。でもそれが今と当時じゃ同じ意味じゃないのは誰にだってわかる。そこに拘ると、「プログラミングの楽しさ」を見失うと思う。
教える必要があるのは「プログラミングは楽しい」ではなくて、もっと本質的な「考えることは楽しい」や「創り出すことは楽しい」の方だと思う。さらに言えばそれも教えるよりやらせてみる方が適切。で、増田さんはプログラミングを「やってみる」ことを通してそれを知ったのかもしれないけど、別にそれにはプログラミングが「最適」なわけじゃないし、むしろ今はいきなり「プログラミングを通して」それを教えるのは難しいんじゃないかな。逆に、「考えること」や「創ること」を楽しいと思える子供が、パソコンに触れる環境にあり、楽しそうにプログラミングしてる親父の姿を見てたら、プログラミングをやりたがる日はそんなに遠くないように思う*1。そんでもって、やりはじめてしまえば自分で勝手にサイトなり書籍なりを探してくると思う。今はそんなものそれこそ溢れてるし。だから、増田さんが「プログラミングの楽しさ」を教えるためにすることは何もない。ただ考えさせ、創らせてやればいいと思う、どんな形でもいいから。
そんなことを考えてて、見事に俺は親父の戦略にはまったんじゃないかと思えてきた。思えば親父は俺に何かをしろと言ってくることはそんなになかった。暇さえあれば本を読んであれこれ考える生意気なガキになったのは、ただそこに本が沢山にあったから。工作やお絵描きに熱中して、ものをつくるって楽しいと知ったのは、そこにただ工作道具や筆記具があったから。それからパソコンをいじるようになったのも、ただそこにあって、親父がいつも面白そうにガチャガチャいじってたからだ。唯一やれと言ってきたキャッチボールには、全く興味を示さなくて、親父ががっかりしてたのは覚えてる。
で、そんな俺がどうなったかというと、今親父と同じプログラマになろうとしてるわけで。親父は何もせず、ただそうなる可能性のある環境を作った*2だけで、息子をプログラマに仕立て上げてしまったんだから、大した策士だ。まぁ、もっともプログラマにしたかったかどうかも定かではないが。
そしてきっと、俺に自分の子供ができたときも、そんなことを繰り返すのかなぁと漠然と思う。子供に俺みたいになって欲しいとはあんまり思わないけども。
今仕事でRailsアプリケーションを組むときに、test/unitじゃなくてRSpecを使ってる。mock周りの使い勝手がいいとか、語彙が馴染みやすいとかいろいろ魅力があるんだけど、その「可読性」を保つにはなかなかコツがいると思う。
言うまでもなくRSpecはRubyのコードを「英語の表現として自然に見える」ようにすることを意図して語彙や書き方を決めている。これは英語圏のエンジニアには非常に素敵なことではあるんだけど、英語が苦手で英作文なんて始めて数分で泣きたくなるようなへたれ外国語学部生にとっては正直やっかいだし、周りの人達の大半は英語に慣れていない人達*1だったりするので、せっかく可読性が高い綺麗な表記でさえむしろ意図を理解する妨げになったりする。いっそドイツ語で書いて「お勉強」に活用してやろうかという衝動に駆られたけども、誰一人として読めない上に一週間後の俺ですら理解に苦しみそうなのでそんな暴走は妄想の中だけにしておく。
ということで、やっぱりSpecやらコメントやらといったものは、とっつきやすくするためにもできるだけ日本語で書きたいところ。ところが、英語の語順を前提にしているのでちょっと工夫しないとコードとして見たときかspecコマンドの出力かどっちかが不自然になるんだよなぁ。
まず、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'に繋がるのであって、日本語で単純に置き換えるとちょっと不自然になる。
最初はもういっそ英語的な部分は無視して、
という箇条書きのイメージで、contextには条件を、'should ...'の部分には説明を書いてしまえと
describe Teacher, '先生が自己紹介をするケース' do it '自分の名前を言う' do ... end it '横書にされると絶望する' do ... end end
と書いてみたところ、
'Teacher 先生が自己紹介をするケース 自分の名前を言う' FAILED
となってしまった。ぬうん。なんか、文章にならないのが気持ち悪い。最初のTeacherもちょっと気持ち悪い。どうせなら、出力も日本語として違和感無く読める物(@ITの記事より)であるといいなあと思うんだよなぁ。
じゃあ、ということで、さっきの画像にならって、出力の文章が繋がるようにしてみる。
describe Teacher, '先生が自己紹介をするという状況では' do it '先生は自分の名前を言うんだ' do ... end it '先生は横書にされると絶望するんだ' do ... end end
'Teacher 先生が自己紹介をするという状況では 先生は自分の名前を言うんだ' FAILED
…出力はいいんだけど、肝心のSpecの記述、日本語が浮いちゃっててなんだかな。Teacherやitが完全に無視されてるのも可哀想スマートでない。
で、大腸のしくみについてよく考えた*3結果、「が〜〜するとき」と「は〜〜すること」というふうにすると不自然さが若干緩和されるなぁというところに至る。
describe Teacher, 'が自己紹介をするとき' do it 'は、自分の名前を言うこと' do ... end it 'は、名前を横書きにされると絶望すること' do ... end end
'Teacher が自己紹介をするとき は、自分の名前を言うこと' FAILED
やった。これならSpecの方では「それ(it)は、〜〜なこと」と読めるし、出力は「〜〜するときは、〜〜なこと」と読めてどちらも自然。俺ってば軸がぶれてない、素敵。…結局それが言いたいだけか。
Lightweight Language Spiritに行ってきました。想像以上に面白かった!!ふんふんふん!!(←興奮しすぎ)
書きたいことは山程あるんだけど、うん、たぶん後で書く。メモ大量に取ったせいで整理できてない。
…ちょっと待て。俺は一体何を聞いてきたんだ。おい。
さっきは興奮しすぎて書けなかった*1、LL魂の感想の続きを。
HHKの和田先生、素敵な方ですね。講演内容の「hackとはplayfulな行為」「好きだからやる」というのが端々から伝わってきて大変面白かった。なんだか楽しくなった。
弾さんの小ネタや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上で動かしてテスト/仕様記述向きのシンタックスを組み込んだらなかなか面白いことになりそうな気がする。
どれも中々興味深いんだけど、参加者のみなさんかなり興味津々だったみたいなんだけど、残念ながら俺個人的には最近あんまりJavaも.NET触れてないのでそんなに思うところはなかったんだよね…。でも、DLRの話が面白かった。Silverlight上でPythonのモジュールを読みこんでそれにJSでイベントハンドラ付けてやってアプリケーションとして動かすってデモを見て、Microsoftすごいことになってるんじゃん、と思いました。DLRは注目しとこう。
あと、荒井さんの発表がさりげなくVistaのデモにもなってるように見えた。全然関係ないけど、高井さんのスライドが本当に次々と横方向にスライドしまくるので酔った。
これは非常に面白かった。
まず、「一般人に使えるプレゼンソフト」っていう要件定義が無視されてたのに笑った。独自のXMLフォーマットで記述とか、HTMLにScriptタグでエフェクト指定とか、無理でしょ普通に。結局「オーサリングツールが要るよね」って話に落ちついたけど、小黒さんのR-Slideの「ドキュメント作成機能は思いきって切り捨てて表示に特化させる」ってアプローチは案外ありかなと思う。何故かは知らないけど、非プログラマの人って意外とドローツールとか使えたりするし。いや、俺の周囲の人がそういう傾向なだけかもしれないけど。でも、独自記法とか新しいソフトの使いかたとかを覚えるよりは一般人には楽そうだ。それでいて逸般人にも素敵なソフトだったし、R-Slide。
amachangさんのJSプレゼンツールは本当に綺麗で使いたくなったし(あのインデックスは素敵すぎる!!感動した!)、下田さんのプレゼンで高橋メソッドはやっぱり素敵だと再認識できた。小黒さんはプレゼン自体が面白い&前述のアプローチが興味深いのはもちろんのこと、チャット連動機能でニコニコ動画化しかけた*5ことで相当盛りあがった。使いどころは難しそうだけど、あれは上手くすればとてつもなく面白いものができそう。
この辺は流石にメモれなかっただけど、大爆笑させてもらいました。ネタに走りまくってたのも普通なのもどれも面白かったんだけど、書ききれないや。
と、こんな感じでお腹いっぱいになったLL魂。実は初めてこの手のイベントに参加したのだけど、今まで行かなかったのが悔やまれるくらいに大満足でした。ところで、来年は定員1300名でやるそうですよ。…なんだその規模!おおお!?
また新しいのが出てたので、こないだ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”
なかなか面白いし、便利そう。まぁ、最近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ターゲットをビルドするとそれらを自動で検証してくれたりするのが理想なわけです。
そんなわけで、こういう手順でやってみた。
ビルドターゲットを最初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プロジェクトを作成してそれをビルドさせてみる。動作としてはこんな感じだった。
これで出来上がり。うん、大体予想してた通りだ。このうちプリコンパイル済みヘッダとやらは多分なくてもいい。あと最初の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手順間違ってる?
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には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向けのフリーソフトがなかなか増えないわけだよなぁ。