Archive for 1月, 2016

2016/01/27 ASOCでUIを動的に生成する場合にはAEInteractWithUserを呼べ?!

US Appleが主催しているメーリングリスト「AppleScript Users ML」に、AppleのAppleScriptエンジニアリングチームのエンジニア、Chris Pageが投稿した内容に驚かされました(最近わりと頻繁にMLに投稿しているのはなぜだろう)。

Scripterの間でASOCによって動的に各種GUI部品(ウィンドウとかボタンとかスライダーとかテーブルとか)を生成して呼び出すことが流行りそうな昨今ですが、Xcode上でInterface Builderを使って画面を作成した時と一緒の挙動にはなりません。具体的にいえば、キーボードフォーカスをうまく取得できないとか、操作感に違和感があるといったところです。

Chris Pageの説明によれば、

「AppleScriptObjC(ASOC)のScriptでAppKit frameworkを用いてUIを表示したとき、さまざまな事情によりAppKitは完全には初期化されておらず、キーボードフォーカスの取得などの機能はたしかに動かない。

Scripting AdditionではローレベルAPIを用いてUIを表示する前に AEInteractWithUser() を呼び出す必要があり、ASOCのScriptも仕様として明記されてはいないが同じ操作をする必要がある。

たとえばScriptがosascript(Terminal上で呼び出すshellコマンド)から呼び出される場合はこのケースに該当する。この場合にはAppKitはAEInteractWithUser()が呼び出されるまでは完全には初期化が完了しない。

Standard Addition内のdisplay dialogなどのコマンド(ダイアログ表示UIを表示する)では、実際にAEInteractWithUser()を呼び出しており、これによって問題なくUIを表示している。」

