- ここは Macintosh のソフトウェアの開発に関する Web サイトです。ほとんど AppleScript 、ちょっとだけ Perl。最近(2005-)、Objective-C と Cocoa にも手を出しています。
- もっぱら、自分が書いたアプリケーションの公開をして行きたいと思っています。
- 配布しているアプリケーションは、すべてフリーウェアかつソースコードを公開しています。しかし、このサイトと配布しているアプリケーションが無くなったら悲しいという方は寄付をお願いします。
- どなたか、Software ページにあるアプリケーション/スクリプトにカスタムアイコンを作ってくれませんか?当然ですが、作っていただいたアイコンの著作権は作っていただいた方に帰属します。僕はそれをお借りするだけで、いつでも僕の作品からアイコンを引っ剥がせます。
- お気軽にコメントを書き込んでいただければ幸いです。
Recent Comments
2009-12-06
TeX Tools for mi 3.3.4
テキストエディタ mi を中心とした LaTeX の統合環境を提供するアプリケーションとスクリプトのセットです。
高橋さんのおかげで多くのバグを修正することができました。
- DVI プレビューアの設定が xdvi のとき、source specials 付きでタイプセットした DVI を表示しようとするとエラーが発生する不具合を修正(高橋さん、ありがとうございました)。
- ターミナルウインドウが複数表示されることがある不具合を修正(高橋さん、ありがとうございました)。
- ParentFile の設定が正しくないファイルが前面にある状態でリファレンスパレットを表示すると、エラーが発生する不具合を修正。
- 適切な警告を表示するようにしました。
OGURA さん、寄付ありがとうございました。
FileClipper をご使用いただけているとのこと。久しぶりの寄付で(久しぶりでないことはほとんど無いのですが)嬉しい限りです。
問題/ご要望がありましたら、お気軽にお声をかけていただければ幸いです。
55 人目。
2009-12-05
ModueLoader 2.1 では新しいモジュールロードの構文を導入します。記述を劇的に簡素化することに成功しました。ModuleLoader 2.1 を紹介できることに興奮しています。他のスクリプト言語では当たり前かもしれないけど、AppleScript にとっては革命的だと思う。
マニュアルを書き上げられるのはもう少し時間がかかりそうなので(どう書くのも悩ましい)、とりあえずバイナリだけβ版として先行公開します。
使い方は次のように超簡単。まず、読み込みたいスクリプトを ~/Library/Scripts/Modules もしくは /Library/Scripts/Modules に置く。これをモジュールとする。トップレベルのスクリプトではモジュールと同じ名前の property を用意し、module コマンドをその定義としておく。こんな感じで。
そして、その後 "boot (module loader) for me" という一文を実行させるようにする。どうです。簡単でしょう。詳細は以下の通り。
- module コマンドは property の初期値として与えなければいけません。
- moduel コマンドが実行されただけでは、モジュールは読み込まれません。
- module コマンドはその property にモジュールを読み込むことを予約します。
- property の名前の同じ名前のモジュールが読み込まれます。上の例だと ModuleA.scptd や ModuleA.scpt などがロードされます。
- property 名と違う名前のモジュールを読み込みたいときは、module "ModuleName" というぐあいに、module コマンドの引数で指定します。
- boot (module loader) for me が実行された段階で、モジュールの読み込みが行われます。
- module loader コマンドは、version 2.0 の make loader コマンドと同じです。名前を変更しました。
モジュールの方で依存しているモジュールの記述は、同じように property の定義部で module コマンドを実行するようにします。
こんだけだ。すごく簡単でしょう。version 2.0 で紹介したやり方も合わせて使えるよ。
否定的な意見でもいいからフィードバックが欲しい。
2009-12-01
AppleScript のスクリプトオブジェクト入門(その4)ModuleLoader の仕組み
現在、ModuleLoader の大幅なアップデータを開発中です。新しいモジュールの読み込み構文を導入します。これまで紹介した ModuleLoader のやり方ができなくなる訳じゃないけど、もっといいやり方を思いついてしまった。
現在の ModuleLoader で不満なのはモジュール側で module loaded ハンドラを用意して、明示的にモジュールの読み込みを記述しなければならないこと。宣言するだけでモジュールを勝手に読み込んでくれるようにはできない物かとずーっと考えていて、ほとんどあきらめていた。でも、この話を書き終わってから、ほとんど理想に近いやり方を思いついちゃいました。実装もほとんど済みました。今のところ、思惑通りうまくいっているようです。
新しい ModuleLoader の公開はまだ先になるし、書いちゃったので現在の ModuleLoader の仕組みを紹介します。
まず、前回の復習です。
- 他のスクリプトにロードされて、使い回されるスクリプトファイルをモジュールと呼びましょう。
- 文字列処理用のモジュール StringHandlers を作りました。
- テキストエディット操作用モジュール TextEditHandlers から、StringHandlers をロードするようにしました。
- load script コマンドは、StringHandlers が更新されても、TextEditHandlers の中の StringHandlers を個苦心してくれません。
- トップレベルスクリプトでも ScriptHandlers をロードします。
- load script コマンドだと、TextEditHandlers の中の StringHandlers と別物になります。
- ModuleLoader を使うと、TextEditHandlers の StringHandlers を自動的に更新してくれるし、トップレベルのStringHandlers と同じ物にしてくれます。同じモジュールの複製は作られません。
さて、今回は ModuleLoader がモジュールを読み込む仕組みについて解説しましょう。
まず、前回のサンプルのモジュール読み込み部分を見てみましょう。
TextEditHandlers
Top level スクリプト
ポイントは以下の二つ
- TextEditHandlers で module loaded ハンドラを実装し、その中で、load module "StringHandlers" を実行していること。
- トップレベルスクリプトで parent に make loader コマンドで生成される loader script を設定し、loader scirpt に対して、load module コマンドを実行すること。
トップレベルスクリプトのコンパイルが行われたときに起こることをの絵を描いてみました。

