AppleScript Language Guide

AppleScript に関する本は、以前 Online で O’Reilly の書籍が読める Safari が利用できたときにパラパラと読んでいたけど、今ひとつ形にならなかった。最近 Apple が公開している AppleScript Language Guide を読み、やっと基本がわかった気がする。

http://developer.apple.com/library/mac/#documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html

スクリプトなので、あまり高い期待をしてはいけないのだが、使い方がわかってくると、もっと機能が欲しくなる。汎用的な sort とか、クロージャ的な使い方も見当たらない。対応する物は限られて入るけど、いろいろなアプリケーションをスクリプトで操作できるのは面白い。

外部ライブラリは scpdt 拡張子のバンドルでインストールできるらしい。MySQL の物もあるようだ。

iCal の特定のカレンダーからイベントを抜き出すスクリプトを作ってみた。個々の入力は GUI でやっといて、後で集計目的にイベントをテキストで取り出せる。コマンドでイベントを登録するようにもできるかも。最も、CalDAV を直接たたく方が汎用的なんだろうが。

(* 簡単な関数、引数は date の month, January - December は定義済みの定数 
   日付のフォーマット関数らしき物は見当たらなかった。月の変換の部分を
   手動で行う
   値の同一性は、違和感があるかもしれないが = を使う。
   最後の値が戻り値になる。
   as text はキャストに相当する Coercion という処理、状況に応じて自動的に
   行われる事もあるが、ここでは明示的に行っている。
   *)
on mon2Num(mon)
  if mon = January then
    "01"
  else if mon = February then
    "02"
  else if mon = March then
    "03"
  else if mon = April then
    "04"
  else if mon = May then
    "05"
  else if mon = June then
    "06"
  else if mon = July then
    "07"
  else if mon = August then
    "08"
  else if mon = September then
    "09"
  else if mon = October then
    "10"
  else if mon = November then
    "11"
  else if mon = December then
    "12"
  else
    mon as text
  end if
end mon2Num

(*
 date format の様な事を行うハンドラ
 文字列の連結は & で行う。
 my mon2Num は current target の date オブジェクトに mon2Num を
 探しにいかせず、script object の mon2Num を使わせるため。
*)
on formatDate(date1)
  tell date1
    set sday to day as text
    if day < 10 then
      set sday to "0" & day as text
    end if
    year & "/" & my mon2Num(month of date1) & "/" & sday & "-" & time string
  end tell
end formatDate

-- 対象のイベントをテキスト形式で保持するリストを宣言、初期化
set targetEvents to {}

-- iCal をデフォルトターゲットに
tell application "iCal"
  -- calenders プロパティを iterate
  repeat with cal in calendars
    -- log "name: " & name of cal & " desc: " & description of cal
    -- カレンダーの名前でフィルター
    if name of cal = "work" then
      -- log "name: " & name of cal & " desc: " & description of cal
      -- cal を default target に指定
      tell cal
        -- log "name: " & name & " desc: " & description
        -- cal の events プロパティを iterate
        repeat with ei in events
          -- event のプロパティ allday が false の物を対象に
          if not allday event of ei then
            -- 対象のイベント ei をデフォルトターゲットに
            tell ei
              -- イベントの長さを分単位の整数値として計算
              set durm to ((end date - start date) / minutes) as integer
              -- 開始次男、長さ、サマリーを文字列にフォーマット
              set ln to my formatDate(start date of ei) & " " & durm ??
                & " " & summary as text
              -- リストの最後に追加。最後にしか追加できないのか? 
              copy ln to the end of targetEvents
            end tell
          end if
        end repeat
      end tell
    end if
  end repeat
end tell

(* 
 結果のリストを \n を区切りに使い join する。
 グローバルの text item delimiters リストを一時的に変更し、
 元に戻す。
 処理を try ブロックで行う事で、エラーが発生しても、
 text item delimiters がデフォルトに戻るようにしている。 
 *)
set savedDelimiters to AppleScript's text item delimiters
try
  set AppleScript's text item delimiters to {"
"}
  set input to targetEvents as string
  set AppleScript's text item delimiters to savedDelimiters
on error m number n
  set AppleScript's text item delimiters to savedDelimiters
  error m number n
end try

(* 
 一時ファイルに出力を行う。
 パスは、特に必要なければ POSIX file で扱う方がわかりやすい。
 file, alias は : を区切りに使うパスをとり、相対パスは : で
 始まるなど、HFS path を使う。
 書き込むので open for acess に with write permission を付けて
 開く。
 write は特に改行を付けてはくれないので、最後に改行を write
 *)
set tmpFilePath to "/tmp/iCalScr.tmp"
set tmpFile to POSIX file tmpFilePath
set ofile to open for access tmpFile with write permission
write input to ofile
write "
" to ofile
close access ofile

(*
do shell script で一時ファイルをソートする。汎用の sort は
標準ではない。iCal のカレンダーのイベントは開始時間でソート
されてかえってくる訳ではない。
 *)
set output to do shell script "sort " & tmpFilePath
log output