サンプルとして提示されたScriptがなかなか衝撃的。use framework “Carbon” なんて見たことがありません。つーか、Carbon呼べたのかAppleScript!(^ー^;;;

実際に、NSTableViewを生成してデータ表示させるAppleScriptにこの記述を追加したら、実にスムースにキーボードフォーカスを受け付けました。

また、これまで何回か繰り返すとScript Editorごとクラッシュしていた処理(Windowとプログレスバーとボタンを生成してプログレス表示)についても、10数回繰り返したぐらいではクラッシュしなくなりました。原因はこれか、これなのか(^ー^;;

UIを表示する側のライブラリなりルーチンなりにAEInteractWithUser()の呼び出しが必要ということではなく、AppKit frameworkの初期化を完全に行うために最初に1回実行しておく、という話のようです。

これが、OS X 10.12でも同様の記述を行う必要があるのか、それともOS X 10.12上のAppleScript v2.6ではこの処理を実行時に(処理系側で)行っておくようにするのか、まだわかりませんが・・・たぶん、後者の対応になるものと見ています。

AppleScript名:UIを動的に生成する際にはCarbonを呼べ
– Created 2016-01-27 by Chris Page@Apple
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit” – NSAlert is in AppKit
use framework “Carbon” – AEInteractWithUser() is in Carbon

if current application’s AEInteractWithUser(-1, missing value, missing value) = 0 then – -1 is kAEDefaultTimeout
  activate
  
current application’s NSAlert’s new’s runModal()
end if

★Click Here to Open This Script 

2016/01/26 Cocoa勉強会関西に行ってきました!

先週末、大阪で行われた「Cocoa勉強会関西」に行ってきました。まーー、会場が大阪駅から近いこと近いこと。設備もたいへんにデラックスな会場で、

「設備がよすぎて、話をするのに慣れずにビビる」

という状態。ペースをつかむのに難儀しましたがなんとか(ちょっと時間をオーバーしてしまいましたが、、、)。

keynote.jpg

発表されているスピーカーの方々もバリエーションに富んでおり、また、日常的に自分が見ていない分野の話も聞くこともできて、たいへん刺激を受けました。

機会があれば、ぜひまた参加させていただきたいと思います。

Keynoteの資料は喫茶店などでこもって作っていきましたが、ほとんど実際にAppleScriptをうごかしたり、参加者の方とお話をしたりして、事前に予定していたようなこんな(↓)シンプルな内容には収まりませんでした(すんません)。

とくに、US Appleの開発者系Mailing Listのほぼすべてを購読しており、それらの話題を整理するためのAppleScriptロボット(メールボックスを掘っておくと勝手にメールを再振り分けしてくれるロボット)の紹介とか、「戦場の絆」リプレイムービーへのアクセス用キーフレーズの画面を撮影した写真からGPS情報を取得して画像加工したあとOCRで文字認識させるなどのAppleScriptを実際に見ていただきました。

keynote001.jpeg

keynote002.jpeg

keynote003.jpeg

keynote004.jpeg

keynote005.jpeg

keynote006.jpeg

keynote007.jpeg

keynote008.jpeg

keynote009.jpeg

keynote010.jpeg

2016/01/21 iMovie v10.1.1にAppleScript用語辞書がついていますが

iMovie 10.1.1アップデートがリリースされ、さまざまな機能が追加されました。

Script Editorで確認するとAppleScript用語辞書が表示され、一見すると中にいろいろ定義されているように見えますが・・・実際のところ、この内容ではアプリケーションの起動と終了、あるいはバージョン番号の確認ぐらいしか行えないため、このレベルで「AppleScript対応である」とは言えません。

imovie_icon.png

imovie2.png

以前から、Apple純正のアプリケーションでAppleScript対応機能を用意していないのに、意味のないAppleScript用語辞書を入れてあるものが見られ(例:iBooks Author)、とくに初心者がだまされるため注意が必要です。

AppleScript名:iMovie 10.1.1の無意味な用語辞書でできること
tell application "iMovie"
  properties
  
–> {frontmost:false, class:application, name:"iMovie", version:"10.1.1"}
  
set wCount to count every window
  
–> 3
  
  
set dCount to count every document
  
–> 1
  
  
tell document 1
    properties
    
–> {modified:false, path:"/Users/me/Movies/iMovie ライブラリ.imovielibrary", class:document, name:"iMovie ライブラリ"}
  end tell
end tell

★Click Here to Open This Script 

2016/01/18 2つの日付の期間を日本語表記でていねいに返す

Pure AppleScriptで、与えられた2つの日付から開始日–>終了日の期間を示す文字列を組み立てて返すAppleScriptです。

Pure AppleScriptのdate objectを利用しているので、localeとかカレンダーの時間帯は一切考慮していません。

OS標準のNSDateIntervalFormatterのJapanese(JST)localeにおける処理があまりにも「そりゃないよ」というレベルだったので、ちょっと書いてみました。

場合によっては曜日の併記を求められるケースがあるでしょうし、これがそのまますべてのケースにおいて使えるわけではないとは思いますが、世間一般的にはこのぐらいはしてほしい気がします。

AppleScript名:2つの日付の期間を日本語表記でていねいに返す
– Created 2016-01-17 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–Date Difference
set sDate to "2016/1/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/1/20" –Japanese Date format "YYYY/MM/DD"
set aDiffStr to retDateDiffStr(sDate, eDate, "/", "/", "", "〜") of me
–> "2016/1/15〜20"

–Month Difference
set sDate to "2016/1/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/2/20" –Japanese Date format "YYYY/MM/DD"
set bDiffStr to retDateDiffStr(sDate, eDate, "年", "月", "日", "〜") of me
–> "2016年1月15日〜2月20日"

–Year Difference
set sDate to "2015/12/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/1/20" –Japanese Date format "YYYY/MM/DD"
set bDiffStr to retDateDiffStr(sDate, eDate, "年", "月", "日", "〜") of me
–> "2015年12月15日〜2016年1月20日"

–2つの日付の期間を日本語表記でていねいに返す
on retDateDiffStr(sDate, eDate, ySeparator, mSeparator, dSeparator, diffSeparator)
  
  
set sDateO to date sDate
  
set eDateO to date eDate
  
  
set diffY to (year of eDateO) - (year of sDateO)
  
set diffM to (month of eDateO) - (month of sDateO)
  
set diffD to (day of eDateO) - (day of sDateO)
  
  
set sYstr to (year of sDateO) as string
  
set sMstr to (month of sDateO as number) as string
  
set sDstr to (day of sDateO) as string
  
  
set eYstr to (year of eDateO) as string
  
set eMstr to (month of eDateO as number) as string
  
set eDstr to (day of eDateO) as string
  
  
if diffY > 0 then
    –Year Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & dSeparator & diffSeparator & eYstr & ySeparator & eMstr & mSeparator & eDstr & dSeparator
  else if diffM > 0 then
    –Month Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & dSeparator & diffSeparator & eMstr & mSeparator & eDstr & dSeparator
  else if diffD > 0 then
    –Date Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & diffSeparator & eDstr & dSeparator
  end if
  
  
return outStr
  
end retDateDiffStr

★Click Here to Open This Script 

2016/01/14 ローカライズドな期間表記

Cocoaの機能を用いて、ローカライズされた(英語、日本語などの言語環境を考慮した)期間表示を行うAppleScriptです。

それほど気の利いた表記をしてくれるわけではないのと、日本語環境だとShortでもMidiumでもLongでも表記内容が変わりません。

  2016/1/14〜27

のように、開始日と修了日の年や月に変更がなければ、それを記載しないといった「気の利かせ方」を発揮していただきたいものであります。

AppleScript名:ASOCでローカライズドな期間表記
– Created 2016-01-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Date Interval

set engNSDateIntervalFormatter to current application’s NSDateIntervalFormatter’s alloc()’s init()
engNSDateIntervalFormatter’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“en-US”)
engNSDateIntervalFormatter’s setDateStyle:(current application’s NSDateIntervalFormatterLongStyle)
engNSDateIntervalFormatter’s setDateTemplate:(current application’s NSDateFormatter’s alloc()’s init()’s setDateFormat:“yyyy-MM-dd HH:mm”)
engNSDateIntervalFormatter’s setTimeStyle:(current application’s NSDateIntervalFormatterNoStyle)
engNSDateIntervalFormatter’s setTimeZone:(current application’s NSTimeZone’s timeZoneWithAbbreviation:“JST”)
engNSDateIntervalFormatter’s setCalendar:(current application’s NSCalendar’s currentCalendar())

set startDate to current application’s NSDate’s |date|()
set endDate to current application’s NSDate’s dateWithTimeInterval:86400 sinceDate:startDate
set outEString to (engNSDateIntervalFormatter’s stringFromDate:startDate toDate:endDate) as string
–>  ”1/14/16 - 1/15/16″–ShortStyle
–>  ”Jan 14 - 15, 2016″–Medium Style
–>  ”January 14 - 15, 2016″–Long Style
–>  ”Thursday, January 14 - Friday, January 15, 2016″–Full Style

set jpnNSDateIntervalFormatter to current application’s NSDateIntervalFormatter’s alloc()’s init()
jpnNSDateIntervalFormatter’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“ja”)
jpnNSDateIntervalFormatter’s setDateStyle:(current application’s NSDateIntervalFormatterFullStyle)
jpnNSDateIntervalFormatter’s setDateTemplate:(current application’s NSDateFormatter’s alloc()’s init()’s setDateFormat:“yyyy-MM-dd HH:mm”)
jpnNSDateIntervalFormatter’s setTimeStyle:(current application’s NSDateIntervalFormatterNoStyle)
jpnNSDateIntervalFormatter’s setTimeZone:(current application’s NSTimeZone’s timeZoneWithAbbreviation:“JST”)
jpnNSDateIntervalFormatter’s setCalendar:(current application’s NSCalendar’s currentCalendar())

