Archive for the 'How To' Category

2017/09/15 64ビット化して処理能力が低下したCocoa Finderの代替ツールはSystem Events?

macOS 10.6〜10.7で64ビット化にともないCocoaで書き直されたFinderのパフォーマンス低下が(当時から)指摘されていましたが、日常的な用途ではあまり気にしていませんでした。

Cocoa Finderのはじめのうちは、OS起動直後に表示されるFinderのウィンドウ内のアイコン描画が間に合わないのか仮アイコンで表示され、徐々に正しいアイコンで表示されるような光景もよく目にしていました(さすがに最近はそういう光景は目にしなくなりましたけれども)。

そんな中、macOS 10.13beta+MacBook Air 2011で大量のファイルを処理したときに、Finder経由で処理するとトンでもなくスピードが(SSDなのに)遅いことに気づきました。SSDに合わせて再設計したAPFS+SSDの組み合わせなのに、とてつもなく遅い。速い速いというふれ込みだったのに、Finder経由だと驚くほど遅い。

最初は、AppleScriptとFinderの間のやりとりが遅いものだと思っていましたが、実はFinderの処理そのものが遅いことが判明。数百個のファイルを選択してFinder上で(メニューから「複製」コマンドを実行して)ファイルコピーさせたりすると、めまいがするほど低速です。

そして、Appleの「AppleScript Language Guide」で「list folder」コマンド(廃止予定)を調べていたら、同コマンドの代替としてSystem Events経由でファイル情報にアクセスするやり方が掲載されているのを見つけ、Finder経由のファイル処理がすでに推奨されていない状態なのではないか、と疑いを持つようになりました。

そこで、同じファイル処理を(macOS 10.13beta上で)System EventsとFinderに対して実行してみたところ、4,224ファイル存在しているフォルダから、全ファイル名を取得する処理は、

 System Events:1秒
 Finder:6秒

同フォルダに対して、ファイル名に「99」という文字を含むファイル名だけを抽出させてみた(フィルタ参照)ところ、

 System Events:14秒
 Finder:計測不能(timeout時間を3,600秒に設定して実行してみたものの、Finderがハングアップして処理が数十分返ってこない)

といったところ。速度、信頼性ともにFinderよりもSystem Eventsの方が高いという状況です。処理対象ファイル数が100以下ぐらいであればFinder経由でも気にならないのですが、それを超えると露骨にパフォーマンス低下が顕在化します。

ただし、最近はAppleScriptでもCocoaの機能(NSFileManager)を利用してファイルの処理を行なっていたので、System Events経由のファイル処理も「驚くほど速いわけでもない」という印象。指定フォルダ内のファイルの抽出もSpotlight経由で行なっていたので、それほど不自由は感じていませんでした。

サンプルを掲載する際にも、なるべくSystem EventsかNSFileManagerを経由してファイル処理を行うようにする考えです。

Finderのコントロールは、選択中のフォルダやファイルを取得するとか、処理結果のフォルダやファイルを新規Finderウィンドウで表示させるといった用途に限定することが望ましいのでしょう(あと、指定フォルダ内のファイル一覧をas alias listで取得するのも(フィルタ参照を併用しなければ)高速です)。

2017/05/25 AppleScript+Web APIで行う自然言語処理

ライター/編集者仲間である友人と雑談していたところ、自然言語処理がいろいろ使えそうなシーンが見えてきました。彼によると、Twitter上で過去記事の紹介ツイートを行いたいが、何も関係ないところに唐突に記事紹介のツイートを投げても不自然だし、興味を持たれにくいので、時事ネタと関連する記事を紹介する仕組みを作れないだろうか、という話になりました。

そこで、比較的鮮度および注目度が高いと思われる「ニュース記事」から固有名詞だけを抽出し、その固有名詞にどのぐらい世間的な注目が集まっているかを判定できると、そのキーワードに関連する過去記事をツイートしやすくなるかもしれないと考えました。

apitoreのREST APIには、ニュースフィードを提供するもの、形態素解析を行うもの、Twitter検索を行うものなどがあり、これらを組み合わせるとできそうな感じがしてきました。

→ Playing with rest api

実際に試してみたところ、ニュースフィードからニュース記事本文を抽出するのは(RSS Feedに本文の冒頭部分が含まれていないケースもあるので、結局記事のサイトを見に行って本文を抽出する必要がある)けっこう大変で、タイトル(題名)のみ処理することに。

次に、タイトルの文章を形態素解析して、「固有名詞」だけを抽出してみました。これは別に難しくもなんともありません。さらに、入り組んだrecordから目的のデータを取り出すのは、AppleScriptでもCocoaの機能を使えば造作もありません。NSDictionaryからvalueForKeyPath:でオブジェクトパスを記述して抽出すれば、データ取り出しのために長々とループ処理で記述する必要はありません。

次の段階は、その時点における「注目度」の計算です。仮にTwitter全体を1つの「世間」とみなし、Twitter上で拡散されていたりお気に入りに入れられる回数の高い単語は、比較的「注目度」が高いものだろうという仮説を立てました。

→ キーワードの言語ごとのTwitter発言内容集計

そこで、ニュースのタイトルから抽出した固有名詞をTwitterで検索し、それぞれの固有名詞がTweet上でどの程度リツイートされたか、お気に入りに入れられたかを計算してみました。これについては、コストの問題からREST APIではなくローカルのmacOS上で動作するAppleScript用Twitterクライアント「TwitterScripter」を呼び出すことにしました。apitore上の各種REST APIは無料で試用できますが、呼び出し回数が増えれば料金がかかるため、その部分を節約することが目的です。TwitterScripterを使用することによるデメリットは、それ自体が並列処理に対応していないこと。Mac上で(AppleScriptによる)並列処理を行ってTwitter検索を行う場合には、直接Twitterの(割と整理されていない)APIを直接呼び出すか、apitore上のREST APIを呼び出すしかなさそうです。

AS.Parallel

指定のキーワード(固有名詞)を含むツイートをTwitter上で検索し、それぞれがどの程度リツイートされたか、お気に入りに入れられたかを実際に数値化。その数値をもとにキーワードのランキングを計算することができました。

一応、「活性度の高い」≒「注目度の高い」キーワードを計算できたわけです。ここまでのプログラムはすでに実稼働状態にあり、「こんな(へんな)単語が注目されてるのかー!」という未知の単語のピックアップに成功しています。

ただし、これでは目的を50%しか達成できていません。

この「注目度の高いキーワード」と「過去記事」の間をブリッジする必要があるからです。もう少しわかりやすくいえば、「カール」という本日注目度急上昇中のキーワードがありますが、この「カール」という固有名詞で過去記事を検索したところで、まったく異なる単語の一部がたまたま偶然ひっかかってヒットする程度で、過去記事が超絶的にヒットしにくいことが予想されます(グスタフ・カールとかザンスカール帝国とかカール自走臼砲とかパリダカールラリーとか)。

この「カール」を「スナック菓子」という上位概念に変換し、さらにスナック菓子に所属する単語を取得して、それらの単語で検索できるとよいでしょう(菓子、和菓子など)。このあたりは個人的に「スター・クエリー」と昔から呼んでいるもので、与えられたキーワードから類似・関連するキーワードを複数生成して検索することで、ヒットする確率を高める仕組みです。GoogleやYouTubeでもおそらく類似の機構が検索エンジンに実装されており、入力した単語以外でもヒットするようになっているようです(とくにYouTube)。

apitoreでも日本語Word.netのデータを利用して類義語や上位概念の言葉を計算できるようになっていますが、日本語の基本的な語句に特化しており、実際に試してみたところ「カール」「ガンダム」といった商品名などから類義語や上位概念を求める用途に向いていないことがわかりました。これらの計算を行うためには、Wikipediaのデータからカテゴリを取得できれば、やりやすくなるものと思われます。

2017/05/19 FileMaker Pro 16でセキュリティ機能が追加される

先日、FileMaker Proの最新バージョンv16が発表され、FileMakerからお試し版がダウンロードできるようになりました。

手元のデータベースを試してみたところ、メニューから(AppleScriptを呼び出している)FileMaker Scriptを実行したら実行権限エラーに。

display dialog程度のコマンドが書いてあるAppleScriptでは実行権限エラーにはなりません。正確に書けば、

「FileMaker Proを操作するAppleScriptがFileMakerスクリプトステップ中に書かれていた場合には実行権限エラーになる」

という状態です。ただし、これは仕様にもとづく動作であり、バグではありません。

FileMaker Pro 16では、アクセス権セットの「拡張アクセス権」で、詳細なシステムへのアクセス機能の許可/禁止が行えるようになったようです。

FileMaker Script中でAppleScriptを実行していると、「Apple EventおよびActive-XによるFileMaker操作の実行を許可」の項目にひっかかってAppleScriptの実行が遮断されるとのこと。

FileMaker Script中におけるAppleScriptの実行を許可するためには、この、

  「Apple EventおよびActive-XによるFileMaker操作の実行を許可」

にチェックを入れておく必要があります。

私が気づいていなかっただけで、より以前のFileMaker Proで追加されていた機能である可能性もあります。

2017/03/19 QuickTime Player+macOS Sierraでのファイル保存

macOS 10.12上でQuickTime PlayerをAppleScriptからコントロールして、デスクトップ上にムービーを保存しようとすると、エラーが出て実行できません。

mov1.png

mov2.png

AppleScriptを実行すると、まずQuickTime Player側で「権限がない」云々というエラーが表示され、QuickTime Player側のエラーダイアログをクリックすると、スクリプトエディタ側でエラーが表示されます。

Appleにバグレポートしておきましたが、Apple的にはバグではなく「仕様」だと見なされている可能性があります。

デスクトップにムービーを保存することはできませんでしたが、ためしてみたら「ムービー」フォルダに保存することはできました

こういう「仕様」を説明もなしに決定されるのは迷惑ですし、きちんとリリースノートなどで説明してほしいものです。

AppleScript名:QTPlayerのバグ再現
set a to (choose file name) as string

tell application “QuickTime Player”
  tell document 1
    save in file a
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:QTPlayerのバグ再現2
set a to (choose file name)

tell application “QuickTime Player”
  tell document 1
    save in a
  end tell
end tell

★Click Here to Open This Script 

2017/02/09 choose file,choose folderの始点ディレクトリ指定にPOSIX pathが使える

以前からチラホラ話は聞いていたのですが、choose fileやchoose folderの始点ディレクトリ(コマンド実行時にファイル/フォルダ選択ダイアログに表示されるフォルダ)を指定する「default location」オプション。

