MOSA Multi-OS Software Artists

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

プログラマーに興味がある方なら誰でも入会いただけます。
MOSA Multi-OS Software Artists
===SINCE 1995===

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

MOSADenバックナンバー 2008年10月発行分

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

    2008-10-28

    目次

    • りんご味Ruby         第34回  藤本 尚邦
    • 藤本裕之のプログラミング夜話   #147
    • 高橋真人の「プログラミング指南」  第145回

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

    これまでに、しばしば、DSL(Domain-Specific Language=ドメイン固有言語)や構文糖衣(syntax sugar)を作りやすいのがRubyの重要な特徴のひとつだということを書いてきました。前回、Mechanizeの構文糖衣について書いたので、今回はその流れで、Rubyでの構文糖衣やDSLの作り方について書くことにします。

    ■ (例) アクセッサ宣言の構文糖衣を追加する

    さて、Objective-C 2.0 では、宣言プロパティという新しい構文が導入されました。例として、TODOリストのアイテムのクラスを定義するとします。Objective-C 2.0で宣言プロパティを使うと以下のようなコードになるでしょうか。

    ----------------------------------------------- TodoItem.m ---
    @interface TodoItem : NSObject {
     NSString* summary;
     int       level;
     BOOL      done;
    }
    - (id)initWithSummary:(NSString*)str;
    @property(readonly)  NSString* summary;
    @property            int       level;
    @property            BOOL      isDone;
    @end
    
    @implementation TodoItem
    - (id)initWithSummary:(NSString*)str {
       if ((self = [super init])) {
           summary = str;
           level = 0;
           done = NO;
       }
       return self;
    }
    @synthesize summary;
    @synthesize level;
    @synthesize isDone = done;
    @end
    -----------------------------------------------
    


    インターフェース部の@propertyでは、外部に対してプロパティに対するアクセサの名前・種類(読み書き属性)・型などを宣言し、実装部の@synthesizeでは、コンパイル時にアクセッサメソッドの定義を(自動)生成する指示を記述しています。

    この宣言プロパティに近いものとして、Rubyには attr_reader, attr_writer,attr_accessor という構文糖衣があらかじめ用意されています(本当は構文ではなくメソッド呼出による疑似構文なのですがそれについては後述)。TodoItemクラスの定義をRubyで書くと

    ----------------------------------------------- TodoItem.rb ---
    class TodoItem
     attr_reader   :summary
     attr_accessor :level, :done
    
     def initialize(summary)
       @summary = summary
       @level = 0
       @done = false
     end
    end
    -----------------------------------------------

    というような感じになります。この attr_reader, attr_accesor は、クラスの定義のときに、指定された名前のインスタンス変数へのアクセッサメソッドを自動生成します。例えば attr_accessor :level のところは以下のようなコードを記述したのと同じことになります。

     

    # reader (Objective-C用語ではgetterに相当)
     def level
       @level
     end
    
     # writer (Objective-C用語ではsetterに相当)
     def level=(new_value)
       @level = new_value
     end
    


    Objective-Cを含め、よく使われているプログラミング言語の多くは構文を拡張するプログラムを書く手段を持っていないので、構文についてのちょっとしたアイディアを持っていても、処理系に新しく実装されるのを待ったり、開発チームに要望したり、あるいは自ら処理系に実装するしかありません。

    (補足 – 構文を拡張する手段を持つプログラミング言語の有名どころは、Common Lisp や Scheme などのLISP系言語でしょう)

    Rubyにも、本物の構文そのものを拡張するプログラムを書く手段はありません。その意味ではObjective-Cなどと同様なのですが、attr_reader のような疑似構文(つまり宣言プロパティ程度の構文)はメソッドとして実装することができます。つまり、Rubyプログラマは、疑似的な構文糖衣を実装してライブラリなどに含めることができるわけです。

    例として、真偽値を返すアクセッサを宣言するための疑似構文attr_predicateを定義してみましょう。Rubyプログラミングでは、真偽値を返すメソッド名の末尾に`?’を付ける慣習があるわけですが、残念ながらそれに対応したアクセッサ宣言の疑似構文がRubyには用意されていません。もし今すぐどうしてもそれが欲しいと思ったら、すぐに自分で作ってみることができるわけです。

    attr_predicate の仕様は、クラス定義の中で

     attr_predicate :done, :important

    のように、真偽値を返すreaderの名前(複数可)を宣言すると

     

    def done?
       @done ? true : false
     end
    
     def important?
       @important ? true : false
     end
    


    のように、`?’の付いた名前を持ち真偽値型を返すアクセッサメソッドの定義が生成されるということにします。attr_prediateを組み込むプログラムは以下のようになります。

    Module.module_eval do
     def attr_predicate(*names)
       names.each do |name|
         define_method("#{name}?") do
           instance_variable_get("@#{name}") ? true : false
         end
       end
     end
    end
    


    このコードをライブラリなどに含めておくと、そのライブラリをロードしたあとは、クラス定義の中で attr_predicate を使ってアクセッサを宣言することができるようになります。このコードの詳細については次回説明します。

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

     前置きなしで話を続ける。「ゲーム作って一発当てる可能性」の話ね。あ,期待されると申し訳ないので最初に断っておくが,「これこれこんなゲームを作れば絶対当たってウハウハだぜ」という話ではない。この世界にエントロピーの増大以外に絶対なんてものはないのである。わかんないヒトのために言っておくと「エントロピーの増大」というのはつまり「どんどんどんどんわけがわかんなくなっていく」ということだからね。

     ……オレが検討したいのはそういうではなくて「ゲームを作って一発当ててあとの人生は悠々自適のヒダリウチワ」みたいな。ま,まぁそこまで言わなくてもそれなりに安定した生活というものを設計できるのか,そういう可能性はどのくらいあるだろうか,という話である。

     まず最初に,ちょっと本論からズレるが(と言ってもはやどこが本論なんだかオレにもよくわからないんだが)「ゲーム」というもの,この文脈でいうところの「コンピュータ・ゲーム」というものをきっちり解析しておきたい。

     世代的に近い多くのヒトがそうではないかと思うが,オレが最初に触れたコンピュータゲームは5mm四方くらいの光る矩形をパドルで打ち合うスカッシュみたいなもんだった。いやみたいなもんというかそういう名前がついていたかも知れない。あれはつまり,現実にあるゲーム(スポーツを含む)をコンピュータ上で実現したもので,Mac OS Xに付属しているチェスや初期の
    Windowsの呼び物(笑)だったリバージ(なぜか「オセロ」とは呼ばない),数多あるトランプ・ゲーム,麻雀ゲーム,ゴルフや野球,サッカー,カーレースなどを模すものもこの類である。これを大ざっぱに第1群とする。

     これらとは別に,最初からコンピュータ上で遊ぶものとして設定,ルール,意匠その他イチから作るというものがある。初期のもので言えばブロック崩し(ああいう現実の遊びはない),インベーダゲーム,スーパーマリオ……。現在でも主にゲーム専門機上で定番化しているドラクエ,ファイナルファンタジー(他に何があるの? 白状するとオレそのテのゲームはやったことがない
    のだ)などがこの類と言えよう。これが第2群ね。

     ちょっと考えれば……いや,やった経験があるヒトにとっては考えるまでもないことだと思うが,第1群に類するゲームをこれから作ってゲーム業界に参入……というシナリオには無理がある。ルールや設定など,ゲームの基礎部分が変わらない以上,商品価値の優劣はどうしても意匠,グラフィックの見事さや動きのリアリティ,音楽などで計られることになるからで,ハワード・ヒューズが映画監督を始めたみたいなシチュエーション以外では現実的ではないからだ。

     第2群にはまだ可能性がある。1980年代末期に一世を風靡した「テトリス」を思い起こして欲しい。旧ソビエト連邦の科学者アレクセイ・パジトノフ博士他3名によって開発されたこのゲームは,PCのみならずアーケードから家庭用ゲーム機,果ては携帯電話にまで移植された。それでもともとの開発者であるパジトノフ博士らがどのくらい潤ったのよ,と聞かれるとれはオレにも判らな
    いが(なにしろ冷戦終結前だしね),あの種のゲームであれば低資本で開発でき,うまく行けば市場を席巻できるかも知れない。

     もちろん(実際このテトリスと類似品の間で裁判が争われたように),ゲームのルールには著作権は認められない。だからすぐに金に飽かして,例えば鳥山明のキャラクターデザイン,X-JAPANの音楽,渡辺久美子の声とかを使って類似品を作るメーカーが現れるかも知れない。まぁでもそういうメーカーも,ユーザから「真似し」とか「簒奪者」みたいな陰グチたたかれるよりはこっちに原案料みたいなものを払うことを選ぶであろうし……それを売り切りでなく歩合と決めておけば逆に鳥山明,X-JAPAN,渡辺久美子のおかげでこっちが潤うということになるわけでと,取らぬ狸の皮算用もあながち夢とは言いきれない。

     と,なると要はアイディアであるわけだが……え? 鳥山明とX-JAPANはいいが渡辺久美子って誰だって? それはあなた「ケロロ軍曹」を演ってる声優のひとであります。では次回はそのアイディアについて。
    (以下次回 2008_10_24)                       

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

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

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

     こんにちは、高橋真人です。
     さて、“アタッチされているViewを探す”という、連載141回目で掲げたアタッチメントを外すための手順の第1ステップの説明がずいぶん長くなってしまいました。前々回と前回での解説をまとめますと、HIViewのFindViewByID()に渡す引数は、ObjectIDTという型で表されるViewの識別子だということになります。
     しかしながら、今回のコード例(連載140回目)に見られるように、引数には単に100などの整数値を与えるだけでよく、ここではObjectIDTという型を特段意識する必要がありません。前回までの説明では「整数を表す型」をいくつでも個別に作れる方法を説明をしましたが、その時の例のような関数の多重定義(オーバーロード)でもしない限り、これら新たに作った型も“普通の整数として”使えるところがこの仕組みの便利なところです。

     そんなこんなで、ようやくViewの検索の説明が済んだのですが、実際のコードではさらにもう一段階の処理が行われています。

      

     MyView *view = PPx::SafeDynamicCast(
                           GetContentView()->FindViewByID(100));

     ルートのViewに対してFindViewByID()を呼んで、アタッチメントの付けられているViewを探すわけですが、その結果として返された値をSafeDynamicCastという関数に渡しています。この関数が行っているのは、ダイナミックキャストを行い、その成否をチェックするということです。
     ダイナミックキャストというのは聞き慣れない方も多いかもしれません。もともとC言語に備わっているキャストという仕組みは、型の変換を行うものであることをご存知と思いますが、型変換にはいくつかの種類があるのです。
     C++においては、「すべての型変換をを一つのキャストで行ってしまうのは乱暴だ」ということから、役割ごとに分けています。const_cast、static_cast、dynamic_cast、reinterpret_castの4つです。これらすべてを解説するのは今の趣旨ではないので、今回はdynamic_castのみに絞ります。
     上のコードを例にしますと、FindViewByID()が返すのはViewへのポインタです。ところが、そのポインタが指しているのがPPx::Viewのインスタンスだとは限らないわけです。つまり、PPx::Viewを継承元に持つ別のサブクラスのインスタンスである可能性もあるわけです。
     そこで、“PPx::View *”を“MyView *”に変換する必要が出てきます。従来形式のキャストですと、仮にPPx::View *の指している実体がMyViewやそのサブクラスのインスタンスではなくても、有無を言わさず変換してしまいます。そうなると、キャストによって得られたポインタを使ってMyViewにしか存在しないメンバ関数を呼びだした場合にまずいことが起きてしまいます。普通
    はアプリのクラッシュでしょう。
     そこでdynamic_castです。これを使って書くとコードは以下のようになります。

    PPx::View *view = GetContentView()->FindViewByID(100);
    MyView *myView = dynamic_cast(view);
    


     ちょっとゴツい見た目をしていますが、dynamic_cast<...>(…)というのがC++で新たに加えられたキャストの書き方です。キャストは目立った方がよい、というのが設計意図なので、あえてこのような見た目をしています。
     さて、上記のようにdynamic_castを使ってキャストを行った場合、たとえばviewがPPx::TextViewのインスタンスだったとしますと、myViewにはNULLが入ります。つまりキャスト自身が型判断も行い、要求している型変換に合わない場合にはNULLを返すようになっているのです。
     使い方としては、dynamic_castが返す値がNULLであるかどうかをチェックすることで、dynamic_castが成功したかどうかを判断します。PPxでは、SafeDynamicCast関数がdynamic_castでキャストして、もしキャストが失敗したら例外を投げる仕組みになっています。
     ところで、オリジナルのPPにも似たような仕組みを実現するマクロがありました。FindPaneByID_()というのがそれです。白状しますと、きょうの今まで、私は両者を全く同じ感覚で使っていたのです。しかし、今回の記事を書くに当たって改めてコードを読んでみると、PPxのSafeDynamicCastでは、キャストの失敗に関してしか例外を投げないということに気付きました。
     PPのFindPaneByID_マクロでは、Pane(*注)の検索に失敗した場合にも例外を投げてくれます。よって今回のコードでは、SafeDynamicCastが返した値に対しても、NULLでないかをチェックする必要があったのでした。
     厳密に考えれば、NULLを返すのはFindViewByID()なので、SafeDynamicCastに渡す以前にNULLかどうかのチェックをすべきだとは思いますが、SafeDynamicCastはNULLが渡された場合には、そのままNULLを返すようになっているため、“後”のチェックでも実質的には問題ありません。

    注:以前の連載でも触れましたがオリジナルPPでは、ViewのスーパークラスはPaneです。Viewは階層構造的にViewまたはPaneを子に持つことができます。
     
    過去記事の訂正です。連載142回目の中ごろ、

     本題に戻ります。PPx::WindowのGetWindowContentView()という関数により…

    という部分。
    【誤】GetWindowContentView()
    【正】GetContentView()

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

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

    2008-10-14

    目次

    • 「Wonderful Server Life」    第79回   田畑 英和
    • 小池邦人のCarbon視点でCocoa探求
    • ターミナルの向こうから      第34回  海上 忍 

    「Wonderful Server Life」  第79回  田畑 英和

      〜「iPhone構成ユーティリティ」編〜

     今回は少し話題を変えて、ようやくNDAも解禁になろうとしているiPhoneについて取り上げてみます。といいましても開発ネタではなくiPhoneの運用に関するお話です。
     システム管理の観点から考えますと、なにか新しい製品を購入した場合、初期設定などの作業を行ってから配置するといった作業が必要になります。Macならばユーザ登録をしたり、アプリケーションをインストールしたりといった作業が考えられますが、これはiPhoneも同様です。
     iPhoneのような高機能な携帯端末はもはや超小型のパソコンといってもいいくらいですが、実際に使用するとなるとWi-Fiの設定やMailアカウントの設定、パスコードの設定やVPNの設定など様々な設定項目があります。
     個人でiPhoneを利用する場合、こういった設定は通常各ユーザごとに行うわけですが、今後企業での大量導入が進んだりするとあらかじめ設定を行ってから社員に配布するといったことが考えられます。このとき、1台1台iPhone上で設定を行っていてはとても手間がかかります。そこでこういった作業を効率よく行うための設定ツールがAppleよりリリースされています。

    ◇iPhone構成ユーティリティ
    「iPhone構成ユーティリティ」というのが設定ツールの名称ですが、最近少しバージョンアップした1.0.1がリリースされました。このツールはMac OS X上で動作し、無料で使用することができます。また、iPhoneの設定だけではなくiPod Touchの設定を行うこともできます。

    ・iPhone Configuration Utility 1.0.1 for Mac OS X
    http://www.apple.com/jp/ftp-info/reference/iphoneconfigurationutility101formacosx.html

     このツールをダウンロードしてインストールすると、「/アプリケーション/ユーティリティ」にインストールされます。
     iPhone/iPod touchの設定を行うには、このツールを使って構成プロファイルの作成を行います。左側のリストから「構成プロファイル」を選択しツールバーの「新規」ボタンをクリックしてプロファイルを新しく作成します。
     プロファイルは複数作成することもでき、それぞれ次のような項目を設定できます。

    ・一般
      プロファイルの名前や識別子、プロファイルの署名などの設定
    ・パスコード
      パスコードのポリシーを設定
    ・Wi-Fi
      アクセスポイントのSSIDやセキュリティの設定、複数設定可
    ・VPN
      VPN接続のための設定、複数設定可
    ・メール
      メールアカウントの設定、複数設定可
    ・Exchange
      Exchange ActiveSyncに関する設定
    ・資格情報
      デバイスにインストールする証明書の設定
    ・詳細
      キャリアのアクセスポイントに関する設定

     パスコードの設定では、通常は数字4桁のパスコードをアルファベットも使用可能にしたり、パスコードの長さや有効期限などの設定もできますので、個人使用の場合でもよりセキュリティを高めたい場合などには有効です。

    ・パスコードの設定
    http://www.htabata.com/img/iPhone/iPCU/iPCU_03.png

    ◇構成プロファイルの配布
     プロファイルの準備が整ったら次はプロファイルをiPhoneやiPod touchのデバイスに配布します。配布の方法はE-mailとWebの2つが用意されています。
    E-mailを使用する場合には「iPhone構成ユーティリティ」から「Mail」アプリケーションを呼び出して、プロファイルの添付書類付きメールを作成することができます。あとはメールを送信してデバイス側で受信します。メール経由で設定を配布するということは、あらかじめデバイス側でメールが受信可能な状態になっている必要があります。
     もう1つの方法はWebサーバ経由での配布です。「iPhone構成ユーティリティ」からプロファイルを書き出して、書き出したファイルをWebサーバ経由でアクセスできるようにします。書き出したファイルの拡張子には.mobileconfigを使用し、デバイス側でこのファイルを正しく認識させるには、あらかじめWebサーバ側で以下のMIMEタイプの設定を行っておく必要があります。

     拡張子:mobileconfig
     MIMEタイプ:application/x-apple-aspen-config

     WebサーバがMac OS X Server v10.5.3以降であればこのMIMEタイプの設定はあらかじめ行われていますので、Webサーバでの追加の設定は必要ありません。

     E-mailでもWebでもプロファイルを取得するにはデバイスがネットワークに接続できる必要があります。つまり、「iPhone構成ユーティリティ」を使って設定をするには、あらかじめデバイスをネットワークに接続できる状態にしておく必要があるということです。
     ちなみに、プロファイルはXML形式のテキストファイルです。暗号化されたり圧縮されたりはしていません。

    ◇構成プロファイルの適用
     E-mailまたはWeb経由でデバイスにプロファイルをダウンロードしたら、いよいよプロファイルのインストールです。たとえばSafariでプロファイルのURLにアクセスすると、プロファイルのインストール画面が表示されます。

    ・プロファイルのインストール
    http://www.htabata.com/img/iPhone/Profile/profile_01.png

     プロファイル作成時にプロファイルの署名が設定できますが、これは必須ではありません。もしプロファイルに署名が設定されていなければインストール画面に「符号なし」と表示さます。ちょっと分かりにくい日本語になっていますがこれはプロファイルが署名されていないことを表しています。また、署名がない場合インストール時に警告が表示されますが、インストールはできます。
     インストール画面で「インストール」ボタンをクリックすればプロファイルをデバイスに適用できます。このとき、プロファイルでパスコードのポリシーを設定していればパスコードの入力が、Wi-Fiの設定をおこなっていればアクセスポイントのパスワードの入力が求められます。

     いったんインストールしたプロファイルを削除したい場合には「設定」>「一般」>「プロファイル」から削除することができます。

    ・インストール済みのプロファイル
    http://www.htabata.com/img/iPhone/Profile/profile_03.png

     今回はMac OS X上で動作する「iPhone構成ユーティリティ」について説明しましたが、Webブラウザ上で設定を行う「Web Utility」も用意されており、こちらはMac版だけでなくWindows版も用意されています。

    ・Web Utility Mac版
    http://www.apple.com/support/downloads/iphoneconfigurationwebutility10formac.html
    ・Web Utility Windows版
    http://www.apple.com/support/downloads/iphoneconfigurationwebutility10forwindows.html

     また、「iPhone構成ユーティリティ」はアプリケーションの配布にも使用することができます。こちらについてはまた機会があればご紹介したいと思いますが、より詳しい情報については「エンタープライズ運用ガイド」を参照してください。

    ・エンタープライズ運用ガイド
    http://www.apple.com/jp/support/iphone/enterprise/
    次回へつづく                             

    小池邦人のCarbon視点でCocoa探求(2008/10/10)

    〜 得られたファイルの種類を調べる 〜

    今回は、 エイリアスファイルに関わる処理をするresolveAlias()ルーチンや、パス名で示されたファイルがImageBrowserで扱える画像かどうかを判断しているchkImageFile:クラスメソッドを中心に解説します。

    まずは、ファイル操作関連のドキュメントから紹介したいと思います。Mac OS Xのファイルシステムに関しての総論については以下のドキュメントを参照します。

    「File System Overview」

    http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/BPFileSystem.html

    次はCocoaアプリケーションでのファイル処理についての解説です。以下のドキュメントには、オープン・パネル(Carbonのファイル選択ダイアログ)やセーブ・パネルなどの利用方法が解説されています。

    「Application File Management」

    http://developer.apple.com/documentation/Cocoa/Conceptual/AppFileMgmt/AppFileMgmt.html

    こちらは、Cocoaアプリケーションで確保したオブジェクトをアーカイブとしてファイル保存するための方法が解説されています。

    「Archives and Serializations Programming Guide for Cocoa」

    http://developer.apple.com/documentation/Cocoa/Conceptual/Archiving/Archiving.html

    次のドキュメントは基本的なファイル操作(作成、オープン、リード、ライトなど)についての解説です。NSFileManagerやNSFileHandleクラスのメソッド紹介が中心ですが、今回取り上げる「エイリアス解析」についても、21ページからの「Resolving Aliases」において解説されています。

    「Low-Level File Management Programming Topics」

    http://developer.apple.com/documentation/Cocoa/Conceptual/LowLevelFileMgmt/LowLevelFileMgmt.html

    Mac OS Xのファイルシステムでは、ファイルの種類(JPEGなのかTIFFなのか等)を判別するために「UTI」(Uniform Type Identifiers)が導入されています。これは、Mac OS X 9までのファイルタイプ(半角4文字)による判別や、拡張子(.textなど)による判別に取って代わる仕組みです。以下のドキュメントは、そのUTIについての解説です。

    「Uniform Type Identifiers Overview」

    http://developer.apple.com/documentation/Carbon/Conceptual/understanding_utis/understand_utis_intro/chapter_1_section_1.html

    今回の話で取り上げるchkImageFile:メソッドでは、UTIを調べることで、ImageBrowserで扱える画像ファイル(ムービーとQuartz Composerファイルも登録可能)かどうかを判断することになります。

    まずはエイリアスの中身を解析して、その実体ファイルの保存場所(パス名)を得るためのresolveAlias()ルーチンです。これはCルーチンとして提供されています。Objectiv-Cのクラス内では、Cルーチンも問題なく記述することができます。そうしたルーチン内でObjectiv-Cのメソッドを利用することも可能ですが、そのクラスのインスタンス変数にはアクセスできませんので注意してください。CocoaのFoundation FrameworkとCore Foundation Frameworkで取り
    扱うオブジェクト(例えばNSStringとCFStringRef)には互換性がありますので、お互いに対応するAPIをうまく利用すれば、CarbonとCocoaで共通利用できるユーティリティルーチンが作成できます。

    NSString *resolveAlias( CFStringRef path )
    {
       CFStringRef    respath=NULL;  // 実体が得られない場合はNULLが返る
       Boolean        folder, alias;
       CFURLRef       url,resurl;
       FSRef          fref;
       OSErr          err;
    
       if( url=CFURLCreateWithFileSystemPath( kCFAllocatorDefault,path,
                                           kCFURLPOSIXPathStyle,FALSE ) )
       {                                   // パス名からCFURLRefを得る
           if( CFURLGetFSRef( url,&fref ) )  // CFURLRefからFSRefを得る
           {
               err=FSResolveAliasFile( &fref,true,&folder,&alias ); // エイリアス解析
               if(err==noErr && alias )  // エイリアスであれば実体のFSRefを得る
               {
                   if( resurl=CFURLCreateFromFSRef( kCFAllocatorDefault, &fref ))
                   {                    // 解析されたFSRefからCFURLRefを得る
                       respath=CFURLCopyFileSystemPath( resurl,
                                                       kCFURLPOSIXPathStyle );
                                       // CFURLRefから実体ファイルのパス名を得る
                       CFRelease( resurl );
                   }
               }
           }
           CFRelease(url);
       }
       return (NSString *)respath; // 実体ファイルのパス名が得られればそれが返る
    }
    


    Core Foundationで確保したオブジェクトはAutoReleaseされませんので、不用なものはCFRelease()で解放することを忘れないでください。次は、chkImageFile:クラスメソッドです。こちらはメソッド内でCore FoundationのAPIを多用する例です。呼び出し方は、MyDocumentクラスのクラスメソッドですので…

    [MyDocument chkImageFile:path];

    という感じになります。メッセージのpathにはファイルパス名を設定します。こちらもresolveAlias()と同様にCルーチンとして記述しても構いませんが、比較のためにクラスメソッドとして用意してみました。

    得られたファイルのパス名からCFURLRefを得て、それをLSCopyItemInfoForURL()に渡すことでLSItemInfoRecord構造体を得ています。
    構造体メンバーに含まれているファイル情報(拡張子とファイルタイプ)を、UTTypeCreatePreferredIdentifierForTag()やUTTypeCreatePreferredIdentifierForTag()に渡してUTI情報を得ています。最終的には、それがCoreGraphicsでサポートしている画像種類に含まれるかどうかを比較して調べます。未サポートであれば、最後に、それがムービーファイ
    ルか?Quartz Composerファイルか?を再調査し、そうであればImageBrowserへの登録対象と判断します。

    + (NSString *)chkImageFile:(NSString*)path
    {
       CFStringRef        cc,type,comf=nil;
       CFStringRef        uti=nil;
       CFArrayRef         suport;
       LSItemInfoRecord   info;
       CFIndex            i,ct;
       CFURLRef           url;
    
       if( url=CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
                   (CFStringRef)path,kCFURLPOSIXPathStyle,FALSE ) )
       {                              // パス名からCFURLRefを得る
           if( ! LSCopyItemInfoForURL( url,kLSRequestExtension | 
                                       kLSRequestTypeCreator,&info ) )
           {                           // CFURLRefからLSItemInfoRecordを得る
               if( info.extension )    // 拡張子が付いていればそこからUTIを得る
               {
                   uti=UTTypeCreatePreferredIdentifierForTag( 
                     kUTTagClassFilenameExtension,info.extension,kUTTypeData );
                   CFRelease(info.extension);
               }
               if( ! uti )  // 拡張子は付いていなかった
               { 
                   if( type=UTCreateStringForOSType( info.filetype ) )
                   {    // その場合はファイルタイプからUTIを得る
                       uti=UTTypeCreatePreferredIdentifierForTag( 
                                       kUTTagClassOSType,type,kUTTypeData );
                       CFRelease( type );
                   }
               }
               if( uti )  // UTIを得ることができた
               {
                   suport=CGImageSourceCopyTypeIdentifiers();
                       // CoreGraphicでサポートする画像情報を得る
                   ct=CFArrayGetCount( suport );
                   for( i=0;i
    


    ここでのLSCopyItemInfoForURL()やUTTypeCreatePreferredIdentifierForTag()などは「LaunchServices Framework」に所属するAPIです。定義されているヘッダファイルはLaunchServices.hとUTType.hですので、APIや構造体の詳細についてはそちらを参照してみてください。

    次回は、ImageBrowserへの画像登録の「別の道筋」である「ドラッグ&ドロップでウィンドウに画像を追加登録」と「アプリ・アイコンへのドロップで新規ウィンドウを開き画像を登録」について解説したいと思います。

    ターミナルの向こうから      第34回  海上 忍

    〜 いま敢えて学ぶTerminalのイロハ(1) 〜

     コマンドはできれば使いたくない、Terminalを起動しても何をすればいいかわからない……CUIが苦手だ、という方からよく聞くコメントです。洗練されたGUIを誇るMacのこと、MPW(Macintosh Programmer's Workshop)などの例外を除けば、CUIに縁がなかったことも事実。会員からコマンド/ターミナル初心者向けの読み物を望む声が多いと聞き、しばらくの間ご要望にお応えしようと考えた次第です。

    ・「コマンド」を知る
     最初に、「コマンド」について説明してみましょう。コマンドとは、ある処理を行う実行形式のファイル、すなわちアプリケーションです。なんらかの処理を行うという意味では、DockやApplicationsフォルダに並んだアプリケーション(.app)と変わりません。Finderからダブルクリックする形でも、コマンドを実行することは可能です。
     ただし、GUIのアプリケーションとは処理を開始するときのスタイルが異なります。1つは、処理を開始するにあたり、なんらかの「動作条件」を与えること。その条件が、「オプション」や「引数」です。オプションや引数を指定してコマンド(オプションや引数を含め「コマンドライン」と呼びます)を実行するために、その専用環境として「ターミナル」を利用するわけです。

    ・「ターミナル」と「シェル」の関係
     ターミナルはコマンドを実行するための専用環境と書きましたが、実際にその役目を司るのは「シェル」と呼ばれるプログラムです。ターミナルの前に、シェルについて説明しておきましょう。
     シェルとは、システムの中核(カーネル)に命令を伝えるためのユーザインターフェイスの一種です。キャラクタベースのアプリケーションで、キーボードなどのデバイスから入力した情報(コマンドライン)を解釈し、カーネルに伝える役割を果たします。プロンプトを表示してコマンド入力待ちの状態を知らせたり、カーソルキーでコマンドラインを編集したりする機能は、シェルに
    より提供されます。
     そのシェルも実行形式のファイルであり、コマンド/アプリケーションですが、人間と情報をやり取りするために文字の描画を必要とします。その機能を提供するのがターミナルソフト(仮想端末/ターミナルエミュレータ)で、かつてVAXなどミニコンの時代に確立された端末画面を模したものです(いまどきの高解像度モニタで80×24字を全画面表示する必要はありませんから)。Mac OS Xを含む現在のUNIX系OSにおいて、シェルとターミナルソフトは事実上不可分な状態にあります。
     Mac OS Xに標準装備の「ターミナル」は、このターミナルソフトの一種です。ターミナルを起動すると、あらかじめ指定しておいたシェル(初期値では「bash」)が起動されコマンド入力待ちになりますが、ターミナルとシェルは別物だということは理解しておくべきでしょう。

    ・まずは「シェル」を理解しよう
     以上を要約すると、ターミナルというアプリケーションは表示用の器で、コマンドを実行するという処理の核心部分では「ユーザインターフェイスであるシェル」と「コマンドライン」こそが重要ということになります。コマンドを自在に使えるようになるためには、シェルの機能を知ることが不可欠です。
     それでは、ターミナルを起動してみましょう。なにも設定されていない状態であれば、「MBPro:~ shinobu$」といった具合に、「コンピュータ名:~ ユーザ名$」の形式でコマンド入力待ちを知らせるプロンプトが表示されているはずです。
     このプロンプトは、キーボードから文字入力を受け付け解釈するために、シェルによって表示されているものです。それでは試しに、このプロンプトをより使いやすく設定してみましょう。以下の文字列をコピーし、プロンプトのところへペースト後に実行(行末でenter)してください。

    - - - - -
    export PS1=' [ e[34m ] @  [ e[33m ] u@ h  [ e[32m ] w e[0m n $ '
    - - - - -
    


     どうでしょう? プロンプトが、「09:45 AM shinobu@MBPro ~」(時刻とユーザ名/コンピュータ名は環境により異なる)と「$」の2行で表示されたはずです。しかも時刻と「shinobu@MBPro ~」の部分はカラー。シェル(bash)のプロンプト表示スタイルを司る環境変数「PS1」にルールに沿った設定を施し、プロンプトをカスタマイズしたに過ぎませんが、シェルの働きの一端を知ることができたはずです。なお、この設定はターミナル(正確にはシェル)を
    終了すれば失われ、元の状態に戻ります。

     それでは最後にもう1つ。プロンプトが表示されているとき、[control]-[p]を押してみてください。前述の例でいえば、「export PS1= …」が表示されたはずです。これは「コマンド履歴(ヒストリ)」というbashに用意された機能で、これまで実行したコマンドラインを時間を遡る(下ることも可)ように呼び出すことができます。Finderに喩えれば、「最近使った項目」といったところでしょうか。

     次回からは、代表的なコマンドの使い方を絡めつつ、シェルの使い方を体系的に解説したいと思います。

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

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

    2008-10-07

    目次

    • りんご味Ruby         第33回  藤本 尚邦
    • 藤本裕之のプログラミング夜話   #146
    • 高橋真人の「プログラミング指南」  第144回

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

    ■ Rubyプログラミングでのsyntax sugar

    前回のMechanizeのコードの中にたくさん出てきた with が気になった方はいらっしゃるでしょうか。

     page.links.with.text("使い方")           # 「使い方」へのリンク全て
     page.forms.with.name('textFormEntry')    # textFormEntryフォーム全て
     form.fields.with.name('text')            # name属性がtextの全フィールド
     form.radiobuttons.with.name('eid').with.value('CR-EJ')[0].check
    


    実は、これらの with は省略することができます。

     page.links.text("使い方")
     page.forms.name('textFormEntry')
     form.fields.name('text')
     form.radiobuttons.name('eid').value('CR-EJ')[0].check
    


    この with は WWW::Mechanize::List クラスのインスタンスメソッドで、その定義は以下の通りです。

     def with
       self
     end
    


    何もせずに単純にレシーバオブジェクト自身を返しているだけですね。したがって、withを省略しても意味的には同じことで、もちろん結果も同じになります。

    with を使うと、使った分だけメソッド呼び出しが増えることになります。メソッドの呼び出しはそれなりに時間的コストのかかるものですから、with を使えば使うほどプログラムの実行速度を遅くすることにもなります。withは、速度を犠牲にしてでもソースコードを読みやすくするという目的のために存在しているメソッドということになるでしょう。

    このWWW::Mechanize::Listのソースは、たったの72行で、しかもその大半はコメントに埋め込まれたドキュメントでコード自体は数行程度ですので、せっかくですから目を通してみるとよいでしょう。OSX 10.5付属のRubyとRubygemsを使ってインストールしている場合には、

    /Library/Ruby/Gems/1.8/gems/mechanize-0.7.8/lib/www/mechanize/list.rb

    にあります(インストール・更新の状況により若干違うかもしれません)。このソースを見ていたら:

         alias :and :with

    のように with の別名として and が宣言されていました。ですから、例えば

     

    form.radiobuttons.with.name('eid').with.value('CR-EJ')

    のところは

     

    form.radiobuttons.with.name('eid').and.value('CR-EJ')

    と書くこともできます。

    ソースのコメントのところにも書いてありますが、このような with や and みたいなものは syntax sugar と呼ばれています。ウィキペディアによると、syntax sugar は、糖衣構文、構文糖衣、構文糖などと訳すことがあるようです。

    (補足 — 厳密に考えると、これら with や and は構文ではなく、WWW::Mechanize::Listクラスのインスタンスメソッドなので、「構文による味付け」というような意味合いを持つ syntax sugar というフレーズで呼んでいいものかどうか、やや微妙なところもあります)

    Rubyプログラミング用に公開されているライブラリでは、プログラムを(自然言語的な意味で)読みやすくすることを考えて、このようなメソッド呼び出しによる疑似的な syntax sugar が用意されているものがたくさんあります。Rubyon Rails が登場したあたりから、主に海外のライブラリ開発者によってこの傾向が加速しているような気がします。

    Rubyは遅いと言われがちですが、プログラミングには、速度を犠牲にしてでもコードの読みやすさを優先すべきときもあるのかもしれません。

    ■ [おまけ] 文字列オブジェクトに翻訳メソッドを追加する

    文字列に翻訳機能があるといいかもしれませんね。

     "おはようございます".translate(:je)
     => "Good morning"
    


    というような感じでしょうか。ということで、YahooHonyakuクラスの初歩的な応用として、Stringクラスに翻訳を実行するメソッドを追加してみましょう。

    class String
     require 'YahooHonyaku'
     @@translator = YahooHonyaku.new
    
     def translate(mode)
       @@translator.translate(mode, self)
     end
    end
    


    これだけで、Rubyの文字列クラスに、自身を翻訳した文字列を返す translateというメソッドを追加しました。このようにRubyでは、実行時に既存のクラスにメソッドを追加することができます。

    @@translatorは(文字列クラスの)クラス変数です。Rubyプログラムでは、`@@’で始まる変数名がクラス変数になります。翻訳器オブジェクトを翻訳のたびに生成するのは無駄にコストが高くつくので、文字列クラスのインスタンスすべてが、クラス変数を介して同じ翻訳器を共有するようにしました(本当は、Cocoa流に、YahooHonyakuクラスに YahooHonyaku.shared_translator みたいなクラスメソッドを用意すべきかもしれませんが省略します)。

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

     実を言えばオレは懐疑的だが(ちうか,こういうのに対して「あるある,あるよね!」みたいな甘い態度でいると早晩スピリチャル系詐欺師にケツの毛まで抜かれることになるぜ,というのがオレの基本的スタンスである),ユング派心理学に「シンクロニシティ(共時性)」という概念がある。

     日本語でいう「ムシの知らせ」というヤツでね,永年思い出しもしなかった親戚の夢を見たら次の朝そのヒトの訃報が届いたとかそういうやつ。マトモな科学者は「そんなの偶然やんけ」と言うところ,フロイドの(ピンク・フロイドぢゃないよ,ところでこのヒトの名前はSigmund Freudというスペルなのになんで多くのヒトが「フロイト」と濁らないで覚えているのだろうか。ハンフ
    リー・ボガートと逆である)影響を受けてかちとオカルトかがったところがあったユング先生は「いやそうやない。これにはワシラが知ってる因果では説明できないツナガリがあるんや,ウケケケケケ」と断じたわけである。

     もっと詳しく知りたいヒトにはWikipediaを調べるなりちょっと旧いがF・D・ピート著「シンクロニシティ」(信じてないオレでもこの本は面白かったよん)を繙いてもらうなりするとして,今回はユング先生だったら「見よ,これぞシンクロニシティ」と言うだろう出来事から……。

     前回最後でワタシは,「次回から,この薄暗いじめじめしたところ……それぢゃ漱石の猫の出生地だ,この先行き拡大することもなさそうなパソコン用アプリケーション市場で,どのようなアプリケーションであれば生き残って行けるのか,どのようなアプリケーションがそれでも売れているのかを見て行きたい」と書いた。書いたものの,忙しくてさぁ,それを調べる時間が取れないで
    いたのである。

     が,そしたらなんと9月25日。ナゴヤの出張先で打ち合わせの合間にブラウズしてたgoo のページにそのものズバリ,「自分のパソコンに追加インストールしているソフトランキング」というのが掲載されてるのを見つけちゃったわけである。これぞまさしくシンクロニシティ,怪しげなオカルト詐欺師に「ほらねフジモトさん,こういうことが起きるのはあなたについている守護霊がとっても強いからなのよ」とか言われそうである。ま,ホントにその守護霊とやらが強いなら,こんな遠回りの支援ではなく,いきなり万馬券が当たるとか数年前に書いた本が突然売れ出して増刷掛かるとかもっと直接助けて欲しいもんです,とこの場を借りて申し上げておきますが。

     とにかくこのランキングによるとあなた,道は険しいのである。1位ウィルス駆除ソフト,2位ファイル圧縮解凍ソフト,3位オフィス用ソフト(これってつまりマイクロソフト・オフィスってことだろ?),4位音楽プレイヤー(バンドル以外の音楽プレイヤーってことはWindowsにiTunesを入れてるってことか?),5位葉書・年賀状作成ソフト……と,上位はほとんど定番があっていまさらクイコムことは不可能と思われるジャンルが並んでいる。我が身をユーザに置き換えても,これまで聞いたこともないような会社から「もんのすごい効果のウィルス駆除ソフトが出ました」と言われて買うかと言われたら否定的だ(そんなんだったら「あんまりマメに更新を迫らない駆除ソフトです」の方が魅力的だったりする)。

     以下画像処理,CD・DVDライティング,インターネットブラウザ(これはつまりIEやSafariに満足しないでFirefoxとかOperaを入れてるってことなんだろうが,これらがほぼ無料であることを考えると,これ以上上のランクにいる有料のソフトがどんだけ強いかわかるよね),動画プレイヤーと続いて10位がゲームである。

     ここまで見てきて曲がりなりにも新規参入定番化……定番化は難しいとしても,それなりに成功が望めそうなのはこのゲームくらいだろ。このゲームという分野にだけはまだ,ニューフロンティアというか,「今までだれも思いつかなかった」とか「なんでこんなモノはこんなに流行ったのか解らない」とかいうシロモノが生まれる余地が残っているような気がする。
     
     ちうことで,次回は「ゲームを作って一発当てる可能性」についてしつこく不覚……不覚をとってどうする,深く考えて行ってみたい。あっと,それから本文中で言及しているランキングのURLは以下の通り。いつまで掲載されているかわかんないので必要のある人(そんなヒトいるのか?)はアーカイブを。

    http://ranking.goo.ne.jp/ranking/009/add_install/&f=news&LID=news

                           (以下次回 2008_10_03)

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

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

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

     こんにちは、高橋真人です。
     前回からの続きですが、「新たな整数型を定義する」ということは、前回の最後に示したFoo(UInt32)とFoo(OSType)が定義できるようになる、即ち、UInt32とOSTypeがコンパイラに別々の型として認識されるようにする、ということです。
     そのために必要なのが、前回出てきたIntegerTypeという名のクラスです。

    template 
    struct IntegerType {
       IntegerType()                       : mValue(0) { }
       IntegerType(TValueType inValue)     : mValue(inValue) { }
       operator TValueType() const         { return mValue; }
       operator TValueType&()              { return mValue; }
       TValueType      Get() const         { return mValue; }
    
       TValueType      mValue;
    };
    


     これが、クラス定義です。説明を簡単にするため、ここでの説明に関係しない要素は省いて、より単純化してあります。オリジナルの完全な形は前述のPPxTypes.hをご覧ください。
     このクラスの意味は後で説明しますが、とりあえずは使い方をご覧いただきます。前回のプログラムを以下のように変更します。

    #include 
    
    // ※この部分は、あとで説明。
    
    struct UInt32Struct {};
    typedef IntegerType   UInt32_t;
    
    struct OSTypeStruct {};
    typedef IntegerType   OSType_t;
    
    void Foo(UInt32_t a);
    void Foo(OSType_t a);
    
    int main()
    {
       OSType_t value = 'TEXT';
       Foo(value);
    }
    
    void Foo(UInt32_t a)
    {
       std::cout << "a is UInt32." << std::endl;
    }
    
    void Foo(OSType_t a)
    {
       std::cout << "a is OSType." << std::endl;
    }
    


     引数の型が、UInt32とOSTypeから、それぞれUInt32_tとOSType_tに変わっていますが、これは既存のシンボルとぶつかることを避けているだけの話です。
     また、main関数でのFoo()の呼び出し部分に直接値を与えずに、変数を作って、それを介して値を渡していますが、これは当然のことで、'TEXT'という“生の”値はC/C++処理系にとっては既にint(GCCの場合。CodeWarriorではlong)の型として認知されていますから、そのままではUInt32_tにもOSType_tにもなりません。
     わざわざ変数を作るのを潔しとしないのであれば、単にFoo((OSType_t)'TEXT');というようにキャストするだけでも問題ありません。
     ところで、上記のコードの※印のところですが、今回の冒頭に掲げたIntegerTypeの定義部分を記述していただくか、PPxオリジナルのIntegerTypeをそのまま使うのであれば、

    #include 
    using namespace PPx;
    


    という2行を入れていただければOKです。
     さて、今回の変更のキモは、UInt32_tとOSType_tという新たな型を導入していることです。定義内容をつぶさに見ていくと、やっていることは全く一緒です。
     たとえば、定義したい型がUInt8(unsigned char)なのであれば、

    struct UInt8Struct {};

    と、独自に型を一つ作っておいた上で、あらかじめ定義してあるIntegerTypeのテンプレート引数に、UInt8と共に与えます。具体的には、

    IntegerType

    という感じです。これにtypedefを使って新たな名前を付けてやれば完成となります。

    typedef IntegerType     UInt8_t;

     いろいろと、複雑に見える仕組みがあるように見えるかもしれませんが、このような手順を経ることによって、言語にもともと組み込まれている型と全く同じような使い方ができるのです。たとえば、

    UInt8_t a = 'A';
    
    std::cout << a << std::endl;
    
    a = a + 0x20;
    
    std::cout << a << std::endl;
    
    UInt32_t b = 10;
    UInt32_t c = a + b;
    
    std::cout << c << std::endl;

    というような書き方ができるのです。つまり、もともとの型の性質を維持したままで、なおかつ型の識別も可能になるという付加価値を付けられることになります。

     ところで、今回の解説を読んでいて「structなのにクラスと言っている」と疑問を持たれた方がおいでかもしれません。実は、C++ではstructもクラス定義のためのものになっています。詳しい話はまたいずれ。

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