2007-11-13
目次
りんご味Ruby 第14回 藤本 尚邦
LeopardについてくるXcode 3.0とInterface Builder 3.0は、Objective-Cに加えてRubyおよびPythonによるCocoaアプリケーションの開発がサポートされています。そこで今回は、LeopardでのRubyによるCocoaアプリケーション(つまりRubyCocoaアプリケーション)の開発手順を紹介します。
おおよそ以下のような手順で作っていきます。
(1) Xcodeでプロジェクトを作成する (名前はMyApp)
(2) Xcodeで空のコントローラ(MyController.rb)を作る
(3) Xcodeでコントローラのアウトレットとアクションを書く
(4) Interface BuilderでMainMenu.nibにビューとコントローラを配置する
(5) Interface Builderでビューとコントローラを接続する
(6) 完成
実際には、Xcode 3.0とInterface Builder 3.0を使っての開発手順そのものは、プログラミング言語が異なるという点を除いて、Objective-CやPythonによる場合とほとんど違いがありません。上記の手順で(4)以降、すなわちInterface Builderでの作業は、RubyでもObjective-Cでも(確認していませんがおそらくPythonでも)まったく同じになります。
ここでは、(1)から(3)までについて、Rubyでのポイントを中心に見ていくことにします。
■ (1) Xcodeでプロジェクトを作成する (名前はMyApp)
Xcodeを起動し新規プロジェクトコマンドを実行(※1)します。新規プロジェクトの選択ダイアログの中に、Cocoa-Rubyで始まる名前のプロジェクト(テンプレート)がいくつか見つかるはずです。ここでは、Cocoa-Ruby Applicationを選んで新規プロジェクトを作成してください。名前はMyAppとします。
【編集部注】
※1:Xcodeのファイルメニューから「新規プロジェクト…」を選びます。
■ (2) Xcodeで空のコントローラ(MyController.rb)を作る
MyAppのプロジェクトのウィンドウの「グループとファイル」の中のMyApp/Classesのコンテキストメニューから追加/新規ファイルコマンドを実行(※2)します。
※2:「グループとファイル」の中の「MyApp」の下の「Classes」をコント
ロール+クリック(右クリック)して表示されるコンテキストメ
ニューの一番上の「追加」サブメニューから「新規ファイル…」
を選びます。
RubyのところのRuby NSObject subclassを選んで、MyController.rbという名前のファイルを作成します。以下のようなRubyプログラムが作られます(コメント部分は省略)。
require 'osx/cocoa'
class MyController < OSX::NSObject
end
■ (3) Xcodeでコントローラのアウトレットとアクションを書く
MyController.rbに、以下のようにアウトレットとアクションを記述します。名前はそれぞれtextFieldとspeechとします。speechアクションは、textFieldに入力された文字列をNSSpeechSynthesizerを使ってスピーチするという実装にしてみました。
------------------------------------------- MyController.rb --
require 'osx/cocoa'
class MyController < OSX::NSObject
ib_outlet :textField
ib_action :speech do |sender|
voice = OSX::NSSpeechSynthesizer.defaultVoice
synth = OSX::NSSpeechSynthesizer.alloc.initWithVoice(voice)
synth.startSpeakingString(@textField.stringValue)
end
end
-------------------------------------------
上記のプログラムでは、Rubyのブロック構文を使って、speechのアクション宣言と定義をいっぺんに書いていますが、以下のように宣言と定義を別々に書くこともできます。
ib_action :speech # 宣言のみ
def speech(sender)
voice = OSX::NSSpeechSynthesizer.defaultVoice
synth = OSX::NSSpeechSynthesizer.alloc.initWithVoice(voice)
synth.startSpeakingString(@textField.stringValue)
end
ちなみに、MyController.rbと同じものをObjective-Cで書くと以下のようになります。
------------------------------------------- MyController.m --
#import
のこりの手順4,5は、Interface Builderでコントロールビューなどを配置したりアウトレットやアクションを接続する作業になります。今回細かい説明は省略しますが、Interface Builder 3.0は以前のバージョンと比べて大幅に改良されています。ポイントは、Objective-Cだけでなく、RubyやPythonで書いたコントローラのプログラムからアウトレットやアクションを自動的に検出してくれるようになったところです。
次回も、LeopardでのRubyCocoaについて見ていくことにしましょう。
藤本裕之のプログラミング夜話 #126
新OS、Leopardが発売されXcodeも新しいバージョンになったわけだが、途中で開発環境を変えて話がアッチャコッチャになってもいけないので、この連載はこのツールバーの話題が終わるまでTiger環境での話として書くことにする。
ホントのことを言うといろいろ忙しくて(今年はMOSAのミーティングにも行けません。みなさん楽しんでください)Leopardの開発環境をあれこれ試してる暇がないのだけど。
とにかく承前、前回のコーディングによりいきなりウインドウが賑やかになったテストプログラムだが、こうなってみると今まで全然気がつかなかったことに気付く。たとえばなんで「Costomize」と「Print」のアイコンはアクティブになってないのかとか、ウインドウをリサイズしてその幅を狭めると一番右に配置した「Align Text」のメニューが隠れちゃって選択できないぢゃないか、とか。で、今回からそういう細かいところを逐一見ていきたい。
まず最初は、なんで「Costomize」のアイコンがアクティブぢゃないのか。これは簡単である。ツールバーがデフォルトではカスタマイズを許さないことになっているからですね。これを変更するには MyApplication のfinishLaunching で、作成したツールバーに「カスタマイズしていいかんね」と教えてやればいい。以下のコードを setDelegate: の次あたりに書き加える。
[aToolBar setAllowsUserCustomization:YES];
これでOK。実行すると「Customize」アイコンがアクティブになり、クリックするとツーツバーのカスタマイズ・シートが出現する。なお、ここで変更したツールバーの設定を保存して次回起動時に再現するには、ここに以下のコードも追加すればいい。簡単でしょ?
[aToolBar setAutosavesConfiguration:YES];
これだけで初期設定ファイルがないときは
toolbarDefaultItemIdentifiers: が呼ばれ、あればそこから前回カスタマイズされた通りのツールバーが出現する。カスタマイズ・シートの上の方(一個一個選択できるところ)に表示されるのが、toolbarAllowedItemIdentifiers:で返すアイテム、すなわち読んで字の通り「ツールバーで使ってもいいと許可されているやつ」というわけである。
お次は、なんで「Print」のアイコンがアクティブぢゃないのか。このツールバーアイテムについてドキュメントには「firstResponder にprintDocument: を送る」と書いてある。われわれのテストプログラムのfirstResponder は「report」と名付けた NSTextView なんだが、このクラスには printDocument: というメソッドがないんですね(つうかこれはNSDocument にしかない)。ない袖は振れないというか、ないメッセージには応えられないのでこのアイコンはインアクティブなのである。
解決先は2つ。1つはズルみたいだけど簡単、もう1つは正攻法だけどちと面倒くさい。まずはズルみたいな方から。……NSTextView に printDocument:はないが print: はある。そんで、ファイルメニューから「Print...」が選ばれるとそいつが送られてくる。ということは、NSTextView にカテゴリとしてprintDocument: を追加し、こいつから print: に呼び出しをリダイレクトしちゃえばいいのである。まずは MyApplication.h のどたまに以下の宣言を追加する。
@interface NSTextView (MOSA)
- (void) printDocument:(id)sender;
@end
次に MyApplication.m にこの中身……ってもたいしたもんぢゃないが、を書く。
@implementation NSTextView (MOSA)
- (void) printDocument:(id)sender {
[self print:sender];
}
@end
これでOK、「Cosutomize」アイコンはアクティブになり、クリックするとファイルメニューから「Print...」を選ばれたときと同じ動作をする。でもまぁせっかくCocoaが用意している正攻法(NSToolbarPrintItemIdentifierのドキュメントでわざわざ説明してる)があるので、次回はそっちを解説しよう。
(2007_11_09)
高橋真人の「プログラミング指南」第124回
〜XcodeによるPowerPlant X入門(15)〜
こんにちは、高橋真人です。
さて、前回と前々回にわたって紹介したプログラムは試してみましたでしょうか? 通常は「あり得ない」プログラムですが、その分興味深かったのではないかと思います。(そこまで言うほどのものでもない?・笑) ところで、前回の最後に少し触れた「テンプレートを使ったクラス」の件ですが、まだ納得の行っていない方もおいでかもしれませんので、補足をします。
今回の例で出てきたSpecificMenuCommandDisableDoerというクラスですが、このクラスが持つ唯一の関数であるDoEvent()は、動作定義自体がヘッダファイルで行われています。
これはまずくはないのでしょうか?
もちろんまずくありません。もしまずければ、先のコードはコンパイルできていないでしょう。
そもそも、C++においてはクラスのメンバ関数の処理内容そのものをヘッダに置くことも珍しくありません。「インライン定義」と言って、関数呼出しのオーバーヘッドを回避するために、見た目は関数でも実行時には呼び出し側に展開された形で動作するものです。*注
しかしながら、今回のようなテンプレートを使った例の場合は少し事情が違います。SpecificMenuCommandDisableDoerというクラスのメンバ関数であるDoEvent()は、先頭にtemplate
テンプレートはコンパイル時に引数が展開される仕組みですので、具体的な値が引数として指定されない限り定義としては不完全であって、コンパイルもできません。
このクラスを実際に使用するコードの側でこのテンプレート引数に具体的な値が与えられて初めて「完全な定義」となってコンパイルされるのです。
今回のプログラムの例ですと、MyWindow.hの冒頭に
#include "MenuCommandDisableDoer.h"
というインクルード文があり、そのファイルのクラス定義の中で、MyWindowの継承元としてSpecificMenuCommandDisableDoer
この、関数にテンプレート引数が渡されて実体化される部分は、C++のコンパイラによって半自動的に行われるため、使う側はこの実体化の部分をいちいち意識する必要がありません。
このように、ソースファイルが不要(というか存在しない)で、単にヘッダをincludeするだけで使えるクラスは「使うのがラク」です。
C言語におけるANSI Cライブラリに当たる標準C++ライブラリ(昔からの習慣でSTL=標準テンプレートライブラリ=と呼ばれることの方が多い)の中にもこの手のクラスは多く存在しますが、私に言わせれば、「Boostを知らずしてテンプレートを語るなかれ」ということになります。
このBoostというのは、正式にはBoost C++ Librariesと言いますが、現在のC++の規格(ISO/IEC 14882)の標準ライブラリを策定した人たちのうちの何人かが、中心になって、標準ライブラリへの採用が見送られた一部の機能や、さらに必要と思われる機能を集めて体系化したものがBoostです。現在でもオープンソース形態で活発に開発とテストが続けられており、日々機能を増やしています。
Boostは、それ自体の成り立ちの経緯からもC++の標準規格に対して大きな影響力のあるものですから、C++ 0xと呼ばれる次期C++の標準規格に既に取り込まれることが決まっているものも含めて、C++プログラマにとってはそのままSTLに準ずるライブラリ集と言ってもよいでしょう。
スレッドを利用するためのBoost.Threadや正規表現のためのBoost.Regexなど、コンパイルをしてライブラリの形にしないと利用できないものもわずかにありますが、多くは単にincludeするだけで利用できるという手軽さがBoostの魅力をより一層高めています。
ちなみに私の場合、Perlで正規表現を覚えて以来、C/C++で使える正規表現ライブラリをずっと求めてきたのですが、いま挙げたThreadやRegexはビルドしないと使えない上に、Boostのビルドはbjamという専用のツールでしなければならないこともあって、いま一つ手を出す気になれないでいました。
最近では、MacPortsなどの助けを借りて、自分でビルドをしなくても利用できることを知ったわけですが、それとは別に今年の5月に登場した1.34というバージョンからはBoost.Xpressiveという、ビルドをしなくても使える(つまり、ヘッダファイルだけで構成されている)正規表現のライブラリも加わっています。
また、現在のリリース版には組み込まれていないものの、手軽に通信機能を組み込めるものやxmlの解析が行えるものなど、「まだまだC++のライブラリは充実していくのだ」と期待させるものが既に数多く含まれています。
興味のある方は、
http://boost.org/
http://www.kmonos.net/alang/boost/
などを覗いてみてください。
注:メンバ関数のインライン定義は、クラス定義の中に直接関数の
実装までも書き込むことを意味します。ヘッダファイルに書い
たからと言って、それがそのままインライン定義となるわけで
はないことにご注意ください。
書籍紹介 レボリューション・イン・ザ・バレー
解説担当:高橋政明
レボリューション・イン・ザ・バレー 開発者が語るMacintosh誕生の舞台裏
Andy Hertzfeld 著
柴田 文彦 訳
オライリージャパン ISBN4-87311-245-1 3,570円
2005年09月発行の少し古い本です。全ページカラーです。美しい写真(Jobsが若い)や技術者の手書き資料(ToDoリストやアセンブラのソースまで)なども載っています。
著者はオリジナルMacintoshの主要な開発者のひとりでSwitcherなどのアバウト画面でもおなじみのAndy Hertzfeld氏です。
この本のもとになったwebサイトは現在でもアクセス可能です。
http://www.folklore.org/
実に楽しい本でした。懐かしい開発ツールやアプリケーションそしてハードウェアがたくさん登場します。開発者用のドキュメント(Inside Macintosh)を作る作業がレビューとしてはたらき、さらに今でいう所のプレファクタリング的効果までもたらしたのはさすがです。
訳者あとがきにもありましたが、まるで自分もMacの開発に参加しているような錯覚にとらわれました。
この日本語版では原著にない5話が加わっているそうです。加わったエピソードはどれも技術的に興味深いものです。特に私のようにかつて68000のMacで開発していたものにとっては。(Cut, Paste and Crash など上記webサイトでは読む事ができます)
オリジナルMacの設計の誤りを懺悔する項もあります。リージョンのサイズが32Kの制限があることはこの制限を超えるような使い方をしてはじめて知ったのですが、これにはとても困りった事を思い出しました。(QuickDrawのこの制限のため開発中のソフトにバグが出のです)
ただQuickDrawやリソースマネージャのオフセットが16bitだったことは当時のハードウェアを考えると妥当な設計だったと思います。なんと言ってもオリジナルMacのRAMは128K、フロッピーは400Kだったのですから。
原著は2004年12月発行です。Appleの開発者の多くも読んだことでしょう。たぶんiPhoneやiPod touchの開発者たちも。
皆さんよくご存知のように紆余曲折のあったApple社ですが、68000からPowerPCそしてIntelとソフトウェアの互換性を保ちながら二度もCPUを切換えたものすごく高い技術と開発力を持った企業です。製品の使いやすさが抜きん出ていて特に一般ユーザにはそちらに注目が集まりますが、使いやすさも技術の寿命の長さも徹底した創意工夫で成し得たものであることがこの本から実感できるはずです。現在のApple社の製品の多くにも当時と同じ精神が感じられますので、オリジナルMacintoshを知らない世代でも共感できる部分があると思います。
iPhoneやiPod touchの開発にあたってもこの本と同様のドラマがあったことでしょう。
プログラマだけではなく製品開発に携わるたくさんの方に読んで欲しい本です。
▼出版社のweb (サンプルページのpdfあり)
http://www.oreilly.co.jp/books/4873112451/
◇MOSAからのお知らせと編集後記は割愛します◇