この「default location」オプションにPOSIX pathが指定できますよ、というお話です。

pathobjects.png

AppleScript/Cocoa関連の主要なパスオブジェクトはだいたいこの図のようになっていて、最近はCocoaに渡すためにPOSIX pathの登場頻度が高くなっています。ただ、よく出てくるとはいっても、「何かに変換するための一時的な形式」であることが多いようです(個人的に)。

このchoose file/choose folderの始点ディレクトリにPOSIX pathが使えるようになっており、おそらくXcode上で作成するCocoa-AppleScript Applet内で事実上aliasが使えないので、その対策として付加された機能と推測しています(根拠はありません)。ちなみに、同環境でaliasが使いたければ、.scpt形式あるいは.scptd形式のScriptとしてXcodeのプロジェクトに入れて、ASOC側からload scriptしつつ呼び出すような処理になると思います(ライブラリにするやりかたもあるかも)。

AppleScript名:choose fileの始点にPOSIX path
choose file default location “/Users/me/Documents”

★Click Here to Open This Script 

AppleScript名:choose folderの始点にPOSIX path
choose folder default location “/Users/me/Desktop”

★Click Here to Open This Script 

始点ディレクトリはフルパスで指定する必要があり、「~」を併用した記法は使えませんでした。

ちなみに、存在しないPOSIX pathを指定すると、

choose_posix_alias.png

のようなエラーが表示されます。コマンド内部ではaliasに変換しているようです。

この仕様がいつごろから実装されているのかはわかりませんが、おそらくmacOS 10.6以降ではないかと推測されます(AppleScript StudioからAppleScriptObjCへの移行期あたり)。

2016/10/13 意図しないiTunesの起動を抑止する

AppleScriptによる自動処理を専門で行わせるMacでは、なるべく最低限の設定しか行わず、プログラムの動作を阻害するような要素は排除しておきたいところですが、

  何も操作していないのに、突然iTunesが起動する

という挙動に悩まされてきました。この解決策を見つけたので、ご紹介しておきます。

(1)キーボードのF1〜F12キーを標準ファンクションキーとして使用

「システム環境設定」>「キーボード」>「キーボード」にある「F1、F2などのすべてのキーを標準のファンクションキーとして使用」にチェックを入れます。

system1.png

自分の経験上、これがオフになっていて(デフォルト状態)F1〜F12が音量調整や再生ボタンなどの役目を担う「メディアキー」として利用可能な状態だと定期的にiTunesが起動してしまうようです。

sys2.jpg

自動処理用のMac(とくにMac mini)では、iTunesに音楽ライブラリなど入れていないですし、アンインストールしておいてもいいぐらいなんですが、とりあえずこれで処理中に不意にiTunesが起動するといった事故は防げています。

(2)すべてのキーボードを外しておく

(1)の理屈でいえば、USB、Bluetooth接続などすべてのキーボードを接続解除しておけば、意図しないiTunesの起動は回避できるはずです(未確認)。

2016/05/17 Duet DisplayのMac側プロセスの死活判定を定期的に実行

iOS用のDuet Displayは、iOSデバイスをUSB経由でMac/Windows機とつなぎ、iOSデバイスを外部ディスプレイ化するアプリです。

AppStoreで1,900円(記事作成時現在の価格)でiOSアプリを購入+インストール、Mac側にはDuet Displayのホームページから無料ダウンロード可能なツールをインストールします。

このDuet Displayを使って、ちょっと使い道のなかったiPadなどをMacのサブディスプレイにすることができます。以前は、Air Displayを使って無線LAN経由でiPadを外部ディスプレイ化してもみましたが、パフォーマンスがいまいちなうえにソフトウェアの安定性が残念なレベルだったので使用をやめてしまいました。

img_3577_resized.png

Duet Displayはさすがにゲームを快適に行えるほどではありませんが、ちょっとした用途であれば違和感なく使えるパフォーマンス。

3・4日ほどは便利に使っていたものの、途中でMac側のduetプロセスがコケたりして、急にディスプレイ表示が消える現象に直面。サブディスプレイとして使っている場合には冗談ぐらいで済みますが、メインディスプレイとして使っていた場合には悲惨です(メインディスプレイとして使ってほしくない雰囲気)。

いろいろ実験(長期間起動させっぱなしとか、スリープからの回復を連続して行うとか)を行ったところ、duetプロセスが落ちることは避けられないという結論に至りました(落ちるものは落ちる)。

そこで、Mac側のduetプロセスの死活判定を定期的に行い、死んでいた場合には起動し直すAppleScriptアプレットを作って運用してみました。このプロセス死活判定は、以前に作成したものを使いまわしたため、プログラムはほぼ2〜3行追加しただけです。

このような仕組みを用意したおかげで、iPadをMac miniのメインディスプレイに設定して、duetプロセスがコケて表示が消えても自動で表示が回復するようになりました。idleハンドラ内のタイマー割り込み時間(秒)を現在は10秒にしていますが、もうちょっと短い間隔でチェックしてもよいと思います。

本AppleScriptはスクリプトエディタで「アプリケーション」として保存し、オプションで「ハンドラの実行後に終了しない」を指定することで立ち上げっぱなしの運用が可能です。また、Dock上から「ログイン時に開く」にチェックすることで、電源オン時→ログイン時に自動起動されるため、おすすめです。

AppleScript名:restartDuet
on run
  idle
end run

on idle
  set aRes to detectAppAliveByID(“com.kairos.duet”) of me
  
if aRes is not equal to true then
    tell application id “com.kairos.duet” to launch
  end if
  
return 10
end idle

–指定プロセスの死活判定(Bundle IDで判定)
on detectAppAliveByID(aProcBundleID)
  set aProcBundleID to aProcBundleID as string
  
  
–Phase 1 psコマンド経由で状態を確認してみる
  
set aRes to false
  
try
    tell application “System Events”
      set aList to bundle identifier of every process
      
if aProcBundleID is in aList then
        
        
set tmpList to name of every process whose bundle identifier = aProcBundleID
        
set aProcName to contents of first item of tmpList
        
        
set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ’ ’ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
return “killed”
        end if
      else
        –指定したBundle IDのプロセスが存在しない場合falseでリターン
        
return false
      end if
    end tell
  on error
    –異常発生時にはさっさとリターン
    
return false
  end try
  
  
–Phase 2 指定アプリに直接コンタクトして反応を見る
  
try
    with timeout of 3 seconds
      tell application id aProcBundleID
        set aTmpvar to name –これができない(Scriptableな)アプリはほとんどないだろう(多分)
      end tell
    end timeout
  on error
    –名称を取得できなかった場合にはコケていると見なしてプロセスを殺す
    
do shell script “/bin/kill -9 “ & processID
    
return “killed”
  end try
  
  
return aRes
end detectAppAliveByID

★Click Here to Open This Script 

2016/05/17 OS X 10.11.5+Safari 9.1.1、新たなAS制限機能が増える

本日、OS X 10.11.5が正式リリースされました。OS X 10.11, El Capitanの最終リリースということになるのでしょう。OS X 10.12がWWDCで発表になり(多分)、2016年10月ごろにリリースになるというのが通例のスケジュールです。

OS X 10.11.5およびSafari 9.1.1では、AppleScript的には大きな変化を経験することになります。

4ac2e0d2-5af0-4a5c-88e6-7811e4b4fe71.jpg

いままで野放図にSafariをdo javascript命令でこづきまわしていましたが、この機能がデフォルトではオフになります。

fb082ac7-6e16-482b-a542-1147a9d548b1.jpg

Safariの「環境設定」>「詳細」で「メニューバーに”開発”メニューを表示」コマンドを実行して「開発」メニューを表示させ、「開発」メニューの「Apple EventsからのJavaScriptを許可」を実行してはじめてdo javascript命令が有効になります。

# 1回実行すれば、その状態が維持されます

このため、Safariでdo javascript命令を使って処理を行う場合には、無難なコマンドを最初に実行してエラーが発生しないかどうかを確認し、エラー発生時には「Apple EventsからのJavaScriptを許可」を実行してもらうようにダイアログを出して実行終了するよう、処理を追加すべきでしょう。

2016/03/13 AppleScriptからWebアプリを操作する場合に用いるWebブラウザは?

Mac系の会合で質問がありました。

「AppleScriptから、Webブラウザに表示されているボタンなどを操作してさまざまなWebアプリを操作できることはわかったが、その際にWebブラウザは何を使うべきなのか?」

script_webbrowser.png

とりあえずの最低条件は、「AppleScript用語辞書を備えているWebブラウザ」ということです。WindowやDocumentをopenしたりcloseでき、その中のTabなどにアクセスでき、URLを設定したり取得したり、ページ内のソースを取得できたりというひととおりの操作ができることが条件です。

sleipnir.png
Sleipnir 4.5.1にはAppleScript用語辞書が入っているものの、実装を間違っているらしくScript Editorでオープンすると真っ白な用語辞書が表示される(直接飲み会でF社の方に報告済み、、、なんですけど、、、、)

FireFoxにもAppleScript用語辞書が入ってはいるものの、肝心の「do javascript」命令がないので、「これで何をしろと??」という状態です。Vivaldiも同様に「do javascript」命令がないので、こうした用途には使えません。

次に、「GUI Scriptingで操作するのに問題がないこと」という条件がつきます。 Webコンテンツを操作するには、JavaScript経由でアクセスしたり、GUI Scriptingでアクセスしたりします。これで脱落するものはありません。だいたいは大丈夫です。

そして、「Webブラウザ独自のアプリストアなどの仕組みによって、予期しないダイアログ表示などが行われないこと」「アップデート通知でいきなり終了したりしないこと」というあたりで、Google Chromeが怪しくなってきます。

結局、こうした用途にOS X標準装備のSafari以外のWebブラウザを使うこと自体がリスキーなので、Safariを使ってくださいという話になります。User AgentでSafari以外のものを使うことがリスキー(銀行のサイトへのアクセスなどで不安が、、、)なので、かさねがさねSafari以外のものを使うことが考えられません。

最近では、Mac miniなどをAppleScript実行専用のロボットとして設定すると、まっさらな状態のOS X環境では、知らないうちに勝手にiTunesを起動されて困ります。iTunes Helperなどのアプリケーションのプロセスはみられませんが、勘弁してほしいところです。

2016/02/03 OS X 10.12での変更予定

OS X 10.12ではいくつか重要な変更が予告されています。AppleScript関連で影響を受けそうなものをいくつかピックアップしてみましょう。

 ・Java SE 6のサポート廃止

