Archive for 6月, 2014

2014/06/28 FMのDBで指定Tableの指定クエリー検索

FileMaker Proのデータベース上で、指定テーブル上に存在するレコードのうち、指定フィールドが条件に該当するものの数をカウントして返すAppleScriptです。

# 初回掲載時に、明示的にリザルトを返していなかったのと、部分一致検索で
# 検索してしまっていたので完全一致に修正しました

FileMaker Pro(以下、FMと省略)はAppleScript対応アプリケーションのうちでも、最初期に対応が行われたものであり、FileMaker Pro v4.xの時代にほぼAppleScript対応機能は完成の域に達していました(逆をいえば、その後の進化がほとんどない、ということでもあります)。

その後、FileMaker Pro v7の時代の大変革を通じて、それまで1データベース書類=1テーブルだったものが、1データベース書類に複数のテーブルを持つようになったり、速度の向上、内蔵のスクリプティングシステムの改良が行われてきました。

一方で、AppleScriptによるプログラム開発において、当初あまりに存在感の大きかったFMへの依存(ソートや抽出などの処理や、GUI作成環境としてのFMへの依存)を減らし、ほぼFMなしでデータベース的な処理が行えるようにサブルーチン群が整備されてきました。また、AppleScript StudioやAppleScriptObjCによりAppleScriptだけで、単体配布可能なGUIベースのアプリケーション開発可能なFMにかわる環境も提供されてきました。

当初(Classic Mac OSの時代に)、FMなしでAppleScriptによる開発を行うことは、安定性や機能面で難しいことでしたが、OS Xへの移行後はFMなしでも十分に安定性と機能性を確保することが可能となりました。

それでもなお、FileMaker Proを併用した方が便利な処理は存在しており、AppleScriptからFileMaker Proをコントロールするためのノウハウも高度化されてきました。

現在、FileMaker Proをコントロールする各種サブルーチンは、部品として使い回すことを念頭に汎用化がすすめられており、本ルーチンにもその方向性が見られます。

本ルーチンにおいては、DB名、テーブル名、検索対象フィールド名(複数)、検索条件データ(複数)を外部からパラメータで与えることにより、同様の検索処理であれば汎用的に使い回すことが可能となっています。

実際の用途は多岐に渡っていますが、データ分析系の処理や……Mac内の全アプリケーションを走査してローカライズ情報をアプリケーションバンドル内から(各国語対応の文字列データを)FMに吸い上げるAppleScriptを作成して運用しています。

スクリプト名:FMのDBで指定Tableの指定クエリー検索

set tmpDataList to {“com.apple.Safari”, “Safari”, “7.0.5″}
set queryCellList to {“bundle_id”, “Name”, “version”}

set aRes to findDataOnDB(“localizedStrings.fp7″, “applications”, tmpDataList, queryCellList)

–指定DB、指定テーブルの指定フィールドが条件に該当するレコードをカウントして返す
on findDataOnDB(dbName, aLayout, aDataList, queryCellList)
  
  
set count1 to length of aDataList
  
set count2 to length of queryCellList
  
if count1 is not equal to count2 then return 0
  
  
tell application “FileMaker Pro”
    
    
tell database dbName
      show layout aLayout
      
      
tell table aLayout
        
        
show every record
        
delete every request
        
        
–指定フィールドが指定条件に該当するレコードを抽出する
        
set aReq to create new request
        
tell aReq
          repeat with i from 1 to count1
            set j1 to contents of item i of queryCellList
            
set j2 to contents of item i of aDataList
            
set cell j1 to “==” & j2 –”==”は、フィールド完全一致指定の演算子
            
set omitted to false
          end repeat
        end tell
        
      end tell
      
      
find
      
    end tell
    
    
tell window 1
      set aCount to count every record
    end tell
    
  end tell
  
  
return aCount
  
end findDataOnDB

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

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/24 2Dの配列変数から任意の添字の項目を取り出す、設定する 2

AppleScriptにおける配列変数であるList型変数。このList型変数内の項目へのアクセスにはかなり不満を持っています。

