MOSA Multi-OS Software Artists

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

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

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

2007-05-15

目次

  • 「りんご味Ruby」       第3回  藤本 尚邦
  • 藤本裕之のプログラミング夜話   #114
  • 高橋真人の「プログラミング指南」  第112回
  • 書書籍紹介    Subversion実践入門 第2版

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

今回は、RSSリーダから離れて、Rubyインタープリタとのインタラクティブな対話、対話型プログラミング環境について、あれこれ書いてみたいと思います。「インタラクティブな対話」などと言うとちょっと堅いかもしれませんが、要するに

 RubyのことはRubyに聞け

ということです。Rubyは尋ねれば気軽に応えてくれます。だったら、Ruby本人に尋ねながらRubyプログラムをあれこれ試行錯誤してみようじゃないか、そんな感じです。CやObjective-Cでのプログラミングにはない、Rubyのようなインタープリタを持つプログラミング言語処理系によるプログラミングならではの醍醐味かもしれません。

■ RubyのことはRubyに聞けその1 – 対話環境を自作する

Rubyでは、evalというメソッド(およびその変種)を使って、「Rubyプログラムを解析・実行」するRubyプログラムを書くことができます。すなわち、対話的プログラミング環境を簡単にプログラムすることが可能です。対話の仕組みを知る・雰囲気を味わうためにも、まずは、実用的かどうかはともかくとして、単純な対話環境を自作してみることにしましょう。

以下の5行のプログラムは、ごく簡単な対話環境プログラムです。

 

$stdout.sync = true
 read_expr = proc { print "ruby> " ; gets }
 while expr = read_expr.call do
   puts eval(expr).inspect rescue puts "ERR -- #{$!}"
 end


このRubyプログラムは、おおよそ以下のことを行っています。

 ・標準入力の終端(コントロール+D)に達しないかぎり、以下を繰り返す:
   ・プロンプトを表示して
   ・標準入力から文字列を1行読み込み
   ・その文字列を(正しいRubyプログラムとみなし)評価して
   ・結果を表示

これをrepl.rbという名前でファイルに保存しておき、ターミナル上でrubyコマンドを使って実行してみてください。

 

$ ruby repl.rb
 ruby>

プロンプト”ruby>”が表示されるので、Rubyプログラムを入力してリターンキーを押すと、実行して結果を表示してから、再び入力待ちとなります。終了する場合は、^D(コントロールキー+D)を入力します。以下は、実行例です。

 