Adobe CS6のインストールができなくなる(らしい)。

 ・Cocoa Garbage Collectionの廃止

について、つまりそれ以前にビルドされたAppleScript Studioアプリケーション(要GC)が動作しなくなる可能性がきわめて高いということになります。また、古いOSでアプリケーション書き出しを行ったAppleScriptアプレットについても、ソースが存在している場合には再書き出しの必要が出てくることでしょう。

一方、AppleScriptObjCアプリケーションでも、OS X 10.6で開発されたものはARC対応への設定を行い、再コンパイルを行う必要があることでしょう。

Intel x86-32bitバイナリのサポートが終了されるかどうか、というあたりも大きなテーマですが、明確な予告もなく32bitサポートを打ち切るのは危険なのでOS X 10.12では行わないと思われます(根拠なし)。

32bits.png

事実、OS X 10.11上でアクティビティモニタにより確認を行うと32bitで稼働しているプロセスがまだいくつかみられます。

2016/02/02 ASOCでScriptの終了時にCocoaオブジェクトをPurge

ASOCでCocoaのオブジェクトを呼び出すと、Script自体の保存が(再編集を行わないかぎり)できない状態に陥りますが、Script側でCocoaオブジェクトを明示的にPurgeする(ただ変数にヌルを代入するだけ)ことで、問題なく保存できるようになります。

プログラムというほどではなく、かんたんなライフハック的なものでしょうか。ちなみに、ASObjC Explorer 4ではこんなことは必要ありません。好きなときにSaveできます。

別のファイルのAppleScriptをload script命令で変数に読み込んで使うことがありますが、その場合にも終了時に変数に読み込んだscript objectをpurgeするというノウハウがあり、巨大なAppleScriptのプログラムを作成するときに必須のノウハウです。

2016-02-02-21_15_03.gif
▲Script Editor

2016-02-02-21_20_55.gif
▲ASObjC Explorer 4

QuickTime Playerで画面のムービーキャプチャを行い、「GIF Brewery」でQuickTimeムービーからアニメーションGIFに変換してみました。・・・1.7MB程度とけっこう巨大になってしまったので、ちょっとどうだか、、、

冒頭のいつもおなじみのヘッダー部についてはコピペでよそから持ってくるか、ASObjC Explorer 4のデフォルトのテンプレートをそのまま使うのが常なので、ムービー収録のためにわざわざ手打ちしていますが、打ち間違いが予想外に多く、、、、

AppleScript名:ASOCでScriptの終了時にCocoaオブジェクトをPurge
– Created 2016-02-02 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set a to current application’s NSArray’s arrayWithObjects:{1, 2, 3}
set a to “” –Purge Cocoa Object

★Click Here to Open This Script 

2015/08/27 100%クラッシュするNSCalendarの操作

AppleScriptObjCでNSCalendarをテストしだしたところ、実行するScript Editorが100%クラッシュする記述に遭遇。OS X 10.10.5でも、OS X 10.11 Betaでもクラッシュします(バグレポートずみ)。

# OS X 10.10.x/10.11.xでこれを実行してクラッシュしない環境があったら、逆におしえていただきたいです(2台でともに100%クラッシュ)

MacScriptersのBBSでもクラッシュの話が(ずいぶん前から)出ており、有名な話のようです。

*** CAUTION: THIS SCRIPT CAUSE CRASH ***

AppleScript名:ASOCでNSCalendarのじっけん(100%クラッシュ)
– Created 2015-08-27 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aCal to current application’s NSCalendar’s alloc()’s initWithCalendarIdentifier:(current application’s NSGregorianCalendar)

★Click Here to Open This Script 

Shane Stanleyから「こう書くとクラッシュを避けられるよ」というのを教えてもらいました。本当に重要ですよね、落とし穴がどこにあいているかの情報は、、、

AppleScript名:クラッシュしないNSCalendarのじっけん
– Created 2015-08-28 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aCal to current application’s NSCalendar’s calendarWithIdentifier:(current application’s NSGregorianCalendar)
–>  (_NSCopyOnWriteCalendarWrapper) <_nscopyonwritecalendarwrapper : 0x610000239e20>

★Click Here to Open This Script 

2015/08/13 Automatorを使ってAppleScriptベースの「サービス」を記述

Automatorについては、最初のバージョンの段階で「検索キーワードに柔軟性がなさすぎ」(日本語のように同義語が多い言語では使いにくい)といったフィードバックをしたものの、とくに改善されずに今日にいたり・・・これを使うよりもScript Editorを起動したほうが手っ取り早いので、1年に一度起動するかしないか・・・といった利用頻度。

同じく、NeXTstepの時代から「これもうちょっとなんとかならないのかな?」と思い続けてきた「サービス」についても、ながらく「有用な用途」が見つけられず(中途半端にアプリを連携させるより、AppleScriptを書いてワークフローすべてを自動化するほうが便利なので)、サービスについてもほとんど使ったことがありませんでした。

オンラインの各種サービスとつないだり、LAN上の他のマシン(上で公開しているサービス)を認識して動的にメニュー表示させたら便利そうだなーと思っていたものの、基本的にはNeXT時代とさほど変わらぬ位置づけで今日にいたります。

たまたまAppleScriptでサービスを書くという話を見かけて、自分用にメモとして残しておきます。

auto1.png
Automatorを起動して、メニューから「ファイル」>「新規」を実行して「サービス」を選択。

auto2.png
とりあえず、Safari上で選択したテキストを受け付けるように設定

auto0.png
アクション「AppleScriptを実行」を選択して、いつもの調子でScriptを記述。useコマンドも使えるし、ASOCも書ける。script文で論理分割したAppleScriptも書けるし、呼び出すことも可能。これを「ASTEST」の名前で保存

auto3.png
Safari上でテキストを選択して・・・

auto4.png
Safariの「サービス」メニューからサービス「ASTEST」を実行

auto5.png
入力データ「input」とパラメータ「parameters」の内容をテキスト化してダイアログ表示してみたところ

inputの内容はリストに入れられたテキストだということが思い出せたので、そのように書けば大丈夫だとわかりました。ただ、たぶんサービスをAutomator上で書くことはほとんどないはず・・・

auto7.png

Safari上に表示された「戦場の絆」のリプレイIDを選択しておくと、リプレイムービーのURLに変換したり、リプレイムービーをダウンロードしたり、リプレイの再生を開始するAppleScriptを作成したので、こういうものを「サービス」に組み込んでおくと何か便利だろうかと思ったのですが、結局Script Menuから実行することになるでしょう、、、

なにげに、実行するScriptのソースコードがまるごと取得できることがわかったので、いろいろ高度な(込み入った)ことができそうな気がいたします。

2015/08/04 ASOCで画像+文字作成テスト_v2

Cocoaの機能を用いて指定サイズの単色塗り画像を作成し、指定の文字列を描画してPNG形式の画像ファイルに書き出すAppleScriptの別バージョンです。

test3.png
▲こんな画像(test.png)がデスクトップに書き出されます

多くの場合、バージョンアップすると機能を増やしたり強化したりしていますが、このv2は初版と機能面で差はありません。出力される画像の色やサイズを変更していることには、とくに意味はありません。

本件についてShane Stanleyと週をまたいでメールのやりとりをしていて、ようやく「なるほど」という落着点を見出せたので掲載にいたっています。

今をさかのぼること10年以上昔、Classic Mac OSの時代に、AppleScriptのサブルーチン(ハンドラ)呼び出しなどで参照渡し(call by reference)によるデータのやりとりを行っていました。当時はまだCPUも遅く、AppleScriptの処理系もいまほど高速ではなかったので、高速化手法のひとつとして参照渡しは割と使われていたテクニックでした。

AppleScript名:参照渡しのテスト
set aList to {1, 2, 3}
modList(aList)
log aList
–> {1, 2, 3, 4}

–Call By Reference
on modList(someList)
  set end of someList to 4
end modList

★Click Here to Open This Script 

ただ、プログラムがわかりにくくなる上にバグが入り込む隙間が大きいので、自分は当時から各種サブルーチンを「値渡し」(call by value)で記述するようにスタイルを固定して今日にいたっています。おかげで、巨大なプログラムを作っても割とトラブル知らずでやってこれたように思います(偏見)。

AppleScript名:値渡しのテスト
set aList to {1, 2, 3}
set aList to modList(aList)
log aList
–> {1, 2, 3, 4}

–Call By Value
on modList(someList)
  set newList to {}
  
copy someList to newList –deep copy
  
set end of newList to 4
  
return newList
end modList

★Click Here to Open This Script 

今回、Shaneが「こういう書き方はどう?」と提案してきた書き方は、この「参照渡し」によるものでしたが、てっきり

 「Cocoaのオブジェクト生成はAppleScriptの範疇とは別で管理されている(ものもある)のか?」

と勘違いしてしまったものでした(MacScripterでたまに見かける記述で、首をひねっていた)。ここ、自分は間違って理解していたので、あえて自分の勘違いも含めて書いておきます。

Shaneによる変更点は、_蔀呂良分の塗りのグラフィックを生成 のあとの、 ▲哀薀侫ックに文字を塗りで描画する の部分で,離哀薀侫ック(aImage1)をハンドラに渡したあと、実行結果を変数aImage1に受け取っている部分です(参照渡し)。

Shaneがここで、判読しにくくなる危険をおかしてでも参照渡しでデータをやりとりした理由は、

「本来は同じ値の変数で処理の段階が異なるものが複数存在していた場合、間違って最新のもの以外を利用してしまう危険が発生する。なるべく同じデータであれば1つの変数に格納しておくべき」

というものでした。メモリー使用量の削減には効果は大してなく、処理速度の問題でもない、と。

内容と使うべき理由について、よく理解できたので掲載しておきます(でも、自分は使用済みゴミ変数を撒き散らしつつ値渡しで書くでしょう、、、)。

海外のMLやBBS(とくに、MacScripter.net)でこのような書き方が見られるケースがありますので、参考にしてください。

AppleScript名:ASOCで画像+文字作成テスト_v2
– Created 2015-07-31 by Takaaki Naganoya
– Modified 2015-08-01 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aWidth to 400.0 –幅
set aHeight to 200.0 –高さ
set outPath to “~/Desktop/test.png” –書き出し先のファイルパス
set fillColor to current application’s NSColor’s blackColor –塗り色
set drawColor to current application’s NSColor’s whiteColor –文字色
set aText to “ぴよまるソフトウェア”
set {xPos, yPos} to {1, 5}