set startDate to current application’s NSDate’s |date|()
set endDate to current application’s NSDate’s dateWithTimeInterval:86400 sinceDate:startDate
set outJString to (jpnNSDateIntervalFormatter’s stringFromDate:startDate toDate:endDate) as string
–>  ”2016/01/14〜2016/01/15″–ShortStyle
–>  ”2016/01/14〜2016/01/15″–Medium Style
–>  ”2016/01/14〜2016/01/15″–Long Style
–>  ”2016/01/14(木曜日)〜2016/01/15(金曜日)”–Full Style

★Click Here to Open This Script 

2016/01/14 ローカライズドな度量衡表示(エネルギー)

Cocoaの機能を用いて、ローカライズされた(英語、日本語などの言語環境を考慮した)度量衡の表示を行うAppleScriptです。

「カロリー」の定義(算出方法)がいろいろあるので、「熱力学カロリー」と明記するのはけっこうなことだと思いますが、一般的にはそこまで厳密に表記しないのでちょっと違和感があります。

このあたり、ローカライズの下請けを行っているLocTeamが先走ってしまったのではないかと思われます。

AppleScript名:ASOCでローカライズドな度量衡表示(エネルギー)
– Created 2015-11-20 by Shane Stanley
– Modified 2016-01-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Energy