処理の流れを説明してみます。
- make loader コマンドで loader script を生成します
- loader script をトップレベルスクリプトの parent に設定します。
- load module コマンドを実行して、"TextEditHandlers" をロードを開始します。
- load module コマンドはスクリプティング機能追加ではなく、 parent の loader script に送られます。
- loader script はキャッシュの中から、"TextEditHandlers" を探します。最初の load module ですから、当然見つかりません。
- loader script は ModuleLoader.oasx にモジュール "TextEditHandlers" へのパスを教えてもらいます(find module コマンドを使う)。
- パスをキー値にして、もう一度キャッシュの中を探します。やっぱり見つかりません。
- load script で、"TextEditHandlers" を読み込んで、キャッシュに登録します。
- TextEditHandlers の module loaded ハンドラを実行します。
- TextEditHandlers の module loaded ハンドラの中で、"StringHandlers" を読み込む為に 3~10 までの処理が実行され、返り値が property StringHandlers に設定されます。
- load module ハンドラからロードした TextEditHandlers が返され、property にセットされます
- トップレベルスクリプトで、load module "StringHandlers" が loader script で実行されます。
- loader script のキャッシュにヒットして、キャッシュの中の "StringHandlers" が返されます。
これで、めでたくモジュールの読み込みは完了します
ちなみに、loader script のキャッシュの中のスリプトオブジェクトと load module コマンドの返り値は別物になるんじゃないかと思われるかと思いますが、スクリプトオブジェクトは copy コマンドや重複した load script を行わない限り、複製は作られません。変数に set したりハンドラの引数に渡したりしても、参照をやり取りしていて、実体は共有されます。スクリプトオブジェクトだけでなくリストやレコードにも同じ性質が有ります。
ちなみに、このような仕組みは僕が考えた訳ではなくて、appleMods というライブラリで使われている仕組みをパクりました。appleMods でいろいろ気に入らないことがあったのでので自分で作ったのですが、不満が無い訳ではありません。モジュール側で module loaded ハンドラのように依存しているモジュールを読み込むコードを書かなければいけないのは気に入らないところです。ついこの間まで、言語のサポートがない限りはどうにもしようがない、現状ではこれがベスト、と思っていたけど、次の ModuleLoader では、module loaded ハンドラがいらなくなります。しかし、ロード時の動的な振る舞いの為に、module loaded ハンドラは残ります。
次は、新しい ModuleLoader を公開してから、新機能を紹介します。
スクリプトオブジェクトの細かい解説より ModuleLoader の解説を先にしたのは、オブジェクト指向云々よりスクリプトオブジェクトを共有する為のインフラを知る方が先だろうと思ったからです。ハンドラを共有する為だけのスクリプトオブジェクトだって十分役に立ちますから。
次の次からは、役に立つモジュールを作る為のスクリプトオブジェクトのオブジェクト指向の側面について解説したいと思っています。
2009-11-28
AppleScript のスクリプトオブジェクト入門(その3)依存性のあるスクリプトオブジェクトを読み込む場合
前回までの復習です。
- テキストエディットで選択されている箇所を取得/置き換えるスクリプトを紹介しました。
- テキストエディットに関するハンドラを独立したスクリプトとしてまとめました。
- 別ファイルとしてファイルに保存したスクリプトを load script コマンドで読み込むことができます。
- でも、load script コマンドはファイルへの参照を与えなければいけないので大変です。
- ModuleLoader を使えば、名前を指定するだけで読み込めます。
このように、他のファイルからロードされて、色んなスクリプトで共有されるスクリプトのことをモジュールと呼ぶことにしましょう。今回は、モジュールが他のモジュールに依存している場合のことを考えます。
まず、テキストの検索置換を行うハンドラもモジュールとしてトップレベルのスクリプトから外部に追い出します。こんな感じで。
このスクリプトを ~/Library/Scripts/Modules/StringEngine.scpt に保存することとします。サンプルだからハンドラが一つしか無いけど、その辺はご勘弁。AppleScript でのテキスト処理はいろいろ面倒なことが多い。テキスト処理のハンドラをまとめたスクリプトを一つつくっておくと何かと便利だと思いますよ。そんな時、拙作 XText をご参考頂ければと思います。
さて、この StringHandlers をテキストエディットに関するスクリプトオブジェクト TextEditHandlers とトップレベルのスクリプトの両方でロードする場合を考えます。
まず、TextEditHandlers はこんな感じになります。replace_in_selection ハンドラを付け加えました。
トップレベルスクリプトは、こんな感じで、StringHandlers と TextEditHandlers の両方をロードすることにします。
さて、load script に完全なファイル参照を与えなければいけないという問題は置いておいて、このように別のモジュールをロードしているモジュールが読み込む場合、次のようは問題があります。
- StringHandlers を更新した場合、TextEditHandlers でロードしている StringHandlers はトップレベルスクリプトをコンパイルしても更新されない。
- TextEditHandlers をコンパイルし直す必要があります。
- 今回みたいに一つだけならいいのですが、複数のスクリプトをロードしたり、ロードしているスクリプトの階層が深くなったりすると手に負えなくなります(経験談)。
- トップレベルの StringHandlers と TextEditHandlers の中の StringHandlers は別物になります。つまり、二つの StringHandlers が存在します。
- 今回の場合、ファイルサイズが大きくなるだけで実害は無いと思います。
- でも、StringHandlers に property を持たせた場合、その値は一致しなくなります。同じ物に統一した方が都合がいいケースがあると思います。
- そのうち紹介したいと思っているスクリプトオブジェクトによる疑似クラス(と僕が名付けたテクニック)の場合は、同じ実体を共有してくれない困ります。
分かりやすく絵に描いてみました。