いくつかある不満のうち、最大のものは添字の書き順が逆ということでした。

前回は、ラベルつきハンドラを用いることで、添字の書き順については納得できる順序を実現しましたが……記述の煩雑さという意味ではいまひとつでした。

そこで、今度は「意味なし予約語」を用いることで、もう少し整理してみることとします。

例によって、添字の上限/下限チェックやリスト項目数が増えた場合への対処などは行っていません。

意味なし予約語を用いることで、それっぽくはなっていますが……ハンドラの呼び出し時にフィルタ参照が使えたり、その他の予約語が使えるようになるといいのにな〜、的なことは考えてしまいます。

スクリプト名:2DのList型変数から任意の添え字の項目を取り出す v2
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}
set b to getArrayItem for aList at {1, 2}
–> 2

–任意の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

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

スクリプト名:2DのList型変数の任意の添え字の項目に値を設定する v2
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}
set b to setArrayItem for aList at {1, 2} by 100
–> {{1, 100, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}

–任意の2次元配列の、array(firstDim,secondDim)に値を設定する
on setArrayItem for aList at anArray by aData
  
  
copy anArray to {aParam, bParam}
  
set item bParam of item aParam of aList to aData
  
  
return aList
  
end setArrayItem

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

2014/06/23 2Dの配列変数から任意の添字の項目を取り出す、設定する

AppleScriptにおける配列変数であるList型変数。このList型変数内の項目へのアクセスにはかなり不満を持っています。

もしここに、aListというList型変数があって、その内容が、

 {{1,2,3}, {2,2,3}, {3,2,3}, {4,2,3}}

だった場合に、普通のプログラミング言語であれば、

 a = aList(1,2)

などと指定することでaList(1,2)の要素にアクセスできるはずです。

 {{1,2,3}, {2,2,3}, {3,2,3}, {4,2,3}}
 –> 2

ところがこれをAppleScriptで書こうとすると、

 set a to contents of item 2 of item 1 of aList

と書く必要があります。通常の添字とは書く順序が逆ですし、ただデータを取り出すだけなのにあまりにも書き方が冗長です。

一応、この順序を反対にするために(普通の言語と同じ順序で指定するために)、

 set a to contents of aList’s item 1’s item 2

のような書き方もできますが…………

いいかげん慣れたので不足なく書けるようになりましたが、当初はこのアクセス方法がものすごくイヤでした(自分も、他の言語を先に覚えていたので)。

イヤなら、「そのように書かなくていいようにカプセル化してしまう」のが大人の対処方法ということで……ラベル付きハンドラを用いて、「それっぽく」書いてみることにしました。冗長な部分については、あまり解決していませんが……

スクリプト名:2DのList型変数から任意の添え字の項目を取り出す
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}
set b to getArrayItem given targArray:aList, firstDim:1, secondDim:2
–> 2

–任意の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

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

配列の任意のアイテムを書き換えるものも作ってみました。とりあえず、目的は達成できていますが……用語辞書を拡張できているわけではないので、冗長さは解決できていません。

ここに掲載したルーチンは、単に可能性を検証しただけなので、実用化に伴うエラーチェック(添字の範囲チェック、型チェック)、高速化(アイテム数が数万以上に増えた場合への考慮)などは行っていません。