set engEFormatter to current application’s NSEnergyFormatter’s alloc()’s init()
engEFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“en-US”)
engEFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong)

engEFormatter’s setForFoodEnergyUse:true
set a1Res to (engEFormatter’s stringFromJoules:85) as string
–>  ”20.315 calories”

engEFormatter’s setForFoodEnergyUse:false
set a1Res to (engEFormatter’s stringFromJoules:85) as string
–>  ”20.315 calories”

set a2Res to (engEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitJoule)) as string –joule
–>  ”1 joule”
set a3Res to (engEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitKilojoule)) as string –k joule
–>  ”1 kilojoule”
set a4Res to (engEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitCalorie)) as string –Cal
–>  ”1 calorie”
set a5Res to (engEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitKilocalorie)) as string –K Cal
–>  ”1 kilocalorie”

set jpnEFormatter to current application’s NSEnergyFormatter’s alloc()’s init()
jpnEFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“ja”)
jpnEFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong)

jpnEFormatter’s setForFoodEnergyUse:true
set j1Res to (jpnEFormatter’s stringFromJoules:85) as string
–>  ”85ジュール”

jpnEFormatter’s setForFoodEnergyUse:false
set j1Res to (jpnEFormatter’s stringFromJoules:85) as string
–>  ”85ジュール”

set j2Res to (jpnEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitJoule)) as string –joule
–>  ”1ジュール”
set j3Res to (jpnEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitKilojoule)) as string –k joule
–>  ”1キロジュール”
set j4Res to (jpnEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitCalorie)) as string –Cal
–>  ”1熱力学カロリー”
set j5Res to (jpnEFormatter’s stringFromValue:1 unit:(current application’s NSEnergyFormatterUnitKilocalorie)) as string –K Cal
–>  ”1キロカロリー”

★Click Here to Open This Script 

2016/01/14 ローカライズドな度量衡表示(重さ)

Cocoaの機能を用いて、ローカライズされた(英語、日本語などの言語環境を考慮した)度量衡の表示を行うAppleScriptです。

重さについては、トン(t=1,000kg)がないのと細かい方の単位(mgとかμgとか)がないのはいかがなものかと。

日本国内では日常的には「ストーン」という単位は使わないので、「何の石かな?」と思ってしまうところです。

AppleScript名:ASOCでローカライズドな度量衡表示(重さ)
– Created 2015-11-20 by Shane Stanley
– Modified 2016-01-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Weight

set engMFormatter to current application’s NSMassFormatter’s alloc()’s init()
engMFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“en-US”)
engMFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong) –NSFormattingUnitStyleShort, NSFormattingUnitStyleMedium, NSFormattingUnitStyleLong

set a1Res to (engMFormatter’s stringFromKilograms:85) as string –Kg
–>  ”187.393 pounds”
set a2Res to (engMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitGram)) as string –g
–>  ”1 gram”
set a3Res to (engMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitOunce)) as string –オンス
–>  ”1 ounce”
set a4Res to (engMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitStone)) as string –ストーン(=14 pounds)
–>  ”1 stone”

set jpnMFormatter to current application’s NSMassFormatter’s alloc()’s init()
jpnMFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“ja”)
jpnMFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong) –NSFormattingUnitStyleShort, NSFormattingUnitStyleMedium, NSFormattingUnitStyleLong