この問題に対する対処法の一つは、いくつか考えられます。それについて細かく説明しませんが、いずれにしても、ロードするモジュールの数が多くなってくると手に負えなくなるのでやめた方がいいです(経験談)。
ModuleLoader を使えば、一気に問題を解決できます。TextEditHandlers の StringHandlers 読み込み部分を次のように手直しします。
module loaded というハンドラを追加しました。このハンドラは ModuleLoader によって TextEditHandlers が読み込まれた時に実行されます。そして、このハンドラの中で StringHandlers を読み込むようにします。by パラメータにモジュールの読み込みおよび読み込んだモジュールをキャッシュする専用のスクリプトオブジェクト(loader script と呼びましょう)が渡されてきます。このスクリプトオブジェクトに対して、load module コマンドを実行します。スクリプティング機能追加の load module コマンドを直接実行すると、ご利益が半減します。
トップレベルスクリプトはこのようになります。
ここで、parent という property が登場しました。これは、特殊な property で、スクリプトはparent に設定されたスクリプトオブジェクトを「継承」します。継承というのはオブジェクト指向用語で、要するは parent に設定されたスクリプトオブジェクトのハンドラや property がを自分のものになるということです。parent につけくわえる形でトップレベルスクリプトを定義するイメージです。
make loader コマンドは前出の loader script を生成するコマンドです。loader script では、独自の load module コマンドを定義しており、それを経由して読み込んだスクリプトをキャッシュします。load module コマンドを持った loader script を parent に設定しているので、それ以降の load module コマンドはスクリプティング機能追加のコマンドではなく、loader script の load module コマンドを実行しています。
こうすると、めでたく次のようになります。

次回は module loaded, make handler コマンドおよび loader script の役割/仕組みなど、ModuelLoader の細かい話をします。あとちょっとだけ ModuleLoader の宣伝をします。
しかし、全然オブジェクト指向の話が出てきませんね〜。次の次ぐらいから、そいう話をしたいです。
