2007-10-16
目次
りんご味Ruby 第12回 藤本 尚邦
前回は、RubyのC言語用ライブラリとしての面からlibrubyについて取り上げました。今回はその続きとして、Rubyの拡張ライブラリを作ってみます。
■ 拡張ライブラリとは?
第2回で紹介したように、Rubyプログラムからライブラリをロードして使うときにはrequireメソッドを使います。
require ロードしたいライブラリを表わす文字列
ここでロードされるライブラリもまた、Rubyインタプリタで実行するためのプログラムです。ライブラリのプログラムはもちろんRubyで書くことができるのですが、C言語で書くこともできます。その場合、前回紹介したlibrubyを使うことになります。C言語で書かれたRubyプログラム用のライブラリのことを拡張ライブラリといいます(Rubyのソースに含まれているREADME.ETX.jaによると)。
あえて、RubyではなくC言語で拡張ライブラリを書くことにはどんな意味があるでしょう? たとえば、速度上のボトルネックとなっている処理をC言語で書くことによりパフォーマンスを出したいということが考えられます。また、C言語などでAPIが提供されているライブラリをRubyから使いたい場合も拡張ライブラリを書くことになるでしょう。外部のライブラリをRubyから使えるようにすることにより、Rubyの応用範囲を広げることができます。
■ 簡単なRuby拡張ライブラリを作ってみる
さて、拡張ライブラリを書くのは面倒なのではないかと思われるかもしれませんが、C言語に親しんでいる方であればきっと想像しているよりも手軽に作ることができます。ここでその手順を紹介します。以下は、ごく単純な拡張ライブラリのプログラムです。
------------------------------------------- myextlib.c --
#include "ruby.h"
static VALUE cMyExtLib = Qnil;
/* メソッド(モジュール関数)の実装 */
static VALUE
myextlib_f_sum(int argc, VALUE *argv, VALUE mdl)
{
long i, sum;
for (i = sum = 0; i < argc; i++)
sum += NUM2LONG(argv[i]);
return LONG2NUM(sum);
}
/* 拡張モジュールがロードされるときに呼ばれる初期化関数 */
void
Init_myextlib()
{
cMyExtLib = rb_define_module("MyExtLib"); /* モジュールを定義 */
rb_define_module_function(cMyExtLib, "sum",
myextlib_f_sum, -1); /* メソッドを追加 */
}
-------------------------------------------
このプログラムでは、MyExtLibというモジュールを定義し、MyExtLibモジュールに MyExtLib::sum というメソッド(モジュール関数)を定義しています。このメソッドは、可変長の引数を受け取り、それを整数とみなしてその総和を返します。
このプログラムから拡張ライブラリを作るために、以下のrubyプログラムを用意してください。
------------------------------------------- extconf.rb --
require 'mkmf'
create_makefile "myextlib"
-------------------------------------------
以上2つのファイルを同じディレクトリに置き、ターミナルアプリケーションで
以下のようにコマンド($はプロンプトです)を実行します。
$ ruby extconf.rb && make
すると、同じディレクトリに myextlib.bundle というファイルが出来上がります。これが拡張ライブラリになります。irb を起動して確認してみましょう。
$ irb
irb(main):001:0> require 'myextlib'
=> true
irb(main):002:0> MyExtLib
=> MyExtLib
irb(main):003:0> MyExtLib::sum(1,2,3,4,5,6,7,8,9,10)
=> 55
実は、当初、CocoaのNSStringをRuby拡張モジュールにしたものを例示しようと考えたのですが、実際に書き始めてみるとこの記事に載せるには少々大きくなりそうだったため、やむなくもっと単純なモジュールに差し替えました。
■ まとめ
今回は、Cプログラマにとって拡張モジュールが割と簡単にできることを示そうと考えたのですがいかがでしたでしょうか? Rubyにビルトインされているクラスやモジュールも、あるいはRubyCocoaにしても、基本的には今回示したようなコードがベースになっています。
最後に拡張ライブラリを作る上での参考資料をまとめておきます。
・README.EXT.ja (Rubyのソースコードに付属)
・Rubyソースコード完全解説 http://i.loveruby.net/ja/rhg/book/
・Rubyのソースコード (array.cなどのクラス定義やext以下のディレクトリなど)
藤本裕之のプログラミング夜話 #124
さて、前回までで一応ツールバーにネコのアイコンを出し、これをクリックするとそれなりの動作が行われるようにするところまでこぎつけたわけだが、知っての通りツールバーに並ぶのはアイコンだけではない。今これを書いているJedit Xのツールバーを見ても、左から順に「フォントメニュー」、「サイズメニュー」、「カラーメニュー」に「検索テキストボックス」、そして一番右に「書類情報」のアイコンてな具合で、我らがネコと同じ仕掛けなのは最後の「書類情報」だけである。
今回からこういう「アイコンぢゃない項目」をツールバーに並べるのはどうやるか、というのを説明していくわけだけど、だんだんコードがややこしくなってくるので、その気のある人は是非いままでのところまでのプログラムを実際に作って、ネコ(別にネコが嫌いならイヌでもムカシトカゲでもゴミムシダマシでもいいんだけどさ)のアイコンがツールバーに並ぶことを確認した上でこっから先を読んでいただきたい。例によって全部終わったらサンプルはMOSAのサイトで公開するけどさ、こういうのは結果でなくプロセスだから。
ほんぢゃ、まずサンプルのプロジェクトファイルをダブルクリックしてXcode を起動していただきたい。MyApplication.hを開き Outlet をひとつ追加して欲しい。
IBOutlet NSView* sampleView;
プロジェクト・ウインドウの「ファイル」タブを開いて「MainMenu.nib」をダブルクリック、Interface Builderを起動する。セーブしたMyApplication.hを「MainMenu.nib」にドラッグ&ドロップすると MyApplication クラスに上の Outlet が追加される。
次にこの View のインスタンスを作る。Cocoa Controllerのツールバーから「Containers」を選び、「Custom View」を「MainMenu.nib」のウインドウ、「Instance」タブの中にドラッグ&ドロップしていただきたい。画面の真ん中へンに「View」というタイトルの「なんでデフォルトでこんなに小さいんだよ」と思うようなウインドウが開くので、これを適当に横に拡げ、今度はこの中に……何がいいかなぁ、そいつの機能をインプリメントするのが話の主眼ぢゃないので簡単なのがいいよね。
よし、Cocoa Container のツールバーから「Controls」を選び、NSPopUpButton を View にドラッグ&ドロップしてくだされ。で、このポップアップの中身を上から「Left」、「Center」、「Right」とし、それぞれのメニューアイテムからメインのウインドウにある NSTextView にアラインメントのアクションをつなげる。「Left」から「alignLeft:」へ、「Center」から「alignCenter:」へ、「Right」から「alignRight」へ。
そしたら「File's Owner」からこの View (NSPopUpButtonぢゃないよ)にコネクションを張って、さっき作った sampleView という Outlet とつなぐ。……一気に書いちゃったけどできましたか?
MainMenu.nib をセーブして MyApplication.m を開き、
[toolbarItems setObject:catItem forKey:@"Cat"];
[aToolBar setDelegate:self];
という2つの文の間に、以下のステートメントを追加する。
NSToolbarItem* alignPop =
[[[NSToolbarItem alloc] initWithItemIdentifier:@"Align"] autorelease];
[alignPop setLabel:@"Align Text"];
[alignPop setPaletteLabel:@"Align Text"];
[alignPop setToolTip:@"Align Text"];
[alignPop setView:sampleView];
[toolbarItems setObject:alignPop forKey:@"Align Text"];
ネコの時は setImage: だった部分が setView: になり、アクションとターゲットはポップアップメニューの受け持ちだからここには書かない。それからArray を返す2つのデリゲート・メソッドに「Align Text」を追加すればできあがり。
- (NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar*) inToolbar {
return [NSArray arrayWithObjects:@"Cat",@"Align Text",nil];
}
- (NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar*) inToolbar {
return [NSArray arrayWithObjects:@"Cat",@"Align Text",nil];
}
NSToolbarItem の見た目を決められるのは setImage: と setView: だけなので、こりゃただのアイコンぢゃないな、というものは複雑に見えてもみんなこれのバリエーションである。次回からはもう少しこの仕掛けの重箱のスミをつっついてみよう。
(2007_10_12)
高橋真人の「プログラミング指南」第122回
〜XcodeによるPowerPlant X入門(13)〜
こんにちは、高橋真人です。
3つめのPPxプログラムのコードの解説が終わりましたので、ここで前々回にお約束していた「何もウインドウが出ていない時には有効になっているメニュー項目が、ウインドウが出ている時には無効になる」というのを実際にやってみたいと思います。
実現の方向としては、最初にすべてのメニューを有効になるようにしたうえで、特定の項目(今回は、「New」=kHICommandNew)がウインドウの表示されている時にのみ無効になるようにします。
ちなみに、すべてのメニュー項目が有効になるというと、2番目のPPxプログラム例(PPxForXcode02)でも、そのようになっていました。しかし、表面的には同じに見えても、実現の仕方には違いがあります。
復習になりますが、前々回の記事で触れたようにCommandConverterが最終的にすべてのメニュー項目(SpecificMenuCommandEnableDoerなどで個別措置をしていないものに限るが)を最終的に面倒を見、無効の状態にします。ですから、CommandConveterを使用せずに、Nibファイルでの設定のままがそのまま結果としてれたのとは違うということです。思い出していただけたでしょうか?
そういうわけで、今回「すべてのメニュー項目を有効にする」というのは、CommandConverterのような動的な処理を行うことによって有効にするわけです。もちろん、CommandConverterですと、メニュー項目は無効になるわけですから、ここでは新たなクラスを起こしてCommandConverterの逆の処理をさせる必要があります。具体的な実現方法としては、CommandConverterのサブクラスを作るという形になります。
メニュー項目をすべて有効にできたら、次は、特定の状況でメニューを「無効にする」動作を実現します。こちらも、SpecificMenuCommandEnableDoerの動作と逆になりますので、同じようにこのクラスのサブクラスを起こして実装します。
具体的には「ウインドウが開いている時にはNewを選べない」ようにするという動作です。つまり、ウインドウを一つ開いたら、それ以上は開けないという仕組みの実現となります。
それでは、実際にプログラムを作成してみましょう。基本は、PPxForXcode03となります。これを複製して、PPxForXcode04として、以前と同じように変更を施してください。
ところで、今までのやり方では、プロジェクトの名前が変わっても、出来上がったアプリケーションの名前は、依然としてPPxForXcode01のままでした。ですので、今回から併せてアプリケーション名も変えることにしましょう。
・プロジェクトメニューから「アクティブターゲット'PPxForXcode04'を編集」
(コマンド+オブション+E)を選択し、「ビルド」タブに切り替えます。
・「コレクション」のポッブアップメニューから「パッケージング」を選び、
プロダクト名の右欄をダブルクリックして編集します。
・編集状態になった時に表れる「PPxForXcode01 $(CONFIGURATION)」を
「PPxForXcode04 $(CONFIGURATION)」に変更します。
この時、名前に関しては必ずしもこの名前にせず、ご自分の好きなものにしても構いませんが、$(CONFIGURATION)の部分は、ビルド時に内部的な変数展開が行われるので、そのままにしておいた方が無難です。
・「構成」のポップアップメニューから「Release」を選択し、同様にプロダ
クト名の欄を変更します。
アプリケーション名の変更のための操作は以上です。
これ以外のプロジェクト複製後の作業が完了したら、以下を参考にコードの編集をしていきましょう。
[MyApplication.h]
class MyApplication : public PPx::Application,
public PPx::CommandConverter,
public PPx::SpecificMenuCommandEnableDoer
とあるのを、以下に変更。
class MyApplication : public PPx::Application,
public ReverseCommandConverter,
public PPx::SpecificCommandDoer
それと、冒頭のヘッダのインクルード部の末尾に
#include "ReverseCommandConverter.h"
と加えておきます。(ヘッダファイルは後ほど作成)
[MyApplication.cp]
MyApplication::MyApplication()
{
EventTargetRef targetRef = GetSysEventTarget();
CommandConverter::Install(targetRef);
PPx::SpecificMenuCommandEnableDoer
この関数を以下のように変更します。
MyApplication::MyApplication()
{
EventTargetRef targetRef = GetSysEventTarget();
ReverseCommandConverter::Install(targetRef);
PPx::SpecificCommandDoer
続きは、次回に掲載します。
書籍紹介 Macintosh的デザイン考現学
解説担当:高橋政明
Macintosh的デザイン考現学
アップルプロダクトと世界的デザインの潮流を探る
大谷 和利 著
毎日コミュニケーションズ ISBN4-8399-0691-2 2,200円+税
古い本で恐縮です。2002年3月に出版され現在のところ、重版は未定(つまり書店で新刊を入手するのは難しい状態)のようです。
Amazon.co.jpの商品の説明ではいきなり『Macintoshほど熱狂的なファンを持つ「機械」はない。その最大の理由は、Appleがずっとこだわり続けてきたデザインにある。』なんて書かれていて、それは最大の理由ではないだろうとツッコミを入れたくなりました。でも、この本の写真をながめていると、故障していても機能しなくてもとにかく手元に置いておきたいと考える人が現れても不思議でない事は実感できます。
この本は1996年から2002年にかけてMac Fan Beginners誌に連載されたコラムを一冊にまとめ、大谷さんご自身が加筆訂正を加えたものです。
Macintoshや他のApple製品が他にない魅力を持っている事は、使えばすぐにわかるし、眺めただけでもわかります。我々がただ漠然と「美しい」とか「デザインが良い」とか言うのと、大谷さんの解説とでは(比較して申し訳ないのですが)全く違います。
起源と歴史、設計者(デザイナー)、どこから影響を受け何に影響を与えたのか、素材・構造さらに細かな形状処理まで多様で緻密な解説は考現学そのものです。
帯に『時代を経ても錆び付かないデザインとは何か?』と書かれていますが、まさにその回答が書かれています。
Apple社の製品だけではなく、多くの魅力的な『もの』たちも紹介されています。表紙にもいくつかありそのユニークさが伝わります。
ここから宣伝も含みますが...
雑誌記事で現在でも大谷さんの最新の解説に触れる機会があります。しかしライブは格別です。大谷さんには今年もMSMのキーノートスピーチを担当していただきます。あっと驚く「物」をご披露していただけること請け合いです。
(物理的な製品に限らず、ソフトウェア、webサイト、コマーシャル、などなどです)ちなみに昨年のMSM(湘南)にはA-bikeを持参されました。
上記の書籍には初代しか掲載されていないiPodですが、iPod touchも登場した今年はどのようなお話が聞けるのか今から楽しみです。
※古い本のため出版社のwebページは見つかりませんでした。
◇MOSAからのお知らせと編集後記は割愛します◇