MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSA Developer News[MOSADeN=モサ伝]第261号

2007-07-31

目次

  • 「りんご味Ruby」       第8回  藤本 尚邦
  • 藤本裕之のプログラミング夜話   #119
  • 高橋真人の「プログラミング指南」  第117回
  • 書籍紹介            たのしいCocoaプログラミング

りんご味Ruby   第8回  藤本 尚邦

先日、最近Ruby on Railsを始めたというCocoaプログラマの方と話していたところ、Rubyのメソッド呼出し記法はややこしいと愚痴を聞かされてしまいました。たしかにバリエーションが多くて、Rubyプログラミングを始めたばかりの人には混乱の元になるかもしれません。

では、Rubyプログラミングに習熟した人にとって、このバリーエションの多さはどんな意味を持っているのでしょうか? 多くのRubyプログラマは、場面に応じて、メソッド呼出し記法を上手に使い分け、プログラムの可読性を高めています。ということで今回は、Rubyにおけるメソッド呼出しについて解説します。

■ メソッド呼出しのプロセス

まず、Rubyにおけるメソッド呼出しのプロセスを明らかにしておきましょう。基本的には、実際の動作も含めてObjective-Cの場合と良く似ています。メソッド呼出しの対象となるレシーバ(受け手)オブジェクトの立場から見ると、おおよそ以下のようなプロセスになります。

・レシーバがメッセージ(メソッド名と実引数)を受信
・対応するメソッドを検索
 ・見つかった    => メソッド実行
 ・見つからない  => 自身にmethod_missingメッセージを送信
・値を返す

method_missingは、デフォルトでは「メソッドが見つからなかった」という例外を発生させます。自分で再定義することにより、柔軟なプログラミングが可能です。例えば、拙作のRubyCocoaでは、method_missingに落ちてきたメッセージを関連するObjective-Cオブジェクトに送信します。

■ メソッド呼出しの記法 — 括弧付き実引数リスト

メソッド呼出しの基本的な構文は以下のようになります。Java,C++あたりの言語に親しんでいる方にはおなじみのものでしょう。

 レシーバ.メソッド名()
 レシーバ.メソッド名(実引数リスト)

レシーバとメソッド名の間はドット「.」で区切ります。ドットの前後にはスペースを置くことができます。実引数リストは、実引数をカンマ「,」で区切ります。カンマの前後にもスペースを置くことができます。具体例を上げておきましょう。以下は文字列オブジェクト(文字列リテラル)をレシーバとした例です。

 "hello,world".length()         # => 11
 "hello,world".gsub('o', 'O')   # => "hellO,wOrld"

■ メソッド呼出しの記法 — 括弧の省略

実引数リストを囲むための括弧は省略できます。実引数が存在する場合には、メソッド名と実引数リストの間にスペースを置きます。一般的に、実引数がないメソッド呼出しでは括弧を省略するのがRuby流と言えるでしょう。

 レシーバ.メソッド名
 レシーバ.メソッド名 実引数リスト

先ほどの例で括弧を省略すると以下のようになります。

 "hello,world".length           # => 11
 "hello,world".gsub 'o', 'O'    # => "hellO,wOrld"

実引数がある場合は、基本的には括弧を付けた方が見やすいかもしれません。このあたりは好みに左右されるところです。私の場合は、返ってきた値を使うメソッド呼出しでは、括弧で引数を囲みます。そうでない場合には、括弧を省略したりつけたり、見た目に応じて臨機応変に書いています。

Rubyの効用としてときどき例に上げられるDSL(Domain Specific Language)では、括弧の省略が効果的に用いられます。

[参考] 以下のURLでは、「リファクタリング」の著者でもあるマーチン・ファウラー氏がDSLとRubyの関係について書いています。興味のある方はご覧ください。

■ メソッド呼出しの記法 — レシーバの省略

実際のところ、本連載でこれまでに書いたRubyプログラムのかなりの部分ではレシーバが省略されていました。

 メソッド名()
 メソッド名(実引数リスト)
 メソッド名
 メソッド名 実引数リスト

具体例を上げましょう。

 require 'rss/2.0'
 open('/etc/hosts')
 puts


などです。レシーバを省略してメソッドが呼び出された場合、self という名前で参照できるオブジェクトがレシーバとなっています。Rubyのプログラムが評価(実行)されているときには、常に何かしらのオブジェクトがselfになっています。インタプリタが動き始めた直後の最上位(TOPLEVEL)では、mainと呼ばれるオブジェクトがselfになっています。今回詳しい説明はできませんが、省略されている場合、実はselfがレシーバなのだ、ということだけ覚えておいてください。

■ (補足) 行末の意味

