Archive for 11月, 2014

2014/11/27 10.10でプリンタの情報を取得する

ASOCでCocoaの機能を呼び出してプリンタの情報を取得するAppleScriptです。

NSPrinterのドキュメントをながめつつ、いろいろ突っついてみていますが・・・Deprecatedだと書かれている機能がまだ呼び出せるようで、プリンターがカラーかどうか、紙排出時に逆方向に(裏面?)出せるかなど調べられるようです。

AppleScript名:10.10でプリンタの情報を取得する
– Created 2014-11-27 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit”

–Get Printer Names
set pArray to current application’s NSPrinter’s printerNames
set pList to (pArray’s ASify()) as list
–> {”KING JIM TEPRA PRO SR3700P”, “NEC MultiWriter 5750C @ MBA13″, “PDFwriter”, “PM-T960-1″}

–Get Printer Type (Driver Name?)
set tArray to current application’s NSPrinter’s printerTypes
set tList to (tArray’s ASify()) as list
–> {”TEPRA PRO SR3700P”, “NEC MultiWriter 5750C v2.4″, “Lisanet PDFwriter”, “EPSON PM-T960″}

set colorPinterList to {}

repeat with i in pList
  set j to contents of i
  
  
–Is it a Printer?
  
set aPrinter to (current application’s NSPrinter’s printerWithName:j)
  
set aDesc to aPrinter’s deviceDescription
  
set aRec to aDesc’s ASify() as record
  
–> {NSDeviceIsPrinter:”YES”}
  
  
  
–Is it a Color Printer?
  
set aColor to (aPrinter’s isColor()) as boolean –isColor() deprecated? It works
  
if aColor = true then
    set the end of colorPinterList to j
  end if
  
end repeat

colorPinterList
–> {”NEC MultiWriter 5750C @ MBA13″, “PDFwriter”, “PM-T960-1″}

★Click Here to Open This Script 

2014/11/27 10.10でプリンタを選択して印刷

ASOCで、現在Macに接続されているプリンターの名称一覧を取得して、印刷を行うサンプルです。

一般的なアプリケーションでの印刷を意図しており、InDesignなどのAdobe系アプリケーションを意図しているものではありません(仕組みや機能が全然別物)。

LAN上で共有されているプリンター(”NEC MultiWriter 5750C @ MBA13”)を指定してみたところ、問題なく印刷できました。

プリンタ名称については、lpstatコマンドで取得した名称一覧とは返ってくる文字列が違う(”NEC_MultiWriter_5750C___MBA13”)のですが、、、どちらでも問題ありませんでした。

AppleScript名:10.10でプリンタを選択して印刷
– Created 2014-11-27 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit”

set pArray to current application’s NSPrinter’s printerNames
set pList to (pArray’s ASify()) as list
–> {”KING JIM TEPRA PRO SR3700P”, “NEC MultiWriter 5750C @ MBA13″, “PDFwriter”, “PM-T960-1″}

set aPrinter to first item of (choose from list pList with prompt “出力先のプリンタを選択してください”)

tell application “Safari”
  tell front document
    set aPrintSetting to {copies:1, starting page:1, ending page:9999, target printer:aPrinter}
    
print with properties aPrintSetting without print dialog
  end tell
end tell

★Click Here to Open This Script 

2014/11/26 1D Listを文字列長でソート v2

1D Listの文字列長によるソートの改良版です。文字列長に着目してソートする場合には、同一長の文字列がソートされている必要はとくにないのですが、同一文字列長の場合にソートを行っています。

1D Listの文字列長ソートを掲載していたら、Shane Stanleyからツッコミが。

「それ、間違いじゃないけど文字列長でソートして、同時に(文字の)ソート順を指定しておいた方がいいよ(意訳)」

たしかに。文字列長でソートする用途しか考えていなかったので、文字列順でソートされていることは重視していませんでしたが、文字列順にソートされていた方がいい感じです。

文字列長でソートする用途というのは・・・Mail.appでSubjectに含まれるキーワードでサブフォルダに仕分けを行うさいに、文字列の長いものを優先して(長い→短い の順に)フォルダとの照合を行うロジックをAppleScriptで作って(&使って)いるためです。

このロジックを使用しているため、「Mountain Lion」のほうが「Lion」よりも優先して処理されることになり、(ほぼ)思い通りの処理をおこなえています。

US AppleがホスティングしているMailing Listにほぼすべて入っており(いくつか、US現地の教育関係者と政府関係者しか入れないMLからは丁重に追い出されましたが)、MLのログをこのようにキーワードごとに細分化したサブフォルダ(複数キーワードをカンマで区切って、類義語を列挙する仕様)に再振り分けしています。

mails.png

AppleScript名:1D Listを文字列長でソート v2
– Created 2014-11-25 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {“Apple”, “Orange”, “Banana”, “Meron”, “Strawberry”, “Lemon”, “Takaaki Naganoya”, “Piyomaru Software”}
set bList to sort1DListByStringLength(aList as list, true) of me –昇順
–> {”Apple”, “Meron”, “Lemon”, “Orange”, “Banana”, “Strawberry”, “Takaaki Naganoya”, “Piyomaru Software”}–v1
–> {”Apple”, “Lemon”, “Meron”, “Banana”, “Orange”, “Strawberry”, “Takaaki Naganoya”, “Piyomaru Software”}–v2

set cList to sort1DListByStringLength(aList as list, false) of me –降順
–> {”Piyomaru Software”, “Takaaki Naganoya”, “Strawberry”, “Orange”, “Banana”, “Apple”, “Meron”, “Lemon”}–v1
–> {”Piyomaru Software”, “Takaaki Naganoya”, “Strawberry”, “Banana”, “Orange”, “Apple”, “Lemon”, “Meron”}–v2

–1D Listを文字列長でソート v2
on sort1DListByStringLength(aList as list, sortOrder as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set desc1 to current application’s NSSortDescriptor’s sortDescriptorWithKey:“length” ascending:sortOrder
  
set desc2 to current application’s NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:true selector:“localizedCaseInsensitiveCompare:”
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
set bList to (bArray’s ASify()) as list
  
return bList
end sort1DListByStringLength

★Click Here to Open This Script 

2014/11/25 1D Listをユニーク化してソート

1D Listをユニーク化してソートするAppleScriptです。

以前に、いろいろ1D Listのユニーク化の方法について検討していましたが、処理後のソート状態が「不定」であるため、決め手に欠けるみたいな話になっていました。

ただ、ソート状態が「不定」なら、明示的にソートすればいいだけの話で、そのように処理を足してやりました。

AppleScript名:1D Listをユニーク化してソート
– Created 2014-11-25 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set aList to {100, 10, 1, 90, 300, 300}

set aRes to uniquifyAndSort1DList(aList, true)
–> {1, 10, 90, 100, 300}

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList as list, 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’s ASify()) as list
  
  
return bList
end uniquifyAndSort1DList

★Click Here to Open This Script 

2014/11/25 1D Listを文字列長でソート

文字列だけで構成された1D Listを、各要素の文字列の長さに注目してソートするAppleScriptです。

以前に作成したルーチンのASOC版です。ただ・・・一般的には1D Listだけで処理するなんてことはほとんどなく、いくつかのデータを一緒にした2D Listで処理することになります。

2D Listの文字列長ソートも書いて(掲載しかけ)たのですが、ASObjCExtras.frameworkが2D Listのソート時に「length」でのソートをサポートしていないことがFrameworkのヘッダーファイルに書いてあったので、おクラ入りしました。残念!

AppleScript名:1D Listを文字列長でソート
– Created 2014-11-25 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {“Apple”, “Orange”, “Banana”, “Meron”, “Strawberry”, “Lemon”, “Takaaki Naganoya”, “Piyomaru Software”}
set bList to sort1DListByStringLength(aList as list, true) of me –昇順
–> {”Apple”, “Meron”, “Lemon”, “Orange”, “Banana”, “Strawberry”, “Takaaki Naganoya”, “Piyomaru Software”}

