JXAの「Error: A privilege violation occurred」の回避


JXAでアプリケーションを指定して`Standard Additions`のメソッドを使おうとすると頻繁に以下のエラーが出る。

```js
var finder = Application("Finder");

finder.includeStandardAdditions = true;
finder.doShellScript("date");
//!! Error on line 1: Error: A privilege violation occurred.
```

この場合`currentApplication`を使えばたぶん大体いける。

```js
var app = Application.currentApplication();

app.includeStandardAdditions = true;
app.doShellScript("date");
//=> "2015年 2月25日 水曜日 17時16分28秒 JST"
```

`currentApplication`はスクリプトを実行しているアプリケーションを取得するメソッド。

Script Editorから実行していればScript Editor。
Terminalから実行していればTerminal...じゃなくて`osascript`コマンド。
Terminalが直接実行してるわけじゃないので。

他にも、例えば
[CotEditor](http://coteditor.com/)はユーザーが作ったスクリプトを利用できる。
そこで実行した場合の`currentApplication`はCot Editor。

## osascriptを参照した際のwarning
>warning: failed to get scripting definition from /usr/bin/osascript; it may not be scriptable.

と毎回出るけど「osascriptには`.sdef`ファイルが無いから、スクリプトで操作できないと思うよ」ってだけ。
osascript自体じゃなく`Standard Additions`のメソッドを使うだけだから問題無し。のはず。

osascriptの参照から名前を得ようとして`.name()`とかやったらエラー出るので注意。
ていうかこれ不安になるだけだから表示しないでほしい。いややっぱ必要か。

# スクリプトメニューから実行した場合のcurrentApplication

Script Editorみたいな分かり易いものならいいけど、スクリプトメニューから実行した場合は何が呼ばれるのか。
`currentApplication`は多用するから、得体の知れないまま使うとモヤモヤする。

AppleScriptと違って、明示的に`Standard Additions`を有効にしないと駄目だし気になったので調べた。

## スクリプトメニューについて

スクリプトエディタの設定からスクリプトメニューを有効にするとメニューにアイコンが追加される。
スクリプトを`~/Library/Scripts/`に入れるとそのメニューに表示される。
コンパイル済みスクリプト(`.scpt`)にすればいつでもどこでもワンクリックで実行できる。

![menu.jpg](https://qiita-image-store.s3.amazonaws.com/0/18902/02ab60b7-240e-1143-f83a-198ceea388a6.jpeg "menu.jpg")

ちなみにScript Editorを経由しないでも設定変更可能。

```js
var app = Application("AppleScript Utility");

// 確認
app.scriptMenuEnabled();
//=> true / false

// 有効にする
app.scriptMenuEnabled = true;
```

## スクリプトメニューの「currentApplication」

これを調べるスクリプトをJXAで書くと難しい。
ていうか結局、分からなかった。

AppleScriptだと簡単だった。

```applescript:where_is_current_app.scpt
display dialog (path to current application)'s POSIX path
```

Script Editorで実行した場合。
![editor.jpg](https://qiita-image-store.s3.amazonaws.com/0/18902/922238e1-ffce-a2f7-3456-1c683eccb2ad.jpeg "editor.jpg")

`/Applications/Utilities/Script Editor.app/`

スクリプトメニューから実行した場合。
![menu_.jpg](https://qiita-image-store.s3.amazonaws.com/0/18902/ee5409cd-9a12-36d2-c036-e2132fe5d5cf.jpeg "menu_.jpg")

`/usr/bin/osascript`

普通に`osascript`だった。

## 蛇足
予想では専用のアプリケーションがあるのか、最前面のアプリが使われるのか、Finderなのかとか考えてた。

昔はこれだったらしい。今は存在しない。(参考:[MacWiki](http://macwiki.sourceforge.jp/wiki/index.php/AppleScript#.E6.A8.99.E6.BA.96.E5.90.8D.E3.81.AE.E3.83.95.E3.82.A9.E3.83.AB.E3.83.80.E9.A1.9E))
`/System/Library/CoreServices/AppleScript Runner.app`

# スクリプトメニューでエラーが発生した場合
何も起こらない。何も通知されない。
途中で単に実行が停止されるので注意。
ちゃんと `try...catch` すればだいじょぶ。

コンソール.appにエラーのヒントが残ってるかもしれない。

![スクリーンショット 2015-02-25 18.55.29.png](https://qiita-image-store.s3.amazonaws.com/0/18902/890ea958-6a18-283e-68de-8e34ece91249.png "スクリーンショット 2015-02-25 18.55.29.png")

## 蛇足2

上に書いたけど`currentApplication`の名前はAppleScriptで一行で得ることが出来た。
JXAで何とかしようとしてた(けど出来なかった)コードをここで供養する。

```js
var app = Application.currentApplication();
app.includeStandardAdditions = true;

var str = Automation.getDisplayString(app);

// これじゃたぶん意味ない。(osascriptで実行してるじゃん)
//msg = app.doShellScript('osascript -l JavaScript -e "Application.currentApplication()" 2>&1 1> /dev/null | cat');
//str += "\n" + msg;

try { // try..catchしとかないとエラー出たら無言でアプレット消える
  str += "\n\nproperties: " + Automation.getDisplayString(Object.getOwnPropertyNames(app));

  str += "\nname: " + app.name(); //osascriptから.name()とか呼んだらエラー出る
  str += "\n\n" + JSON.stringify(app.properties(), null, "  ");
	
} catch(e){
  str += "\n\n" + e.toString();
}

app.displayDialog(str);
```

Script Editorで実行した場合のダイアログ。

```text
Application.currentApplication()

properties: ["__private__"]
name: Script Editor

{
  "frontmost": true,
  "class": "application",
  "name": "Script Editor",
  "version": "2.7"
}
```

スクリプトメニューから実行した場合のダイアログ。

```text
Application.currentApplication()

properties: ["__private__"]

Error: Message not understood.
```

JXAのStandard Addisionsにも`pathTo`はある。
けど`current application`を文字列で渡したりcurrentApplicationをそのまま渡してもパスを得られなかった。
JXAでパスを得る方法があったなら知ってる方は教えて下さい。

# 参考

- [AppleScriptのファイル参照にまつわるメモ - ザリガニが見ていた...。](http://d.hatena.ne.jp/zariganitosh/20100924/apple_script_alias_posix_file)
- [標準エラー出力をパイプに流し込む方法 | CentOS・Red Hat Linux実践テクニック - サンプルコードによるPerl入門 ～ 安定と信頼のPerlを学ぼう ～](http://d.hatena.ne.jp/perlcodesample/20101214/1298764341)