スクリプト名:2DのList型変数の任意の添え字の項目に値を設定する
set aList to {{1, 2, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}
set b to setArrayItem given targArray:aList, firstDim:1, secondDim:2, aData:100
–> {{1, 100, 3, 4}, {2, 2, 3, 4}, {3, 2, 3, 4}, {4, 2, 3, 4}}

–任意の2次元配列の、array(firstDim,secondDim)に値を設定する
on setArrayItem given targArray:aList, firstDim:aParam, secondDim:bParam, aData:aDatum
  
  
set item bParam of item aParam of aList to aDatum
  
  
return aList
  
end setArrayItem

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

2014/06/20 InDesign CC 2014でpropertiesを取得できないバグ

InDesign CC 2014のAppleScript用語辞書の(InDesign CCからの)差分内容を確認していたところ、このInDesign CC 2014の最初のリリースにはバグがあり、オブジェクトのpropertiesを一切取得できないことが判明しました。

idcc20141.png

ものすごくよく使う、GUI上で選択したテキストフレームのpropertiesを取得するという、まさに「display dialogでメッセージを表示するぐらい基本的な」Scriptを実行するとエラーになります。

idcc20142.png

アプリケーション自体のpropertiesを取得しようとしても……

idcc20144.png

エラーになります。何をやろうとしてもお手上げ状態です。これだけ属性の多いInDesignで属性値をproperties ofで取得できないのは、事実上Scriptingができないのと同じことです。

idcc20145.png

……もしかして、AppleScript用語辞書から「properties」という予約語がなくなったのかも? と思って確認してみると……

idcc20143.png

なくなったわけではありません。この程度で見つかるバグを放置するというのは、出荷前にまったくチェックしてないんでしょうねぇ。

InDesign CC 2014は、早々にSSD上から消去しました(InDesign CCにバージョンダウン)。

2014/06/19 Adobe Creative Cloud 2014がリリース

AdobeのCreative Cloudの各アプリが更新され、身近なところではAdobe Photoshop CC 2014、Adobe Illustrator CC 2014、Adobe InDesign CC 2014がリリースされました。

cc2014.png

主要なアプリケーションのバージョンアップの履歴や動向などを(勝手に想像して)まとめていますが、2014年はMicrosoft Officeもバージョンアップする見込みですし、FileMaker Proも小幅なバージョンアップをしてきそうですし、なかなか過渡期感がたっぷりです。

cc20142.png

今回のCC 2014のPhotoshop、Illustrator、InDesignのバージョンは上記のようになっています。アプリケーション名はそれぞれ「Adobe Photoshop CC 2014」「Adobe Illustrator CC 2014」「Adobe InDesign CC 2014」となっており、前バージョンと別にインストールされます(Gバイト級のアプリケーションが3つも増えて、SSDの空き容量が減ったので、CCの方を消しておきました)。

名前がとても長いのでbundle idで指定したほうが便利と思えるほどです。

cc20143.png

それぞれ、AppleScript用語辞書のバージョン間のdiffをとって確認していますが……

Photoshop:変更点なし。ASからファイルをオープンできないという伝統のバグが残っているかどうか?(確認しました。はい、あいかわらずです)
Illustrator:2箇所追加(preset settings dialog option、artwork)
InDesign:追加箇所たくさん

となっているようです。

InDesign CC 2014のCCからの変更点(追加点)について概要を調べてみたところ、

・Event Listener関連の機能拡張
・グループ化(階層化)されたSwatchの取扱いについての機能追加
・packageコマンドの属性追加
・epubプレビューアプリケーション(外部ヘルパーアプリケーション)の登録、確認、削除など
・data mergeでqrcode関連の機能にアクセスできるようになった(らしい)

といったところです。すべてサンプルコードまでチェックしたわけではないので概要のみ。階層化されたSwatchについてはけっこうしつこくコードを書いて確認しましたが、そもそもInDesign CC 2014に巨大なバグがあるので、作業が停まっていました。

2014/06/17 2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す

2次元のリストから、指定インデックスアイテムで、指定データが該当する最初のものを返すAppleScriptです。

つまり……

{{”a”, 1}, {”b”, 2}, {”c”, 3}, {”c”, 2}}

のような2Dのリストがあった場合に、各アイテムの1番目のアイテム(ここでは、便宜上インデックスアイテムと呼んでいます)、

“a”, “b”, “c”, “c”

のうち、”c”が該当する最初のデータを返す……といったときには、

{”c”, 3}

を返します。データベース的にいえば、指定フィールドが特定の値である最初のレコードを取得する……といったところでしょうか。

データベースをわざわざ使わずにデータベース的な処理を行うサブルーチン群はたいへんに重要です。Classic Mac OSの時代にはこうしたサブルーチンが揃っておらず、なかなかFileMaker ProなどのスクリプタブルなDB(当時はValentinaなどもあった)を使わずにDB処理を行うのは大変でした(ほぼ無理)。

Mac OS Xになってから、脱FileMaker Pro、脱テキストエディタ、脱OSAXという方針を打ち立てて、それぞれの代替になるサブルーチンを整備してきました。いまや、DB的な処理にFileMaker Proは必要ありませんし、テキストの処理のために特定のテキストエディタに依存することもなくなりました。

スクリプト名:2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す
set aList to {{“a”, 1}, {“b”, 2}, {“c”, 3}}
set anItem to searchInListByIndexItem(aList, 1, “c”) of me

–2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す
on searchInListByIndexItem(aList, indexItem, hitData)
  script spd
    property aList : {}
  end script
  
  
copy aList to (aList of spd)
  
  
repeat with i in (aList of spd)
    set j to contents of (item indexItem of i)
    
    
if j is equal to hitData then
      return contents of i
    end if
  end repeat
  
  
return false –hitしなかった場合
end searchInListByIndexItem

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

一応、「意味なし予約語」を用いてそれっぽく英文らしい呼び出し方をしようとすると、こんな感じでしょうか?

スクリプト名:2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す v2
set aList to {{“a”, 1}, {“b”, 2}, {“c”, 3}}
set anItem to searchInListByIndexItem from aList at 1 for “c”

–2Dリストから、指定インデックスアイテムで、指定データが該当する最初のものを返す
on searchInListByIndexItem from aList at indexItem for hitData
  script spd
    property aList : {}
  end script
  
  
copy aList to (aList of spd)
  
  
repeat with i in (aList of spd)
    set j to contents of (item indexItem of i)
    
    
if j is equal to hitData then
      return contents of i
    end if
  end repeat
  
  
return false –hitしなかった場合
end searchInListByIndexItem

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

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予約語の拡張)を行えるわけですが、そこまでやらなくてもこれらのラベルつきハンドラや意味なし予約語の併用によって可読性を上げるようなことも考えられます。

