Google先生も知らないJXAのプライベートメソッド


ドキュメント・用語説明に書いてない、ググってもどこにもない
ネット上でここにしか存在しないプライベートメソッドの使用方法を含むメモ
(少なくともググる限り)

役に立つのか？
知りません。

プロパティ名やコマンド名を取得するメソッドがあるので、用語説明を見る機会を減らせるかもしれません。

## 注意

この記事は自分で試しつつ手探りで調べた内容ばかりです。
まだ分かっていない部分も多いですが、公開したら誰かが調べてくれるかなと期待して書きました。

**誤情報や嘘も多く含まれてると思う**ので、ガンガン指摘してほしいです。

# ObjectSpecifierクラスについて

`Application("Finder")`とかで得られる。
アプリケーションやその部品等の参照を表す。

[JavaScript for Automation Release Notes#ObjectSpecifier](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-SW33)

`ObjectSpecifier`は特殊なオブジェクトです
普通のJavaScriptみたいにプロパティ名を得ようと思っても無駄です

```js:普通にはプロパティ取得できない
var finder = Application("Finder");

Object.keys(finder); //=> []
Object.getOwnPropertyNames(finder) //=> ["__private__"]

finder.hasOwnProperty("a"); //=> true
finder.hasOwnProperty("ab"); //=> true
finder.hasOwnProperty("abc"); //=> true //なわけないじゃん
```

## instance variables (Application)

|property|type|description|
|---|---|---|
|includeStandardAdditions|boolean|[see document](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-SW13)|
|strictCommandScope|boolean|[see document](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-SW34)|
|strictParameterType|boolean|[see document](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-SW34)|
|strictPropertyScope|boolean|[see document](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-SW34)|
|properties|ObjectSpecifier|get all properties|
|after|ObjectSpecifier|(unknown)|
|before|ObjectSpecifier|(unknown)|

`properties`はめちゃくちゃ便利なのでどんどん使うべき
だいたいどのObjectSpecifierでも使えます
(コマンドと複数形のプロパティ(ArraySpecifier)は取得できません)

```js:usage(properties)
var itunes = Application("iTunes");

itunes.properties()
/*=> {
  "class": "application",
  "name": "iTunes",
  "playerState": "stopped",
  "version": "12.1",
  "frontmost": false,
  "soundVolume": 100,
  "mute": false,
  "visualsEnabled": false,
  "fullScreen": false,
  "visualSize": "large",
  "eqEnabled": false,
  "fixedIndexing": false,
  "playerPosition": null,
  "converting": false,
  "currentStreamTitle": null,
  "currentStreamURL": null,
  "airplayEnabled": false,
  "currentAirPlayDevices": [
    null
  ],
  "iadIdentifier": null
}*/
```

after / beforeは複数形のプロパティで前後のオブジェクトを表すのかもしれない

## instance methods (Application)

大体`Application`からしか使えません
(他のサブクラスで使えるメソッドもいくつかあります)

### ~~OfClass

|method|arg|return|description|
|---|---|---|---|
|commandsOfClass|-|texts|get command names|
|elementsOfClass|text|texts|get element names|
|propertiesOfClass|text|texts|get property names|
|parentOfClass|text|text|get parent object name|

用語説明を見なくてもだいたい分かるようになって便利！
(用語説明は見辛いし、Script Editorいちいち起動するのめんどくさい)

- `commandsOfClass`: コマンド名
- `elementsOfClass`:  複数形のプロパティ(ArraySpecifier)
- `propertiesOfClass`: それ以外の普通のプロパティ名


引数にはObjectSpecifierのクラス名を[キャメルケース](http://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%83%A1%E3%83%AB%E3%82%B1%E3%83%BC%E3%82%B9)で指定します。
`commandsOfClass `だけ引数を渡さなくても動く。
引数を渡しても無意味っぽい。

```js:usage
var itunes = Application("iTunes")

itunes.commandsOfClass()
//=> ["add", "backTrack", "close", "convert", "count", "delete", "download", "duplicate", "eject", "exists", "fastForward", "make", "move", "nextTrack", "open", "openLocation", "pause", "play", "playpause", "previousTrack", "print", "quit", "refresh", "resume", "reveal", "rewind", "run", "search", "set", "stop", "subscribe", "update", "updateallpodcasts", "updatepodcast"]

itunes.elementsOfClass("application")
//=> ["airplayDevices", "browserWindows", "encoders", "eqPresets", "eqWindows", "playlistWindows", "sources", "visuals", "windows"]
itunes.elementsOfClass("track")
//=> ["artworks"]

itunes.propertiesOfClass("application")
//=> ["airplayEnabled", "converting", "currentAirPlayDevices", "currentEQPreset", "currentEncoder", "currentPlaylist", "currentStreamTitle", "currentStreamURL", "currentTrack", "currentVisual", "eqEnabled", "fixedIndexing", "frontmost", "fullScreen", "iadIdentifier", "mute", "name", "playerPosition", "playerState", "selection", "soundVolume", "version", "visualSize", "visualsEnabled"]
itunes.propertiesOfClass("track")
//=> ["album", "albumArtist", "albumRating", "albumRatingKind", "artist", "bitRate", "bookmark", "bookmarkable", "bpm", "category", "class", "comment", "compilation", "composer", "container", "databaseID", "dateAdded", "description", "discCount", "discNumber", "duration", "enabled", "episodeID", "episodeNumber", "eq", "finish", "gapless", "genre", "grouping", "id", "index", "itunesu", "kind", "longDescription", "lyrics", "modificationDate", "name", "persistentID", "playedCount", "playedDate", "podcast", "properties", "rating", "ratingKind", "releaseDate", "sampleRate", "seasonNumber", "show", "shufflable", "size", "skippedCount", "skippedDate", "sortAlbum", "sortAlbumArtist", "sortArtist", "sortComposer", "sortName", "sortShow", "start", "time", "trackCount", "trackNumber", "unplayed", "videoKind", "volumeAdjustment", "year"]

itunes.parentOfClass("application")
//=> undefined
itunes.parentOfClass("track")
//=> "item"
```

`iTunes#Track`は`Item`のサブクラスです。

### displayNameFor~~

|method|arg|return|description|
|---|---|---|---|
|displayNameForCommand|text|text|get command name|
|displayNameForElementOfClass|text|text|get element name|
|displayNameForPropertyInClass|text|text|get property name|
|displayNameForPropertyOfClass|text|text|get property name|

なお使い道は不明

```js:usage
var app = Application("Finder");

app.displayNameForCommand("cleanUp");
//=> "clean up"

app.displayNameForElementOfClass("documentFiles")
//=> "documentFiles"
```

`displayNameForProperty~~`の **In**Class と **Of**Class の違いはよく分かりません

```js:usage
app.displayNameForPropertyInClass("name")
//=> "name"
app.displayNameForPropertyOfClass("name")
//=> "name"

app.displayNameForPropertyInClass("productVersion")
//=> undefined
app.displayNameForPropertyOfClass("productVersion")
//=> "product version"
```



### etc

|method|arg|return|description|
|---|---|---|---|
|enumeratorsForEnumeration|text|texts|get enumerator name|
|propertyTypeForNameInClass|text|text|get property type|
|parameterNamesForCommand|text|texts|get param names|
|parameterTypeForNameInCommand|(unknown)|(unknown)|(unknown)<br>get param types?|
|addElement|(unknown)|(unknown)|(unknown)|
|callAsFunction|(unknown)|(unknown)|(unknown)|

Enumerationは列挙型のことです。
状態を文字列で表すやつ。用語説明の「enum」。

```js:usage
var term = Application("Terminal");

var enumerators = term.enumeratorsForEnumeration("save options")
//=> ["yes", "no", "ask"]

var propType = term.propertyTypeForNameInClass("name")
//=> "text"

var params = term.parameterNamesForCommand("make")
//=> ["at", "new", "withData", "withProperties"]
```
parameterはメソッドの第二引数で追加で渡すオブジェクト。
連想配列みたいなやつ。

`parameterTypeForNameInCommand`は何を渡してもundefinedが返ってきたので詳細不明
`addElement`はウィンドウとかで前後になんか挿入するあれかもしれない...

### activate / launch / quit

名前そのまま。

```js
// アプリケーションを取得
var qt = Application("QuickTime Player");
// この時点で起動してなかったら起動される

qt.activate(); //フォーカスを移す
qt.quit();  //終了
qt.launch(); //起動
```

### set / setProperty / get / getProperty

プロパティのセッタとゲッタ。
TextEditを開いて文字列の書き込み・取得をしてみます。

```js
str = "hello"

// launch new TextEdit window
editor = Application("TextEdit");
doc = editor.Document().make();

// set text
doc.text = str;
//=> "hello"
doc.text.set(str); //same above
//=> true
doc.setProperty("text", str); //same above
//=> true

// get text
doc.text();
//=> "hello"
doc.text.get(); //same above
//=> "hello"
doc.getProperty("text").get(); //same above
//=> "hello"
```

普通は使う必要ないですし、覚える必要は全くありません。
プロパティ名を文字列で指定したいときでも、以下のようにも書けますので。

```js
// set text
doc["text"] = "hi"
// "hello"

// get text
doc["text"]()
// "hi"
```

## class methods

|method|arg|return|description|
|---|---|---|---|
|hasInstance|any|boolean|is ObjectSpecifier's Instance?|
|classOf|any|text|get ObjectSpecifier class name|
|callAsFunction|-|ObjectSpecifier|(unknown)|

`classOf`はドキュメントにありますが`hasInstance`はありません
存在を知らなくても全く困りませんが

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

ObjectSpecifier.hasInstance(finder);
//=> true
ObjectSpecifier.hasInstance("foo");
//=> false

ObjectSpecifier.classOf(finder);
//=> "application";
ObjectSpecifier.classOf("foo");
//=> undefined
```

# Automationクラスについて

|method|arg|return|description|
|---|---|---|---|
|getDisplayString|any|text|get display string|
|log|any|undefined|same to console.log?|
|initializeGlobalObject|(unknown)|(unknown)|(unknown)|

`getDisplayString`はドキュメントの最後のほうに書いてあるやつ。便利。
[JavaScript for Automation Release Notes](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/#//apple_ref/doc/uid/TP40014508-CH109-DontLinkElementID_3)

```js
var app = Application("Finder");
var win = app.windows[0];

Automation.getDisplayString(win)
//=> "Application(\"Finder\").windows.at(0)"

>> Automation.log(win)
//[object ObjectSpecifier]
//=> undefined
```

ちなみにJXAのconsoleはlogメソッドしかないです
warnとかassertとかありません

# ArraySpecifierクラスについて
`Finder.windows`などの複数形のプロパティのこと。ObjectSpecifierの配列。
`Finder.windows()`のようにArraySpecifierに()をつけるとただのArrayになる。
`Finder.windows.name()`のようにすると子要素のプロパティを一気に得られる。

こっちにもちょっと書いた→[JXAで子要素のプロパティを一気に得る](http://qiita.com/zakuroishikuro/items/c09afdc62f5ff8283704)

# 調査方法について

OS X 10.11から、[Safariでデバッグできるように](https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-11.html#//apple_ref/doc/uid/TP40014508-CH110-SW1)なりました。
コンソールで見たこと無い関数名とかも列挙されるので、勘で引数に文字列などを渡して調べましょう。
アホなんでもっといい方法知りません。教えて下さい。

何か気づいたことがあればコメントや編集リクエストください。