set cList to sort1DListByStringLength(aList as list, false) of me –降順
–> {”Piyomaru Software”, “Takaaki Naganoya”, “Strawberry”, “Orange”, “Banana”, “Apple”, “Meron”, “Lemon”}

–1D Listを文字列長でソート
on sort1DListByStringLength(aList as list, sortOrder as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aList
  
set descs to current application’s NSArray’s arrayWithObject:(current application’s NSSortDescriptor’s sortDescriptorWithKey:“length” ascending:sortOrder)
  
  
set bArray to aArray’s sortedArrayUsingDescriptors:descs
  
set bList to (bArray’s ASify()) as list
  
return bList
end sort1DListByStringLength

★Click Here to Open This Script 

2014/11/22 Keynote 6.5で各スライドのタイトル、マスタースライド名を取得してデータ化

Keynote 6.5で作成中の書類(開発中のシステムの仕様書)から、各ページタイトルを取得。さらに各スライド(ページ)のマスタースライド名を取得しておいて、目次の文字の大きさに違いをつけようとして、データを作成するAppleScriptの試作品です。

実際に、一般的なアプリケーションであるKeynoteをコントロールしつつ、データ処理をASOCベースのサブルーチンで行わせてみました。

40ページ強あるKeynoteのデータの処理を1秒以下で行えます(MacBook Pro Retina mid 2012)。

また、各スライド(ページ)のマスタースライド名については、出現頻度をカウントし、出現頻度の少ないものが各章のトビラであると仮定して、各タイトルにレベル設定(トビラページは1、通常ページは2)を行っています。

実際に、OmniGraffleではこうした処理(各ページのタイトルを求めて、目次ページを動的に作成してすべての項目に実際のページへのリンクを設定)をすべてAppleScriptで行っていますが(PDFに書き出したときに便利)・・・OmniGraffleで行うよりも、(ユーザーの多い)Keynote上で行えたほうが便利です。

Keynote 6.5もけっこうAppleScript対応機能が向上してきてはいるのですが、たとえばテキストオブジェクトを生成しても・・・左寄せ/センタリング/右寄せを指定できないとか、フォントと文字サイズも設定できないとか(ここはまだ試行錯誤の余地あり)、他のスライド(ページ)へのリンク設定が行えないなど、実践的な処理を記述するためには「いまひとつ」な印象です。

とはいえ、Keynote 6.5のAppleScript用語辞書を見ていると、オブジェクトにScript Labelを(将来的に)設定できるように考えられているなど、楽しみです(グラフ方面は手付かずだったり)。

Keynoteには、早く完全体になってほしいところです(永遠に未完成ということはないと思いたいですが、なかなか進捗しないですね)。

ちなみに、Keynoteへのtellブロック内でcocoaの機能にアクセスするコードを直接書くと、実行時にScript Editorがクラッシュするなどなかなかたいへんでした。ASOCのコードは通常のアプリケーションへのアクセスと分けたほうが得策のようです。

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

property sPage : 3 –1ページ目が表紙、2ページ目が目次として3ページ目以降を処理対象とする

–最前面のドキュメントを取得する
tell application “Keynote”
  set aDocRef to front document
end tell

set tList to retKeynoteSlideTitleFrom(3, aDocRef) of me
–> {”システム概要”, “ハードウェア構成概要”, “ソフトウェア構成概要”,….}

–ドキュメント中の3ページ以降のslideの各マスタースライドの名称を取得して、各マスタースライドの出現頻度を取得して昇順ソート
set bList to retKeynoteSlideBaseSlideNameFrom(sPage, aDocRef) of me
–> {{”タイトル(中央)”, 8}, {”タイトル(上)”, 32}}–{マスタースライド名, 登場頻度カウント}

set {masterList, freqList} to conv2dListTo1dLists(bList) of me
–> {{”タイトル(中央)”, “タイトル(上)”}, {8, 32}}

set tOutList to {}

tell application “Keynote”
  tell aDocRef
    repeat with i from sPage to (count every slide)
      tell slide i
        –Title
        
set aIndex to (i - sPage + 1)
        
set aTitle to contents of item aIndex of tList
        
        
–Base Slide
        
set aBaseName to name of base slide
        
set aLevel to offseOfList(masterList, aBaseName) of me
        
        
set the end of tOutList to {aTitle, aLevel}
        
      end tell
    end repeat
  end tell
end tell

return tOutList
–> {{”システム概要”, 1}, {”ハードウェア構成概要”, 2}, {”ソフトウェア構成概要”, 2}, {”プログラム概要”, 2}, {”プログラム呼称一覧”, 2}, ….}
–1=マスタースライドが”タイトル(中央)”
–2=マスタースライドが “タイトル(上)”

–List中の指定項目の出現位置を返す(複数ヒットした場合には最初の項目番号)。1はじまりのAS仕様のインデックスを使用
on offseOfList(aList, anItem)
  set aResList to (current application’s SMSFord’s indexesOfItem:anItem inArray:(aList) inverting:false) as list
  
set aRes to (first item of aResList)
  
return (aRes + 1)
end offseOfList

–指定ページ(slide)から末尾までの各ページのTitleを取得して返す
on retKeynoteSlideTitleFrom(startPageNum as integer, aDocRef)
  
  
set tList to {}
  
  
try
    –全ページ(slide)のtitleを一括で取得するのが一番高速
    
tell application “Keynote”
      tell aDocRef
        set sCount to count every slide
        
        
if sCount < startPageNum then error
        
if startPageNum < 1 then return {}
        
        
set tList to object text of default title item of every slide
      end tell
    end tell
  on error
    return {}
  end try
  
  
–取得したタイトルから、前後の改行、前後の空白、および途中に入っている改行を削除する
  
set t2List to {}
  
repeat with i in tList
    set j to contents of i
    
set jj to cleanUpText(j) of me
    
set jj to cleanUpCRLF(jj) of me
    
set the end of t2List to jj
  end repeat
  
  
  
  
–一括取得した内容を適宜加工して返すのがベスト
  
set ttList to contents of items startPageNum thru -1 of t2List
  
  
return ttList
  
end retKeynoteSlideTitleFrom

–文字列の前後の改行と空白文字を除去
on cleanUpText(someText)
  set theString to current application’s NSString’s stringWithString:someText
  
set theString to theString’s stringByReplacingOccurrencesOfString:” +” withString:” “ options:(current application’s NSRegularExpressionSearch) range:{location:0, |length|:length of someText}
  
set theWhiteSet to current application’s NSCharacterSet’s whitespaceAndNewlineCharacterSet()
  
set theString to theString’s stringByTrimmingCharactersInSet:theWhiteSet
  
return theString as text
end cleanUpText

–文字置換
on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
set cString to (bString’s ASify()) as string
  
return cString
end repChar

–指定文字列からCRLFを除去
on cleanUpCRLF(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:(string id 10) withString:“” –remove LF
  
set cString to bString’s stringByReplacingOccurrencesOfString:(string id 13) withString:“” –remove CR
  
set dString to (cString’s ASify()) as string
  
return dString
end cleanUpCRLF

–2D Listを1D Listに変換
on conv2dListTo1dLists(aList as list)
  
  
set newList to {}
  
set aLen to length of first item of aList
  
  
repeat aLen times
    set the end of newList to {}
  end repeat
  
  
  
repeat with i in aList
    repeat with ii from 1 to aLen
      set the end of item ii of newList to (item ii of i)
    end repeat
  end repeat
  
  
return newList
  
end conv2dListTo1dLists

–指定ページ(slide)から末尾までの各ページのbase slide名を取得してユニーク化して返す
on retKeynoteSlideBaseSlideNameFrom(startPageNum, aDocRef)
  
  
set aList to {}
  
  
tell application “Keynote”
    tell aDocRef
      set sCount to count every slide
      
if sCount < startPageNum then error
      
      
repeat with i from startPageNum to sCount
        tell slide i
          set aBase to name of base slide
          
set the end of aList to aBase
        end tell
      end repeat
      
    end tell
  end tell
  
  
  
–結果をユニーク化する
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
  
set bList to bArray’s ASify() as list
  
–> {1, 1.1, 2, 3, 4}
  
  
  
–Base Slide名の出現頻度を調べる
  
set cList to {}
  
  
repeat with i in bList
    set aName to contents of i
    
set aCount to countSpecifiedItem(aList, aName) of me
    
set the end of cList to {aName, aCount}
  end repeat
  
  
  
–出現頻度(aCount)をキーにして昇順ソート
  
set dList to sort2DList(cList, 2, {true}) of me
  
  
return dList
  
end retKeynoteSlideBaseSlideNameFrom

–リスト中の指定項目の出現回数を返す
on countSpecifiedItem(aList, countItem)
  set aRes to (current application’s SMSFord’s indexesOfItem:countItem inArray:aList inverting:false) as list
  
set aCount to length of aRes
  
return aCount
end countSpecifiedItem

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j - 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to “compare:”
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSFord’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
  
end sort2DList

★Click Here to Open This Script 

2014/11/22 レコードのリストから抽出(別リストに該当するもののみ)

レコードのリスト(List化したRecord)から、条件に合う項目を抽出するAppleScriptです。

指定項目が別途指定したリストの中に入っている値とマッチする場合のみ抽出します。

AppleScript名:asoc_レコードの抽出(別リストに入っている値に該当するかチェック)
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set aRecList to {{aName:"piyoko", aVal:100}, {aName:"piyomaru", aVal:80}, {aName:"piyoo", aVal:10}, {aName:"Gundamo", aVal:10}}
set nList to {"piyoo", "piyoko"}

set bList to filterRecListByLabelAndSublist(aRecList, "aName IN %@", nList) of me
–> {{aName:"piyoko", aVal:100}, {aName:"piyoo", aVal:10}}

–リストに入れたレコードを、指定の属性ラベルの値で抽出。値が別途指定のリストの中に存在していることが条件
on filterRecListByLabelAndSublist(aRecList as list, aPredicate as string, aSubList as list)
  –ListからNSArrayへの型変換
  
set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aSubArray to current application’s NSArray’s arrayWithArray:aSubList
  
  
–抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_(aPredicate, aSubArray)
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  
–NSArrayからListに型変換して返す
  
set bList to (filteredArray’s ASify()) as list
  
return bList
end filterRecListByLabelAndSublist

★Click Here to Open This Script 

2014/11/22 リストから抽出(asoc)

リストから条件に合う項目だけを抽出するAppleScriptです。

こういう感じで1D Listだけでなく2D Listを抽出できると便利でしょう。ああ、2D Listの抽出をやりたい、、、

AppleScript名:listの項目をフィルタリング(項目文字長)
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {“piyomaru”, “Piyomaru Software”, “Naganoya”, “Takaaki”, “MacBook Pro Retina mid 2012″}

set bList to filterListUsingPredicate(aList, “length > 8″) –文字列長が8文字より長い項目を返す
–> {”MacBook Pro Retina mid 2012″, “Piyomaru Software”}

set cList to filterListUsingPredicate(aList, “SELF MATCHES ’.*e$’”) –正規表現で末尾が”e”
–> {”Piyomaru Software”}

set dList to filterListUsingPredicate(aList, “SELF LIKE ’piyo*’”)
–> {”piyomaru”}

set eList to filterListUsingPredicate(aList, “SELF LIKE[c] ’piyo*’”)
–> {”piyomaru”, “Piyomaru Software”}

set fList to filterListUsingPredicate(aList, “SELF CONTAINS[c] ’Piyo’”)
–> {”piyomaru”, “Piyomaru Software”}

on filterListUsingPredicate(aList as list, aPredicateStr as string)
  –ListからNSArrayへの型変換
  
set setKey to current application’s NSMutableSet’s setWithArray:aList
  
  
–抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicateStr
  
set aRes to (setKey’s filteredSetUsingPredicate:aPredicate)
  
set bRes to aRes’s allObjects()
  
  
–NSArrayからListに型変換して返す
  
set cRes to (bRes’s ASify()) as list
  
return cRes
end filterListUsingPredicate

★Click Here to Open This Script 

2014/11/22 レコードのリストから抽出(asoc)

レコードのリスト(List化したRecord)から、条件に合う項目を抽出するAppleScriptです。

本来、AppleScriptの処理系だけで、

  set aList to {{aName:”ぴよまる”, weight:70}, {aName:”ぴよこ”, wight:60}}

のようなリスト化したレコードをフィルタ参照(set bList to every record whose cell “aName” is equal to “ぴよまる” とか)で抽出できるべきですが、長年搭載されてきませんでした。

こうした処理をAppleScriptで実現するためには、FileMaker Proなどのデータベースを併用するか、OS標準搭載のDataBase Events(フィルタ参照で該当データを抽出する専用のDBシステム。ソート機能がない)を利用することに(ASだけでゴリゴリ記述するという方向性もありますが、、、)。

さすがにDataBase Eventsを使うぐらいなら、ASOCで記述したほうが簡単です。

数百万件や数千万件の規模のデータを扱うにはFileMaker Proなどのデータベースを併用すべきだと思いますが、十万件ぐらいの規模のデータであればAppleScriptだけで便利にデータ処理できてよさそうです。

AppleScript名:asoc_レコードのリストから抽出
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aRecList to {{aName:“piyoko”, aVal:100}, {aName:“piyomaru”, aVal:80}, {aName:“piyoo”, aVal:10}, {aName:“Gundamo”, aVal:10}}

set bList to filterRecListByLabel(aRecList, “aName like ’Gun*’”) of me
–> {{aName:”Gundamo”, aVal:10}}

set cList to filterRecListByLabel(aRecList, “aVal >=80″) of me
–> {{aName:”piyoko”, aVal:100}, {aName:”piyomaru”, aVal:80}}

set dList to filterRecListByLabel(aRecList, “aVal=80 or aVal=10″) of me
–> {{aName:”piyomaru”, aVal:80}, {aName:”piyoo”, aVal:10}, {aName:”Gundam”, aVal:10}}

set eList to filterRecListByLabel(aRecList, “aVal=10 and aName like ’piyo*’”) of me
–> {{aName:”piyoo”, aVal:10}}

set fList to filterRecListByLabel(aRecList, “aName matches ’.*u$’”) of me –名前の最後が u で終わるものを、正規表現を用いて抽出
–> {{aName:”piyomaru”, aVal:80}}

set eList to filterRecListByLabel(aRecList, “aName == ’piyomaru’”) of me
–> {{aName:”piyomaru”, aVal:80}}

set eList to filterRecListByLabel(aRecList, “aName.length > 6″) of me –指定ラベルのデータの文字列長が6以上
–> {{aName:”piyomaru”, aVal:80}, {aName:”Gundamo”, aVal:10}}

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel(aRecList as list, aPredicate as string)
  –ListからNSArrayへの型変換
  
set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
–抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  
–NSArrayからListに型変換して返す
  
set bList to (filteredArray’s ASify()) as list
  
return bList
end filterRecListByLabel

★Click Here to Open This Script 

2014/11/21 レコードのリストをソート(asoc)

レコードのリストをソートするAppleScriptです。

{{aName:”piyoko”, aVal:100}, {aName:”piyomaru”, aVal:80}, {aName:”piyoo”, aVal:10}}

のようなレコードをリスト化したデータに対して、レコードの属性ラベルを指定してその値でソートを行います。

AppleScript名:asoc_レコードのリストをソート
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aRecList to {{aName:“piyoko”, aVal:100}, {aName:“piyomaru”, aVal:80}, {aName:“piyoo”, aVal:10}}

set bList to sortRecListByLabel(aRecList, “aVal”, true) of me –昇順ソート
–> {{aName:”piyoo”, aVal:10}, {aName:”piyomaru”, aVal:80}, {aName:”piyoko”, aVal:100}}

set bList to sortRecListByLabel(aRecList, “aVal”, false) of me –降順ソート
–> {{aName:”piyoko”, aVal:100}, {aName:”piyomaru”, aVal:80}, {aName:”piyoo”, aVal:10}}

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList, aLabelStr, ascendF)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
  
set bList to (sortedArray’s ASify()) as list
  
return bList
end sortRecListByLabel

★Click Here to Open This Script 

2014/11/21 レコードの操作

ASOCでAppleScriptのレコード(record)を操作するテストです。

指定のレコードに対して、指定の属性の値を取得したり、設定します。

AppleScriptには本来レコードから属性値を動的に(属性ラベルを変数で指定しつつ)取得する機能はありませんし、同様に動的に値を設定する機能もありません。

そこで、Scripter側の創意工夫によりAppleScript自体を動的に生成・実行することで本来存在しない機能を実現してきました

現状でもレコードに関するAppleScript自体の(本来必要な)機能が用意されていたりはしないのですが、通常のScript Editor上で記述・実行するAppleScriptでもCocoaの機能が利用できるAppleScriptObjCを使えるようになりました。

そのため、Scripter側で勝手に記述していろいろやっているところです。

AppleScript名:KeyValueTest3
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aRec to {myAge:36, myHight:166, myWeight:70}
set aKey to “myAge”

set aRes to retRecordValByLabel(aRec, aKey) of me
–> 36

set bRes to setRecordValByLabel(aRec, “myHight”, 1000) of me
–> {myAge:36, myHight:1000, myWeight:70}

–指定レコードの指定ラベルの値を取得する
on retRecordValByLabel(aRec as record, aKey as string)
  set aDic to current application’s NSDictionary’s dictionaryWithDictionary:aRec
  
set aVal to aDic’s valueForKey:aKey
  
set aValNum to (aVal’s ASify()) as list
  
set aRes to first item of aValNum
  
  
return aRes
end retRecordValByLabel

–指定レコードの指定ラベルの値を設定する
on setRecordValByLabel(aRec as record, aKey as string, aVal)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
aDic’s setValue:aVal forKey:aKey
  
set aRecord to (aDic’s ASify()) as record
  
  
return aRecord
end setRecordValByLabel

★Click Here to Open This Script 

2014/11/21 2D Listを1D Listに変換

2D Listを1D Listのセットに変換するAppleScriptです。

ASObjCExtras.frameworkでさまざまな処理を行う際、各種命令が1D Listしか受け付けないことが多く、やむをえず2D Listを1D Listに変換するケースがあったため、さくっと作ってみました。

AppleScriptでデータ処理を行う場合には、2D Listが最も多く、、場合によっては3D Listで処理したりもするので、そうした多次元配列(非1Dという意味であって、10次元とかではないんですが)を考慮した処理を書けないと、なかなかつらいです。>ASObjCExtras

AppleScript名:2D Listを1D Listに変換
set aList to {{“title(Center)”, 8}, {“title(Upper)”, 32}}
set {aRes, bRes} to conv2dListTo1dLists(aList as list)
–> {{”title(Center)”, “title(Upper)”}, {8, 32}}

–2D Listを1D Listに変換
on conv2dListTo1dLists(aList as list)
  
  
set newList to {}
  
set aLen to length of first item of aList
  
  
repeat aLen times
    set the end of newList to {}
  end repeat
  
  
  
repeat with i in aList
    repeat with ii from 1 to aLen
      set the end of item ii of newList to (item ii of i)
    end repeat
  end repeat
  
  
return newList
  
end conv2dListTo1dLists

★Click Here to Open This Script 

2014/11/21 asocで文字置換

asocで文字置換を行ってみました。

repCharは最頻出ルーチンといっても過言ではないほどよく使うルーチンで、これをASOCベースのものに置き換えてみました。

純粋なASベースでも高速だったので、あえて書き換えるメリットはないのですが、練習ということで。

AppleScript名:asocで文字置換
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

–テスト用データ
set a to
㍿株式会社

oo”

–文字置換
set b to repChar(a, string id 10, “”) of me –remove LF
set c to repChar(b, string id 13, “”) of me –remove CR
–> “㍿株式会社–oo”

–CRLF除去
set d to cleanUpCRLF(a) of me
–> “㍿株式会社–oo”

–文字置換
on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
set cString to (bString’s ASify()) as string
  
return cString
end repChar

–指定文字列からCRLFを除去
on cleanUpCRLF(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:(string id 10) withString:“” –remove LF
  
set cString to bString’s stringByReplacingOccurrencesOfString:(string id 13) withString:“” –remove CR
  
set dString to (cString’s ASify()) as string
  
return dString
end cleanUpCRLF

★Click Here to Open This Script 

2014/11/21 1D List中の指定データの出現回数を取得

1D List中に指定データが何回出現するか、その回数を取得するAppleScriptです。

非常に頻繁に使う処理ですが、あえてサブルーチンとして残しておく必要もないほど簡潔な処理(ただループで指定データの出現回数をカウントするだけ)です。

ASOCで書いてみても、さほど速くなりませんでした(逆にASの方がわずかに速くて驚いた)。10万件のデータでテストをしても有為な差が生じなかったので、通常の数十件程度のデータ処理では全然差がわからないことでしょう。

AppleScript名:1D List中に指定要素が何回出現したかを取得
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set aList to {5, 1, 3, 2, 4, 5, 5, 6}
set countItem to 5

set aRes to countSpecifiedItem(aList, countItem) of me
–> 3

–リスト中の指定項目の出現回数を返す
on countSpecifiedItem(aList, countItem)
  set aRes to (current application’s SMSFord’s indexesOfItem:countItem inArray:aList inverting:false) as list
  
set aCount to length of aRes
  
return aCount
end countSpecifiedItem

★Click Here to Open This Script 

AppleScript名:1D List中に指定要素が何回出現したかを取得(時間計測用)
– Created 2014-11-21 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

script spd
  property aList : {}
end script

set aList of spd to {}

repeat 100000 times
  set the end of aList of spd to random number from 1 to 10
end repeat

set countItem to 5

set aRes to (current application’s SMSFord’s indexesOfItem:countItem inArray:(aList of spd) inverting:false) as list
set aCount to length of aRes
–> 9801(乱数データなので、毎回結果が違うはず)

★Click Here to Open This Script 

AppleScript名:1D List中に指定要素が何回出現したかを取得(時間計測用、as)
script spd
  property aList : {}
end script

set aList of spd to {}

repeat 100000 times
  set the end of aList of spd to random number from 1 to 10
end repeat

set countItem to 5

set hitC to 0
repeat with i in aList of spd
  set j to contents of i
  
if j = countItem then
    set hitC to hitC + 1
  end if
end repeat

return hitC

★Click Here to Open This Script 

2014/11/21 1D Listのユニーク化(asoc) 処理内容比較

1D Listのユニーク化の方法について、Shane Stanleyからいろいろと助言をもらいました。

Shaneは処理速度について高速化のために提案してくれたのですが、10万アイテムのListに対して10回計測で平均をとってみたら、「いずれも高速ではあるものの、それほど変わらない」という結果に(#1より#2,#3の方が微妙に高速)。

問題は、ユニーク化したあとの結果。ソートされているものもあれば、されていないものもある、という状況。

少々疑問点があったので、小数点以下の値やマイナスの値などいろいろ突っ込んで追試に次ぐ追試を行ってみたところ・・・数値リストのユニーク化については、結果はどれも「ソートずみの値」として使ってはいけないということに。

uniquify.png

AppleScript名:listのユニーク化(asoc)_method1
– Created 2014-11-19 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set aArray to current application’s NSArray’s arrayWithArray:aList
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”

set bList to bArray’s ASify() as list
–> {3, -1, 1, 1.1, -1.1, 4, 2}

★Click Here to Open This Script 

AppleScript名:listのユニーク化(asoc)_method2
–By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set theSet to current application’s NSOrderedSet’s orderedSetWithArray:aList
set bArray to theSet’s array() – get set’s items as array
set bList to bArray’s ASify() as list
–> {-1, 4, 1, 2, 3, 1.1, -1.1}

★Click Here to Open This Script 

AppleScript名:listのユニーク化(asoc)_method3
–By Shane Stanley
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {-1, 4, 4, 4, 4, 4, 1, 2, 3, 1, 2, 1.1, -1.1}

set theSet to current application’s NSSet’s setWithArray:aList
set bArray to theSet’s allObjects() – get set’s items as array
set bList to bArray’s ASify() as list
–>{3, -1, 1, 1.1, -1.1, 4, 2}

★Click Here to Open This Script 

2014/11/19 1D Listのユニーク化(asoc)

1D List(1次元配列)のユニーク化(重複削除)を行うAppleScriptです。

ものすごくよく使う処理で、大規模プログラムでは使わないほうが珍しいほど。

例によって、Cocoaの機能を呼び出して高速化を図ってみました。

10,000件の乱数リストを作成して、ASOC版と通常のAS版で比較してみたところ、初回実行時では14倍、10回実行平均値では57倍、ASOC版の方が高速になりました。

Script Geekで計測したため、テストデータ作成部(乱数による10,000件の1D List作成)を含んだ実行時間です。

asoc版でテストデータ作成部分だけで実行してみると、平均0.182秒程度で終わっているので、1万件のユニーク化(重複削除)およびNSArrayからListへの変換だけであれば0.01秒で終わっている計算になります。

uniq1.png

AppleScript名:listのユニーク化(asoc)
– Created 2014-11-19 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 2, 3, 4, 4, 4, 4, 4, 1, 2, 1.1}

set aArray to current application’s NSArray’s arrayWithArray:aList
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”

set bList to bArray’s ASify() as list
–> {1, 1.1, 2, 3, 4}

★Click Here to Open This Script 

AppleScript名:listのユニーク化(asoc) 計測用
– Created 2014-11-19 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

script spd
  property aList : {}
end script

set aList of spd to {}

repeat 10000 times
  set the end of aList of spd to random number from 1 to 100
end repeat

set aArray to current application’s NSArray’s arrayWithArray:(aList of spd)
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”

set bList to bArray’s ASify() as list

★Click Here to Open This Script 

AppleScript名:listのユニーク化(as)
script spd
  property aList : {}
end script

set aList of spd to {}

repeat 10000 times
  set the end of aList of spd to random number from 1 to 100
end repeat

set bList to removeDuplicates(aList of spd) of me

on removeDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set anItem to item 1 of aList
    
set aList to rest of aList
    
if {anItem} is not in aList then set end of newList to anItem
  end repeat
  
return newList
end removeDuplicates

★Click Here to Open This Script 

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/18 listの共通項を返す(asoc)

2つのListをくらべて、共通項を返すAppleScriptです。

Cocoaの流儀にしたがって、Cocoaの機能を使って実装してみました。

AppleScript名:listの共通項を返す
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 2, 3, 4, 5}
set bList to {0, 1, 2, 4, 5, 6}

set aRes to getSameItemsInLists(aList, bList) of me
–> {2, 5, 1, 4}

on getSameItemsInLists(aList as list, bList as list)
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分だけを返す
  
set resArray to duplicateSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end getSameItemsInLists

★Click Here to Open This Script 

2014/11/18 list同士のdiffをとる(asoc)

2つのListのdiffをとるAppleScriptです。

検索していろいろ調べ、主にこちらのページの内容を参考にして、Cocoaの流儀にしたがって、Cocoaの機能を使って実装してみました。

以前にAppleScriptだけで実装したものもありますが、データ量が増えるとこちらの方が有利と思われます。

・・・などと書いていたら、Shane Stanleyが2つのAppleScriptの実行速度を計測するツール「Script Geek v.1.27」を公開していました

geek.png

この用途のために作られたとしか思えないツールなので、素直に使っておきましょう。指定回数実行して、平均実行時間を計測してくれるツールです。

実際に使ってみると、

(1)テストデータ作成部分を時間計測してほしくない
(2)計測結果をグラフ表示してほしい
(3)テスト中に画面の内容をアップデートしたほうがいい

といった率直な感想が(^ー^;;

それはいいとして、ASだけで実装したものとASOCで実装したものだとASOCの方が120倍速いという結果が出ました。ASだけで実装した方は、けっこう忙しいときに書いたらしく処理内容が入り組んでおり「どうしてこう書いたんだろう」という話が思い出せません、、、

また、繰り返し実行するとASOCの処理速度が(一桁ぐらい)上がるのに驚きました(初回実行時は0.27秒なのに、平均実行速度が0.03秒、、、)。

(4)各計測結果を数値またはグラフで表示

があると、どういった傾向があるのか分かってよいでしょう。

AppleScript名:listのdiffをとる
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 2, 3, 4, 5}
set bList to {0, 1, 2, 4, 5, 6}

set aRes to diffLists(aList, bList) of me
–> {0, 6, 3}

on diffLists(aList as list, bList as list)
  –以下を参照
  
–http://qiita.com/ar_tama/items/b69d6ab5c505be89c414
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to allSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end diffLists

★Click Here to Open This Script 

AppleScript名:listのdiffをとる(時間計測用)
– Created 2014-11-18 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

script spd
  property aList : {}
  
property bList : {}
end script

set aList of spd to {}
set bList of spd to {}

repeat 1000 times
  set the end of aList of spd to random number from 1 to 1000
  
set the end of bList of spd to random number from 1 to 1000
end repeat

set aRes to diffLists(aList of spd, bList of spd) of me

on diffLists(aList as list, bList as list)
  –以下を参照
  
–http://qiita.com/ar_tama/items/b69d6ab5c505be89c414
  
  
–ASオブジェクトをCocoaオブジェクトに変換
  
set aArray to current application’s NSArray’s arrayWithArray:aList
  
set bArray to current application’s NSArray’s arrayWithArray:bList
  
  
– まとめる
  
set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to allSet’s allObjects()
  
  
set resList to resArray’s ASify() as list
  
  
return resList
  
end diffLists

★Click Here to Open This Script 

AppleScript名:listのdiffをASだけでとる(時間計測用)

script spd
  property aList : {}
  
property bList : {}
end script

set aList of spd to {}
set bList of spd to {}

repeat 1000 times
  set the end of aList of spd to random number from 1 to 1000
  
set the end of bList of spd to random number from 1 to 1000
end repeat

set aRes to diffList(aList of spd, bList of spd) of listDiffKit
–> {{0, 9, 11}, {5}}

script listDiffKit
  
  
–リスト同士のdiffをとる
  
on diffList(aaList, bbList)
    copy {aaList, bbList} to {aList, bList} –fix?
    
set notExistInBlist to {}
    
    
if aList is equal to bList then
      return {{}, {}}
    end if
    
    
repeat with i in aList
      set j to contents of i
      
if j is in bList or j is equal to bList then
        set bList to deleteSpecifiedItemFromList(bList, j) of me
      else
        set the end of notExistInBlist to j
      end if
    end repeat
    
    
return {notExistInBlist, bList}
  end diffList
  
  
–指定内容の要素をリストから削除して返す
  
on deleteSpecifiedItemFromList(aList, anItem)
    set iCount to 1
    
repeat with i in aList
      set j to contents of i
      
if j = anItem then
        set aaList to oneItemDelete(aList, iCount) of me
        
return aaList
      end if
      
set iCount to iCount + 1
    end repeat
    
    
return aList
    
  end deleteSpecifiedItemFromList
  
  
–リスト中の指定要素を削除して返す
  
on oneItemDelete(aList, chgNum)
    set newList to {}
    
set aLen to length of aList
    
    
if chgNum = 1 then
      set aLen to length of aList
      
if aLen > 1 then
        set maeList to items 2 thru aLen of aList
        
set newList to maeList
      else
        set newList to {}
      end if
    else if chgNum = aLen then
      set maeList to items 1 thru (aLen - 1) of aList
      
set newList to maeList
      
    else
      set maeList to items 1 thru (chgNum - 1) of aList
      
set atoList to items (chgNum + 1) thru -1 of aList
      
set newList to maeList & atoList
    end if
    
    
return newList
  end oneItemDelete
  
  
on retDelimedText(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 retDelimedText
  
  
–文字置換ルーチン
  
on repChar(origText, targStr, repStr)
    set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
    
set temp to text items of origText
    
set AppleScript’s text item delimiters to repStr
    
set res to temp as text
    
set AppleScript’s text item delimiters to txdl
    
return res
  end repChar
end script

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動 v3

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

あまり手間をかけずに、複数Windowの回転に対応させました。

当初は、内部でスレッドを発生させて1Windowあたり1スレッドで管理するなど、いろいろ実装方法を検討してみましたが・・・何も、こんな意味のないくだらないScriptにそこまで血眼になる必要はないので、一番楽ができそうな方法で実現してみました。

プロパティ「maxWin」にWindow枚数を設定しておくと、その数だけFinder Windowを作成し、回転させます。手元のMacBook Pro Retina Mid 2012(寝床でバッテリ駆動中)では8ぐらいが上限っぽい感じでしたが(きれいに見える上限)、さらに強力なマシンでは数を増やして実行してみるとよいでしょう。

wins.png

AppleScript名:Finder Windowを円運動 v3
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0
property maxWin : 8
property winList : {}
property randList : {}
property winSize : 400

–Initialize
set winList to {}
set randList to {}

repeat maxWin times
  tell application “Finder”
    activate
    
set aWin to make new Finder window
    
    
tell aWin
      set toolbar visible to false
      
set sidebar width to 0
      
set statusbar visible to false
      
set position to {100, 100}
      
set bounds to {100, 100, 100 + winSize, 100 + winSize}
    end tell
    
    
set the end of winList to aWin
    
set the end of randList to {random number from 0 to 400, random number from 0 to 400, random number from 1 to 360}
    
  end tell
end repeat

–Main
repeat with i from 1 to 360 by 6
  
  
repeat with ii from 1 to maxWin
    
    
set aWinObj to contents of item ii of winList
    
set {aRandX, aRandY, aRandDegree} to item ii of randList
    
    
set aDeg to i + aRandDegree
    
    
set aSinNum to (current application’s SMSFord’s sinValueOf:aDeg) as real
    
set aCosNum to (current application’s SMSFord’s cosValueOf:aDeg) as real
    
    
set x to ((aNum * aSinNum) + aNum) * 2.0 + aOffset
    
set y to (aNum * aCosNum) + aNum + aOffset
    
    
ignoring application responses
      tell application “Finder”
        tell aWinObj
          set position to {(x as integer) + aRandX, (y as integer) + aRandY}
        end tell
      end tell
    end ignoring
    
  end repeat
  
end repeat

–Sweep
tell application “Finder”
  repeat with i in winList
    tell i
      close
    end tell
  end repeat
end tell

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動 v2

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

なぜか、海外から好評を博して、びみょーにアップデートしました。

変更点:
Finderをactivateするようにした(そんなに変わらない気も、、、)
Satimage OSAXの予約語とコンフリクトを起こすasin, acosの変数名を変更した

複数スレッドを生成して、複数のFinder Windowをズラしながらぐるぐる回せると「やったな!」という感じがしていいかもしれません。自己満足ですが・・・。

AppleScript名:Finder Windowを円運動 v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0

set {newX, newY} to (current application’s NSScreen’s mainScreen()’s frame()’s |size|()) as list

tell application “Finder”
  activate
  
set aWin to make new Finder window
end tell

repeat with i from 1 to 360 by 6
  
  
set aSinNum to (current application’s SMSFord’s sinValueOf:i) as real
  
set aCosNum to (current application’s SMSFord’s cosValueOf:i) as real
  
  
set x to ((aNum * aSinNum) + aNum) * 2.0 + aOffset
  
set y to (aNum * aCosNum) + aNum + aOffset
  
  
tell application “Finder”
    tell aWin
      set position to {x as integer, y as integer}
    end tell
  end tell
  
end repeat

tell application “Finder”
  tell aWin
    close
  end tell
end tell

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

実行にはASObjCExtras.frameworkが必要なので、事前にインストールが必要です。楕円軌道でぐるぐるFinder Windowを回します。それだけです。

この手の、意味がぜんぜんないAppleScriptというのが割とエンドユーザー受けがよかったりするので、載せておきます。

Classic Mac OSの時代に、システムフォルダ内の名前に「A」を含むフォルダを開閉させる「open a」という意味のないScriptを書いてデモしたら、何かものすごい処理をしているように見えて受けがよかった、ということがありました。

ASObjCExtras.frameworkの三角関数機能を利用しています。一応、メイン画面のサイズを取得して円運動の大きさとかオフセット値とか扁平率に反映しようかと思ったものの、とくによいアイデアが思い浮かばなかったので、求めてそれっきり放置状態です。

img_0246_resized.png

1994年ごろに購入した「The Tao Of AppleScript」(日本語訳版)にFinderのウィンドウを四角く移動させるScriptが掲載されており、自分はこれを見て「なんて意味のない処理なんだ!」と呆れて登場当時のAppleScriptへの興味を失ってしまいましたが、他のユーザーがこの円運動Scriptを見て呆れないか心配です(^ー^;;

AppleScript名:Finder Windowを円運動
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0

set {newX, newY} to (current application’s NSScreen’s mainScreen()’s frame()’s |size|()) as list

tell application “Finder”
  set aWin to make new Finder window
end tell

repeat with i from 1 to 360 by 6
  
  
set aSin to (current application’s SMSFord’s sinValueOf:i) as real
  
set aCos to (current application’s SMSFord’s cosValueOf:i) as real
  
  
set x to ((aNum * aSin) + aNum) * 2.0 + aOffset
  
set y to (aNum * aCos) + aNum + aOffset
  
  
tell application “Finder”
    tell aWin
      set position to {x as integer, y as integer}
    end tell
  end tell
  
end repeat

tell application “Finder”
  tell aWin
    close
  end tell
end tell

★Click Here to Open This Script 

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/11/14 指定ファイルからサイズ情報を取得

ASObjCExtras.frameworkを用いて、指定ファイルのサイズ情報を取得するAppleScriptです。

fileSizeはファイルの大きさ、totalFileSizeというのは・・・対象がバンドルの場合に総容量ということでしょうか。

allocation sizeというのは、記録しているメディア内でどのぐらいのセクター数を占めていて、そのセクター数を容量に換算したものでしょうか(512で割り切れるし)。

AppleScript名:ASObjCExtrasのじっけん_指定ファイルからサイズ情報を取得
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set anAlias to choose file
set b to (current application’s SMSFord’s sizeInfoForFile:anAlias) as record
–> {totalFileSize:199432, totalFileAllocatedSize:200704, fileAllocatedSize:200704, fileSize:199432}

★Click Here to Open This Script 

2014/11/14 2DリストでPivot

ASObjCExtras.frameworkを用いて、2D ListをPivotするような感じのする処理を行うAppleScriptです。

PivotというのはExcelの・・・指定データ領域を90度回転させるような処理ですが、厳密にいえばこの処理内容はPivotではありませんね。

図にすると・・・

pivot.png

という不思議な処理です。何に使うのでしょう?(^ー^;

AppleScript名:ASObjCExtrasのじっけん_2DリストでPivot
use AppleScript version "2.4"
use framework "Foundation"
use framework "ASObjCExtras"
use scripting additions

–3×3のデータ
set aList to {{1, 2, 3}, {11, 12, 13}, {21, 22, 23}}
set b to (current application’s SMSFord’s colsToRowsIn:aList |error|:(missing value)) as list
–> {{1, 11, 21}, {2, 12, 22}, {3, 13, 23}}–結果も3×3

–3×5のデータ
set aList to {{1, 2, 3}, {11, 12, 13}, {21, 22, 23}, {31, 32, 33}, {41, 42, 43}}
set b to (current application’s SMSFord’s colsToRowsIn:aList |error|:(missing value)) as list
–> {{1, 11, 21, 31, 41}, {2, 12, 22, 32, 42}, {3, 13, 23, 33, 43}}–結果は5×3

★Click Here to Open This Script 

2014/11/14 2D Listの各要素に指定の1Dリストの内容をインサートする

ASObjCExtras.frameworkを用いて、2D Listの各要素の指定位置に、指定の1D Listの内容をインサートするAppleScriptです。

2D Listの任意の場所に埋め草を入れるような感じでしょうか。処理対象の2D Listと埋め草データ用の1Dリストの要素数が合っていないと、エラー({missing value}が返ってくる)になります。

インサートする位置については、Cocoa風の0はじまりなので注意が必要です。

AppleScript名:ASObjCExtrasのじっけん_2Dリストの各要素に指定の1Dリストの内容をインサートする
use AppleScript version “2.4″
use framework “Foundation”
use framework “ASObjCExtras”
use scripting additions

–リストの要素数が合っている場合
set aList to {{1, 2, 3}, {11, 12, 13}, {21, 22, 23}}
set insArray to {100, 101, 102}
set anIndex to 0
set b to (current application’s SMSFord’s subarraysIn:aList withItems:insArray insertedAtIndex:anIndex |error|:(missing value)) as list
–> {{100, 1, 2, 3}, {101, 11, 12, 13}, {102, 21, 22, 23}}

–リストの要素数が合っていない場合
set aList to {{1, 2, 3}, {11, 12, 13}, {21, 22, 23}}
set insArray to {100, 101}
set anIndex to 0
set b to (current application’s SMSFord’s subarraysIn:aList withItems:insArray insertedAtIndex:anIndex |error|:(missing value)) as list
–> {missing value}

★Click Here to Open This Script 

2014/11/14 2Dリストで最長の要素に満たない個数の要素は後ろに埋め草を追加

ASObjCExtras.frameworkを用いて、2D List内部の要素で、最長の要素数に満たない個数の要素は後ろに埋め草を追加するAppleScriptです。

  {{1,2,3,4,5,6,7}, {1,2}, {1,2,3}}

という2D Listの場合、少ない要素に0で埋める指定を行うと、

  {{1,2,3,4,5,6,7}, {1,2,0,0,0,0,0}, {1,2,3,0,0,0,0}}

と、最長のアイテムに合わせて埋め草を追加してくれます。

ちなみに、例によってベンチマークとして1万要素の2D Listを作成し、各要素は乱数で要素を作成しておき・・・埋め草を全要素に付加してみたら、0.3秒。なかなかです。

AppleScript名:ASObjCExtrasのじっけん_2Dリストで最長の要素に満たない個数の要素は後ろに埋め草を追加
use AppleScript version "2.4"
use framework "Foundation"
use framework "ASObjCExtras"
use scripting additions

set aList to {{1, 2, 3, 4, 5}, {1, 2, 3}, {1, 2}}
set aPad to 0

set b to (current application’s SMSFord’s subarraysIn:aList paddedWith:aPad |error|:(missing value)) as list
–> {{1, 2, 3, 4, 5}, {1, 2, 3, 0, 0}, {1, 2, 0, 0, 0}}

★Click Here to Open This Script 

AppleScript名:ASObjCExtrasのじっけん_リスト中のmissing valueの要素を指定内容に置換する v2
use AppleScript version "2.4"
use framework "Foundation"
use framework "ASObjCExtras"
use scripting additions

script spd
  property aList : {}
end script

–テストデータ作成
set aList of spd to {}
repeat 100000 times
  set a to random number from 0 to 9
  
if a = 9 then
    set the end of aList of spd to missing value
  else
    set the end of aList of spd to a
  end if
end repeat

set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() –時間計測

set repItem to 0
set b to (current application’s SMSFord’s arrayByReplacingNullsIn:(aList of spd) withItem:repItem) as list

set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() –時間計測
set c1Dat to b1Dat - a1Dat
–> 0.258893966675

★Click Here to Open This Script 

AppleScript名:ASObjCExtrasのじっけん_1Dリストを指定個数ごとにリスト化して2D化して要素数が足りないアイテムに埋め草を追加
use AppleScript version "2.4"
use framework "Foundation"
use framework "ASObjCExtras"
use scripting additions

set aList to {1, 2, 3, 11, 12, 13, 21, 22, 23}

set aGroupNum to 5
set bList to (current application’s SMSFord’s subarraysFrom:aList groupedBy:aGroupNum |error|:(missing value)) as list
–> {{1, 2, 3, 11, 12}, {13, 21, 22, 23}}

set aPad to 0
set cList to (current application’s SMSFord’s subarraysIn:bList paddedWith:aPad |error|:(missing value)) as list
–> {{1, 2, 3, 11, 12}, {13, 21, 22, 23, 0}}

★Click Here to Open This Script 

2014/11/13 指定リストの次元を取得する

指定のリスト(配列変数)の次元を求めるAppleScriptです。

リストの各要素の最初のものがリストかどうかをチェックして、リストだったら再帰で本ルーチンを呼び出します。

リスト内の全要素をチェックするわけではないので、途中でいびつな入れ子構造が部分的に存在していた場合には検出できませんが、常識的にはこんなものでよいでしょう。

本ルーチン呼び出し時の第1パラメータはチェック対象のリストですが、第2パラメータは1を指定しておく必要があります。

OS X 10.10で導入された無指定時のデフォルトパラメータ指定機能を使うと、この無意味な第2パラメータを省略できてよいでしょう。

AppleScript名:指定リストの次元を取得する
use AppleScript version “2.4″
use scripting additions

set aList to {{1, 2, 3}, {4, 5, 6}} –2D List
set aDim to getDimension(aList, 1) of me
–> 2

set bList to {{{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}} –3D List
set bDim to getDimension(bList, 1) of me
–> 3

set cList to {1, 2, 3, 4, 5, 6} –1D List
set cDim to getDimension(cList, 1) of me
–> 1

set dList to {{{{1, 2}, {2, 3}}, {{1, 2}, {2, 3}}, {{1, 2}, {2, 3}}}} –4D List
set dDim to getDimension(dList, 1) of me
–> 4

–指定Listの次元を再帰で取得する
on getDimension(aList as list, aNum as integer)
  
  
set anItem to contents of first item of aList
  
set aClass to class of anItem
  
  
if aClass = list then
    set aNum to aNum + 1
    
set aRes to getDimension(anItem, aNum) of me
  else
    return aNum
  end if
  
end getDimension

★Click Here to Open This Script 

こちらが、OS X 10.10で導入された、パラメータ無指定時のデフォルト値自動補完機能を利用した記述です。機能に変わりはありません。

AppleScript名:指定リストの次元を取得する v2
use AppleScript version “2.4″
use scripting additions

set bList to {{{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}, {{1, 2}, {2, 3}, {3, 4}}} –3D List
set bDim to getDimension given targArray:bList
–> 3

–指定Listの次元を再帰で取得する
on getDimension given targArray:aList as list : {}, curDim:aNum as integer : 1
  
  
set anItem to contents of first item of aList
  
set aClass to class of anItem
  
  
if aClass = list then
    set aNum to aNum + 1
    
set aRes to getDimension given targArray:anItem, curDim:aNum
  else
    return aNum
  end if
  
end getDimension

★Click Here to Open This Script 

2014/11/13 OS X 10.10 Yosemite のAppleScript関連バグまとめ

OS X 10.10, YosemiteにおけるAppleScript関連バグがいろいろ明らかになってきました。

個人的には、OS X 10.10はAppleScript系の野心的な機能が満載で、10.9と並んでプログラムを組んでいて楽しい環境です。マルチコアCPU環境に対応して、Scriptランタイム環境をマルチスレッド化+高速化させたり、Script Editor上でASOCが実行できたりと、さわっていて驚きに満ちています。

ただ、野心的な実装の影響がきちんと検証されていなかったりで、そのあたりにアンバランスさを感じます。

大きなものから小さなものまで、海外+国内のScripterからMLやらTwitterやらで報告のあったものをまとめておきます。

(1)アプレット実行時、ダイアログでキーボードからの文字入力を受け付けない

久しぶりに大型のバグがやってきました(By @fixdotさん)。

 display dialog “Input Some Message:” default answer “”

などと書いて、モーダルダイアログを表示しユーザーに文字列入力を行わせる定番の処理がありますが、この記述をアプレット書き出しして実行すると、キーボードからの入力を一切受け付けないというものです。

→ 10.10.1 Updateで修正されていません
→ 10.10.2 Updateで修正

回避方法:なにがしかのアプリケーションへのtellブロック内でdisplay dialogを実行すると大丈夫です。ちなみに、tell current applicationでは回避できませんでした。アプレット書き出し時にCodeSignしてもダメでした。

dialog.png

なにか、OSのセキュリティを向上させるためにいろいろ水面下でやっているところで、巻き込まれた感じがします。OS Xのセキュリティ向上は今後も行われていくのは必至なので、昔は可能だったゆる〜い処理(defaults readコマンドで設定ファイルを読み込むとか)がどんどんできなくなっていくはずです。

(2)アプレット実行時、delayが効かない

delay(時間待ち命令)は地味ですが、アプリケーションのコントロールでは欠かせないものです。アプレット書き出しして実行中にdelayが全部無視されます(US AppleScript Users MLより)。

→ 10.10.1 Updateで修正されたようです
→ 10.10.2 Updateで修正

Dock上のアプリケーションアイコンにバッジ表示するASOCのプログラムを試していたときにうすうす気づいていたのですが、やっぱりそうかというところ。

回避方法:shell scriptとかCocoaの機能を呼び出すなどして代用する。標準命令自体のバグなので、ハンドラで命令を乗っ取るようにすれば、Script自体の書き換えが少なくて済みます。

AppleScript名:Yosemiteのdelayバグ対策
use AppleScript version “2.4″
use scripting additions

delay 0.1

–add & override “delay” command
on delay delayNum as real
  do shell script “sleep “ & (delayNum as string) & “s”
end delay

★Click Here to Open This Script 

(3)ASOCで小数以下の数値を含む数値リストをASに返すと値に誤差が出る

Cocoaの機能を通常のAppleScriptから直接呼び出せるようになったのはいいのですが、小数点以下の数値を含むリストをCocoaオブジェクトからAppleScriptオブジェクトに変換すると、値が変わってしまいます

xcode.png

→ 10.10.1 Updateで修正されていません
→ 10.10.2 Updateで修正されていません

回避方法:Scripting Bridge自体のバグで深刻なうえに根が深いため、OS X 10.10台では修正されないでしょう。Appleを当てにしないで、Shane StanleyのASObjCExtras.framework(フリー)を導入してこちらを使うのがベストです。

framework.png

(4)Script EditorにScriptableでないアプリをドラッグ&ドロップするとバイナリモードでオープンしてしまう

Script Editorのアイコンにアプリをドラッグ&ドロップすると、Scriptableなアプリでは用語辞書が表示されますし、対応していないアプリケーションだと表示されない・・・のが普通ですが、なぜかアプリケーション自体がバイナリモードでオープンされてしまいます。

→ 10.10.1 Updateで修正されていません
→ 10.10.2 Updateで修正されていません

回避方法:Script Editorの「ライブラリ」表示から辞書をオープンさせるか(おすすめ)、AppleScript自体で対象アプリケーションのScriptable度を調べてオープンさせる(やりすぎ)ことになります。

(5)Script Editor上でCocoaオブジェクトの操作を行うと、Scriptを保存できなくなる

けっこう腹がたつバグです。ASOCのプログラムを書いて実行すると保存できない、というものです。

cannotsave.png

従来のバージョンのOS X上でも、Script Editor上で巨大なデータを読み込んだり処理したりすると、保存できなくなる現象はありました。その場合には、Scriptを編集(うしろにカラの行を足すとか)すると問題なく保存できていました。

ところが、この10.10のバグは「ちょっと空行を足した」ぐらいでは回避できません。お手上げです。

→ 10.10.1での判定:保留

回避方法:ASOCのプログラムは実行前にあらかじめ保存しておく必要があります。または、Scriptの内容をコピペで新規Scriptに移して保存します。

(6)AppleScriptの言語プロパティの説明文字に不要な「。」がある

単なるローカライズ時の間違いですが、これはダメです。

→ 10.10.1 Updateで修正されていません
→ 10.10.2 Updateで「。」が「.」に修正されましたが、なんで削除しないかな。

回避方法:見なかったことにする。

osa1.png

各OSA言語のプロパティを取得して、さまざまな処理を行う場合に、この「description」属性を参考にするとひどい目に遭いそうなので、nameとかidで判別するのがよさそうだ・・・ということに。

スクリプト名:OSA言語のプロパティを取得
tell application “Script Editor”
  set langList to every language
  
–> {language “AppleScript Debugger 5″, language “AppleScript”, language “JavaScript”}
  
  
repeat with i in langList
    tell i
      properties
      
      
–> {name:”AppleScript Debugger 5″, supports compiling:true, description:”AppleScript Debugger 5 Scripting System”, class:language, supports recording:true, id:”asDB”}
      
      
–> {name:”AppleScript”, supports compiling:true, description:”AppleScript。”, class:language, supports recording:true, id:”ascr”}
      
      
–> {name:”JavaScript”, supports compiling:true, description:”JavaScript”, class:language, supports recording:false, id:”jscr”}
      
    end tell
  end repeat
end tell

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

(7)Script Editorの編集ビューで拡大縮小をするとハングアップ

Script Editor上の文字が小さくて見にくいときに、トラックパッドでピンチイン/ピンチアウトのジェスチャーを行うと文字が拡大/縮小されます。なかなか便利な機能です。

pinch.png

ただ、この機能を(連続して数回)呼び出すとScript Editorがかなりの高確率でハングアップします(危険)。

→ 10.10.1 Updateで修正されたように見えます
→ 10.10.2 Updateでも修正されているように見えますが、油断できません

拡大された状態のままクラッシュして、Script Editorを再起動しても起動時に「名称未設定」のScriptが拡大されたままオープンされて、延々ハングアップするという「怪奇現象」にも遭遇しました。

OS Xの再起動、Script Editorのキャッシュ削除などいろいろ行いましたが、Script Editorを起動すると前回編集していた「名称未設定」がオープンされ(OSの仕様)、そのたびにハングアップするという無限地獄。

結局、編集中の(保存前の)ScriptがiCloud Driveに自動保存されていることに気づき、iCloud DriveにあったScript Editorの編集しかけのScriptを削除することで、解決はしたのですが、、、、久しぶりにハマりました。

完全なバグではないけれど、腐っている機能

XML-RPC、SOAP関連はCarbon系のAPIで実装されており、WordPressへの記事新規作成を行わせるとクラッシュするなど、腐っています。Appleのエンジニアも「Carbon関連のものは直さない」と明言しているため、AppleScriptからCocoaのAPIを直接呼び出して実行するほかなさそうです。

Web CGI関連の予約語もAppleScript用語辞書の中に残っていますが、標準ではWebサーバー機能関連の設定UIなどがなくなっているため、盲腸みたいな存在です(なくならないのが不思議)。

Finderでファイルに「タグ」をつける機能がありますが、AppleScriptからは単にラベル(色)をつけられるだけです。これは、Cocoaの機能を呼び出して処理することになります。