2014/06/14 OS X 10.10, Yosemite(Pre-Release版)のAppleScriptリリースノートが公開される

AppleのWebサイト上にOS X 10.10, Yosemite(PreRelease版)のAppleScriptリリースノートが公開されています(2014年5月19日にアップデートされたようですが、公開日は未確認)。

これまで、βリリースの際にはリリースノートが用意されておらず、β版のテストといっても何を試せばよいのかぼんやりしていましたが、リリースノートが先に用意されるというのはテストしやすくてよいと思われます。

読んで、ちょっと驚いてしまいました。意外といろいろ変更点があります。

プログレスバー表示機能

実際に試せていないので、具体的な記述文の掲載はできませんが、AppleScript単独でプログレスバーの表示ができるようになるようです。

指定すると、AppleScript実行中にプログレスバーが表示されるのか、プログレスバー表示ダイアログを表示しつつループ中にバーの内容を更新させていくのか、サンプルコードが掲載されていないので、いまひとつ把握しずらい感じがします。

複数の型タイプを指定しての型変換

「as」を用いて型変換を行う際に、複数の型をリストで指定できるようになったとのこと。

set a to “10″
set b to a as {integer, text}

などと書けるようで……リスト内に指定した型にリストに登録されている順に先頭から順次変換を試み、リスト内のすべてマッチしなかったらエラーを発生させるとのこと。

ハンドラのパラメータで型指定オプションが記述可能に

ハンドラの宣言部分で、パラメータをどのように解釈するか型宣言ができるとのこと。

on frotz(x as integer)

と宣言すると、xはかならずintegerと解釈されて(型変換されて)実行されるようになるとのこと。

たしかに、パラメータの型チェックなどが最初にできるとエラーチェックの手間が省けるかも? とは思います。

また、ハンドラの引数をどのように受けるかの記述が拡張されたとのこと。

これまでにも、

スクリプト名:プロパティつきハンドラ宣言
make with properties {aTEST:“10″}

on make with properties {aTEST:a}
  log a
  
