load script を置き換える

お手軽にコメントをしてもらえるように Google ドキュメントのフォーム機能を使ってみたのですが、よくよく考えたら、一方通行なのでした。コメントを頂くことはできるのですが、ブログのように一覧として表示はされません。コメントでの会話というのができない。メールアドレスを書いていただければ、返信も(メールで)できるのですが...(もちろん、アドレスはなくても構いません)。そんなコメント機能なのですが、ご意見等々を頂ければ幸いです。

あ。きちんとご意見は届いています。ありがとうございます。励みになっています。

さて...。

load script やスクリプトオブジェクトを使って既存のスクリプトを再利用するようになると、不満なところがいくつか出てきます。いくつかの不満点は工夫すればなんとか解決できるものですが...もっと気楽に利用したいと思うのは人間の性。

そんな状況を改善しようと、Script factory さんが ModuleLoader.osax という OSAX を作成されました。

OSAX は、AppleScript の機能を拡張するためのもので、display dialog や choose file、load script 命令も OSAX が提供している命令です。OSAX を利用すると AppleScript で正規表現も扱えるようになりますし、ミリ秒単位で時間の計測も行えるようになります。AppleScript に足りない機能を追加するものとして Mac OS X 以前は重宝していたものです。

OSAX はローカルの /Library/ScriptingAdditions、もしくは ~/Library/ScriptingAdditions に置いておきます。前者に置いておくと全てのユーザーが利用できますし、後者ならインストールしたユーザーだけが利用できます。

...ところで、OSAX ってどうなのでしょうか?

Mac OS X 以降、OSAX はあまり普及していません。もしかすると OSAX で AppleScript の機能を拡張できるということを知らない人も多いかもしれません。

Mac OS X の AppleScript 固有の問題、多くの OSAX が Mac OS X に対応しなかったこと等の事情が重なり Mac OS X 以降、個人的にも OSAX は利用しなくなりました。OSAX を利用するなら、代替方法を模索します。さいわいなことに Mac OS X 以降なら代替方法が複数あるのでそれで困らなかったのです。

この姿勢は今後も変わらないと思います。正直なところ「このスクリプトには OSAX が必要です。こちらからダウンロードしてください」とユーザー(もちろん、ユーザーには未来の自分も含まれます)の手を煩わせるのがいやなのですが...。

OSAX を配布するスクリプトに同梱することも可能ですし、スクリプトバンドルの中に入れておくという手もあるのですが、そのための条件が面倒なものが多いのも事実。そのあたりがどうも...ねえ...。

と、いろんな理由で OSAX を使っている人って案外少ないのではないでしょうか?と、思うのです。特に開発者は OSAX に依存することを嫌います。だから、OSAX の話題はここでは取り上げていませんでしたし、そういう要望も皆無でした。

OSAX を紹介するのは複雑な胸中なのですが...ModuleLoader.osax はここ(ModuleLoader)からダウンロードできます。まずは、ModuleLoader.osax をインストールしておいてください。インストールしていないと以降に掲載されているスクリプトは利用できません。

試してみた環境は、以下の通り。

  • Mac OS X 10.5.8
  • Intel Core 2 Duo
  • AppleScript 2.0.1
  • Script Editor 2.2.1

ModuleLoader.osax はディスクイメージで配布されています。このディスクイメージを開くと、中に「ModuleLoader をインストール.app」という AppleScript アプリケーションがあるので、起動します。

起動するとローカル以下にインストールするか、ホーム以下にインストールするかを尋ねられるので、自分がインストールしたい場所を指定します。インストールが完了後、もし、Script Editor が起動しているなら、いったん終了させて、再起動します。これで OSAX が提供する命令を利用できるようになります(ここではユーザーのホーム以下にインストールしました)。

ModuleLoader.osax は再利用可能なスクリプトを手軽に扱えるようにすることを目的にしています。そのため、再利用可能なスクリプト(作者は「モジュール」と表現しているので、以降、それに倣います)を一定の場所に保管しておく必要があります。

モジュールの保管場所(検索パス)は /Library/Scripts/Modules か、~/Library/Scripts/Modules 以下になります。ModuleLoader.osax はこれらの場所からモジュールの検索を開始します。検索パスの追加は可能になっています。

ModuleLoader.osax の使い方は同梱のマニュアル(ReadMe.html というエイリアスファイル)を見てもらうのが一番手っ取り早いです。まず、目を通しておくのがいいでしょう。

ModuleLoader.osax の特徴として以下の点があります。

  1. スクリプトファイルをファイル名で指定して読み込める
  2. scpt、scptd、app の拡張子を持ったスクリプトファイル、もしくはこれらのエイリアスから読み込める
  3. スクリプトを常に最新の状態で読み込む
  4. 複数のスクリプトファイル間の依存を解決してから読み込む
  5. スクリプトオブジェクトの共有が行える

load script 命令を置き換える load module 命令を使ってみます。最初に次のスクリプトを ~/Library/Scripts/Modules に Value.scpt という名前で保存しておいて下さい。このスクリプトをモジュールとして読み込みます。

Script Editor で開く

property _value : missing value

on set_value(val)
    if _value of me is val then return
    set _value of me to val
end set_value