–新規画像を作成して背景を塗る
set aImage1 to makeImageWithFilledColor(aWidth, aHeight, outPath, fillColor) of me

–画像に文字を塗る(参照渡し(call by reference)で、結果はaImage1に入る)
drawStringsOnImage(aImage1, aText, “HiraKakuStd-W8″, 36.0, drawColor, xPos, yPos) of me

–ファイル保存
set aRes to saveImageRepAtPathAsPNG(aImage1, outPath) of me

–画像のうえに指定の文字を描画して画像を返す
on drawStringsOnImage(anImage, aText, aFontName, aPoint, drawColor)
  
  
set aString to current application’s NSString’s stringWithString:aText
  
set aDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSFont’s fontWithName:aFontName |size|:aPoint, drawColor} forKeys:{current application’s NSFontAttributeName, current application’s NSForegroundColorAttributeName}
  
set imageSize to anImage’s |size|()
  
set textSize to aString’s sizeWithAttributes:aDict
  
set xPos to ((width of imageSize) - (width of textSize)) / 2
  
set yPos to ((height of imageSize) - (height of textSize)) / 2
  
–文字描画開始
  
anImage’s lockFocus()
  
aString’s drawAtPoint:(current application’s NSMakePoint(xPos, yPos)) withAttributes:aDict
  
anImage’s unlockFocus()
  
end drawStringsOnImage

–指定サイズの画像を作成し、背景を指定色で塗る
on makeImageWithFilledColor(aWidth, aHeight, outPath, fillColor)
  
  
–Imageの作成  
  
set anImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
  
–描画開始
  
anImage’s lockFocus()
  
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to current application’s NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
  
anImage’s unlockFocus()
  
–描画ここまで
  
  
return anImage –画像を返す
  
end makeImageWithFilledColor

–画像を指定パスにPNG形式で保存
on saveImageRepAtPathAsPNG(anImage, outPath)
  
  
–画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
  
end saveImageRepAtPathAsPNG

★Click Here to Open This Script 

2015/06/04 在来型のAppleScriptからAppleScriptObjCへの移行でハマるポイント(バンドル内のScriptの読み込み)

従来のAppleScriptを、OS X 10.10, Yosemiteで導入された(普通にScript Editor上で記述できる)AppleScriptObjC(Cocoa-Bridged AppleScript)に書き換えを行なった際にハマったポイントをひとつ紹介します。

bundle_script.png

このような(↑)単なるバンドル形式のAppleScriptがあって、バンドル内の「Scripts」フォルダ内に「A1.scpt」という別Scriptが存在している状態を想定しています。

このように、機能別にScriptを分割して「A1.scpt」単体で実行テストが行えるような形式にしておくことは、よくあることです。メイン側はただパラメータを各Scriptに渡して呼び出すようにしておく、というのもよくあることです。