–> (*10*)
end make

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

のような書き方はできたのですが(趣味に合わなかったので使わなかっただけ)、この際に型指定ができるようになったとのこと。

on make new theClass with data theData : missing value

また、(呼び出し側でオプション値を指定しなかった場合の)デフォルト値の指定が行えるとのこと。

呼び出し側でtheDataに当たる値を指定しなかった場合には、ハンドラ中のローカル変数theDataにはmissing valueが入るようです。

パラメータの型指定もハンドラ宣言部で行えるようになるとのこと。

on make new theClass with properties (theProperties as record) : {}

……なんか、AppleScriptではないような雰囲気になっていますが、他の言語との仕様の「差」を埋めようということでしょうか。

AppleScriptエディタの名称変更

JavaScript OSAもデフォルトで扱うようになったため、AppleScriptエディタの名称が「スクリプトエディタ」に変わるとのこと。

スクリプトエディタ(旧称AppleScriptエディタ)の用語辞書ブラウジングについても、AppleScriptの言語表現による表示のほか、JavaScript、Objective-C(Scripting Bridge)文法による表示が加わるとのこと。

OS X 10.10より前のスクリプトエディタとBundle IDは変わらないはずなので、スクリプトエディタをAppleScriptからコントロールする際には(個人的にはけっこうあります)、tell application id “com.apple.ScriptEditor2″と指定するとアプリケーション名称の影響を受けずによいと思われます。

do shell scriptコマンドの拡張

do shell scriptでパスワードのダイアログを表示する際のカスタムメッセージの表示指定が可能になったとのこと。

2014/06/12 戦場の絆のリプレイ動画の時間別分布(日付別、クラス別) v3(文字列出力機能つき)

「戦場の絆」というアーケードゲームがあり、同ゲームにはYouTubeへのリプレイ動画アップロード機能があります。

動画のアップロードは1プレイヤーあたり1日2回まで申請可能で、あとからリプレイ動画を見て自分のプレイを振り返ることが可能です。

senjonokizuna.png

そこで、動画アップロードの時間の密度や度数を調べることで、同ゲームのオンライン対戦しやすい時間の傾向分析ができるのではないかと考えました。

kizuna2.png

実際にAppleScriptでSafariをコントロールして、YouTubeから、

{{”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Aクラス ‌”}, {”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Aクラス ‌”}, {”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Sクラス ‌”}, {”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Aクラス ‌”}, {”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Sクラス ‌”}, {”戦場の絆”, “14/06/08″, “22:09″, “ニューヤーク(R)”, “6VS6″, “Aクラス ‌”}}

のようなデータを取得できるAppleScriptを書いてみました(Webブラウザごしにデータを突っ込んだり、データを大量に取り出すのは割とかんたん)。

問題は、取り出した膨大なデータの分析。

とりあえず、放っておいても自動で「データ取得」→「分析」を行っておいてほしいところです(人間が寝ている間に処理)。

本Scriptは、取得したデータの日付別、クラス別(Aクラス/Sクラス)の分析出力を実際に行うAppleScriptです。

各フォルダに月ごとのデータがAppleScriptのlist形式でそのまま書き込まれており、フォルダがYYYYMM形式の名前になっていることが実行前提条件です。

kiz100.png

けっこういろいろと分析できるScriptを作りためましたが……膨大なプログラムを作ったわりに、外部に公開できるものが多くないという、、、

出力例(本当は1か月ぶんすべて出力する):

■■■■ Aクラス ■■■■

■2014/06/8 日曜日

10時:絆絆絆絆絆絆絆絆絆絆絆絆絆
11時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
12時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
13時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
14時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
15時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
16時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
17時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
18時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆絆
19時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆
20時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆
21時:絆絆絆絆絆絆絆絆絆絆絆絆絆絆

■■■■ Sクラス ■■■■

■2014/06/8 日曜日