set j1Res to (jpnMFormatter’s stringFromKilograms:85) as string –Kg
–>  ”85キログラム”
set j2Res to (jpnMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitGram)) as string –g
–>  ”1グラム”
set j3Res to (jpnMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitOunce)) as string –オンス
–>  ”1オンス”
set j4Res to (jpnMFormatter’s stringFromValue:1 unit:(current application’s NSMassFormatterUnitStone)) as string –ストーン(=14 pounds)
–>  ”1ストーン

★Click Here to Open This Script 

2016/01/14 ローカライズドな度量衡表示(長さ)

Cocoaの機能を用いて、ローカライズされた(英語、日本語などの言語環境を考慮した)度量衡の表示を行うAppleScriptです。

AppleScript名:ASOCでローカライズドな度量衡表示(長さ)
– Created 2015-11-20 by Shane Stanley
– Modified 2016-01-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Length

set engLFormatter to current application’s NSLengthFormatter’s alloc()’s init()
engLFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“en-US”)
engLFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong) –NSFormattingUnitStyleShort, NSFormattingUnitStyleMedium, NSFormattingUnitStyleLong

set a1Res to (engLFormatter’s stringFromMeters:85) as string –m
–>  ”92.956 yards”
set a2Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMillimeter)) as string –mm
–>  ”1 millimeter”
set a3Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitCentimeter)) as string –cm
–>  ”1 centimeter”
set a4Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMeter)) as string –m
–>  ”1 meter”
set a5Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitKilometer)) as string –Km
–>  ”1 kilometer”
set a6Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitInch)) as string –inch
–>  ”1 inch”
set a7Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitFoot)) as string –feet
–>  ”1 foot”
set a8Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitYard)) as string –Yard
–>  ”1 yard”
set a9Res to (engLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMile)) as string –Mile
–>  ”1 mile”

set jpnLFormatter to current application’s NSLengthFormatter’s alloc()’s init()
jpnLFormatter’s numberFormatter()’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:“ja”)
jpnLFormatter’s setUnitStyle:(current application’s NSFormattingUnitStyleLong) –NSFormattingUnitStyleShort, NSFormattingUnitStyleMedium, NSFormattingUnitStyleLong

set j1Res to (jpnLFormatter’s stringFromMeters:85) as string –m
–>  ”85メートル”
set j2Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMillimeter)) as string –mm
–>  ”1ミリメートル”
set j3Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitCentimeter)) as string –cm
–>  ”1センチメートル”
set j4Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMeter)) as string –m
–>  ”1メートル”
set j5Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitKilometer)) as string –Km
–>  ”1キロメートル”
set j6Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitInch)) as string –inch
–>  ”1インチ”
set j7Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitFoot)) as string –feet
–>  ”1フィート”
set j8Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitYard)) as string –Yard
–>  ”1ヤード”
set j9Res to (jpnLFormatter’s stringFromValue:1 unit:(current application’s NSLengthFormatterUnitMile)) as string –Mile
–>  ”1マイル”

★Click Here to Open This Script 

2016/01/12 Cocoa勉強会関西にて発表を

2016/1/23(土)に大阪梅田 グランフロント大阪にて行われる「Cocoa勉強会関西」にて「AppleScriptから使うCocoaの世界」と題して、AppleScriptObjCについていろいろ発表してこようと思います(13:35〜14:05の30分)。

Objective-CとSwiftのプログラマーが揃っている前でまったく異なる言語の内容を発表するとどうなるのか? はたして、、、

Cocoa勉強会については存在および活動内容は存じ上げておりましたが、AppleScript自体があまりCocoaそのものと接点がなかったので参加自体を考えたことがありませんでした。

しかし時代は流れ、OS X 10.10でAppleScript-Cocoa Scripting Bridgeが標準搭載に。通常のAppleScriptでもCocoaの機能呼び出しが常態化するなど、もはやCocoaとAppleScriptは切っても切れない関係です。

だいたいは、本Blogに掲載した内容の紹介になると思います。関西方面でASOCに興味のある方はぜひご参加ください(参加無料。要事前登録)。

→ 参加ページ

2016/01/10 レコードのリストからラベル値のみ抽出してユニーク化してソート v2