こうすることで、どこかで問題が発生したときに問題の切り分けと対策が行いやすくなるので、よくこのような構造にしています。ただ、OS X 10.10のScript Editorの出来が悪くて、上図(↑)のような状態で、ウィンドウ右側に表示されているサブScript(A1.scpt)を編集するとScript Editorが無反応に(ーー;;

# そういう場合には、Finder上でScriptバンドルの内部をこじあけて、Finder上に表示させたサブScriptを個別にScript Editorで編集することに。以前のバージョンではできていたことが10.10でできなくなるのは勘弁してほしいです

AppleScript名:load_script_test_1
set mePath to (path to me) as string
set extScript to (mePath & “Contents:Resources:Scripts:A1.scpt”) as string

set extO to load script file extScript
–> «script» –OK!

★Click Here to Open This Script 

(↑)最初の段階です。きちんと、バンドル内の「A1.scpt」ファイルをload scriptで読み込めています。

AppleScript名:load_script_test_2
use AppleScript version “2.4″
use scripting additions

set mePath to (path to me) as string
set extScript to (mePath & “Contents:Resources:Scripts:A1.scpt”) as string

set extO to load script file extScript
–> «script» –OK

★Click Here to Open This Script 

(↑)冒頭の部分にAppleScriptのversion宣言と、scripting additions(OSAX)の利用を宣言しています。ここまででは、とくに問題は発生しません。

AppleScript名:load_script_test_3
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set mePath to (path to me) as string
set extScript to (mePath & “Contents:Resources:Scripts:A1.scpt”) as string

set extO to load script file extScript
–> error “current application のタイプを file に変換できません。” number -1700 from current application to file

★Click Here to Open This Script 

この段階(↑)で問題が出ます。use framework “Foundation”の1行を加えた瞬間、そのScriptはCocoaの機能を呼び出すAppleScriptObjCとして解釈されるため(?)、load script文に影響が出ました。

AppleScript名:load_script_test_4
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set mePath to (path to me) as string
set extScript to (mePath & “Contents:Resources:Scripts:A1.scpt”) as string

tell current application
  set extO to load script file extScript
end tell
–> «script» –OK!

★Click Here to Open This Script 

(↑)問題の解決を行ったものです。load script文をcurrent applicationへのtellブロック内で実行しています。

ちなみに、AppleScriptObjCの代名詞ともいえる「Objective-Cっぽいハンドラ」は、現行バージョンのAppleScript v2.4では普通にサポートしています(Xcode上でないと書けない、とかいうことはない)。

AppleScript名:objCっぽいハンドラ
my setA:“test”

on setA:aParam
  display dialog aParam as string
end setA:

★Click Here to Open This Script 

2015/02/04 AppleScript用語辞書(sdef)にサンプルを掲載

いくつかのアプリケーションで、AppleScript用語辞書に書き方(サンプルScript)を掲載しています。この書き方について説明しておきます。

アプリケーションのsdefファイル中に、


<documentation>
    <html>
        < ![CDATA[

        --HTMLコードを直接書ける

        ]]>
    </html>
</documentation>

と、documentationタグを書いておき、その中にHTMLコンテンツを書けば、Script Editor上で表示されます。

asd1.png

asd2.png

asd3.png

現行のNumbers 3.5.2では、

numbers.png

のような資料がAppleScript用語辞書に記述されています。

このため、本Blogに掲載しているようなサンプルScript(Script Editorに内容を転送できるScriptリンクつき)をそのまま突っ込めます。

ただ、こういうのはAppleScript用語辞書が小さいツールに向いた方法であり、普通に展開すると数万行に及ぶような巨大なAppleScript用語辞書(InDesignとか)では、やらないでしょう。

巨大なAppleScript用語辞書はsdefファイルをテキストエディタでオープンすると、なぜか改行コードが削除してあり・・・おそらく、改行コードを削除することで(parseの)処理速度の向上を図るような(Classic Mac OS/PowerPC時代の、過去の)ノウハウだと思うのですが、現在ではどうなんでしょう。

AppleScript用語辞書にサンプルが掲載されていると便利だと思うのですが・・・

asdic.png

OSA言語を切り替えたときに、サンプルの内容(documentationタグの内容)も切り替えられるようになっているとよいのですが・・・現状ではそのような機構がないので、Script Editor上でOSA言語を切り替えると違和感がものすごくあります。

asdic2.png

2015/02/01 badcharanさんがXcode 6.1.1のASOC用ファイルテンプレートを公開

Xcodeの新しいバージョンが公開されるごとに、ASOCのプロジェクトテンプレート「Cocoa-AppleScript」がどこに配置されているかを確認してしまうところ。Cocoa-AppleScriptが「Application」ではなく「Other」に分類されているのはいやな感じです(カスタマイズしたいな〜)。

sc1.png

さらに、XcodeプロジェクトにFileを追加しようとしても、ファイルテンプレートとして「AppleScirpt Class」が存在しておらず、「Other」の「Empty」を選択させられるのが微妙に「大きなScriptアプリケーションを作らせない」ようにクパティーノから嫌がらせを受けているような気がしていました(QuartzComposerみたいに、A社のエンジニアから露骨に「もうバグも直さないし機能追加もしません」宣言をされるよりはマシですけれども)。

sc2.png

そう思っていたのが自分だけではなかったのか、badcharanさんがXcodeプロジェクトでAppleScript(ASOC)ファイルの追加を楽にできるよう、ファイルテンプレートを公開されました

ダウンロードしてきて、内容を確認して・・・内容が理解できたのでさっそく自分でも追加してみました。

sc4.png

sc6.png

sc5.png

自分的にマイブームがきている「ASOCアプリのScriptable化」でよく作る、NSScriptCommandをparent classに設定してある.applescriptファイル。ついでに、最初から「on performDefaultImplementation()」ハンドラを宣言しておきます。my directParameter()にアクセスするコードも書いておきましょう。

sc3.png

Xcode上のASOCについては、いまひとつ生産性の向上が図りづらかったことがありますが、このあたりから生産性をガンガン向上させていきたいところです。

ASOCでCustom Viewを手軽に作れるようになるとよいのですが、、、

2015/02/01 ScriptableなASOCアプリからrecord型の値を返す

Xcode上でGUIベースのASOCアプリを開発できるわけですが、これをAppleScriptからコントロール可能な「Scriptableな」アプリケーションにすることは可能です。具体的な作業については、Shane Stanleyの電子ブック「AppleScriptObjC Explored fifth edition」に詳しく書かれています。

同書ではAppleScript側に返す「返り値」について、stringとfile型を扱っていました。

ASOCからrecord型のデータを返す

ASOCアプリからrecord型でAppleScriptに値を返すのは「大変」と聞いていたのですが、追加調査を行ったところ3つ方法があることがわかりました。

タイプ1:resultのtypeをsdef上で自前で定義

1つは、sdefファイル中でコマンドの返り値を「record」ではなく「別のもの」として宣言すること。「別のもの」を「record type」として宣言。それだけ。AppleScriptへの返り値としてrecordっぽく値が返りますが、ラベルについているのは一般的なrecordのラベルではなく「アプリケーション予約語」。該当するアプリケーション(ASOCアプリ)へのtellブロック外でrecord内の要素にアクセスするとエラーになります。
scriptable1.png

タイプ2:Objective-Cの併用による強制型変換。sdef上でresult typeをrecordと記述

もう1つは、Ron ReuterがDirect Mailで教えてくれたもので、Objective-CでNSDictionaryを拡張しておいて、sdefファイルにはコマンドの返り値として「record」を記述するというもの。普通にASOCアプリ側からrecordを返せました。返り値(record)内の要素にASOCアプリへのtellブロック外でアクセスしてもエラーになりませんでした。

タイプ3:ASOCらしくASOCで強制型変換。sdef上でresult typeをanyと記述

最後のものも、Ron ReuterがAppleScriptObjC Dev ML上で公開したもので、ASOC側から値を返すさいにCocoaの機能を呼び出して加工するもの。普通にrecordがAppleScript側に返ってくるので、ASOCアプリへのtellブロック外で返り値の要素にアクセスしてもエラーになりません。sdef上ではresultのtypeを「any」と書いておくのがポイントです。
scriptable2.png

ただ、返り値に「any」って書いてあったら、AppleScriptを書く側からするとかなり困惑します。ここが、このタイプ3を選ぶかどうかのポイントになるでしょう。

scriptable100.png

これらのやりかたで、

–> {aLabel:”test1″}
–> {aLabel:{”test1″, “test2″, “test3″}}

といった値を返せるようになりました。ここ2・3日で「できない」ことが「手軽にできる」ようになったわけで、実にけっこうなことです。

これら3つの方法について、すべてサンプルProjectを作ってひととおり試してみました。

難易度でいえば、タイプ1が一番簡単です。返り値の取り扱いの簡単さ(普通のレコードとして扱える)でいえばタイプ2とタイプ3が簡単。タイプ1かタイプ3を選択して使ってみるといいかも、というところかと。タイプ3も、badcharanさんのXcode Projectテンプレートの中に変換用ハンドラごとテンプレート化しておけば実装コストもほぼゼロに

まだ返せないデータ形式

ひととおりデータを返せるようになってきた気がしますが、

–> {{”test”, “test2″}, {”test3″, “test4″}}

といった入れ子のlist(2D list)は返せていませんし、

–> {aLabel:{bLabel:”test1″, cLabel:”test2″, dLabel:”test3″}}

といった入れ子のrecordも返せていません。

ただ、一応recordは返せるようになっているので、複雑な構造のデータは返さないようにすれば、問題はないでしょう。

2015/01/30 ASOCアプリをScriptableにして値を返す

基本的に、「AppleScriptObjC Explored fifth edition」のP-157「25. Making it Scriptable」を読めば、ASOCアプリをAppleScript対応にして、AppleScriptからASOCアプリを操作できるようにすることは可能です(この本よりいい本はないので、ASOCを使おうとしたら買うべき)。

基本的には、

(1)Info.plistに「Bundle creator OS Type Code」を英数字4文字で設定

(2)Info.plistに「Scripting definition file name」を設定(”.sdef”ファイルのファイル名。拡張子を含む)

(3)Info.plistに、「Scriptable」のエントリを作成し、値をYES(Boolean)に設定

(4)Xcodeプロジェクトにsdefファイルを追加

(5)sdefファイルの内容を記述

(6)AppDelegate.applescriptにプロパティへのアクセス許可/不許可イベントハンドラ「application_delegateHandlesKey_」を追加

(7)sdef内で宣言したコマンド(class)に対応するサブscriptをASOCプロジェクト内に作成し、コマンド内で行う処理を記述

といった手順でScriptableにできるわけですが、ASOCアプリからAppleScript側に返す値の種類によって難易度が変わるということを、身を持って体験しました。

  string:文字列。かんたん。実際に確認ずみ
  file:ファイルパス。かんたん。実際に確認ずみ
  number:数値。かんたん。実際に確認ずみ
  record:レコード。超難しい。挫折
  record:レコード。情報が少ない。難しくはなかった

アプリケーションからAppleScriptコマンドの返り値をレコードで返すというのは、Finderをはじめとする一般的なアプリケーションでは常識的な動作であり、ASOCアプリでこれを行おうとすると大変、ということがわかりました。

これなら、アプリケーション操作と同等のAppleScript Librariesを(AppleScript用語辞書なしで)別途提供したほうがずっと簡単です。

Objective-Cのプログラムを併用することで、ASOCアプリからNSDictionaryの値をAppleScript側に返してあげられるとよいのですが、、、

あとになって、よくよく考えてみるとAppleScript対応のアプリケーションが、コマンドの実行結果として直接record型のデータを返してくるケースを見たことがないような気がしてきました。true/falseとか、結果が入ったオブジェクトをいくつも返してきて、結果を確認するためにはそれらのオブジェクトの属性にアクセスするような処理が多いような・・・

・・・とか書いていたら、海外から「え、やったことあるけどサンプル送ろうか?」という声が(^ー^;;; ありがたく見せていただくことに。このあたりの書き方でイケるんでしょうか。

・・・あ、自分で試してたらできちゃった。これは、AppleScript用語辞書ファイル(sdef)の書き方の問題なのかー。本当にそれだけなんだー。難易度が高くない(情報が見つかりにくい)ことがわかりました。Objective-Cのコードを1行も書かずに、ASOCだけで実装可能でした。

2015/01/29 ASOC on Xcodeで他のScript上のハンドラを呼ぶ

Xcode上でASOCのプログラムを書いていると、「これどうやるんだろうなぁ?」と素朴な疑問に思うことがいくつもあります。

アプリケーションバンドル内で、いくつものファイルに分割された状態でscriptが存在しているわけで、そのscript間で機能を呼び出すにはどうしたらよいか、という疑問がありました。

delegate methodの呼び出し

メインのAppDelegate.applescript内のハンドラ(method)を、他のscriptから呼び出すのに、どうしたものか?

ありました。delegate methodを呼び出すやりかたが「AppleScriptObjC Explored」(Fifth Edition)のP-169に載っていました(汗)。

アプリ内の他のscriptのmethodの呼び出し

いろいろ、バンドル内のscript同士で呼び出すやりかたをまとめておきました。これがわからなくて困ったことがあったので、「最初にこういう資料があれば」と思うことしきりです。

call_otherscript.png

また、以前にまとめておいた「ASOCのプログラムをScriptableにする」方法が、最新のOS+最新のXcodeだと動かなかったりして、Scirptableにするやりかたも再度調査。こちらも、「AppleScriptObjC Explored」(Fifth Edition)のP-169に載っていました。

ただし、目下ASOCのアプリ側からAppleScriptにresultをrecordで返せなくて悩んでいます。さんざん調べたうえで、AppleScriptObjC Developers MLに「ええい、どうにでもなれ〜!」と投げてしまいましたが、果たしてどうなることやら、、、Appleのprivate methodを使ってデータ変換するやりかたなどまでは行き着いたものの、それで変換してもASOCアプリからAppleScript側にどーーしてもrecordを返せない、、、

→ Recordで返すのはあきらめました。オマケ機能だったので別にいいです。

2015/01/20 Xcode上のASOCにScript Editor上のASOCの機能を移植する

最初、AppleScriptObjC(Cocoaの機能を呼び出せるAppleScript)というのは、Xcode上でしか書けないものでした(OS X 10.6で登場)。

asoc1.png

それが、10.7、10.8、10.9、10.10と進化するにしたがい、実行環境や記述環境が広がっていきました(これらのほかに、AutomatorやFileMaker Pro上の実行環境もありますが、ここでは扱いません)。

当初、OS X 10.6で導入されたXcode上のASOCは、同様にXcode上でGUIベースのAppleScriptアプリ開発を行う「AppleScript Studioの置き換え」と言われてきたため、Cocoaの機能を利用するのはもっぱらGUIまわりの部分だけで、内部処理の部分は従来のピュアなAppleScript(Cocoaの機能を利用しない)で作られることが多かったように思います(そうでないケースもありますが)。

OS X 10.10になってCocoaの機能を呼び出すASOCが、ほぼ通常のAppleScriptと不可分の位置付けとなったため、通常のAppleScriptでも積極的にCocoaの機能を利用するよう本Blogでも方向転換を行い、内部処理もCocoaの機能を呼び出すScriptでXcode上のASOCアプリケーション開発も行うようになりました。

実際に、実践的なAppleScriptのプログラム(レコードのリスト同士のdiffを求める)で試してみたところ・・・ピュアなAppleScriptだけで書いたものが420行、処理に10秒ちょっとかかっていたのが、ASOCで1からすべて書き直したところ行数が270行に(40%減)、処理速度は8.4倍の1.2秒までに短縮されました。

# 上記の処理時間計測は、考えられるMAXのサイズのテストデータを処理させたものです

asoc2.png

そこで、GUIアプリ開発環境であるXcode上のASOCにこのScriptを移し替えたいよね、という話に(必然的に)なるわけです。

ASOC on XcodeにASOC on Script EditorのScriptを

ASOC on Xcodeでは、プロジェクト作成時に自動的に作成されるdelegate scriptには、アプリケーション本体のさまざまな挙動(GUIに近い部分とか)を記述し、処理本体部分は別のScriptに追い出して記述するのが自分の流儀です。

というわけで、本体scriptから外部script(bundle内に存在)を呼び出すことになります。このあたりは、XcodeのInterface Builder上で、

asoc3.png

NSObjectの部品を画面上に配置して、そのNSObjectのclassを外部Scriptのscript文で指定したclassと同じものに設定。

asoc4.png

delegate script側で外部script連結用のpropertyを作成して、

asoc5.png

Interface Builder上でpropertyとNSObjectをつなげば、delegate script側から外部scriptのハンドラを呼び出せるようになります。まだ、ここまでは「準備」の部分です。

asoc62.png

ハンドラの書き方、呼び出し方が問題

〜delegate scriptから外部script上のハンドラを呼び出す

asoc7.png

外部script呼び出し用に作成したproperty(ここでは、diffLib)を用い、

  diffLib’s testMe:”TEST”

のように書きます。

呼び出される側のハンドラ側についてはOS X 10.10では、(1)パラメータの型指定、および(2)パラメータ省略時のデフォルト値指定ができるようになっていますが、ASOC on Xcodeでは(1)のみ可能でした。

  on testMe:aStr as string–parameter casting

(2)はコンパイル時にエラーになってしまいます。

  on testMe:aStr as string:”"–default value–Error
  on testMe(aParam as string:”")–Error

外部script内で他のハンドラを呼び出す

asoc8.png

ここで問題。Script Editor上のASOCで書いていたハンドラは、

  testSub(param1,param2)

のような書き方を(自分は)していたわけですが、これをすべてASOC流の、

  testSubWithp1: p2:

などと書き換えるのは大変です。

試行錯誤してみたところ、これを、

  my testSub(param1,param2)

と書けば、あまりASOC on Script Editorのハンドラ名称を書き換えなくても大丈夫でした(よかった)。myと書かないとコンパイルが通らないパターンとか、of meでもコンパイルが通るパターンもあるようで・・・安全のためにmyを使っています。

外部Scriptにおけるuse文

まだプロジェクトが終わっていないので、暫定情報ですが・・・

ASOC on Xcode上ではuse frameworkは書くとエラーになるので書きません。

一応、use AppleScript version “2.4″とかuse scripting additionsといった記述をscript節の内側に書いています。

asoc9.png

だいたいこんな感じでしょうか。試行錯誤をいろいろ行ったおかげで、思ったよりもうまく行っています。

2015/01/16 FM13をASから骨までしゃぶる

仕事で用件があってFileMaker Pro 13 AdvancedをOS X 10.10の環境にインストールしてみました。

一応最新のバージョンということになりますが、1年に1度バージョンアップを行ってきたFileMaker Proとしては、そろそろ13.5なり14なりのバージョンが出てもおかしくない頃です。

OS X 10.10のAppleScript環境に、FileMaker Pro 13はどの程度追いついているのでしょうか?(AppleScript用語辞書自体は、FM Pro v11から変わっていません)。

fm13_1a.png

Scriptステップ「AppleScriptを実行」にASOCのScriptを書いてみる

OS X 10.10で普通のAppleScriptにASOCのScriptをまぜて書けるようになったので、FileMaker ProのScriptステップ「AppleScriptを実行」にASOCを書いてみましょう。

fm13_2a.png

ASObjCExtras.frameworkのテスト用の機能を呼び出してみます。

fm13_3.png

予想外の結果が! 

fm13_4.png

ASOBjCExtras.frameworkは64bit onlyのframework。・・・ということは・・・FileMaker Pro 13というのは・・・

fm13_5.png

fm13_6.png

32bitアプリケーションだったんですね(汗) Shane Stanleyに一応フィードバックしておきましょう。

一応、ASObjCExtras.frameworkを使わないASOCのプログラムを実行させてみたら、「AppleScriptを実行」から実行できました。ただ、ASObjCExtrasが使えないと不便で仕方ないので、使えるようになってほしいところです。

# Xcode上でビルドオプションを変更すれば済むような話でもなさそうなので、実現するかどうかはちょっとわからないです、、、どうせFMも毎年アップデートするので、、、じきに64bitに、、、

JSXを書いて実行してみる!

これは、あっさり却下されました。記入欄にAppleScriptの文法にマッチしないものを書き込むとエラーになります。

ASOC経由でJavaScriptを実行してみる

ASOC経由でJavaScript Coreの機能を呼び出して、JavaScriptを実行させたところ実行できました。また、WebViewを動的に生成してJavaScriptの実行を行い、そちらもうまく実行できました。やはり、WebViewが使えると「できること」の範囲が広がります。

# 最初、WebViewの動的生成&JS実行は行えない、と書きましたが・・・追試を行い、問題なく実行できることを確認しました

異なるバージョンのFM間でScriptを相互呼び出し

異なるバージョンのFMを(2つ同時に起動しておいて)、「AppleScriptを実行」から異なるバージョンのFM DB上のScriptを実行できました。

2015/01/15 セキュリティ上、リスキーな技術

AppleScriptで自動処理システムを構築する際に、「リスキーな」「危険度の高い」技術というものがあります。

OS X 10.6以降、セキュリティポリシーが大幅に以前とは変更され、「怪しい動きをしたプログラムはkillされる」ようになったと感じています。

ここでは、開発マシン=OS X 10.10.1、ターゲットマシン=10.9.5で開発、運用した場合にハマった例をご紹介します(Custom URL Protocol以外この環境)。

(1)GUI Scripting

Appletを連続して動かすような場合に、GUI Scriptingを使っていると問題に直面するケースがあります。

どうもGUI Scriptingを同時に許可するAppletの数に上限があるようで、サブプログラムを8個ほどAppletにして起動させたままにしておいたところ、実行環境でいくつかのAppletは GUI Scriptingを許可されませんでした。

fig1.png

結局、この「GUI Scriptingを許可する暗黙の上限」を回避するため、Sub-AppletをMain Appletの中に読み込むようにプログラムを書き換えました。

fig2.png

この(↑)形態に書き換えたら、実行環境上で問題なく動作するようになりました。

(2)Custom URL Protocol

Appleが最も目の敵にしているのが、このCustom URL Protocol。

mailto:とかhttp:といったURL Protocolは一般的ですし、本Blogでもapplescript:というURL Protocolをプログラムリストの末尾に入れてScript EditorにScriptを転送させていますが・・・ユーザー(開発者)が定義したCustom URL Protocolは、その動作が厳しく監視されています。

Custom URL Protocol経由でAppleScriptを起動して、さらにそこから他のアプリケーションに命令を出したりすると、1つぐらいは大丈夫なんですが、複数・・・だいたい3つぐらいのアプリケーションに命令を出したりすると、OS側が「疑わしい動作」と判断してクラッシュさせられるケースが多いと感じています。

fig4.png

明文化もされていないし、Appleからの発表もありませんが、Custom URL Protocolを利用するようなツールで調子にのって大規模なAppleScriptを書くと、思わぬ落とし穴にハマる危険があります。

(3)AppleScript Libraries

自分も目を疑ったのが、このAppleScript Librariesの導入にともなうクラッシュ。システムのメンテナンスを行いやすいようにAppleScript Librariesを活用するように書き換えてみたら・・・

fig3.png

ターゲットマシン上でクラッシュするようになってしまいました(T_T)。開発マシン上では問題なく動くのですが、ターゲットマシンに持っていくと100%クラッシュしました。

ちなみに、これを・・・

fig2.png

の形式に差し戻したら、クラッシュしなくなりました。

ターゲット環境がOS X 10.9だったので、10.9上でのAppleScript Librariesの管理機能がまだこなれていなかったために発生した問題なのか、それとも開発環境/ターゲット環境の(OSバージョン以外の)違いが引き起こした問題なのか、具体的な発生源の追求できるところまで時間がありませんでした。このような構成で、問題が発生したという事実のみ明記しておきます。

たかだかAppleScriptのAppletをただ漫然と動かしていても(Code Signはしているんですが、、、)、OS側の疑惑の目を向けられるとは・・・非常にやりにくいところです。少なくとも開発者にはルールを明かしてほしいところです。

2015/01/07 【基礎】アプリケーションの操作は、用語辞書に書いてあるとおり記述しないと動かない

「コンピュータは、あなたが思ったとおりには動かないが、操作したとおりに動く」

名言だと思います。同様に、

「プログラムは、あなたが思った/願ったようには動かないが、書いたとおりに動く」

と言い換えることが可能です。さらに、

「AppleScriptは、あなたが願ったようには動かないが、書いたとおりに動く」

とも言い換えられます。とくに、アプリケーションの操作については「AppleScript用語辞書」に書いてあるとおりに書くのが鉄則です。それ以外の書き方をして「動いてしまった」としても、その方が不思議なわけで。

自分でも、海外のScripter連中でもそうだと思うのですが、Scriptを書いている最中は、AppleScript用語辞書を数枚ひらきっぱなしです。AppleScriptObjCのプログラムを書いているときには、AppleのReferenceサイトも表示させっぱなしです。さらに難問になってくるとUS AppleのAppleScript Users MLとか、www.macscripter.netとかを検索しまくることになり複数モニタが欠かせません(3枚使っているといったらShane Stanleyに「ずいぶん枚数多いな!」と驚かれましたが、、、)。

ひと昔前(Classic Mac OSの時代)、AppleScript用語辞書はわざわざ人間(開発者)が書くもので、さらに実際のアプリケーション側の機能とリンクしていない「ただの書き方見本」だったので、「用語辞書には書いていないけれど使える」とかいう「隠し命令」なんてものもありました(初代のEntourageとか)。単なる書きもれ、ケアレスミスでしたが、マニアさんの間では「隠し命令」の存在がちょっと「通」な話題になっていたりしました。

いまのAppleScript用語辞書はXMLファイル(sdefファイル)で、この用語辞書がイコールAppleEventの解釈用の辞書であって、「書き方見本」ではありません。そのため「隠し命令」が存在する余地というのはありません。逆にいえば、用語辞書のとおりに動かなかったら完全なバグなわけです(実装が「不完全」「残念」なために期待したとおりに動かないというKeynote/Numbers/Pagesは例外として)。

たまたま、魔が差してTwitter上で議論になったのですが・・・アプリケーションにファイルをオープンさせる場合には、AppleScript用語辞書をScript Editorでオープンして、コマンドなりオブジェクトなりの使い方を調べることになります。このあたり、Objective-CでCocoaのAPIの使い方をAppleのサイトで調べながら書くのと同じです。AppleScript用語辞書は、アプリケーションバンドル内にあってScript Editorからオープンできます。

textedit_asdic.png

で、この「AppleScript用語辞書を見る」ことをしない方がけっこう多いようで・・・逆にこれを見ないでよくプログラムが書けるもんだと感心してしまうんですが、用語辞書を見ないとハマりやすいんですね。

前述のように、アプリケーションの操作は「決められたとおりに書かないと正しく動かない」ものであり、さらにその先に「ファイルをオープンもしないで中を調べたりはできないよ」といったアプリケーションの挙動(経験則に基づく)の話になるわけなんですけれども、まずは用語辞書を見ないと分かりません。

アプリケーションで書類をオープンする際には、ごく一部の残念な例外(Adobeのアプリ)をのぞいては、パス情報をaliasにしてopenコマンドに渡す必要があります。

textedit_open.png

ここで、POSIX pathやらfileやらを渡してもオープンはしないわけです。

AppleScript用語辞書には「openコマンドにはaliasを渡してね」と書いてあるので、

textedit_open.png

alias以外を渡すのはアウトです(aliasのlistはOK)。それ以外の形式のパス情報を渡して、たまたま間違って動いていたとしても、たまたまです。それ以上でも、それ以下でもありません。

最近は、AppleScript用語辞書にHTMLコンテンツを入れることができるようになり、一部のアプリケーションでは用語辞書内にサンプルScriptを掲載しだして、「サンプルをそのままコピペで動く」いい時代になってきたはずなんですが、これまた残念なことに「Apple社内の連中が書くScriptが絶望的に読みにくい」ために(theとかresultとか使いまくる&1行を長く記述して初心者にわかりにくい)、サンプルを読むと逆に理解しづらくなるという事態が(ーー;;

もういっそのこと、アプリケーションバンドル内に、典型的な利用法を記述したAppleScript Librariesを内蔵してしまって、Scriptから呼び出せるようにすべきではないかとも考える次第です。

余談:

途中から(OS X 10.8あたり?)挙動が変わってしまって困っていた、Mail.appのmove命令。前は複数のmessageをlistに入れて一気にmoveできていたのが、1つのmessageしかmoveできないように変わり、処理速度を稼げなくなっていました(複数一度にmoveできたほうが速い)。

いましらべたら、

mailapp_move.png

複数のmessageを示すobject(s)の表記がありますね。でも、「Move an object to new location」とも書いてあり・・・微妙な。

2014/11/19 UI Browser 2.5が登場

発音不能のpfiddle soft・・・早い話がBill Cheesemanのツール「UI Browser」の新バージョン(v2.5)が出ていました。同ツールは、GUI ScriptingのAppleScriptを対話的に生成するもので、GUI Scriptingをこれなしに記述するのはほぼ不可能と思われるほど欠かせないものです。

AppleScript関連で「なくなると死ぬほど困るサードパーティのツール」を3つ挙げろと言われたら、

Script Debugger・・ステップ実行、ブレークポイントの設定や変数のリアルタイムモニタなど常識的なAppleScriptデバッグ環境を提供。上級者よりもむしろ入門レベルのScripterに有用。個人的には最近使っていないものの、ないと困るツールの筆頭

ASObjC Explorer 4・・・Cocoaオブジェクトへのアクセス時にCocoaオブジェクトの情報をログ表示してくれるため、ASOC記述に必須。この機能はScript Debuggerにはついていない

に並んで、このUI Browserを迷わず挙げることでしょう。

他に操作方法が存在しない場合にやむにやまれず仕方なく書くGUI Scriptingのコード。そのための、オブジェクト階層の取得やアクセスコードの生成、指定オブジェクトの各種属性値のモニタリングなど、UI Browserがないと話になりません。

逆をいえば、これなしでGUI Scriptingを書くのは「時間の無駄」以外のナニモノでもありません。

uib2.png

そんなUI Browserの最新バージョンでは、OS X 10.10に対応しフォーカスモードでのクラッシュなどを低減させたもので、従来バージョンのユーザーには無償アップデートとして提供されます。新規購入は55ドルで、30日間の無料評価版が用意されています。

ちなみに、OS X 10.10にインストーラーからインストールを行ってみたところ、自分の環境にはv2.4がすでにインストールされており、UI Browserの起動時に「システム環境設定でアクセスを許可させろ」と表示され、そのように設定されていることを確認しましたが・・・何度確認しても操作可能になりませんでした(Access is deniedの表示)。

そこで、システム環境設定でいったんUI Browserの登録を削除して、再度v2.5を登録し直したらOK(Access is allowed)に。

uib1.png
▲すでにUI Browserが登録されているのにAccess is deniedのままだったら、いったんUI Browserの登録を削除して再登録

余談:

アクセシビリティ機能へのアプリケーションごとのアクセス許可については、アプリケーションが存在しているフォルダの位置(階層)やバージョンなどをOS側が細かく管理しています。最近はセキュリティ問題へのAppleの取り組みが進んだ結果、強力な機能には一定の歯止めが用意されるようになりました。

アクセシビリティ機能やカスタムURLプロトコルなどは、OS側の監視がきびしくなった機能の筆頭です。昔ほど自由気ままに無茶なプログラムは組めません。

極端な例では・・・・常駐アプレットを10本ぐらい書いて、コントロール側のアプレットからサブプログラムをコントロールするようなシステムを作っていたときに、サブプログラム側で何本かは「このプログラムにはアクセシビリティ機能へのアクセスを許可しない」とOSのメッセージが出て(暗黙の上限があるらしい)、OSからアクセスを許可されませんでした。

1つ1つのプログラムで動作チェックを行って問題はなかったのに、結合段階で文句を言われてしまったわけです(よくある話ではありますが・・・)。

仕方がないので、サブプログラムはメインプログラムのバンドル内に格納し、load scriptで読み込んで順次実行するようにすべて書き換えしました。アクセシビリティ機能は便利ですが、このように思わぬところに落とし穴が存在しているので注意が必要です。

2014/11/19 デバッグ機能が秀逸な、ASOC記述のためのエディタ「ASObjC Explorer 4」

通常の、Script Editor上で記述するAppleScriptでCocoaの機能がダイレクトに呼べるようになったため、OS X 10.10ではAppleScriptとAppleScriptObjCの垣根がこれまでになく低くなりました。

言語処理系としてはパワーが上がったわけですが、OS標準添付のScript Editorがそれ相応に機能がアップしたかと言われれば、Cocoaのオブジェクトを操作している最中のログ表示などはさっぱりです。処理系の機能向上にScript Editorの機能が追いついていません。

そんな中、Shane Stanleyの「ASObjC Explorer 4」を試す機会があり、実際に使ってみました。

前バージョンまでは、ASOCによる箱庭環境(AppleScript Librariesを記述、AppleScript用語辞書を作成して呼び出す)を志向していたように見受けていたのですが、Ver 4ではデバッグ機能が向上したことが売りになっています。

もちろん、従来のASObjC ExplorerのようにXcodeの外部エディタに指定して、Xcode上で記述するAppleScriptObjCアプリケーションの開発用に使用することも可能です(これがだいたい主な用途)。

気になるASOCのデバッグについてですが、

asoe1.png

ふつーに起動して、ふつーにASOCのプログラムを記述して、ふつーに実行しただけでは分かりません(もったいない!!!)。

asoe2.png

「Log Events」にチェックを入れて・・・

asoe3.png

「Run+Log」ボタンを押して実行させると・・・

asoe4.png

AppleScriptから操作したCocoaオブジェクトの情報がログ表示されます。そうそう、これこれ。こういう情報が欲しかったんだ! と、いたく感動しました。

あと、デフォルトでCocoaオブジェクトのログを表示するように設定して、Run機能をオプションにしてデフォルト動作を「Run+Log」にしたほうがいいと思います、、、

Bluetoothにつながっているデバイス名称の一覧を取得するAppleScriptとかTextToSpeechのVoice一覧を取得するAppleScriptなどをさくっと書いてしまえたのも、このCocoaオブジェクトのログ機能があったからです(ログを見ればわかるので)。

まずは、ASObjC Explorer 4の30日間無料お試し版がダウンロードできるので、記事記載時6,200円の本ソフト(為替レートの影響で価格変動あり)の威力を体感してみてはいかがでしょうか?

2014/11/15 ドロップレットのデバッグ方法

AppleScriptのドロップレット。アプリケーション形式で書き出したAppleScriptで、かつon openハンドラでファイルのドラッグ&ドロップを受け付けるように宣言してあるものが、ドロップレットと呼ばれています。

droplet.png

AppleScriptの自動処理で、ファイルを渡すと処理してくれる・・・という処理の流れがわかりやすいので、エンドユーザーに好まれる実行形態です。

ただ・・・ドロップレットのデバッグがやりにくいという声は聞きます。アプリケーションとして書き出してから実行するので、Script Editor上ではないためデバッグがやりにくい、と。

そういう場合には、on runハンドラをScriptに追加して、Script Editor上でデバッグします。on runハンドラではファイルの選択やらFinderの選択ファイル/フォルダを取得するような処理を書いておき・・・それらのファイルをリストにまとめてon openハンドラを呼び出します。

本来は、Script Debuggerを使ってデバッグするのが楽でよいのですが(openハンドラのシミュレーション機能あるし)、いろいろな場所で作業を行うと「Script Debuggerのない環境」というのに出くわすことがあります(ない場所のほうが多いわけで、ScripterにノートPCが必須な理由のうちのひとつ)。

そこで、Script Debuggerなしでデバッグするノウハウが蓄積していったわけで・・・ノウハウというよりも工夫というレベルでしょうか。

AppleScript名:ドロップレットのデバッグ(1)
on run
  set a to choose file
  
set aa to {a}
  
  
open (aa) of me
end run

on open fileList
  
  
set aLen to length of fileList
  
end open

★Click Here to Open This Script 

AppleScript名:ドロップレットのデバッグ(2)
on run
  set a to choose folder
  
set aa to {a}
  
  
open (aa) of me
end run

on open fileList
  
  
set aLen to length of fileList
  
end open

★Click Here to Open This Script 

AppleScript名:ドロップレットのデバッグ(3)
on run
  tell application “Finder”
    set aa to selection
  end tell
  
if aa is not equal to {} then
    open (aa) of me
  end if
end run

on open fileList
  
  
set aLen to length of fileList
  
end open

★Click Here to Open This Script 

2014/07/01 Parallels Accessを使ってiPadをリモートAppleScriptプログラミング端末に

コンピュータを持たずに自転車で出かけて、ふらっと入った喫茶店でいいアイデアを思いついて、プログラムを実際に書いて試したいと思うことがままありました(だったら最初からMacBook Airを持って歩けよ、というツッコミは当然なんですが)。

そのため、MacBook Airよりも非力でよいので薄くて軽いMac(のようなもの)が作れないものかと思い、いろいろ調べてみました。

img_2581.JPG

とくに最近、8インチのIntel Tablet(Windows 8)が手頃な値段で登場しはじめており、ハードウェア的にはほとんどMacもWindows PCも変わらないため、

  「8インチTabletの上でOS Xが動いたらいいのにな〜」

そんな動機から調べてはみたものの……ハイパワーなPCを組んでOS Xをインストールするという方向では世間的にノウハウがたまっている一方で、バッテリー動作のPC TabletにOS Xを入れて動かすのは、世間的にもノウハウがほとんどないことが分ってきました(それ以前に怪しい領域なので……)。

そんな折、仮想環境であるParallels Desktopをバージョン9にバージョンアップし、新機能についてひととおり確認を行っていたところ……なかなか面白い機能があることに(いまごろ)気付きました。

Parallels Desktop for Mac v9が標準搭載している機能で、リモートデスクトップ機能の「Parallels Access」というものが存在しています(Parallels Desktopと別アプリになっており、これだけインストールすることも可能)。以前の(自分はパスした)バージョンからこの機能が存在していることはうっすらとは覚えていたものの、それほど重視していませんでした。

このParallels Accessは、LAN内だけではなくネットワーク的に直接つながっていない場所にあるMacに対して、iPhoneやiPadからリモートアクセスするというものです(アクセスする端末、アクセスされる端末ともにインターネットにはつながっている必要がある)。

Team Viewerみたいなもの」といえば分りやすいでしょうか。

iOS用とAndoroid用にリモートアクセス端末アプリがあり、iOS用をApp Storeからダウンロード(フリー)して試してみました。

parallels_access.png

主にWindowsのアプリケーションをリモートで使うことを念頭に置いて開発されたParallels Accessですが、これが……Mac OS Xのネイティブ・アプリケーションもリモートで使えるようになっているのが面白いポイントです。

img_2576.JPG

img_2578.JPG

img_2579.JPG

img_2580.JPG

画面の小さいiOSデバイスからOS Xのアプリケーションを使うのは、物理的になかなかつらい(Air Serverでメニューの小さい文字に難儀したことが何度も)ものがありますが、iOSデバイスから使いやすいように、Parallels Accessでアクセス中にはOS X上のアプリを擬似的にシングルウィンドウで動かすようになっており、画面の解像度もiOSデバイス側に合わせて低く変更されます。

img_0673.PNG

デフォルトはシングルウィンドウモードですが、マルチウィンドウがそのまま表示/操作できるデスクトップモードもあります。

img_0676.PNG

つまり……OS Xが動くタブレットを無理矢理作って持ち歩くのではなく、OS Xにリモートアクセスできるタブレット(iPad mini Retina)を持ち歩いても同じことではないか、という話です。

iPad mini RetinaでデスクにあるMacBook Proにアクセスして、AppleScriptのプログラムを組んで試すようなことを実際に行えました。ストレスは……少ないほうだと思います。よくできています、Parallels Access。

Parallels Accessは、Parallels Desktop購入者には半年間のお試しアカウントが提供されているようです。購入者でなくても14日間のお試しが行えるとのこと(Parallels Desktopを持っていないと意味がないんですけれども)。

年間2,000円でParallels Accessを利用できるとのことで……月300円程度と考えると、なかなか納得の行きそうな価格に思えます。

半年のお試し期間中に、iPhone 5経由でインターネットにテザリング接続しているiPad miniで、毎月どの程度のデータ転送量になるのか試しておきたいところです(盛大にデータ転送を行われると、テザリング契約そのものが7GB制限にひっかかって、本当に使いたいときに使えないことに、、、)。

「快適さ」はひたすらネットワーク接続速度に依存するため、「あくまで緊急用」という位置付けになるかもしれません。ただ、風呂に入っている最中に防水ケースに入れたiPadからMacの中に入っているラジオ録音ファイルを聞く……とかいう使い方だとけっこう合っている感じがします(音声もリモート端末側に出力されるので)。

Parallels Accessに問題があるとすれば、複数台のモニタをつないでいるマシンにアクセスs中はすべてのディスプレイがミラーモードで同じ内容が表示され、接続解除したあとのディスプレイ解像度は元に戻るものの、ウィンドウ配置などは「元通り」……とはいかないため、マルチディスプレイ持ちにはちょっと気持ちが悪いというところでしょうか。

2014/06/26 意味なし予約語とラベルつきハンドラは、どちらが高速?

英文として「それっぽく」見せるための「意味なし予約語つきハンドラ」と、呼び出し時に属性ラベルをgiven句以降に明示的に記述する「ラベルつきハンドラ」。

AppleScript誕生初期からあったと思われるものの、あんまり(自分的に)見ないことにしてきた2つの記法について、今後どうも無視できない雰囲気がする(Swiftと記法が似る方向に進化する予感)ので、日々いろいろ調べています。

# 10.10ではラベルつきハンドラを書くと便利になる場面が出てきているし

handle2.png
▲Emulator上のClassic Mac OS 8.6上で「意味なし予約語」「ラベルつきハンドラ」をためしてみたら、両方ともサポートされていました。これより古い環境はさすがに持っていません

気になるのは、書きやすさもさることながら……スピード。

他愛もない、些細な記述の違いが膨大な回数の繰り返しループの中では、大きな差を生むこともままあります。

結果は、ラベルつきハンドラの方が32%高速ということに(ちなみに、通常のハンドラ記述も試してみましたが、ラベルつきハンドラと同じ時間でした)。

handle1.png

実行環境は、MacBook Pro Retina 2012モデル(15インチ、メモリ8GB)。

1000万回呼び出してこのぐらいの差が出るということで、100万回なら5秒と3.4秒。現実的なところで10万回なら0.5秒と0.34秒……と、たいていの場合には無視できる気がしますが、覚えておいて損はない数字だと思います。

スクリプト名:意味なし予約語で1000万回ハンドラ呼び出し
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}

set aDat to current date

repeat 10000000 times
  set b to getArrayItem for aList at {1, 2}
end repeat

set bDat to current date

display dialog (bDat - aDat) as string –50sec

–任意の2次元配列で、array(firstDim,secondDim)から値を取り出す
on getArrayItem for aList at anArray
  
  
copy anArray to {aParam, bParam}
  
set anItem to contents of item bParam of item aParam of aList
  
  
return anItem
  
end getArrayItem

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:ラベルつきハンドラで1000万回ハンドラ呼び出し
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}

set aDat to current date

repeat 10000000 times
  set b to getArrayItem given targArray:aList, firstDim:1, secondDim:2
end repeat

set bDat to current date

display dialog (bDat - aDat) as string –34sec

–任意の2次元配列で、array(firstDim,secondDim)から値を取り出す
on getArrayItem given targArray:aList, firstDim:aParam, secondDim:bParam
  
  
set anItem to contents of item bParam of item aParam of aList
  
  
return anItem
  
end getArrayItem

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/06/16 AppleScriptの「意味なし予約語」

AppleScriptには、とくに機能を持たない予約語……「意味なし予約語」(あるいは「意味なし修飾句」)があります。

意味なし予約語として用意されているものには、

about, against, apart from, around, aside from, at, below, beneath, beside, between, by, for, from, instead of, into, on, onto, out of, over, since, through, thru, under

などがあります。

これが何のために用意されているかといえば、ハンドラ(サブルーチン)呼び出しを英語の文章っぽく記述するため、です。使用頻度については……ぶっちゃけ、そんなに多くないのですが、今後増えていく可能性がありそうな気配がしています(OS X 10.10のリリースノートを見ると)。意味なし予約語やラベル付きハンドラを使うと、Swiftとの文法的な差異が少なく見えるので(別物ということでは、ものすごく別物ですが)、いいんじゃないでしょうか。

まず、ハンドラの「基本」を説明し、ラベルつきハンドラ、意味なし予約語つきハンドラの順番で説明しましょう。

基本的なハンドラの書き方

基本的なハンドラは、onまたはtoで書き始め、ハンドラ名、ハンドラパラメータ受信部があり……最後は「end ハンドラ名」で終了します。

スクリプト名:基本的なハンドラ(1)
set a to testMe(“TEST”)
–> “TEST”

on testMe(aParam)
  
  
return aParam
  
end testMe

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:基本的なハンドラ(2)
set a to testMe(“TEST”)
–> “TEST”

to testMe(aParam)
  
  
return aParam
  
end testMe

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

宣言部分はonでもtoでもよく、自分はonで統一しています。これは、AppleScript自体をAppleScriptで解析する(相互呼び出し関係をマインドマップ上にプロットするとか)場合に、宣言句が統一されていた方が都合がよいためです。

本Blogに掲載しているサブルーチンは、複雑さを排除するためにすべてこの書き方(on)で統一しています。

ラベルつきハンドラ

基本的なハンドラ、

on testMe(aParam, bParam)

があったときに、これを呼び出す部分の書き方は、

set aRes to testMe(”100″,”20″)

となります(testMeが値を返す場合)。

この書き方はシンプルではあるものの、この”100″および”20″が何を意味しているかが分りません(書いているうちに本当にそう思ってきた!)。

そこで、呼び出し部分のパラメータに

set aRes to testMe given fromD:”1″, toD:”2″

などと「ラベル」を付ける書き方が用意されています。このさい、「fromD:」と「toD:」がラベル部分です。なんとなく、開始値と終了値であることが見てとれます。

「ラベル」にはAppleScript自身やアプリケーションの持つ「予約語」と重複するものは使えません(構文確認時にエラーになります)。

set aRes to testMe given from:”1″, to:”2″

と書けたらスッキリするのですが、このラベルはAppleScriptの予約語と重複しているため構文確認時にエラーになります。

スクリプト名:ラベルつきハンドラ(1)
set aRes to testMe given fromD:“1″, toD:“2″
–> {”1″, “2″}

on testMe given fromD:d1, toD:d2
  
  
return {d1, d2}
  
end testMe

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

上記のハンドラをラベルを使わずに、プレーンな記述法を用いると以下のようになります。

スクリプト名:ラベルつきハンドラ(2)
set aRes to testMe(“1″, “2″)
–> {”1″, “2″}

on testMe(d1, d2)
  
  
return {d1, d2}
  
end testMe

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

「意味なし予約語」をまじえたハンドラ呼び出し

ハンドラ呼び出し部分の可読性を上げる(読みやすくする)ために、意味なし予約語をまじえて記述できます。

繰り返しになりますが、意味なし予約語は……

about, against, apart from, around, aside from, at, below, beneath, beside, between, by, for, from, instead of, into, on, onto, out of, over, since, through, thru, under

などがあります。位置関係を示す単語が多いですね。

英語の文章的に意味が通らないように滅茶苦茶に使っても、とくにチェックはないのですが……やはり基本は「英文として意味があるような感じっぽい感じ」で書くのがよいのでしょう。

これは……たとえばInDesignのドキュメント上で指定したScript Labelを持つpage itemに、座標的に最も近い位置にあるpage itemを返す、といったサブルーチンの呼び出しに記述するとよいのではないでしょうか。

スクリプト名:意味なし予約語つきハンドラ(1)
set a to listUp beside “TEST”
–> “TEST”

on listUp beside anObject
  
  
return anObject
  
end listUp

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

こちらは、開始日から終了日までの間に増分値を指定してdate objectを返す、というサブルーチンの呼び出しによさそうな感じもします。

スクリプト名:意味なし予約語つきハンドラ(2)
set aRes to makeDays thru “2014/1/1″ to “2014/6/1″ by 7
–> {”2014/1/1″, “2014/6/1″, 7}

on makeDays thru startDate to endDate by dateStep
  
  
return {startDate, endDate, dateStep}
  
end makeDays

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

……今後、OS X 10.10でハンドラの書き方が拡張されるようなので、このあたりもおさえておくとよいでしょう。可読性を上げられるかどうかは、いろいろ実際に試してみないといけないでしょう。

OS X 10.9で導入されたAppleScriptライブラリを記述するような場合に、ライブラリ本体にAppleScript用語辞書を加えることで用語の定義(AppleScript予約語の拡張)を行えるわけですが、そこまでやらなくてもこれらのラベルつきハンドラや意味なし予約語の併用によって可読性を上げるようなことも考えられます。