10時:絆絆絆絆
11時:絆絆絆絆絆
12時:絆絆絆絆絆絆絆
13時:絆絆絆絆絆絆絆絆
14時:絆絆絆絆絆絆絆絆絆絆絆絆絆
15時:絆絆絆絆絆絆絆絆絆絆絆絆
16時:絆絆絆絆絆絆絆絆絆絆絆絆
17時:絆絆絆絆絆絆絆絆絆絆絆
18時:絆絆絆絆絆絆絆絆絆
19時:絆絆絆絆絆絆絆絆絆絆
20時:絆絆絆絆絆絆絆絆絆絆
21時:絆絆絆絆絆絆絆絆絆絆
22時:絆絆

スクリプト名:戦場の絆のリプレイ動画の時間別分布(日付別、クラス別) v3(文字列出力機能つき)
–フォルダ(YYYYMM形式)を指定すると、その1か月分の絆のYouTubeアップロード状況を
–日付別に時間単位で集計して出力する。Aクラス、Sクラス別に集計を行う
–By Piyomaru Software (Takaaki Naganoya)

–2014/6/7 作成

script spd
  
  
property aList : {}
  
property bList : {}
  
property aClass : {}
  
property sClass : {}
  
  
–10〜22時 × 31日(Aクラス)
  
property aHours : {}
  
  
–10〜22時 × 31日(Sクラス)
  
property sHours : {}
  
  
property tmpOurs : {}
  
  
property outStr : {} –文字列出力用
  
end script

–プロパティ
property outputCharacter : “絆” –文字グラフに出力する文字の指定
property outputScale : 10 –グラフに出力する、1つの文字あたりのデータ。1に指定すると実数。10だと1つの文字あたり10データ

–集計用変数の各種初期化
set aList of spd to {}
set bList of spd to {}
set tmpOurs of spd to {}
set (outStr of spd) to {} –文字列出力用リスト(最後に一括でリストから文字列に変換)
set classList to {“A”, “S”} –Aクラス、Sクラスのループ用リスト