Cocoaの機能を用いて、レコードのリストからラベル値のみ抽出して、ユニーク化してソートして返すAppleScriptです。

Shane Stanleyから指摘があって、「そこもっと短くかけるよ〜」ということで、大幅に短くなりました(Thanks !!)。NSMutableSetを使うのは、とってもいい方法だと思います。

AppleScript名:レコードのリストからラベル値のみ抽出してユニーク化してソート v2
– Created 2016-01-08 by Takaaki Naganoya
– Modified 2016-01-08 by Shane Stanley (retEveryKeys)
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aDic to {{field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field2:"test 29"}, {field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field3:"test 29"}}

set theDataSource to current application’s NSMutableArray’s arrayWithArray:aDic
set kList to retEveryKeys(theDataSource) of me
–>  {"field1", "field2", "field3"}

–リストになったRecordのすべてのアイテムのkey値を取得してユニーク化してソートして返す
on retEveryKeys(aDic)
  set tempSet to current application’s NSMutableSet’s |set|()
  
repeat with aDict in aDic
    (tempSet’s addObjectsFromArray:(aDict’s allKeys()))
  end repeat
  
return (tempSet’s allObjects()’s sortedArrayUsingSelector:"compare:") as list
end retEveryKeys

★Click Here to Open This Script 

2016/01/08 レコードのリストからラベル値のみ抽出してユニーク化してソート

Cocoaの機能を用いて、レコードのリストからラベル値のみ抽出して、ユニーク化してソートして返すAppleScriptです。

AppleScript名:レコードのリストからラベル値のみ抽出してユニーク化してソート
– Created 2016-01-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aDic to {{field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field2:"test 29"}, {field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field3:"test 29"}}

set theDataSource to current application’s NSMutableArray’s arrayWithArray:aDic
set kList to retEveryKeys(theDataSource) of me
–>  {"field1", "field2", "field3"}

–リストになったRecordのすべてのアイテムのkey値を取得してユニーク化してソートして返す
on retEveryKeys(aDic)
  set aLen to aDic’s |count|()
  
set tmpKeys to {}
  
  
repeat with i from 0 to (aLen - 1)
    set aRec to (aDic’s objectAtIndex:i)
    
set keyList to (aRec’s allKeys()) as list
    
set tmpKeys to tmpKeys & keyList
  end repeat
  
  
set aRes to uniquifyAndSort1DList(tmpKeys, true) of me
  
return aRes
end retEveryKeys

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
  
set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
  
set bList to cArray as list
  
return bList
end uniquifyAndSort1DList

★Click Here to Open This Script 

2016/01/07 テーブルビューを表示

Cocoaの機能を用いて、NSTableViewを表示するAppleScriptです。

asoctable.png

Xcode上のAppleScriptでNSTableViewを表示するプログラムを書くのなら、片手間でできるぐらい簡単ですが、通常のScript Editor上でプログラマティカルに100%AppleScriptから作ろうとすると、ものすごく苦労させられました。

Mac上ではXcode+InterfaceBuilderによるGUIツールによる開発が推奨されており、このようにプログラムからGUI部品を生成するケースはあまり見られません。ゆえに、たいへんに調査に苦労させられたわけですが(足掛け2か月以上かかってます)、表示してしまうとけっこうあっけないものです。

本Scriptの実行には、Script Editor上でControl-Command-Rの操作で行ってください。

AppleScript名:ASOCでテーブルビューを表示
– Created 2016-01-07 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

property theDataSource : {}

set aWidth to 300
set aHeight to 300

set aTitle to “NSTableView Test”

set aScroll to current application’s NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
set aView to current application’s NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))

set aColumn to current application’s NSTableColumn’s alloc()’s initWithIdentifier:“field1″
set bColumn to current application’s NSTableColumn’s alloc()’s initWithIdentifier:“field2″
aColumn’s setWidth:150
bColumn’s setWidth:150

aColumn’s headerCell()’s setStringValue:“field1″
bColumn’s headerCell()’s setStringValue:“field2″

aView’s addTableColumn:aColumn
aView’s addTableColumn:bColumn