JavaやCを始めとするメジャーな言語の多くは、セミコロン「;」を文の区切りとしています。同じく、Rubyでもセミコロンは文式(Rubyの文は式でもあります)の区切りを意味します。しかし、実際にRubyのプログラムを見ると「;」はあまり使われていないことにお気づきかもしれません。なぜでしょうか? それは、Rubyでは行末が文式のおわりである場合に「;」を省略できるからです。

メソッド呼出しの記法にもどると、レシーバとメソッド名を区切るドットおよび実引数リストを区切るカンマの「後」には改行文字を置くことができます。「前」ではなく「後」だけです。これは、まさに行末のセミコロンが省略可能であることと表裏一体の関係になっています。

以下は、NSWindowのインスタンスを生成初期化するRubyプログラムです。この場合、レシーバが「NSWindow.alloc」で、メソッド名は「objc_send」になります。両者の間のドット「.」と行末の位置関係に注目してください。

----------------------------------------------- 正しいプログラム ---
NSWindow.alloc.
 objc_send(:initWithContentRect, [0,0,800,600],
                     :styleMask, NSTitledWindowMask,
                       :backing, NSBackingStoreBuffered,
                         :defer, false)
-----------------------------------------------

----------------------------------------------- 2行目が構文エラー ---
NSWindow.alloc
 .objc_send(:initWithContentRect, [0,0,800,600],
                      :styleMask, NSTitledWindowMask,
                        :backing, NSBackingStoreBuffered,
                          :defer, false)
-----------------------------------------------


前者では、レシーバ NSWindow.alloc に対して objc_send メッセージが呼ばれるのに対して、後者では、NSWindow.alloc で文式が途切れてしまいます。2行目は、レシーバの部分がなくて、いきなり「.」で始まるため構文エラーになります。

次回も、引き続きメソッド呼出しについて説明する予定です。

藤本裕之のプログラミング夜話 #119

 というわけでようやく,というか遂にというかここまで来たぞ。前回まででヘッダファイルにその宣言だけ行ったメソッドをさくさくとコーディングしていこう。まず最初は呼び出し側,すなわち…なんて名前にしたんだっけ? あんまり長期に渡る大河連載なので忘れちゃったよ,そうそう,MyApplication.hを開き,このオブジェクトに前回定義したプロトコルをサポートさせる。最初にプロトコルの定義を書いたヘッダーファイルをインポートする。

#import "MyTabViewController.h"

 次にこのオブジェクトの定義にプロトコルの宣言を加える。こんな具合。

@interface MyApplication   : NSApplication 
{
    AboutWindowController*        aboutWindowController;
    MyTabViewController*          tabViewController;
}

 NSApplication というスーパークラスの後にある<>で示された部分が,「こ
のオブジェクトは MyTabViewOwner というプロトコルをサポートしてます」と
いう意味である。次にプロトコルのためのメソッドの宣言。これはIBAction
ぢゃないので(まぁIBActionの定義は「#define IBAction void」なので
IBActionと書いてもいいんだけどさ)以下のようになる。

- (void)button1:(id)sender;
- (void)button2:(id)sender;
- (void)button3:(id)sender;

 そしたら MyApplication.m を開き,-tabView:didSelectTabViewItem: の
コードにこのオブジェクトをターゲットとして渡すシーケンスを加えて,上の
3つのメソッドを書く。

-(void)tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
    NSString* identifier = [tabViewItem identifier];
    if([identifier isEqualToString:@"2"]){
         if(tabViewController == nil){
              tabViewController = [[MyTabViewController alloc]
                                  initWithWindowNibName: @"TabView"];
              [tabViewController setTarget:self]; /* 今回追加分 */
              [tabViewItem setView:[[tabViewController window] contentView]];
         }
    }
}
- (void)button1:(id)sender {
    NSLog(@"button1 pressed.");
}
- (void)button2:(id)sender {
    NSLog(@"button2 pressed.");
}
- (void)button3:(id)sender {
    NSLog(@"button3 pressed.");
}

 お次は MyTabViewController.m,まずは上で呼ばれている setTarget: を
コーディング。

- (void)setTarget:(id  )target {
    _target = target;
}

 そして各ボタンからのアクションをこのターゲットにリレーする。

- (IBAction)button1:(id)sender{
    [_target button1:sender];
}
- (IBAction)button2:(id)sender{
    [_target button2:sender];
}
- (IBAction)button3:(id)sender{
    [_target button3:sender];
}


 これでよし。ボタンを押すと MyApplication の該当のメソッドにそのアクションが飛んでくる。……これでおしまいのつもりだったが,タカハシ編集長からこれらのボタンのEnable/Disableも切り替えたいという要望があったので,次回はそれをやります。いよいよ暑くなりましたが皆さんご自愛くだされ。
                            (2007_07_26)

高橋真人の「プログラミング指南」第117回