on get_value()
    return _value of me
end get_value

では、読み込んでみます。

Script Editor で開く

on run
    set value_object to load module "Value"
    tell value_object
        set_value("Hello, world")
        get_value()
        --> "Hello, world"
    end tell
end run

動きますね(当たり前です)。実際に使ってみると分かるのですが、スクリプトファイルをファイル名だけで読み込めるのはとても気持ちのいいものです。

ModuleLoader.osax は拡張子 app, scpt, scptd のスクリプトファイル(もしくはこれらのエイリアスファイル)をモジュールとして認識します。上記のスクリプトを見てもらうと分かるように拡張子の指定は必ずしも必要ではありません。

また、検索パスにあるサブフォルダ以下も再帰的に検索します。検索パスのサブフォルダ以下にあるモジュールを指定する場合は検索パスからの相対パスを命令の引数に与えます。

Script Editor で開く

on run
    -- ~/Library/Scripts/Modules/Utilities にある File Utility.scpt を読み込む
    set value_object to load module "Utilities:File Utility.scpt"
end run

拡張子や相対パスを指定しても同一名のスクリプトファイルがあった場合はどうなるのでしょうか?結論からいうと、先に見つかった方を読み込みます。ファイル名の競合を避けたり、特定の検索パスから特定のモジュールを指定したい場合は load module 命令のオプションで対処します。

Script Editor で開く

on run
    -- ~/Library/Scripts/Modules/Value.scpt を読み込む
    -- additional paths オプションで検索パスを指定
    -- 検索パスを other paths オプションで additional paths で指定したパスだけに制限
    set modules_folder to (path to scripts folder from user domain as text) & "Modules:"
    set value_object to load module "Value.scpt" additional paths ¬
        {file modules_folder} without other paths
end run

逆に additional paths で指定したパス(と ModuleLoader.osax のデフォルトの検索パス)を全て含めたいなら other paths オプションに true を指定します。

上記のスクリプトはこれで動くのですが...しかし、以下のスクリプトは動きません。

Script Editor で開く

on run
    -- /Library/Scripts 以下から AppleScript Help.scpt を検索
    -- additional paths オプションで検索パスを指定
    -- 検索パスを other paths オプションで additional paths で指定したパスだけに制限
    set modules_folder to path to scripts folder from local domain
    find module "AppleScript Help.scpt" additional paths ¬
        {modules_folder} without other paths
end run

指定しているのは Mac OS X 10.5 インストール時に最初から入っているスクリプトファイルです。自分で作成したスクリプトなら階層の深いところにあっても探し出してくれるのですが...。古い環境で作られたスクリプトファイルだからでしょうか。

上記のスクリプトが動かなかったのは ModuleLoader.osax のバージョンが古かったためでした。バージョン 2.2.1 ならこのエラーは発生しません。確認不足でした。申し訳ございませんでした。

モジュールの検索パスをオプションで毎回指定してもいいのですが、すでにスクリプトライブラリを作成していたりするなら set additional module paths to 命令で既存のスクリプトライブラリの場所を ModuleLoader.osax に記憶させておくといいと思います。

個人的には既に ~/Library/Application Support に ASKit という名前でスクリプトライブラリを作っているのでそれを追加してみます。

Script Editor で開く

on run
    -- ModuleLoader.osax の検索パスに既存のライブラリを加える
    set support_folder to path to application support from user domain as text
    set modules_folder to support_folder & "ASKit:"
    set additional module paths to file modules_folder

    -- ModuleLoader.osax の検索パス一覧を取得
    module paths
end run

set additional module paths to 命令は実行すると ModuleLoader.osax が記憶してます(Preferences に Scriptfactory.ModuleLoader.plist という名前のファイルを作って、そこにパスを保存しています)。

だから set additional module paths to 命令は一回だけ実行すればよく、ライブラリを場所を変更したときなどに利用します。この命令で追加したパスは上書きはできますが、削除はできません。削除するには Scriptfactory.ModuleLoader.plist を削除するしかないようです。

ModuleLoader.osax は ~/Library/Scripts/Modules(もしくは、/Library/Scripts/Modules)を検索パスとして利用していますが、Modules フォルダが存在しない場合は検索パス自体が設定されません。

Script Editor で開く

on run
    -- Modules フォルダを作成していない状態で検索パス一覧を取得
    module paths
    --> {}
end run

だから、~/Library/Scripts 以下に Modules フォルダを作成せず、set additional module paths 命令で既存のスクリプトライブラリを追加しておけば、そこだけを検索するようになります(もしかすると、推奨されないのかもしれませんが...)。

ところで...ModuleLoader.osax の特徴としてモジュールの自動的なアップデートとあるのですが...。次のようなスクリプトで Value.scpt をいくら変更しても自動的にアップデートしないのですが、load module 命令ではアップデートしないのでしょうか?

Script Editor で開く

property value_object : load module "Value"

on run
    tell value_object to get_value()
end run

再コンパイルするとアップデートされるのですが...、これは当たり前ですね。

とりあえず、ModuleLoader.osax の一部の機能だけを使ってみました。まだ、他にも機能があるのですが、長くなってしまうので次回に...と。

0 件のコメント :

コメントを投稿