set aDic to {{field1:“test 10″, field2:“test 20″}, {field1:“test 11″, field2:“test 21″}, {field1:“test 12″, field2:“test 22″}, {field1:“test 13″, field2:“test 23″}, {field1:“test 14″, field2:“test 24″}, {field1:“test 15″, field2:“test 25″}, {field1:“test 16″, field2:“test 26″}, {field1:“test 17″, field2:“test 27″}, {field1:“test 18″, field2:“test 28″}, {field1:“test 19″, field2:“test 29″}, {field1:“test 10″, field2:“test 20″}, {field1:“test 11″, field2:“test 21″}, {field1:“test 12″, field2:“test 22″}, {field1:“test 13″, field2:“test 23″}, {field1:“test 14″, field2:“test 24″}, {field1:“test 15″, field2:“test 25″}, {field1:“test 16″, field2:“test 26″}, {field1:“test 17″, field2:“test 27″}, {field1:“test 18″, field2:“test 28″}, {field1:“test 19″, field2:“test 29″}}

set theDataSource to current application’s NSMutableArray’s alloc()’s init()
theDataSource’s addObjectsFromArray:aDic

–aView’s setDataSource:theDataSource
–aView’s reloadDataForRowIndexes:1 columnIndexes:1

–aView’s setDelegate:me
aView’s setDataSource:me
–aView’s reloadData()

aScroll’s setDocumentView:aView
aView’s enclosingScrollView()’s setHasVerticalScroller:true

set aWin to makeWinWithView(aScroll, aWidth, aHeight, aTitle, 1.0)
–aWin’s makeKeyAndOrderFront:(missing value)
–aWin’s makeFirstResponder:aView

–NSWindowControllerを作ってみた
set wController to current application’s NSWindowController’s alloc()
wController’s initWithWindow:aWin

wController’s showWindow:me

delay 5
my closeWin:aWin

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to current application’s NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to current application’s NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
aWin’s setBackgroundColor:(current application’s NSColor’s whiteColor())
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(current application’s NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
aWin’s makeKeyAndOrderFront:(me)
  
  
– Set Custom View
  
aWin’s setContentView:aView
  
  
return aWin
  
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set aRec to (my theDataSource)’s objectAtIndex:(aRow as number)
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle)
  
return aRes
end tableView:objectValueForTableColumn:row:

★Click Here to Open This Script 

2016/01/07 OSAScriptViewでAppleScriptをソース取得&コンパイルして書式付きでPDF出力

Cocoaの機能を用いて、指定のAppleScriptのソースを取得して、再度OSAScriptView上でコンパイル(構文確認)を行い、構文色分けを反映させたスタイルつきのPDFとして出力するAppleScriptです。

わかりにくいですが、AppleScriptの書類をPDF出力するAppleScriptです(正確に書けば書くほどわからなくなるのはなぜだろう)。デスクトップフォルダ上に元Scriptのファイル名でPDF出力します。

script1.png
▲出力対象のAppleScript書類

scriptpdf.png
▲上記書類をPDF出力したもの

PDF出力部分は、指定URLの内容を1枚モノのPDFに書き出すAppleScriptを書いた際に利用した記述そのままです。ページネーションは一切していないため、こういう用途ではページネーション指定をしてPDF出力したほうがよいかもしれません。

AppleScriptのパスだけ与えれば、あとはGUIアプリの機能は利用していないため、大量データの並列処理に適した構造になっています。

「なんでこんなもの作ったの?」と聞かれましたが、結局「これじゃない何か」を作ろうとして、その途中経過ができたものなので、本Scriptは本当に作りたいものの副産物です。

AppleScript名:OSAScriptViewでAppleScriptをソース取得&コンパイルして書式付きでPDF出力
– Created 2016-01-07 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “OSAKit”
use framework “AppKit”
use framework “Quartz”

set targX to 1024 –PDF Width
set targY to 2048 –PDF Height

–Select & Read AppleScript Source (Only Editable AppleScripts are available)
set aScriptAlias to (choose file with prompt “Choose AppleScript to convert to PDF” of type {“com.apple.applescript.script-bundle”, “com.apple.applescript.script”})