プログラマのためのオブジェクト指向再入門(25)

〜XcodeによるPowerPlant X入門(8)〜

 こんにちは、高橋真人です。早速続けます。
 さて前回のプログラムで、なぜウインドウがあるときにHandleClose()が呼ばれなかったのかということについて見ていきたいと思います。
 それには、前に説明しましたイベントターゲットが関係しています。前回の例では、Carbonイベントのターゲットをすべてアプリケーションにしてありました。つまり、自前でインストールしたイベントハンドラはすべてアプリケーション(MyApplicationのインスタンス)が受信したイベントのみを処理していたわけです。
 ところが、Windowが表示されてアクティブになっている場合、Carbonイベントはまずそのウインドウに送られるようになっています。
 お分かりと思いますが、この辺は、PPxに特有の話ではありません。詳しくは、

http://developer.apple.com/documentation/Carbon/Conceptual/Carbon_Event_Manager/Concept/chapter_2_section_2.html#//apple_ref/doc/uid/TP30000989-CH202-TPXREF103

などを読んでいただくと理解できると思います。
 簡単に解説しますと、メニューの選択によって発生したHICommandのCarbonイベントは、アプリケーションに送られる前にアクティブなウインドウに対して送られます。
 Carbonイベントの仕組みとして、最初にイベントを受け取ったウインドウが処理しなければこのイベントはアプリケーションに渡ってくるわけですが、PPx::Windowには最初からウインドウに対して送られる主だったイベントを処理するハンドラが装備されているため、kHICommandCloseのコマンドイベントは、そこで処理されて(つまりWindowを閉じた)しまいアプリケーションには渡らなかったのです。(だから、MyApplicationのHandleClose()は呼ばれなかった)

 これを確かめるために、簡単な実験をしてみましょう。
 Xcodeで新規のCarbonアプリケーションを作成してください。CでもC++でもよいですが、必ずnibファイルを使用しているステーショナリを選んで作成してみてください。
 コードは特にいじらずに、そのままビルドして走らせると新規ウインドウが開きますね? それが確認できたら一度アプリケーションを終了させ、この新規ウインドウを作成する元になっているNibファイルを開き、ウインドウのインスペクタを表示させて”Standard handler”のチェックボックスをオフにしてください。
 Nibを保存したら再度ビルドして走らせてみましょう。表示されたウインドウをいろいろいじってみてください。

 どうでしたか? メニューからCloseを選んでもウインドウが閉じないのをはじめ、ドラッグもリサイズも、ウインドウのミニマイズ(ドックにしまうこと)以外の動作はメニューにもマウスクリックにも一切反応しないはずです。
 これが、ウインドウにイベントハンドラがインストールされていない時の挙動です。
 それでは今度は同じことをPPxアプリに対してもやってみましょう。先ほどと同様にNibファイルを開いてウインドウの”Standard handler”のチェックを外してみて試してみてください。
 どうでしょう? 同じになりましたでしょうか? ならなかったと思います。”Standard handler”のチェックを外したにもかかわらず、ウインドウはちゃんとすべての動作に反応します。
 一体、どうなっているのでしょう?
 実は、PPx::WindowはNibを使わずに作成することも可能になっているため(以前、PPxがNibを使うようになったのは最初からではないとお話ししたことを思い出してください)、以下のようなコードだけで、新規にウインドウを生成することができるのです。

PPx::Window* theWindow = new PPx::Window;
Rect bounds = { 20, 20, 400, 400 };
theWindow->Initialize(kDocumentWindowClass, kWindowNoAttributes, bounds, CFSTR("PPxWin"));


 注目してほしいのは、Initialize()の引数としてkWindowNoAttributesというのを渡していて、外部からはこのウインドウに対してハンドラをインストールするように指示してはいないことです。(一般的なCarbonの処理では、kWindowStandardHandlerAttributeをウインドウ作成の際に渡す)
 それでも、クローズボックスなどはアクティブにならないものの、ドラッグなどのマウスイベントには対応しますし、メニューからのClose命令にもちゃんと応じるようになります。
 何でそんなことが起きるかと言えば、単純な話で、PPx::Windowがウインドウの生成の際に「勝手に」kWindowStandardHandlerAttributeなどの属性指定をしてウインドウを作成しているだけのことなのです。(先ほどのNibで外したチェックボックスはこの属性をコントロールしていたわけです)
 まあ、実際のアプリを作る場合これらの標準的なイベントハンドラはあるのが普通なので、これでいいのです。「必要なことには極力ユーザーの手を煩わせない」。これが、アプリケーションフレームワークの正しい姿でしょう。
 しかしながら、アプリケーションフレームワークとしては、同時に逆のケースにも対応できなければなりません。つまり、ユーザーがその標準的なハンドラを組み込みたくない場合にその要求を満たす手段を用意することです。
 PPxにも当然その手段は用意されています。HandlerNew()の先頭に、