$ ruby repl.rb
 ruby> 1 + 2 + 3
 6
 ruby> puts "hello,world"
 hello,world
 nil
 ruby> Time.now
 Thu May 10 22:17:00 JST 2007
 ruby> def factorial(n) n==0 ? 1 : n*factorial(n-1) end
 nil
 ruby> factorial(10)
 3628800
 ruby> (2..50).inject([]) {|a,i| a.find{|j| i%j==0 } ? a : a<


というような感じで、何かしらRubyプログラムを入力すると結果が表示されます。いかかでしょうか? 前回提示したRSSリーダプログラムを1行ずつ入力してみるのもよいでしょう。

このrepl.rbは、正しいRubyプログラムを1行に収めなければならない・エラー処理がおざなりであるなど、REPLとしての実用度には欠けるのですが、「『Ruby プログラムを解析・実行』するRubyプログラム」がどんなことをしているのか、その匂いを感じとってもらえればと思います。

(余談)ちなみに、上の実行例で、最後に実行したプログラムは、50までの素数の配列を生成するプログラムです。たまにはRubyらしさ濃厚なプログラム片を見せたいなと思って差し挟みました。(余談終)

■ REPLとは?

さて、上のプログラムにはrepl.rbというファイル名を付けましたが、REPLという用語を聞いたことはあるでしょうか?

 ・read  – ユーザが入力したプログラムを読み込んで
 ・eval  – それを実行(評価=evaluate)し
 ・print — 結果を表示する

といったことを対話的に繰り返し行うプログラミング環境のことを、Read-eval-print loop、略してREPLといいます。Rubyを含めて、インタープリタを備えたプログラミング言語処理系の多くが、何らかの形でREPLを備えています。

Rubyと同様にMac OS Xに付属しているインタープリタ型のプログラミング言語のPythonの場合には、pythonコマンドを引数なしで実行すると、REPLが起動するようになっています。また、大昔のパソコンでは、スイッチを入れるとBASICインタープリタの対話型プログラミング環境が初期画面になっているというのが一般的でした。

さらに、筆者も愛用しているEmacsは、見かけ上テキストエディタに分類されがちですが、その実体は、テキストエディタを備えたインタープリタ型Lisp処理系によるアプリケーション実行環境と言えます。Emacsを起動して最初に表示されるscratchバッファは、Lispプログラムを落書きするためのREPLそのものです。

Rubyを含めて、インタープリタを持ったプログラミング言語処理系の存在意義は、REPL・対話型プログラミング環境による試行錯誤を通して、スケッチ・落書きするようにプログラミングできるところにあるかもしれません。

■ まとめ

今回は、もともと、Rubyに付属の標準的なREPLであるirbコマンドと拙作のCocoaRepl.appなどについて説明するつもりだったのですが、対話型プログラミング環境への思い入れが強過ぎて、ついつい脱線してしまいました。irbまでたどり着くことができず、あまり実践的な話もできず。次回は「RubyのことはRubyに聞け」の続きとして、irbとCocoaRepl.appについて説明して、再びRSSリーダの説明に戻りたいところなのですが、はたしてどうなることやら…

筆者は、10年くらい前、Java(JDK 1.0あたり)で遊びつつ、主にCやC++を使ってプログラミングしており、RubyやLispのようなタイプの言語のことはあまりよく知りませんでした。Rubyのソースに昔から付いてくるサンプルとしてeval.rbというプログラムがあるのですが、それを見てRubyではREPLが簡単に実装できることを知り、「Rubyすげー!」と感動した覚えがあります。今回は、そんなところが少しでも伝わればいいなと思うのですが、いかがだったでしょうか?

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

 連休も終わり,来月のWWDCに向けて仕事にスパートをかけているヒトもおられることと思う。かく言うワタシはと言えば,「WWDC前のひと稼ぎ」と当てにしていた仕事が流れてしまい,現在この原稿を書くくらいしか仕事がない。暇なら暇でいい季節なんだからそこらに遊びに出ればいいではないかという意見もあろうがいろいろ事情もあってそうも行かず……いや,そういう話はまた書き出すと止らないからやめておこう。さて今回からまた新しい話。タカハシ編集長からのリクエストで「Nibファイルの分割」ちうのを説明したい。

 Nibファイルとは何かということについては説明の必要はないだろう。Xcodeを起動してファイルメニューから「新規プロジェクト」を選び,アプリケーションその他のプロジェクトを作成すればたいてい自動的に作られる(コマンドライン・ツールなどでは使えないので作られない)。前にも書いたことがあると思うが……いつだったっけと思って今調べてみたら2005年の始め頃だ,NSApplicationを解説したとき。デフォルトではこの自動的に作られるNibファイル(Cocoa アプリでは「MainMenu.nib」という名前になる)が「メインNibファイル」となりアプリケーション起動時にその中に定義されたオブジェクトが生成される。ここまではいいよね?

 Nibファイルの分割というのはつまり,必ずしも起動時に生成されなくてもいいオブジェクトを,別のNibファイルに定義しておいて,必要に応じて読み込もうということである。メインのウインドウが一個に初期設定用のダイアログが一個というようなアプリケーションならその初期設定用のダイアログだけを別にしてもたいした効果はないが,巨大なアプリケーションになればなるほどNibファイルの分割による起動時間のスピードアップは効いてくる。

 もちろんその分の時間は分割されたそれぞれのNibファイルをロードする際に分散されるだけで物理的に短縮されるわけではない。でもね,アプリケーションを起動してから終了するまでの1回のセッション中に,そのアプリケーションが用意している全てのウィンドウを表示する,なんてことは滅多にない。

 例えば今私はこの原稿を JeditXを使って書いているのだが,起動してから今までの間,さっき,前にNibファイルについて説明したのはいつかを調べるのに検索ウィンドウは表示したけど,一度もアバウトボックスを表示していない。ということは,アバウトボックスだけでも別のNibファイルに入れておけば,それをロードするための時間分だけ……まぁわずかだけども起動は速くなるわけだ。ってJeditXは既にそうなってるみたいだけどね。

 具体的な話に入る。おそらくはこれが一番簡単な例だと思うので,上のようなアバウトボックスを別のNibファイルに格納してみよう。分割されたNibファイルに格納されるこのアバウトボックスは,アプリケーションメニューの「About …」というアイテムからのメッセージを受け取って表示されることになるわけだ。

 まず最初に,Interface BuilderでMainMenu.nibを開き,File’s Ownerを選んで「Class」タブをクリック,プリンシパルクラスである NSApplicationのサブクラスを派生させてしまおう。仮にこれをMyApplicationとするが,このクラスで NSApplicationのorderFrontStandardAboutPanel: メソッドをオーバーライドし,これから作る別のNibファイルからアバウトボックスをロードするコードを書けばいい。サブクラスを選択状態にしてClassメニューから「Create Files For MyApplication」を選んでソースファイルを作る。

 おっとここで一つ注意。NSApplication の説明の時に書いたと思うが,こんな風にプリンシパルクラスをサブクラスした時には,プロジェクトのInfo.plist ファイルの NSPrincipalClass キーに対応する文字列を派生させたサブクラス名(この例でMyApplication)に変更するのを忘れないこと。これを忘れるといくらコードを書いてもそれらは金輪際実行されない。いや,笑ってるけどこれ意外と忘れがちで,ぼやぼやしてると半日くらい変だな変だなと首を傾げっぱなしになるので覚えておこう。……では次回は今作ったMyApplication.h とMyApplication.m の中身のコーディングから。お元気で。
                            (2007_05_10)

高橋真人のプログラミング指南  第112回

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

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

 こんにちは。高橋真人です。
 お待たせしました。早速続きを始めます。
 新しいプロジェクトは準備してあったので、あとはコードを書いていくだけです。とりあえず今回はメニューもウインドウもあるまともなアプリケーションが出来ますが、さほどコード量は多くありません。
 このくらいではまだ「真価を発揮」というほどまでには至りませんが、フレームワークの恩恵はところどころで味わえます。

 では、手順を説明します。まずは、Applicationクラスのサブクラシング、すなわち、Applicationクラスからサブクラスを作るわけです。

 プロジェクトウインドウの「Sourcesグループ」(連載110回参照)を選択して、メニュー「ファイル→新規ファイル…」を選択します。
 CarbonのC++ファイルを選んで「次へ」ボタンをクリック。MyApplication.cpとファイル名を付けます。「ヘッダも作成する」のチェックは付けたままです。
 ちなみに、C++のソースファイルの拡張子は.cppにしているケースも多いですが、PowerPlantは伝統的に(?).cpなのです。Panther(Mac OS X10.3.x)だと.cpをXcodeがC++ファイルと見なしてくれないこともありますが、Tigerでは問題ないようです。
 ちなみに、C++のソースの拡張子としては他に.cc、.cxx、.C(大文字)などもありますが、余り一般的ではないので、.cppか.cpのどちらかにしておいてください。(.cppがお好みであれば、それでも構いません)
 完了ボタンをクリックすると、プロジェクトに加わった形でMyApplication.hとMyApplication.cpの二つのファイルができます。
 前回から引き継いだmain.cpを含めたそれぞれのファイルを、以下のように変更します。

====================== main.cp =========================

#include "MyApplication.h"

#include 
#include 


void Setup();

int main()
{
    Setup();

    MyApplication theApp;
    theApp.Run();

    return 0;
}


void
Setup()
{
    PPx::SysNib menuNib(CFSTR("main"));
    menuNib.SetMenuBar(CFSTR("MenuBar"));

    PPx::RegisterCommonNibDecoders();
}


====================== MyApplication.h =========================

#include 

#include 
#include 

class MyApplication : public PPx::Application,
                      public PPx::CommandProcessDoer
{
public:
                        MyApplication();


protected:
    virtual OSStatus    DoCommandProcess(
                            PPx::SysCarbonEvent&    ioEvent,
                            HICommand               inCommand,
                            UInt32                  inKeyModifiers,
                            UInt32                  inMenuContext);

private:
    OSStatus            HandleNew();
    OSStatus            HandleClose();

    virtual CFStringRef ClassName() const;

};


====================== MyApplication.cp =========================

#include "MyApplication.h"

#include 
#include 
#include 

MyApplication::MyApplication()
{
    EventTargetRef targetRef = GetSysEventTarget();

    PPx::CommandProcessDoer::Install(targetRef);
}


OSStatus
MyApplication::DoCommandProcess(
    PPx::SysCarbonEvent&        ioEvent,
    HICommand                   inCommand,
    UInt32                      inKeyModifiers,
    UInt32                      inMenuContext)
{
    OSStatus status = eventNotHandledErr;

    switch (inCommand.commandID) {
        case kHICommandNew:
            status = HandleNew();
            break;
        case kHICommandClose:
            status = HandleClose();
            break;
    }

    return status;
}


OSStatus
MyApplication::HandleNew()
{
    OSStatus status = eventNotHandledErr;

    WindowRef theWindow = ::GetFrontWindowOfClass(kDocumentWindowClass, true);
    PPx::Window* win = PPx::Window::GetWindowObject(theWindow);
    if (win) {
        win->Close();
    }

    ::CFShow(CFSTR("HandleClose called."));

    return noErr;
}


OSStatus
MyApplication::HandleClose()
{
    OSStatus status = eventNotHandledErr;

    WindowRef theWindow = ::GetFrontWindowOfClass(kDocumentWindowClass, true);
    if (theWindow) {
        PPx::EventUtils::SetMenuCommandStatus(kHICommandClose, true);
    }

    return noErr;
}


CFStringRef
MyApplication::ClassName() const
{
    return CFSTR("MyApplication");
}


 では早速ビルドしてみましょう。
 アプリケーションを実行させてみると、メニューもきちんとあり、メニューから新規ウインドウを作れるアプリケーションが動くはずです。
 今回のコードのポイントは、もともとプロジェクトのステーショナリに加わっていたNibファイルをPPxがちゃんと読み込んで、それを使用していることです。
 オリジナルのPowerPlantでは、GUIの構築のためにPPobリソースという独自のリソースを使用していました。PPobリソースの編集のためにConstructorというツールが付属していて、これがPowerPlantの使いやすさの一翼を担っていたのです。
 PowerPlant Xの最初のリリース時には、GUI構築のために新規にxml形式のデータ形式を使うことになったのですが、Constructorのようなビジュアル編集ツールがなかったことから、決してGUIの編集はラクではありませんでした。
 初期のPPxが提供していたのは、PPobリソースとInterface BuilderのNibファイルをこの形式のデータに変更するツールでした。しかし、PPxを作っていた人たちは早い段階でこの方式に見切りを付け、Interface Builderが生成するNibファイルを直接読み込んで利用する方式に変更しました。この仕組みが採用されたPowerPlant Xのversion1.1が結果的に商品としては最後のリリースになってしまいましたが、私はこの考え方は正しかったと思っています。
 PowerPlant時代、Mac OSが新しいウィジェット(コントロール)を作り出す度に、PowerPlantユーザーは、PPがそれに対応するのを待っていなければならなかったのです。
 しかし、Nibファイルは、xml形式のデータであり、CarbonフレームワークにはInterface Builder Servicesというというフレームワークが備わっていますから、OSのバージョンが上がって、新たなコントロール(HIView)が登場しても、ちょっとソースを書き足せば対応が可能なのです。
 いずれ、この方法についても解説したいと思います。

書籍紹介          Subversion実践入門 第2版

 解説担当:高橋政明

Subversion実践入門 第2版
  Mike Mason著
  でびあんぐる監訳
  株式会社オーム社 ISBN978-4-274-06680-1  本体2,600円(税別)

 ソースコード管理ツールであるSubversionの解説書です。初版もおすすめでしたが早くも第2版が出ました。
 この本の初版は Pragmatic Version Control: Using Subversion を翻訳したものです。第2版は原著が2nd Editionになりそれに対応したようです。原著のwebには2nd EditionではSubversionのバージョン1.3に対応したと明記されていますが、日本語版ではその点は明示されてはいないようです。

 ソースコード管理(バージョン管理)については食わず嫌いの方もいらっしゃるかもしれません。本書はそんな方にもおすすめです。単にツールとしてのSubversionの使い方に留まらず、「序章」と「バージョン管理とは何か」の二つの章を使い具体例を示し文字通りバージョン管理とは何かを解説しています。

 私が特にありがたかったのは「3.7競合の発生」「3.8競合の解決」でした。実際に試すことで、深刻な状況に思えた競合と競合の対処の意味を理解する事ができました。競合以外も具体的に書かれているので試しながら理解を深めて行く事ができます。
 CVSに慣れたユーザ向けのヒントも載っていてCVSからの乗り換えにも最適です。
 「付録E.2レシピ」はやりたい事を実現するためのサブコマンドがすぐにわかる構成で便利です。

 Mac OS Xにも数カ所で言及されていますが残念ながら索引には載っていません。もっともWindows特有の解説部分を除きすべてはMac OS Xでもそのまま使えますので支障はありません。

●第2版の変更点
 出版社のwebに詳細な目次がありますが、第2版では第7章「ファイルロックとバイナリファイル」と「付録D高度なトピック」が追加されました。ありがたいことに価格は変わっていません。
 図版も変わっていてUnixのシェルプロンプトにはAquaのウインドウ(明らかにターミナル.app)が載っています。

 日本語版独自に監訳者による注釈やコラムも追加になっていました。またWindows Vistaに言及している部分もありました。
 初版とは表紙の写真が違うので初版をお持ちの方はすぐに気がつく事と思います。既に初版をお持ちの方はあえて第2版を購入される必要は少ないとは思います。なお原著のwebで追加になった第7章がまるまるpdfで公開されています。(太っ腹!)

▼出版社のweb
http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06680-1

▼原著 Pragmatic Version Control using Subversion, 2nd Ed. のweb
http://www.pragmaticprogrammer.com/titles/svn/

▼サンプルページ(原著の第7章)2.2MB
http://www.pragmaticprogrammer.com/titles/svn2/Locking.pdf

◇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.