set srcStr to getASsourceFor(aScriptAlias) of me
if srcStr = missing value or srcStr = “” then
  –Error
  
display dialog “Error in reading script source….” buttons {“OK”} default button 1 with icon 1
  
return
end if

–Making PDF Out Path from source script file name
set outName to getFileNameFromAlias(aScriptAlias) of me
set outFol to POSIX path of (path to desktop)
set outPath to outFol & outName
set pathString to current application’s NSString’s stringWithString:outPath
set newPath to pathString’s stringByDeletingPathExtension()
set pdfOutPath to newPath’s stringByAppendingPathExtension:“pdf”

–Compile AppleScript
set osaCon to current application’s OSAScriptController’s alloc()’s init()
set osaView to current application’s OSAScriptView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, targX, targY))
osaCon’s setScriptView:osaView
osaView’s setString:srcStr
osaCon’s compileScript:(missing value) –Compile(構文確認)

–Make Print into PDF
set aPrintInfo to current application’s NSPrintInfo’s sharedPrintInfo()
set newPrintOp to current application’s NSPrintOperation’s PDFOperationWithView:(osaView) insideRect:(current application’s NSMakeRect(0, 0, targX, targY)) toPath:pdfOutPath printInfo:aPrintInfo

set runPrint to newPrintOp’s runOperation()
return (runPrint as boolean)

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
– Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set anHFSpath to anAlias as string
  
set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anHFSpath)
  
set theScript to current application’s OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
return theScript’s source() as text
end getASsourceFor

–指定のAliasからファイル名を取得する
on getFileNameFromAlias(anAlias)
  set aPath to POSIX path of anAlias
  
set pathString to current application’s NSString’s stringWithString:aPath
  
set newPath to pathString’s lastPathComponent()
  
return newPath as string
end getFileNameFromAlias

★Click Here to Open This Script 

2016/01/07 OSAScriptController+OSAScriptViewでAppleScriptを実行

Cocoaの機能を用いて、OSAScriptController+OSAScriptViewの組み合わせでAppleScriptのテキストを実行するAppleScriptです。

osascriptexe.png

AppleScriptの動的生成(テキストを組み立ててコンパイル(構文確認)してAppleScriptにして)+実行については、

 (1)AppleScriptのコマンドrun scriptで実行するもの
 (2)shellのosascriptコマンドで実行するもの
 (3)OSAScriptのinitWithSource: compileAndReturnError:メソッドで実行するもの

ぐらいが定番でしょうか。文法的に無茶なことを実現(recordの動的生成など)するために、昔から使われてきたブラックテクノロジー(セキュリティ的に穴になりそうな無茶な処理)です。

#  recordの動的生成については、OS X 10.10から通常のAppleScriptでもCocoaの機能が普通に呼び出せるようになったので、NSDictionaryを作成してrecord生成できます。正規表現なども普通に使えるようになったので、かつての「常識」が根底から変わってきています

で、なんでOSAScriptController+OSAScriptViewとかいう「自分流Script Editorを作る部品」を引っ張り出してきたかといえば、

 AppleScriptを直接PDF化したい(書式つきで)

ような場合に、OSAScriptViewからリッチテキストを取得して、RTF、HTML、PDFなどに変換するような処理ができると考えたからです。まっとうに考えれば、Script EditorをAppleScriptでコントロールして書き出すあたりになりますが、それだと並列処理できませんので。

並列処理実行できるように、このような部品を使ってみた次第です。

AppleScript名:OSAScriptViewでAppleScriptを実行
– Created 2016-01-07 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “OSAKit”
use framework “AppKit”

set srcStr to current application’s NSMutableString’s stringWithString:“display dialog \”OSAScript TEST\”"

set osaCon to current application’s OSAScriptController’s alloc()’s init()
–>  (OSAScriptController) <OSAScriptController: 0×7ff7240ae190>

set osaView to current application’s OSAScriptView’s alloc()’s init()

osaCon’s setScriptView:osaView
osaView’s setString:srcStr
–osaCon’s compileScript:(missing value)
osaCon’s runScript:(missing value)

–set aRT to osaView’s

★Click Here to Open This Script