PPx::Window::SetDefaultAttributes(kWindowNoAttributes);

という一行を追加するだけでOKです。これをすることで、PPxが「勝手に」ウインドウにイベントハンドラを組み込むことを抑止できます。

 ちょっといろいろと試してしまいましたが、ようやくこれで最初の目的を達成できるようになりました。つまり、いま触れたやり方を使えば、ウインドウにkHICommandCloseを処理するハンドラもインストールされないので、イベントはアプリケーションに渡り、MyApplicationのHandleClose()が呼び出されるようになります。
 実際に試されてみれば、コンソールに、HandleClose called.と表示されるのが確かめられるでしょう。
 あれ、ちょっと待ってください。メッセージは表示されたのに、肝心のWindowを閉じる処理が行われなくありませんか?
 困ったことに、これはPPxのバグなのです。
 PPxWindow.cpを開き、Window::Close()を以下のように書き換えれば、このバグは解消されます。

void
Window::Close()
{
    SysCarbonEvent    closeEvent(kEventClassWindow, kEventWindowClose);

    SysEventParam::Set(closeEvent, kEventParamDirectObject, GetSysWindow());   // ここを追加

    closeEvent.PostTo(GetSysEventTarget());
}


それから、ソース冒頭のinclude部分に一行追加してください。

冒頭部
#include 
#include 
#include 
#include 
#include 
#include   // ここを追加

namespace PPx {
....

書籍紹介        木下 誠 著 たのしいCocoaプログラミング

 解説担当:高橋政明

たのしいCocoaプログラミング
 木下 誠著
 株式会社ビー・エヌ・エヌ新社  ISBN978-4-86100-443-8  2,940円

 六月末に出版されたばかりのCocoaプログラミングの入門書です。著者はモサ伝でニュース解説を担当していただいていた木下さんです。書籍紹介で木下さんの著書をご紹介するのは二度目ですが木下さんのCocoaの本としては五冊目だそうです。

 Macのデスクトップアプリケーションのプログラミングがはじめての人とプログラム作りそのものが初めての人両方に向けて書かれていて、全体は五つのパートに分かれています。合計20のLessonからなり、すべてのLessonの最後のページには半ページほどの「このレッスンで学んだこと」が載っています。
 プログラムを作る作業はたくさんの(現在では膨大と言った方が正確なほど)の前提知識が必要ですが、要所ごとにこのようにまとめがあり次のレッスンへ導く書き方は読者に親切ですね。

 入門書は実際にプログラムを作るためのたくさんの情報を整理して記述しなければなりません。この点木下さんがAppleでCocoaのセミナーを担当された経験を生かしてまとめられています。開発環境のインストールにはじまり、アプリケーションやフレームワークの解説とXcodeの解説、開発手順の説明とMVCアーキテクチャとアウトレットとアクションの説明、C言語とObjective-Cの解説、Cocoaの基本的なクラスの解説、最後にエラーメッセージの対応とデバグ作業そしてアプリケーションにアイコンを付けたり日本語を表示する方法まで続きます。
 全ページ二色刷り、350ページを超えますが紙質を工夫し物理的にも軽い本に仕上がっています。ただし情報はC言語の解説も含むなど盛りだくさんで相対的にCocoaの細かなクラスの解説は必要最小限です。この点最後にさらに一歩進むための情報として「もっといろんなCocoaのクラスを使う」「いろんなフレームワークを使う」「サンプルを調べる」「Appleのサイトを参考にする」が解説付きで載っています。

 これからCocoaをはじめるCarbonプログラマにも「最新環境に対応した入門書」のひとつとしておすすめです。

 プログラミングはやり始めるまでが大変ですが、知識が広がりその知識をプログラミングに実際に活かすことは「たのしい」経験です! Mac OS XにはXcodeが付属していてすぐにプログラミングが体験できます。この点現在職業としてプログラムを作っていない学生さんや一般ユーザーがプログラムを体験するには良い条件と思います。

 Macプログラマの裾野を広げるには最適の一冊です。

▼出版社のweb (詳しい目次あり)
http://www.bnn.co.jp/books/title_index/mac/cocoa.html

▼著者のweb
http://hmdt.jp/books/enjoyCocoa/index.html

◇MOSAからのお知らせと編集後記は割愛します◇

 

 MOSA Developer News   略称[MOSADeN=モサ伝]
        配信停止 mailto:mosaden-ml@mosa.gr.jp
 記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
      記事投稿受付 http://www.mosa.gr.jp/?page_id=850
Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
特定非営利活動法人MOSA  http://www.mosa.gr.jp/
Copyright (C)2007 MOSA. All rights reserved.