v12で発生していた、新規書類をAppleScriptから保存できないバグは修正されていません。
新発売:AppleScript高速化テクニック
電子書籍の新刊を発売しました。「AppleScript高速化テクニック」です。PDF 86ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
本書は、高速なAppleScriptを書くための実践的なノウハウをまとめた、おそらく世界で初めての、現時点では唯一の書籍です。
AppleScript自体はインタプリタ型の処理系であるため、実行速度はSwiftやObjective-Cなどで書かれたプログラムにスピード面では遠く及びません。
ただし、処理系そのものや周辺環境に対する十分な理解をともなわずに書かれたScriptは、本来期待されるレベルを大きく下回るスピードしか出せません。大変残念なことです。AppleScriptはプログラミング言語というよりも、OSに対するシェルであるとか、一種のアプリケーションとしての性格が強いものです。そこには、明確な「使いこなし」のノウハウが存在しますし、癖もあります。
残念な状態に書かれたAppleScriptのプログラムは、自動車でいえば整備不良、ガス欠で、洗車も行われずに野ざらしになっている状態です。
本書は、いわばそうした残念な状態の自動車に対しての、整備、ガソリン補給、オイル交換や洗車についてご提案するものです。
実機で実際にAppleScriptのプログラムを動かし、実行時間を計測。どの程度速くなるか、そのメリットを数値でご理解いただけることでしょう。
目次
■AppleScriptは遅いのか?
書き方によって速度差が出やすいAppleScript
①大規模データ操作時の固有ノウハウ
②GUIアプリ操作の固有ノウハウ
③各アプリ固有の操作ノウハウ
④適材適所
⑤連携運用できるプログラムなどへの知識
まとめ:AppleScriptは遅いのか?
■遅いScriptを実際に高速化
とても遅くて下手なScriptのサンプル
素人Scriptからの高速化:さまざまな方向から
Script高速化の第一歩は「時間計測」
下手なScriptは、少ないデータ件数では目立たない
高速化ポイント1:一括取得
高速化ポイント1:一括取得
高速化ポイント2:受け取ったデータの保持
高速化ポイント3:受信データの変換
高速化ポイント4:rangeの変換処理を自前で
素人Scriptを高速化①:データ保持方法を変える
素人Scriptを高速化②:通信頻度を減らす
■高速化しやすい処理の傾向
AppleScriptの処理で高速化しやすい箇所
Finderをファイル処理に使わない①
Finderをファイル処理に使わない②
1次元リスト(配列)のソート
1D Listのソート
1D Listのソート
2次元リスト(配列)のソート
2D Listのソート(1/2)
2D Listのソート(2/2)
2D Listのソート
アプリケーションのオブジェクトへのアクセス
画面部品を強引に動かすGUI Scripting
指定の値をクリップボードに入れる
遅くなりがちな処理を避ける
漠然と「遅い」と言われた処理の傾向
スクリプトエディタとAppleScript間の通信①
スクリプトエディタとAppleScript間の通信②
■データ量と処理内容のバランスを取る
複数アクセス方法すべてで実行速度を計測
リスト(配列)データの要素数によって変わる選択肢
1000〜3万件文字列追加+時間計測
まとめて操作できるデータを個別操作
要素が連続する部分をリスト上で検出
まとめて書式設定(1/2)
まとめて書式設定(2/2)
RTF読み取りライブラリ(1/2)
RTF読み取りライブラリ(2/2)
RTF読み取りライブラリ(rtfToDict)の結果
非同期実行モードの利用
Numbersの表のセルを100個埋めるテスト
処理対象に応じて因数分解を行う部品を変更
■処理内容を見直す &使用部品を変える
AppleScriptの速いバージョンのmacOSを選択
処理に使用する部品を変更(乱数生成)
処理に使用する部品と方式を変更
処理モジュールを一体化
使用するマシン構成を変更:複数のマシンで分散処理
使用するマシンを変更:本当に速いマシンを使う
■ランタイム環境の選択
AppleScriptのさまざまな実行環境
AppleScript実行環境の名称を取得する方法
エディタ①
エディタ②
エディタ③
アプレット,ドロップレット①
アプレット,ドロップレット②
メニュー実行①
メニュー実行②
メニュー実行③
その他実行プログラム①
その他実行プログラム②
その他実行プログラム③
アプリケーション内蔵メニュー①
アプリケーション内蔵メニュー②
相対パスを計算で求める
指定のPOSIX pathを元に相対パスを計算するAppleScriptです。
Unix shellであれば、相対パスについては「../../../」などと表現できるわけですが、シェルを介さずに計算する方法が見つからなかったので、必要に迫られて作っておきました。
AppleScript名:上位パスを相対的に求める.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/06/14 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set aFile to "/Users/me/Documents/1/2/3" set aNum to 1 set bFile to getUpperDir(aFile, aNum) of me –> "/Users/me/Documents/1/2" set aNum to 2 set cFile to getUpperDir(aFile, aNum) of me –>"/Users/me/Documents/1" set aNum to 3 set dFile to getUpperDir(aFile, aNum) of me –> "/Users/me/Documents" –与えられたパスから指定階層「上」のパスを求める on getUpperDir(aPOSIXpath as string, aNum as integer) if aNum < 1 then return aPOSIXpath set pathString to current application’s NSString’s stringWithString:aPOSIXpath repeat aNum times set pathString to pathString’s stringByDeletingLastPathComponent() end repeat return pathString as string end getUpperDir |
AppleScript名:下位パスを配列で追加して求める.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/06/14 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set aPOSIXpath to "/Users/me/Documents/" –AppleScriptのPOSIX path表現(フォルダを表現するさい、末尾に「/」) set catDirList to {"1", "2", "3"} set bPath to getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList) of me –> /Users/me/Documents/1/2/3 set aPOSIXpath to "/Users/me/Documents" –CocoaのPOSIX path表現(フォルダを表現する場合でも、末尾に「/」入らず) set catDirList to {"3", "2", "1"} set cPath to getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList) of me –> "/Users/me/Documents/3/2/1" on getChildPathByAppendingDirsByArray(aPOSIXpath, catDirList) set pathString to current application’s NSString’s stringWithString:aPOSIXpath set aList to (pathString’s pathComponents()) as list set aList to aList & catDirList set bPath to current application’s NSString’s pathWithComponents:aList return bPath as string end getChildPathByAppendingDirsByArray |
新発売:AppleScript基礎テクニック集(15)フォルダアクション
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第15巻、「フォルダアクション」です。PDF 33ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
フォルダアクションは、任意のフォルダにAppleScriptを添付して、ユーザーがファイルを入れたり削除したり、フォルダをオープンしたりクローズすると指定のAppleScriptが実行されます。
実際には、共有フォルダに対してフォルダアクションを設定、多くのユーザーが所定のファイルをフォルダに入れることで、提出処理を簡略化したり、時間のかかる処理を集約してサーバー機で行わせる、所定の処理を確実に所定のパラメータや手順で行わせるといったシステムが使われてきました。
本書では、Macの便利で強力な機能である本フォルダアクションについて、ローカルのMac上に設定する方法について、基礎的な内容をご説明しています。
目次:
■フォルダアクションの歴史と仕組み
フォルダアクションとは?
フォルダアクション運用例
Classic Mac OS時代から続く伝統の機能
フォルダアクション関連ツール、ファイル
フォルダアクションScript中で利用可能な技術
■フォルダアクションの設定方法
フォルダアクション設定の使い方①
フォルダアクション設定の使い方②
フォルダアクション設定の注意点①
フォルダアクション設定の注意点②
■フォルダアクション自体のAppleScriptからの操作
Script側から行えるフォルダアクション操作①
Script側から行えるフォルダアクション操作②
Script側から行えるフォルダアクション操作③
Script側から行えるフォルダアクション操作④
■フォルダアクションの種類と書き方
イベントハンドラのパラメータ内容①
イベントハンドラのパラメータ内容②
実例1:入ってきたフォルダ中のPDFを大きさで分類①
実例1:入ってきたフォルダ中のPDFを大きさで分類②
実例1:入ってきたフォルダ中のPDFを大きさで分類③
実例2:指定フォルダのウィンドウ操作を受信
新発売:AppleScript基礎テクニック集(14)ファイルサーバーのマウント
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第14巻、「ファイル処理」です。PDF 32ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
サーバー上の任意のマウント対象フォルダの情報を確認する方法がそっけなくて(地味で)、知らないと手も足も出ないという状況でもあります。
サーバー上の特定のフォルダをドライブとしてマウントする、という些細な処理ではあるものの、知っておくべき要点が多いのでまとめてみました。
続刊として予定しているeppc(リモートAppleEvent)について、このファイルサーバーのマウントの延長線上にあるため、eppcを使いたい人にはマスターしておくべきテーマといえるでしょう。
目次:
■macOSのファイル共有の仕組み
ファイル・サーバーとクライアントの関係
macOSのバージョンとファイル共有機能の変化
資料:ファイル共有プロトコルの歴史
共有する側(サーバー)の共有設定
共有する側(サーバー)の共有設定
共有URLの確認①
共有URLの確認②
共有URLの確認③
■サーバー・マシン名の確認
サーバー名の確認
サーバーURLの表記方法
■LAN上のサーバーの存在確認
LAN内のサーバー・プロトコル
指定プロトコルのサーバー一覧の取得①
指定プロトコルのサーバー一覧の取得②
指定プロトコルのサーバー一覧の取得③
指定プロトコルのサーバー一覧の取得④
■AppleScriptのmount volumeコマンド
mount volumeコマンド
指定のサーバー/フォルダをマウント
ファイルサーバーちょっといいノウハウ
Keynote書類中のスライドのトビラページを推測する
Keynote書類中の各スライド(ページ)のベースレイアウト(テンプレート)の名称から、トビラのページを推測するAppleScriptです。
まずは、なんでトビラのページを特定する必要があるのかといえば、TOC(Table Of Contents)つきでPDFに書き出す際に必要だからです。
トビラのページとは、
こういうものです。記事の開始ページに入っており、記事と記事の区切りをわかりやすくするために入れるものです。
そして、TOCはこういうものです。
目下、このTOCにおける階層をベースレイアウト名から推測するロジックをAppleScriptで組んでいますが、ざっくり言って「ベースレイアウト名」から推測している状態です。
もともと、Keynote書類からAppleScriptで各スライドの階層(Level)を取得できるとか、そもそもKeynote自体にTOCつきPDFを書き出す機能がついていれば、外部からScriptで操作しなくても済むわけですが、バージョンアップを繰り返してもそんな便利な機能がつく気配すらありません。Appleに機能追加のリクエストを出して、それが実装されるまで気長に待つよりも、今日すぐにでもScriptから実装したほうがよほど建設的です。また余計なことをされて機能不全を起こされても迷惑ですし。
なので、非常に遠回りな方法ではあるものの、ベースレイアウト(テンプレート)の名称からレベルを推測せざるを得ないというのが現状です。
ただ、これにも限界があります。「だいたい扉のページにはこのベースレイアウト(テンプレート)を使うよね」という「お約束」をベースに、処理を組み立てることになります。
扉のページにつかいがちなベースレイアウト(テンプレート)をあらかじめリストアップしておいて、該当するものを一律に「扉」とみなしてもいいはずです。
ただ、これもいまひとつ信用できないので、もう1手間かけておきたいところです。
Keynote書類のすべてのスライドからベースレイアウト(テンプレート)名を取得し、出現頻度やスライドの傾向から扉ページを特定したいところでもあります。
まずは、ベースレイアウト名一覧を取得し、ユニーク化(重複削除)。それぞれのベースレイアウト名でループして、書類中における出現頻度を求めます。
出現頻度については、1回ということはないでしょうし(規模によってはあるかもしれない)、全ページが該当するものでもないでしょう。また、表紙(最初のページ)、裏表紙(最後のページ)も異なります。
さらに、扉ページについていえば、ページ内に存在する文字アイテム(text item)が少ないことが期待されます。少なくとも自分が作るようなコンテンツではそうした傾向があります。
とりあえず、AppleScriptでKeynote書類からさまざまな情報を取得し、統計的なデータを取得(ページ上に存在するtext item数の標準偏差)するなどして、全体的な傾向を把握して検討するところでしょう。
あまりやりたくはないものの、完全な一括処理(ユーザーにどれが扉ページかを問い合わせない)を行うのではなく、ユーザー(自分)に扉ページのベーススライド名を確認する処理を追加することになるでしょうか。
--> {{baseLayoutName:"タイトルのみ", itemNumList:{10, 3, 3, 7, 14, 16, 10, 8, 6, 17, 9, 11, 16, 17, 11, 3, 3, 3, 15, 7, 16, 7, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 10, 3, 3, 3, 13}, stdDev:4.939129779062}, {baseLayoutName:"タイトル(上)広告用", itemNumList:{56, 22}, stdDev:17.0}, {baseLayoutName:"セクション", itemNumList:{4, 3, 2, 2, 2, 2, 2}, stdDev:0.728431359085}}
AppleScript名:各ベースレイアウト出現頻度およびレイアウト上のアイテム数の分布から扉を推測するテスト.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/06/04 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions property NSExpression : a reference to current application’s NSExpression property NSMutableArray : a reference to current application’s NSMutableArray tell application "Keynote" tell front document set themeNames to name of base layout of every slide set themeList to items 2 thru -2 of themeNames –> {"タイトルのみ", "タイトル(上)_飾りなし", "タイトル(上)広告用", "タイトル(上)広告用", "セクション", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ", "セクション", "タイトルのみ", "タイトルのみ", "タイトルのみ", "タイトルのみ"} set uniList to uniquify1DList(themeList) of me –> {"タイトルのみ", "タイトル(上)_飾りなし", "タイトル(上)広告用", "セクション"} set tobiraKouhoList to {} repeat with i in uniList set j to contents of i set tmpSList to (every slide whose name of base layout is equal to j) if length of tmpSList ≥ 2 then set tRatioList to {} repeat with ii in tmpSList set jj to contents of ii tell jj set aList to (every iWork item) set the end of tRatioList to length of aList end tell end repeat set d1Res to calcStddev(tRatioList) of me set the end of tobiraKouhoList to {baseLayoutName:j, itemNumList:tRatioList, stdDev:d1Res} end if end repeat return tobiraKouhoList –> {{baseLayoutName:"タイトルのみ", itemNumList:{10, 3, 3, 7, 14, 16, 10, 8, 6, 17, 9, 11, 16, 17, 11, 3, 3, 3, 15, 7, 16, 7, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 12, 12, 10, 3, 3, 3, 13}, stdDev:4.939129779062}, {baseLayoutName:"タイトル(上)広告用", itemNumList:{56, 22}, stdDev:17.0}, {baseLayoutName:"セクション", itemNumList:{4, 3, 2, 2, 2, 2, 2}, stdDev:0.728431359085}} end tell end tell –標準偏差を計算する on calcStddev(aList) –https://nshipster.com/nsexpression/ set anArray to NSMutableArray’s arrayWithArray:aList set anExp to NSExpression’s expressionForFunction:"stddev:" arguments:{(NSExpression’s expressionForConstantValue:anArray)} set valList to anExp’s expressionValueWithObject:(missing value) context:(missing value) return valList as real end calcStddev on uniquify1DList(theList as list) set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList return (theSet’s array()) as list end uniquify1DList |
最近お蔵入りした企画
やたらと本ばかり書いている昨今ですが、すべての企画が通っているわけでもなく、チーム内の会議で没になったものもいくつかあります。
最新の、没になりたてホヤホヤの活きのいいピチピチの没企画がコレ(↑)です。
以前から「TerminalからMacを使う、Unix系やWindows系の開発者がいるらしい」「ASを使ってみたいらしいがよく分からないらしい」という、割とふわっとした情報をもとに企画を立てていました。
ただ、真面目に書くと、けっこうな分量(Webブラウザ本ぐらい)になり、それ相応の時間がかかることがわかりました。
そこまで手間をかけても、そこまで強力なニーズがあるのかは不明です。
そこで、急きょこの本のテーマを最小限度にまで縮小して、「AppleScript基礎テクニック集」に再編集したのが、
コレです。この本だけでも、ASからdo shell script経由でshellを呼び出すためのノウハウや、Terminal内のshell commandからASを呼び出す際に知っておくべきことなどを網羅できています。
この「Terminalから使う本」から「AppleScript基礎テクニック集」本に変換する際に削除した要素が、
・さまざまなデータ型をパラメータに指定してやりとりするための支援プログラム
といったあたりです。
配列でデータを渡すのにJSON形式に変換して、結果もJSONで返すとか、そういうデータ変換を行うライブラリを「本」というかたちで提供しようかと考えてみたものの、これもやはり「それなり」に時間がかかるのでなんとも。
「AppleScript基礎テクニック集」のshell script編で様子を見ています。現時点ではお蔵入り判定です。
ずいぶん昔(「AppleScript最新リファレンス」を書いた直後)から企画を温めてはいるものの、なかなか形になりません。
DTKeychainのじっけん
オープンソースのFramework「DTKeychain」をUniversal Binaryビルドして、Script Debugger環境からこれをAppleScriptで呼び出すテストを行なったものです。
–> Download DTKeychain.framework (To ~/Library/Frameworks)
macOS 10.7でKeychain Scriptingが廃止されて以来、shell commandの「security」や、さまざまなCocoa Frameworkを呼び出すようにScript側の対応が迫られてきたわけですが、割とKeychain関連のFrameworkは入れ替わりが激しいジャンルです。
ときて、いまmacOS用のKeychain系のFrameworkとして個人的に注目しているのが、
です。SAMKeychainでひととおりのKeychainの機能を持っていたので、まだ機能が少ないDTKeychainは完全に代わりになってはいないのですが、SAMKeychainで様子を見つつDTKeychainの機能の充実に期待といったところでしょうか。
# DTKeychainもそんなに新しくないプロジェクトではあるものの、SAMKeychainの作者に問い合わせたところ「SAMKeychainはもうメンテしていないので他人に推奨しないでくれ(意訳)」と言われています
AppleScript名:DTKeychainのじっけん 1.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/05/31 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions use framework "DTKeychain" –https://github.com/Cocoanetics/DTKeychain — get shared instance set keychain to current application’s DTKeychain’s sharedInstance() — create a keychain query for generic passwords set query to current application’s DTKeychainGenericPassword’s keychainItemQueryForService:"foo" account:(missing value) –> {class:"genp", svce:"foo"} — retrieve matching keychain items set {itemList, errorRes} to keychain’s keychainItemsMatchingQuery:query |error|:(reference) –> {{}, missing value} if itemList as list is not equal to {} then log errorRes’s localizedDescription() end if |
AppleScript名:DTKeychainのじっけん 2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/05/31 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions use framework "DTKeychain" –https://github.com/Cocoanetics/DTKeychain — get shared instance set keychain to current application’s DTKeychain’s sharedInstance() — just create a new instance of the generic password and set values set pass to current application’s DTKeychainGenericPassword’s new() pass’s setAccount:"bar" pass’s setService:"foo" pass’s setPassword:"PIYOMARU" — write the new object to the keychain set kRes to keychain’s writeKeychainItem:pass |error|:(missing value) –> true |
新発売:AppleScript基礎テクニック集(13)ファイル処理
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第13巻、「ファイル処理」です。PDF 33ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
AppleScriptによるファイル処理は、MacBook AirからはじまったSSD標準採用、macOS 10.10以降のCocoa Scriptingの標準化、高速なApple Siliconへの移行なども相まって、非常に高速なものとなってきました。とくに、NSFileManager経由で処理をしたときの速度がすさまじく高速です。最新のOS、最新のマシンの組み合わせで必携の一冊!
目次:
最近のmacOSのファイル処理事情
AppleScriptのファイル処理には3通り
フルディスクアクセスの設定を
64ビット化されてFinderは遅くなった
どこで差がつく? ファイル処理
複数の条件をつけてFinderでファイル取得
条件抽出
ファイル情報の抽出
Finderラベルによる抽出
リネーム(名称変更)
ファイルの名称変更=リネーム
フォルダの名称変更=リネーム
コピー(複製)
ファイルのコピー
フォルダのコピー
移動
ファイルの移動
フォルダの移動
削除
ゴミ箱への移動を行うだけの「ファイル削除」
ファイルの完全削除
ゴミ箱への移動を行うだけの「フォルダ削除」
フォルダの完全削除
RectangleBinPackを用いて2D Bin Packを解く v2.3
オープンソースの「RectangleBinPack」を用いて2D Bin Packagingを解き、Keynote上の汎用オブジェクト(iWork item)を指定矩形内に詰め込むAppleScriptです。
2D Bin Packは、指定のオブジェクトを面積で評価して、ターゲットの領域に「詰め込む」(オブジェクト回転あり)という処理で、ワードクラウドであるとか、記事レイアウト時の最適化配置といった用途に用いられます。
さまざまなアルゴリズムが提唱され、コンピュータの登場初期からどえらい先人たちが攻めまくった分野であるため、ありがたく、その成果をいただいているという用途でもあります。
よく、ゲームのテクスチャ画像を1枚の画像ファイルに詰め込む際に2D Bin Packの処理を用いている例を見かけます。なんでファイルごとに分けないのかはわかりませんけれども(ファイル容量の節約???)。
–> Download Script bundle with RectangleBinPack in its bundle + sample Keynote document
# This AppleScript requires RectangleBinPack executable in its bundle. So, download the whole AppleScript bundle archive from the link above (↑)
オープン中のKeynote書類の表示中のスライド(ページ)上にある矩形オブジェクト(Shape)を指定の矩形エリア内に2D Packingします。エリアの大きさが小さすぎると正常にPackingされなかったり、false(エラー)を返したりします。
変更履歴:
v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Makeを書き換えて直接Universalバイナリに仕立てられるといいのに)
v2.2: BridgePlusがなくても動くように書き換えた(ないと動かないのはいろいろ運用上問題がある)
v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した
AppleScript名:rectBinPack v2.3_Universal.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/05/31 — – Copyright © 2019-2022 Piyomaru Software, All Rights Reserved — — 2D Bin Packing by juj https://github.com/juj/RectangleBinPack — v2.1: BinPackTestをIntel x64とARM binaryのそれぞれのバイナリでビルドしてバンドルに入れた(Universalバイナリに仕立てられるといいのに) — v2.2: BridgePlusを外した(ないと動かないのはいろいろ運用上問題がある) — v2.3: shapeに対してBinPackしていたのを、Keynote上の汎用オブジェクトへのアクセス予約語iWork itemでアクセスするように変更した use AppleScript version "2.4" use framework "Foundation" use scripting additions –Packaging Target Area set binSizeX to 600 set binSizeY to 600 set packRes to packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY) of me on packKeynoteObjectsOnCurrentSlide(binSizeX, binSizeY) set {tList, a0List} to retRectsFromKeynote() of me set aList to sortList2DDecending(a0List, {"myWidth", "myHeight", "myArea"}) of me –Sorting key is Width(main) and Area(sub) and Height(sub) set aRes to twoDBinPacking(binSizeX, binSizeY, aList) of me if aRes = false then return false tell application "Keynote" tell front document tell current slide repeat with i in aRes set {posX, posY} to myPos of i set itemIndex to myID of i set aDeg to myDegree of i –sample data {itemCounter:5, myWidth:573, myHeight:52, myArea:29796} set anObjID to itemCounter of (item itemIndex of aList) set rotation of iWork item anObjID to aDeg set position of iWork item anObjID to {posX, posY} end repeat end tell end tell end tell return true end packKeynoteObjectsOnCurrentSlide on twoDBinPacking(binSizeX as integer, binSizeY as integer, boxList as list) set aParamList to {binSizeX, binSizeY} repeat with i in boxList –copy i to {tmpID, tmpX, tmpY, tmpArea} — {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea} set tmpID to itemCounter of i set tmpX to myWidth of i set tmpY to myHeight of i set tmpArea to myArea of i set aParamList to aParamList & tmpX set aParamList to aParamList & tmpY end repeat set aParam to retDelimitedText(aParamList, " ") of me –> "800 800 340 243 340 73 340 73 155 240 147 125 147 125 147 125 147 125" –Parameters for result parsing set s1Str to "Packed to (x,y)=(" set s2Str to ")" set s3Str to "," set cpuRes to CPU type of (system info) if cpuRes begins with "ARM" then set exName to "arm" else if cpuRes begins with "Intel" then set exName to "x86" end if set binName to "BinPackTest_" & exName set aPath to POSIX path of (path to resource binName) try set aRes to do shell script quoted form of aPath & " " & aParam on error return false end try if aRes does not end with "Done. All rectangles packed." then return false set aList to paragraphs of aRes set bList to {} set aCount to 1 repeat with i in aList set j to contents of i if j begins with "Packing rectangle of size " and j does not contain "Failed!" then set xyRes to pickUpFromToStrAndParse(j, s1Str, s2Str, s3Str) of me –RectangleBinPackがオブジェクトの回転をサポートしているため、その対処 if xyRes is not equal to false then set s11Str to "(w,h)=(" set s12Str to ")" set s13Str to "," set whRes to pickUpFromToStrAndParse(j, s11Str, s12Str, s13Str) of me set tmpBox to item aCount of boxList — {itemCounter:5, myWidth:573, myHeight:52, myArea:29796} –copy tmpBox to {tmpID, tmpX, tmpY, tmpArea} set tmpID to itemCounter of tmpBox set tmpX to myWidth of tmpBox set tmpY to myHeight of tmpBox set tmpArea to myArea of tmpBox if whRes = {tmpX, tmpY} then set aDeg to 0 else if whRes = {tmpY, tmpX} then set aDeg to 90 else return false end if set the end of bList to {myPos:xyRes, myID:aCount, myDegree:aDeg} end if set aCount to aCount + 1 end if end repeat return bList end twoDBinPacking on pickUpFromToStrAndParse(aStr as string, s1Str as string, s2Str as string, s3Str as string) set a1Offset to offset of s1Str in aStr if a1Offset = 0 then return false set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr set a2Offset to offset of s2Str in bStr if a2Offset = 0 then return false set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr set {x, y} to parseByDelim(cStr, s3Str) of me return {x as integer, y as integer} end pickUpFromToStrAndParse on parseByDelim(aData, aDelim) set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set dList to text items of aData set AppleScript’s text item delimiters to curDelim return dList end parseByDelim –リストを指定デリミタでテキスト化 on retDelimitedText(aList, aNewDelim) set aText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aNewDelim set aText to aList as text set AppleScript’s text item delimiters to curDelim return aText end retDelimitedText on retRectsFromKeynote() tell application "Keynote" tell front document tell current slide set tList to every iWork item set bList to {} set iCount to 1 repeat with i in tList set aWidth to width of i set aHeight to height of i set {xPos, yPos} to position of i set anArea to aWidth * aHeight set the end of bList to {itemCounter:iCount, myWidth:aWidth, myHeight:aHeight, myArea:anArea} set iCount to iCount + 1 end repeat return {tList, bList} end tell end tell end tell end retRectsFromKeynote –入れ子のリストを降順ソート on sortList2DDecending(a, keyLabelList) set fLen to length of keyLabelList set fList to {} repeat fLen times set the end of fList to false end repeat return cocoaSortListAscending(a, keyLabelList, fList) of me end sortList2DDecending –Cocoaで入れ子のリストをソート true:昇順、false:降順 on cocoaSortListAscending(theList as list, keyLabelList as list, ascendingF as list) set anArray to current application’s NSMutableArray’s arrayWithArray:(theList) set sortDesc to {} set dLen to length of keyLabelList repeat with i from 1 to dLen set tmpKeyLabel to contents of item i of keyLabelList set tmpSortF to contents of item i of ascendingF set theDescriptor to (current application’s NSSortDescriptor’s sortDescriptorWithKey:(tmpKeyLabel) ascending:(tmpSortF)) set the end of sortDesc to theDescriptor end repeat set sortedList to anArray’s sortedArrayUsingDescriptors:(sortDesc) return sortedList as list end cocoaSortListAscending |
人類史上初、魔導書の観点から書かれたAppleScript入門書「7つの宝珠」シリーズ開始?!
いつものようにコードレス糸電話(FaceTime Audio)で企画会議を行なっていたら、「プログラミングを魔導書の形式で書くことが可能なのではないか?」というアイデアが登場。その場でアイデアスケッチを行い、あれよあれよという間に、実物ができてしまいました。
ノリと勢いだけで作ってしまった1冊ですが、ビジュアル要素多めでまとめられました。ただ、宗教的なアレとかナニとかを完全に無視して作ったものなので、日本国内でしか流通させないほうがよいでしょう。
本書は、プログラミングという魔法について、「魔導書」の観点から記した人類最初の書物である。
難解なプログラミングを、なじみ深い魔導書の観点から説明すると親しみやすくなるのだろうか、という1つの魔術モルモット実験でもある。
本書で扱う内容はごくごく簡単で基礎的な内容だが、このぐらいにしぼって解説すれば難しく見えないという7テーマ、七宝珠である。
「習うより慣れろ」ということわざがあるように、難解な魔術であっても苦手意識を持たずに「慣れる」ことは重要である。 本書をもってしても、真の魔道士を育成することは難しい。だが、「だいたいこんなかんじ」という感覚をつかむためには、このぐらいの分量に抑えることが肝要だろう。
PDF 31ページ
目次
■魔導書「7つの宝珠」
神(Computer)との対話を行う人の子の書
失われし魔法の7つの宝珠を求めて
変数と代入文という最初の宝珠
if文〜条件分岐という宝珠
繰り返しループ 体力を削らせない宝珠
配列変数 詠唱呪文の機能を高める宝珠
コメント文 失われた知恵の宝珠
ログ表示 簡単に変数の中身を確認する宝珠
終了 そこで呪文実行を止める宝珠
■第1の宝珠 変数と代入文
神の言葉から人の子の言葉への移行
巻物で満ち溢れる人の子の世
牛飼いを羊飼いに変える変数
変数に牛や羊を入れるのが「代入」
変数の中に何がある?
■最短詠唱呪文集
魔術入門〜最短詠唱呪文
警告音を鳴らす魔術「beep」
現在の日付を知る魔法「current date」
クリップボードの内容を調べる魔法
時間待ちを行う魔法「delay」
ゆうしゃ(=あなた)のステータス
Keynoteの現在の書類と同じ階層に没スライド入れを作成
Keynoteの最前面の書類(現在の書類)と同じ階層に没スライドを入れるゴミ箱用のスライドを、編集中の現在のスライドと同じサイズ(Normal/HD)で同じテーマで作成するAppleScriptです。
ふだん、Keynoteで作業をしているときに、不要になったスライド(ページ)を完全削除せず、別書類に移動させて復活させられるようにしているのですが、その作業が煩雑だったのでScriptで自動化したものです。
同階層にゴミ箱用のスライド書類が存在していたら、それをオープンします。存在していなければ、新規作成して指定ファイル名で保存….というところで、v12のバグに遭遇してしまったわけです。
AppleScript名:Keynoteの現在の書類と同じ階層に没スライド入れを作成.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/05/29 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" property newFileName : "没.key" —"trash.key" tell application "Keynote" tell front document set dName to getCurThemeName() of me set curFile to (file of it) as alias set myHeight to height of it set myWidth to width of it end tell end tell –書類の親フォルダを取得(POSIX path) set parentFol to getParentFol(curFile) of me set newKeynoteFile to parentFol & "/" & newFileName –ファイルの存在確認 set exRes to chkFileExistence(newKeynoteFile) of me if exRes = true then –すでに存在している場合はそれをオープン set newKeynoteFileAlias to (POSIX file newKeynoteFile) as alias tell application "Keynote" open newKeynoteFileAlias end tell return else –まだ存在していない場合、最前面の書類と同じテーマ、縦横比(SD、HD)の新規書類を作成する set parentFolAlias to (POSIX file parentFol) as alias as string –POSIX path to HFS path string set saveFilePathStr to (parentFolAlias as string) & newFileName tell application "Keynote" set newDoc to make new document with properties {document theme:theme dName, width:myWidth, height:myHeight} –save newDoc in file saveFilePathStr as Keynote–Keynote v12のバグに遭遇したため機能オフに end tell end if –ファイルの存在確認 on chkFileExistence(aFilePathStr) set fileManager to current application’s NSFileManager’s defaultManager() set aRes to fileManager’s fileExistsAtPath:aFilePathStr return aRes as boolean end chkFileExistence on getParentFol(anAlias) set aPath to POSIX path of anAlias set pathString to current application’s NSString’s stringWithString:aPath set newPath to pathString’s stringByDeletingLastPathComponent() return newPath as string end getParentFol on getCurThemeName() tell application "Keynote" set dCount to count every document if dCount = 0 then error "No Document" tell front document set aTheme to document theme set atThemeName to name of aTheme end tell end tell end getCurThemeName |
Keynoteで選択中のスライドのすべての表のセル内文字色を黒にする
Keynote v12.0以降で、最前面の書類で選択中のスライド(複数可)にある表のすべての文字色を「黒」に変更するAppleScriptです。
Keynote v12.0で「selection」がまともに機能するようになったので、Keynote用Scriptの実用性がたいへんに高まっています。
# ファイル保存できないとかいうバグが一刻も早く治ることを希望しています。とくに、Pages!
もともと、複数ページにわたって掲載している「表」の中に赤字でマークした箇所があって、そのマークの意図とは別の赤字を入れたかったので、いったんすべて書式をリセットしたかったので書いたものです。
もうちょっと長いScriptを書かなければならないかと思っていたのですが、ことのほかシンプルに書けました。
もっとシンプルに書けるか(everyを使ってスライドごと指定するとか)も試してみたのですが、どうやらこのあたりが限界のようです。
Keynoteのselectionを活かしたScriptでいまいちばん活躍しているのは、Keynoteのテキストアイテム(text item)から内容を取得して、メモリ上でAppleScriptとしてコンパイルし、構文色分けを反映させたスタイル付きテキストを取得して、テキストアイテムに書式を反映させるものです。実に、Keynote上にテキストで書いておいたAppleScriptのリストを構文色分けを反映させた掲載リストに変換できるので便利です。
AppleScript名:Keynoteで選択中のスライドのすべての表のセル内文字色を黒にする.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/05/27 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — tell application "Keynote" set aVer to version considering numeric strings if aVer < 12.0 then return –Keynote v12.0より以前のバージョンでは実行できない end considering tell front document set aaSel to selection set selClass to class of contents of first item of aaSel if selClass is not equal to slide then return –選択中のオブジェクトがslide(ページ)でなければ処理終了 repeat with i in aaSel set j to contents of i tell j –現在のスライド上のすべての表のすべてのセルの文字色を黒 {0, 0, 0}に set text color of every cell of every table to {0, 0, 0} end tell end repeat end tell end tell |
新発売:AppleScript基礎テクニック集(12)Unix shell commandの利用
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第12巻、「Unix shell commandの利用」です。PDF 34ページ、サンプルAppleScriptのZipアーカイブを添付。
Unix shell commandの利用といったときに、「AppleScriptからdo shell scriptコマンドでshell commandを呼び出す」話と、「shell commandやshell scriptの中でAppleScriptで書いたプログラムを呼び出す」という、まったく価値観の異なる別の話が含まれています。
本書は、これらのまったく別な話に含まれている概念やノウハウを整理し、わかりやすく具体的にその方法や制限についてご紹介する本です。
目次
■Terminal環境とdo shell script環境の違い
shell scriptをAppleScriptと組み合わせるために
ターミナルに書類のパスを入力する方法
Terminalからプロセスの確認と終了を
Terminalとdo shell sciptの環境変数
Terminal.appをAppleScriptで操作できる①
Terminal.appをAppleScriptで操作できる②
AppleScriptからshell scriptを呼び出す
do shell scriptコマンド
パス形式変換
Terminal.app上と同じ環境変数を使用するには
参考資料:新規インストールしたユーザーの環境変数
パラメータの与え方について
do shell scriptコマンドちょっといいノウハウ
コマンドライン呼び出しプログラムをScriptに同梱
shell scriptからAppleScriptを呼び出す
AppleScript関連のshell command
shell scriptからAppleScriptを呼び出す方法①
shell scriptからAppleScriptを呼び出す方法②
パラメータ指定できるAppleScriptの書き方
AppleScriptライブラリを呼び出せる?
パイプで指定した内容を受信できる?
GUI Scriptingを利用できる?
ホームディレクトリ下のFrameworkを呼べる?
Pages v12に謎のバグ。書類上に11枚しか画像を配置できない→解決
Pages v12に謎のバグを見つけました。Pagesでは書類上に任意の画像を配置できるわけですが、11枚目までは配置できるものの、12枚目を配置できません。実際には120枚ほど画像を用意してテストしていたので、12枚目が配置できればそれでOKかと言われれば、ぜんぜん不十分です。
→ OSの再起動を含む、追試を何回か行ってみたところ、その後このままでは画像の貼り込みができなくなっていました。そして、画像ファイル貼り込み前にパスの文字列をaliasにcastしたところ、問題なく120枚貼り込めました。
以前にも、Keynoteに「特定サイズ以上の表を作るとエラーになる」とかいったバグが発生していましたが、この12個目を配置するとエラーになるというのも、内部で何か不可思議なリミッターを設けているように見えます。
スクリプトエディタ、Script Debuggerの両方で発生しています。おそらく、ランタイム環境が何であるかはこの問題に影響を与えていません。
macOS 10.12以降で、日本語環境限定で発生しているバグで有名なものに、「日本語入力Input Method経由でファイル名を入力している最中に、不必要な不可視文字が入力されてしまい、これがファイル処理を妨げる危険性がある」というものがありますが、これらの画像のファイル名をチェックしたところ、そうした危険な不可視文字は混入していませんでした。
# こうした、複数チームの担当製品の間で発生しているバグは、どこが担当してバグを調査するということはないようです。組織の細分化にともない、こうした組織境界面でバグが発生するととたんに無責任になるのがいまのAppleです(組織の構造上の問題です)
ちなみに、GUI経由で画像をPages書類上に配置してみたところ、12枚以上配置できました。Pagesにそのような上限が存在しているわけではないようです。
Pages書類(バンドル書類)内で何かファイル名の重複のようなものが発生したのかと考え、別の画像を(番号をずらして)指定してみましたが、同様の枚数を配置した時点でエラーになりました。
内部で発生している(していた)別のエラーを発生させないように、謎のリミッターをかけていた可能性もありますが、その必然性がよくわかりません。
AppleScript名:指定の画像をPagesに順次貼り込む(12枚で止まってしまう!).scpt |
set baseName to "book24_" set baseFol to (choose folder) as string set pMax to 10 (* tell application "Pages" –set newDoc to make new document tell front document set dCount to count every page repeat with i from (dCount + 1) to pMax make new page end repeat set newDCount to count every page end tell end tell *) repeat with i from 1 to 120 set aFN to baseFol & baseName & makeFN(i, 4) of me & ".jpg" tell application "Pages" tell front document tell page i set newItem to make new image with properties {file:aFN} tell newItem set position of it to {0, 0} set height of it to 843 –set position of it to {-1, 0} set locked to true end tell end tell end tell end tell end repeat on makeFN(aNum, aDigit) set aText to "00000000000" & (aNum as text) set aLen to length of aText set aRes to text (aLen – aDigit + 1) thru -1 of aText return aRes end makeFN |
iWorkアプリケーションv12に共通のバグ? 新規ファイルの保存ができない
Apple iWorkアプリケーション(Keynote、Pages、Numbers)の最新バージョンv12.0において、共通のバグがあるのではないか? と見ています。もちろん、見ているだけでなくAppleにバグレポートもしています。
症状は、新規作成した書類を「保存できない」というものです。
以前にも、PDFをexportできないという致命的なバグが発生していましたが、今回のも同様のメカニズムで発生しているものと見ています。つまり、「Appleが自社OSに設定したセキュリティ機能によって、自社アプリであるKeynote、Pages、Numbersが自家中毒を起こしている」という状態です。
自分の勘違いだとよいのですが….
あとは、Numbersのsaveコマンドをよく見てみると、書類フォーマットに「as Numbers」というenumがあるのですが、これはAppleScriptの処理系では「number」の複数形として認識されてしまうので、この予約語自体に無理があります。ここは、「as Numbers format」といった予約語に変えるべきです。
AppleScript名:Keynoteで新規書類作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".key" set savePath to dtPath & uuidStr tell application "Keynote" set nDoc to make new document with properties {document theme:theme id "Application/21_BasicWhite/Standard", width:1024, height:768} save nDoc in file savePath as Keynote end tell |
AppleScript名:Pagesで新規書類を作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".pages" set savePath to dtPath & uuidStr tell application "Pages" set nDoc to make new document with properties {document template:template id "Application/Blank/ISO"} save nDoc in file savePath as Pages Format end tell |
AppleScript名:Numbersで新規書類作成して指定名称で新規保存.scpt |
set dtPath to (path to documents folder) as string set uuidStr to (do shell script "uuidgen") & ".numbers" set savePath to dtPath & uuidStr tell application "Numbers" set nDoc to make new document save nDoc in file savePath as numbers –change "Numbers" word into "numbers format" because "numbers" is alredy registered as "list of number" or "every number" end tell |
新発売:AppleScript基礎テクニック集(11)AppleScriptアプレットとドロップレット
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第11巻、「AppleScriptアプレットとドロップレット」です。PDF 41ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
本シリーズも、着手した頃には「そんなに細切れのテーマで書けるのか?」「そんな作り方で作れるはずがない」といった意見が集まっていたものですが(チーム内の打ち合わせ時には割と批判的です)、実際に作り出したらトンでもなく「書くべきこと」があって、書けば書くほど新たなテーマが見つかるという恐るべき状態。
今回の「アプレット」「ドロップレット」については、あまり振り返ったことがなかったのですが、いざ書いてみると尋常でないほどの情報が溜まっていました。
スクリプトエディタとScript Debuggerという2つの開発環境のちがい、アプレット、ドロップレット、Cocoa-AppleScriptアプレット、Script Debuggerの拡張ドロップレットなどなど。常駐タイプのアプレットに、タイマー割り込み処理のアプレット。アプレットのアイコンのカスタマイズに、アプレット内にAppleScriptライブラリを同梱する方法、Cocoa Frameworkを入れて呼び出す方法など、盛りだくさんな内容をお送りしています。
目次
■アプレット
AppleScriptをアプリケーション形式で書き出し
AppleScriptアプレットの種類
AppleScriptアプレットの作成方法
AppleScriptアプレットのオプション指定
常駐型AppleScriptアプレットの作成方法
常駐型AppleScriptアプレットの記述
アプレットの「初期画面」を指定
「初期画面」に画像をペーストした場合の動作
アプレット/ドロップレットのユーザーインタフェース
資料:スクリプト/アプレットのバンドル構造
資料:アプレットのカスタマイズ①
資料:アプレットのカスタマイズ②
資料:アプレットのカスタマイズ③
■Cocoa-AppleScriptアプレット
Cocoa-AppleScriptアプレットの作成方法
参考資料:Delegateスクリプトの内容確認方法
参考資料:Delegateスクリプトのヘッダー内容
参考資料:Delegateスクリプトのハンドラ
■Script Debuggerのアプレット/拡張アプレット
AppleScriptアプレット(SD)の作成方法
AppleScript拡張アプレット(SD)の作成方法
AppleScript拡張アプレット(SD)の作成方法
■ドロップレット
AppleScriptドロップレットの作成方法
AppleScriptドロップレットの作成方法
ドロップレットによるファイルの受信
macOS 10.12以降の問題への対策ドロップレット
macOS 12.4上でドロップレット処理を実験
Keynoteで選択中のGroup内オブジェクトを座標でソートし、テキスト抜き出し
Keynote v12.0以降でオープン中の最前面の書類の、表示中のスライド(ページ)上で選択中のグループから、その内部に収められているオブジェクトからテキストを取り出し、リスト(配列)にまとめるAppleScriptです。
▲1冊分のデータがグループにまとめられており、グループ内にオブジェクトを格納
いったんデータを組み上げた「書類」からデータを抜き出すのは、AppleScriptの重要な仕事です。各データ内のフィールドについて座標情報から自動判別するようにしていますが、座標値が想定どおりになっていない場合もあるため、これでもまだ不十分なので、相対的な位置関係(左上、右上、下 などといった)を定義してデータを取り出すようにするとよいでしょう。
……そこまで高度なものを作らなくても、文字列の長さに着目してソートしたら瞬殺でした。
AppleScript名:選択中のGroup内オブジェクトを座標でソートし、テキスト抜き出し.scpt |
use AppleScript version "2.8" use framework "Foundation" use framework "AppKit" use scripting additions property NSFont : a reference to current application’s NSFont property NSColor : a reference to current application’s NSColor property NSFontAttributeName : a reference to current application’s NSFontAttributeName property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName script spd property allList : {} property aaSel : {} end script set (allList of spd) to {} tell application "Keynote" set aVer to version if aVer < "12.0" then return set acceptClass to {text item, shape} tell front document set (aaSel of spd) to selection –need Keynote v12.0 or later repeat with i in (aaSel of spd) set j to contents of i set aClass to class of j if aClass = group then tell j set gItemList to every iWork item end tell set posList to {} set aCount to 1 repeat with ii in gItemList set jj to contents of ii set bClass to class of jj if bClass is in acceptClass then tell jj set {posX, posY} to position try set tmpStr to object text as string on error set tmpStr to "" end try end tell set the end of posList to {positionX:posX, positionY:posY, objID:aCount, myStr:tmpStr} end if set aCount to aCount + 1 end repeat –座標データをもとにソート set sortedList to sortRecListByLabel(posList, {"positionY", "positionX"}, {true, true}) of me –1グループ分のテキストを組み立てる set tmpList to {} repeat with ii in sortedList set jj to contents of ii set aStr to myStr of jj set the end of tmpList to aStr end repeat set the end of (allList of spd) to tmpList end if end repeat end tell end tell return (allList of spd) –> {{"変数名", "❺", "意外と苦労している人が多い、変数やプロパティ名の命名ルール。とくに、予約語と衝突しない名前について"}, {"条件分岐", "❼", "条件分岐はプログラムに必須。自転車でいえば、カーブで曲がれないとか、水たまりを避けられないぐらい困ります。"}, {"用語辞書", "❹", "読めないと書けない、でも、あの人もこの人も読めない用語辞書。自由自在に読めれば、自由自在に書ける!"}, {"ループ処理", "➓", "プログラムをシンプルに書くための一番大事な構文。書き方によって速度が違ったり、高度な処理を簡潔に書ける!"}, {"アプレット", "⓫", "AppleScriptをアプリケーションとして書き出す、簡易アプリケーション「アプレット」の最新動向!"}, {"間接指定", "❶", "対象としたデータだけでなく、幅広いデータに対応できるよう、プログラムに柔軟性を与える間接指定"}, {"ダイアログ表示", "❾", "簡単に行えるメッセージ表示手段。外部ライブラリの利用でさらなる高機能ダイアログを紹介。"}, {"環境整備", "❽", "macOSに標準で入っているツールを呼び出しやすくしたり設定したりする程度。全体像を掴んでレッツ環境整備。"}, {"フィルタ参照", "❻", "AppleScript独特の概念で、「膨大なデータから正規表現で絞り込む」などの他の処理系と異なる、基礎にして奥義"}, {"tellブロック", "❷", "AppleScriptの7割以上を占める、tellブロックの記述や整理方法を楽に書く秘訣のかずかず"}, {"❸", "ファイルパス", "まさに「基礎」中の「基礎」。「できて当たり前」といえるパス操作。知っているだけで差がつく基礎"}} –リストに入れたレコードを、指定の属性ラベルの値でソート on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list) set aArray to current application’s NSArray’s arrayWithArray:aRecList set aCount to length of aLabelStr set sortDescArray to current application’s NSMutableArray’s new() repeat with i from 1 to aCount set aLabel to (item i of aLabelStr) set aKey to (item i of ascendF) set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey) (sortDescArray’s addObject:sortDesc) end repeat return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list end sortRecListByLabel |
新発売:AppleScript基礎テクニック集(10)ループ処理
電子書籍の新刊を発売しました。新シリーズ「AppleScript基礎テクニック集」の第10巻、「ループ処理」です。PDF 33ページ、サンプルAppleScriptのZipアーカイブを添付。
→ 販売ページ
ループ処理について、さまざまなrepeat文のバリエーションをまんべんなくすべて知って理解するよりも「間違いなく必要な場所で使える」ことが重要です。
repeat文にもいくつか書き方はあるものの、おおよそ2パターンぐらいでだいたい足ります。
それでも、複数の配列を同時にループしなくてはならないとか、ステップ値を想定の値に合わせるための調整とか、ノウハウらしきものはいろいろあります。
また、参照値をそのまま使うとエラーになる例もあるため、「contents of」でオブジェクトを取り出す必要があるといったささいなノウハウが必要なものでもあります。
目次
■ループによる繰り返し処理
AppleScriptの制御構文
繰り返しループ
repeat文①
repeat文②
repeat文③
repeat文④
repeat文⑤
repeat文⑥
exit repeat
多重ループ+exit repeat
■アプリケーションから取得したオブジェクトでループ
アプリケーションのオブジェクトを処理
Photos上の選択中の写真から情報を取得
Keynoteで選択中のオブジェクトを位置でソート
Numbersで表のセルが連結されていたら分離
targetが重複しているFinder Windowをクローズする
ミュージック.appで選択中のtrackの情報取得
大量のオブジェクト受信に備える
■高度な処理を簡潔に記述
複数の配列の同時ループ
ページ分け
再帰処理
Safariで表示中のYouTubeムービーのサムネイル画像を取得
Safariで表示中のYouTubeムービーのサムネール画像を取得、保存、表示するAppleScriptです。
YouTubeのムービーのサムネール画像の取得方法を確認し、動作確認用にダイアログ表示+画像保存の機能を追加したものです。Script Debugger上で動かしている分には、NSImageの内容を結果表示ビューワで自動表示されますが、ない人向けに付けた機能です。
画像自体は、「ピクチャ」フォルダにUUIDつきでPNG形式で保存します。
–> Download Script bundle with Library
掲載リストには、画像表示ライブラリが含まれていないため、そのままでは実行できません。上記のScript Bundleをダウンロードして実行する必要があります。
AppleScript名:Safariで表示中のYouTubeムービーのサムネイル画像を取得.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/05/09 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" use imgLib : script "imageDisplayLib" property NSUUID : a reference to current application’s NSUUID property |NSURL| : a reference to current application’s |NSURL| property NSString : a reference to current application’s NSString property NSImage : a reference to current application’s NSImage property NSPNGFileType : a reference to current application’s NSPNGFileType property NSURLComponents : a reference to current application’s NSURLComponents property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep property NSMutableDictionary : a reference to current application’s NSMutableDictionary tell application "Safari" tell front document try set aURL to URL on error set aURL to "https://www.youtube.com/watch?v=_fmDtIV9vvI" end try end tell end tell if aURL does not start with "https://www.youtube.com/watch?" then return set urlDict to parseURLParamsAsDict(aURL) of me set aParam to urlDict’s valueForKey:"v" if aParam = missing value then return set imgURL to "https://i1.ytimg.com/vi/" & (aParam as string) & "/mqdefault.jpg" set newURL to |NSURL|’s URLWithString:imgURL set aImg to NSImage’s alloc()’s initWithContentsOfURL:newURL set imgPath to (POSIX path of (path to pictures folder) & ((aParam as string) & "_") & (NSUUID’s UUID()’s UUIDString()) as string) & ".png" –Save saveNSImageAtPathAsPNG(aImg, imgPath) of me –Display dispImage(aImg, "YouTube thumbnail") of imgLib on parseURLParamsAsDict(aURL) set components to NSURLComponents’s alloc()’s initWithString:aURL set qList to (components’s query())’s componentsSeparatedByString:"&" set paramRec to NSMutableDictionary’s dictionary() repeat with i in qList set keyAndValues to (i’s componentsSeparatedByString:"=") (paramRec’s setObject:(keyAndValues’s objectAtIndex:1) forKey:(keyAndValues’s objectAtIndex:0)) end repeat return paramRec end parseURLParamsAsDict –NSImageを指定パスにPNG形式で保存 on saveNSImageAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep set pathString to NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –成功ならtrue、失敗ならfalseが返る end saveNSImageAtPathAsPNG |