–時刻リスト(1日分×31日)の初期化
set aDayList to {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
set aHours of spd to {}
set sHours of spd to {}
repeat 31 times
  set the end of aHours of spd to contents of aDayList –ここの、contentsがものすごく大事(外すとまともに動かない)
  
set the end of sHours of spd to contents of aDayList –ここの、contentsがものすごく大事(外すとまともに動かない)
end repeat

set a to choose folder

tell application “Finder”
  set tmpName to name of a
  
  
tell folder (a as string)
    set aList of spd to every file as alias list
  end tell
end tell

set aYear to text 1 thru 4 of tmpName
set aMonth to text 5 thru 6 of tmpName

–set aClass of spd to {}
–set sClass of spd to {}

repeat with i in aList of spd
  
  
set bList of spd to read i as list
  
  
set aCount to 0
  
set sCount to 0
  
  
repeat with ii in bList of spd
    
    
set anItem to contents of item 3 of ii –時刻(”20:39″)
    
set dateStr to contents of item 2 of ii –日付(”14/06/06″)
    
set classStr to first character of (contents of item 6 of ii) –クラス別(”Sクラス “, “Aクラス “)
    
    
set wDate to day of (date (“20″ & dateStr)) as integer –日付を数字で(1〜31)
    
    
log {“wDate”, wDate}
    
    
    
if classStr = “A” then
      
      
–Aクラスのデータの場合
      
set hourStr to ((text 1 thru 2 of anItem) as integer)
      
log {“hourStr”, hourStr}
      
set tmpA to contents of item hourStr of item wDate of (aHours of spd)
      
log {“tmpA”, tmpA}
      
set tmpA to tmpA + 1
      
set item hourStr of item wDate of (aHours of spd) to tmpA
      
    else if classStr = “S” then
      
      
–Sクラスのデータの場合
      
set hourStr to ((text 1 thru 2 of anItem) as integer)
      
log {“hourStr”, hourStr}
      
set tmpA to contents of item hourStr of item wDate of (sHours of spd)
      
log {“tmpA”, tmpA}
      
set tmpA to tmpA + 1
      
set item hourStr of item wDate of (sHours of spd) to tmpA
      
    end if
  end repeat
  
end repeat

–文字列出力部分ここから

repeat with i2 in classList
  
  
set dC to 1 –日付インクリメントカウンタ
  
  
set i2j to contents of i2
  
set the end of (outStr of spd) to “■■■■ ” & i2j & “クラス ■■■■”
  
set the end of (outStr of spd) to {}
  
  
–つじつま合わせのための強引な処理
  
if i2j = “A” then
    copy aHours of spd to tmpOurs of spd
  else if i2j = “S” then
    copy sHours of spd to tmpOurs of spd
  end if
  
  
  
  
–set wdCount to 1
  
set wdList to {“日曜日”, “月曜日”, “火曜日”, “水曜日”, “木曜日”, “金曜日”, “土曜日”}
  
  
repeat with i in tmpOurs of spd
    
    
set hourNum to 1
    
    
–set aYear to text 1 thru 4 of tmpName
    
–set aMonth to text 5 thru 6 of tmpName
    
    
set the end of outStr of spd to “■” & aYear & “/” & aMonth & “/” & (dC as string) & “ ” & (contents of item (weekday of date (aYear & “/” & aMonth & “/” & (dC as string)) as integer) of wdList)
    
set the end of outStr of spd to {}
    
    
repeat with ii in i
      
      
–10時から22時を対象
      
if hourNum 10 and hourNum < 23 then
        
        
set jj to contents of ii
        
set the end of outStr of spd to (hourNum as string) & “時:” & retSeriesOfSameChar(outputCharacter, (jj div outputScale)) of me
      end if
      
      
set hourNum to hourNum + 1
    end repeat
    
    
set the end of (outStr of spd) to {}
    
    
–set wdCount to wdCount + 1
    
    
–日付インクリメント
    
set dC to dC + 1
    
  end repeat
  
  
set the end of (outStr of spd) to {}
  
set the end of (outStr of spd) to {}
  
  
  
end repeat

set aText to retArrowText((outStr of spd), return) of me
–ここまで

on retSeriesOfSameChar(aChar, aCount)
  set outStr to “”
  
repeat with i from 1 to aCount
    set outStr to outStr & aChar
  end repeat
end retSeriesOfSameChar

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

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

2014/06/07 Scriptingを楽にするツール「ASDiff」(→PropDiff)をリリース予定(2)

AppleScriptのプロパティ値のdiffを計算するツール「ASDiff」は、いわゆる「秘蔵のツール」で……自分はこれがないとちょっと初見のアプリケーションのScriptを書くのは無理ですし、大きなAppleScript辞書を持つアプリケーション(Adobe InDesignとかIllustratorとかPhotoshopとか)のScriptingも時間がかかって仕方ありません。

asdif11.png

GUI画面上の各種機能と、AppleScript内の機能との対応を調べるのに、これがないとやっていけません。……と、そのぐらい(自分には)必要不可欠なツールです。必要に迫られて作って、必要に応じてバージョンアップを行ってきました。

β版を知り合いに使ってもらったら、好感触。ただし、「自分しか使っていないツール」の暗黒面も明らかになり……「結果表示がそっけなさすぎる」とか、いろいろ反応が返ってきました。

これまでのバージョンでは、差分情報をプログラム内で再利用するために、差分結果をAppleScriptのリスト形式で出力していました。

そのあたりを書き換えたり、AppleScriptエディタの「結果」欄からのコピー&ペーストが正しく行われているかのチェック機能を付けたりして、なんとか出せるかもといったレベルに。

あとは、Mac AppStoreに申請するための手続きをイロイロと……自分的には開発中の「本命」アプリをストアに送るための「前座」ではあるものの、ひじょうに有用性の高いツールです。

asdif10.png

……ただ、Release Noteを読んだかぎりでは、JavaScript OSAのPropertiesの出力フォーマットがほとんどAppleScriptのPropertiesと同じようなので、両方で使えることを考慮して名前を変更したほうがいいかも。

「Prop Diff」とか?

2014/06/07 OS X 10.10 Yosemite関連

yosou.png

WWDC前にこんな予想をしていました。基本的な流れ(LLVMの強化、LLVMを活かしたScript言語)は把握していましたが、新言語(swift)を作るとは思ってもみませんでした。

WWDC 2014 Keynoteの後、外部に書いていいことといけないことの線引きがひじょーに難しく、しばらく様子見をしていました。ただ、今年のWWDCの各Sessionのビデオ自体も外部に公開している状態ですし、各種MLなどで話が出ているものについては「そこまでは大丈夫なんだな」という認識です。

今年のWWDCというか、Yosemiteについてはいろいろ驚かされました。新しいハードウェアが出てくるよりも驚きに満ちあふれていたと思います。

JavaScript OSAの標準搭載

これまでにも怪しい動きは何度かあったのですが、ついにJavaScript OSAがOS X標準搭載に。すでに実物にさわっているので、実物についての感想などは控えておきます。

USのAppleScript Users MLでの反応といえば、

・書ける人が多いのはメリット
・JavaScript OSAが標準搭載になったことの意義は大きい

などの声もあれば……

・JavaScript OSAが使っているScripting BridgeのAppleEventサポート機能はOSのアップデートのたびに壊れたり、使えなくなったりしてきた。歴史的にいまひとつ信用できない
・悪しき先例が多すぎて信用できない。Dashboard、Automatorなど出すだけ出して、まともにサポートを継続していないモノが多すぎる

といった意見もあり、評価が別れています。

AppleScriptについては、言語そのものの仕様は小さいものの……アプリケーションのコントロール自体にノウハウや慣れや情報集積が必要で、記述言語がJavaScriptになったころで、それは変わりません。つまり、JavaScript OSAでアプリケーションのコントロールを書こうとして、「先例」が全然ない世界でどの程度の問題を解決できるのかは、分りません。

JavaScript OSA自体は、サードパーティ(Late Night Software)のものが長年存在しており、JavaScriptで書くこと自体は可能だったわけですが、OS標準搭載でないのと、ユーザー数の問題、実際のユーザー側の情報量の蓄積の問題などでいまひとつ普及していませんでした。これが、OS標準搭載になって何が変わるのか……そのあたりは見極めたいところです。

海外のScripterの動向には、これまでになく注意を払う必要があると思います。

個人的な意見をひとつ言うなら……アプリケーションのScriptingは、仕様を見てすぐに書けるようになるような種類のものではない、ということです。

言語が何に変わっても、アプリケーションを使いこなして十分に理解しなくては、Scriptingは無理です。アプリケーションを使いこなして、深くまで理解して、そこからはじめて「じゃあ、どうやってScriptingしようか」という話になるので……

「プログラムはあなたが書いたように動くが、あなたが願ったように動くとは限らない」

という有名な話を、「プログラミング言語」と「アプリケーション」の2層にわたって経験することになるでしょう。

AppleScriptObjCの方向性は?

いまひとつ分らないのが、AppleScriptObjCの方向性。推進したいんだかしたくないんだか、いまひとつ分りません。Apple自体が開発言語をObjective-Cからswiftに切り替えたいのだとすれば、AppleScriptにswiftライクなCocoaの呼び出し機能を付けたAppleScriptSwiftyといったものを作るのか、AppleScriptObjC自体をフェードアウトさせていくのか……分らないところです。

ただ、swift自体はけっこう好印象なので、(アプリなど)swiftで書けるものは書いていけるといいですね。Swiftのプロジェクト中にObjective-Cをまぜられるということは、AppleScriptObjCもまぜられるということですし。

Dialogueのゆくえは……?

MacとiPhoneの連携アプリケーションをいろいろ探しては、日常的に使っています。そのうちの、iPhoneへの着信をMacで受け取れる「Dialogue」についてはものすごく便利なのですが、あまりに目の付けどころがよさすぎて、Appleにパクられてしまいました。

対応スマートフォンの機種を増やすなど、いろいろ頑張っているようで……今後とも応援していきたいところです。なので、着信時のAppleScript実行サポート機能をぜひ追加してほしいところで。