Macで実行可能なFileMakerコード管理 CodeManager

FileMaker Proに集めたスクリプトのメモをそのまま実行環境にしてしまった話の続き、具体的にいきます。 前回のあらすじ

どこかで見つけたコマンドやスクリプトなどのコードをコピペしてメモっていると散在して探しにくくなってきたのでFileMakerで一元管理。一元管理だけに留まらず、簡単な小技を使うことでコマンド発射装置として育った…

実際に作ってみて手元にあるCodeManager.fmp12ファイルをネタにして具体的に行きます。

ファイル CodeManager 概要

このファイルの目的と機能は、コマンドやスクリプトなどコードをメモっておくことです。もう一つ、メモったコードを実行させます。

codeTemp.fmp12
メモ&実行装置のFileMaker書類

主な機能とフィールド

メモやコードを書き溜める

codeTemp と名付けされたテキストフィールドがメインです。ここにメモやらコードを書き溜めます。コードを書くときは少しルールがあります。

書き方のルール

パラメータの値がある場合、パラメータ部分を変数名で仮置きし、実際の値を別フィールドに書きます。 

CodeTempフィールド
CodeTempフィールド

パスを書くべき場所に直接パスを書かずに「ここにパスを書きますよ」の印として「$POSIX1」と書きます。

具体的なパスは別のフィールド param_posix1 に書きます。

パラメータ用パス蘭
パラメータ用フィールド(この例ではパス)

「$POSIX1」という変数名は仕込み段階で決定させておりまして、揺るぎません。

posix以外にも、$NAMEや$TIMESTUMPなど、いくつかの「変数名とそれに対応するフィールド」を用意しています。 別の計算フィールドが置換を行い、実行できる形に整形するんです。

メモったコードを実行する

実行ボタン

実行を担当するのはスクリプトステップ「AppleScriptを実行」です「AppleScriptを実行」で、最終的な完成コードのフィールドを指定し、実行します。

最終的な完成コードのフィールド

ということは最終的な完成コードのフィールドが大事ってことです。最初の入力フィールドとパラメータのフィールドを元に計算式で整形し、完成させます。

詳しい話は後に譲るとして、とにかくCodeTempに書かれたコードが最終的にAppleScriptになり、それを実行するという流れです。

結果を受け取る(結果フィールド)

実行してお仕舞いっていうコードならここまででOKですが、「何かを取得する」コードというものがあります。

「結果フィールド」というフィールドがあって、そこに結果を受け取ります。結果を受け取る方法は、現状ではクリップボード経由です。コードを書くとき、最後に、結果をクリップボードに格納するコードをくっつけることで、結果フィールドにペーストするわけです。

概要としては以上です。

 


ファイルをダウンロードして試せます。 当初のファイルから、改良されたv2に差し替えました。

Download CodeManager_v2.zip

Mac専用です。 あらかじめいくつかのサンプルレコードが入っています。 管理>セキュリティ の拡張アクセス権で、AppleEventのところにチェックを入れておいたほうがいいかも。

v2 変更点とこのポストの不整合 ファイルが更新されたことに伴い、このポストの内容と合わないところも出てきました。内容の更新が完了するまで宙ぶらりんな状態ですがご容赦ください。 


ということで、ここからは技術的な話になります。

コードを実行させる機能

コードを書いてそれを実行させる流れの中で、最初の入力フィールド、パラメータの扱い、計算式の条件、実際の計算、とフィールドをまたがってルールやら手順やら関連する他のフィールドやらがあります。

コードを書くフィールド – codeTemp

メインであるメモやコードを書き記し溜め込んでいくフィールドです。手順的には「新規レコード」のあと、メモやコードを書き記し溜め込みます。

メモやコードが混在するので、別途カテゴリーフィールドを設けています。カテゴリーを条件に整形の計算がなされますから重要です。例えばカテゴリー「メモ」ならそもそも実行のための計算を行いません。

変数名

コードにパラメータ値が必要であれば「ここにパラメータ置きますよ」の印を付けます。パスであるべき箇所なら $POSIX1 、2個目のパスを書く箇所があれば $POSIX2と書きます。タイムスタンプであるべき箇所では$TIMESTAMP1を書くといった案配です。

このルールは厳密かつ具体的で、作り手が設定した以外のものは認められません💦

$POSIX1 $POSIX2 $NAME1 $NAME2 $TIMESTAMP1 $TIMESTAMP2 $TIME1 $TIME2 …など 厳密である理由は、変数のそれぞれに1対1で対応するパラメータを入力するフィールドがあるからです。$POSIX1 なら param_posix1、$NAME1 なら param_name1 といった具合です。

[ オマケ ] 入力補助

仮置きの変数文字列は絶対なので、入力欄にカーソルがあるときにボタンで入力する仕組みまで作ってます。
codeTemp 入力補助
入力補助
また、トリガに仕込んでカラーリングも施しています。
みんな大好きSubstituteを使ったカラーリングスクリプト

値のフィールド – param_XX

パラメータのフィールドです。実際の値を書き入れます。POSIXにはパスが、TIMESTAMPにはタイムスタンプが入ることが望ましいフィールドです。望ましいだけで、なるべくそうしましょうということです。パスを示すPOSIX以外は、この細かな振り分けに技術的な理由はありません。「ぱっと見てどういうパラメータの値なのかが分かりやすいから」程度のことです。あと、履歴からの再入力をするときに動的一覧で振り分けられるからです。

パラメータフィールドのフィールド定義
パラメータフィールドのフィールド定義

パラメータの中に「FM」がありますが、これはパスをFileMaker形式に変換する計算フィールドで、ファイルによって使用することがあります。

 

[ オマケ ] 履歴の機能

param_XX のパラメータフィールドに入力しやすくするため、多く機能を詰め込んでしまってます。そのひとつが履歴からの入力です。

履歴テーブル
履歴テーブル
履歴テーブルにパラメータフィールドで決定した履歴を残し、ポップアップで選択して再度の入力が簡単にできます。posixならパス、timestampならタイムスタンプです。変数の代用語やフィールド名をposixやtimestampで分けた理由のひとつがここにあります。

ポップアップ
POSIXではパスがポップアップされる
ポップアップ 名前
NAMEでは名前がポップアップされる
逆に言うと、たったこれだけのためにフィールド定義や仕組みを煩雑なものにしてしまったと言えなくないかもしれません。

あとついでに、パスである場合は「フォルダを選択」「ファイルを選択」ボタンでダイアログから選択できるようにもしています。フォルダ選択はスクリプトステップにあるけど、ファイルを選択ってどうやると思います?無理矢理なやりかたで実現しています。

 

完成コードのフィールド – codeFinal

最終的な実行できる完成コードが書かれる codeFinal というフィールドです。計算によってコードが作成されます。

さてここで追記の改編部分です。囲みをご覧ください。

当初のバージョンと改良版v2のバージョン

当初は、単純な置換によってコードを完成させ、そのコードを「どう実行させるか」の工夫をしていました。つまり、スクリプトに依存していました。

  1. [フィールド] 単純な置換で完成コードを作成する
  2. [スクリプトA] AppleScriptなら、AppleScriptを実行する
  3. [スクリプトB] コマンドなら、AppleScriptでターミナルウインドウにコードをコピペリターンする
  4. [スクリプトFinal] 元のコードに応じてAかBかどちらかを採用して実行する

ファイルを改良し、ここが大きく変更されました。フィールドの計算式だけで最終のコードを作成し、スクリプトはただ Final を実行するだけになりました。つまり、フィールド依存になりました。

  1. [フィールドA]  単純な置換による完成コード(元がAppleScript)
  2. [フィールドB] “do script”を使った AppleScriptに変換(元がターミナルのコード)
  3. [フィールドFinal] 元のコードに応じてAかBかどちらかを採用して転記
  4. [スクリプト] フィールドFinal を実行する

何が起きたかというと、雑魚の作成者がちょっぴり育ったということでした。最初はコマンドをどうして良いか分からず「ターミナルウインドウを開いてコピペしてリターン」していました。やがて do script を覚え、さらに汎用的に計算式で変換する方法を覚えました。

以下に、改良前の記述が残っていますので差し引いてご覧ください<(_ _)> 

単純な置換

コードとパラメータの値から完成コードを作る工程です。置き換えは完全に1対1の関係ですから単純です。$POSIX1をparam_posix1で置き換えるといった案配です。

Substitute ( CodeTemp ;
 [ "$POSIX2" ; param_POSIX2 ] ;
 [ "$POSIX1" ; param_POSIX1 ] ;
 [ "$POSIX" ; param_POSIX1 ] ;
 [ "$NAME2" ; param_NAME2 ] ;
 [ "$NAME1" ; param_NAME1 ] ;
 [ "$NAME" ; param_NAME1 ] ;
 [ "$TIMESTAMP2" ; param_TIMESTAMP2 ] ;
 [ "$TIMESTAMP1" ; param_TIMESTAMP1 ] ;
 [ "$TIME2" ; param_TIME2 ] ;
 [ "$TIME1" ; param_TIME1 ] 
)
codeManager画面
codeTempとparamフィールドとcodeFinal、基本的な置換のかたち

改訂前のバージョンではこれが codeFinal でした。元のコードがAppleScriptならFinalもAppleScript、ターミナルのコマンドならターミナルのコマンドのまま仕上がります。

実行するスクリプト

AppleScriptを実行スクリプトステップを使います。

書かれたコードが AppleScript かターミナルのコマンドかによって実行スクリプトが異なります。

素で実行

codeTempフィールド内容がAppleScriptのスクリプトの文であるなら、「AppleScriptを実行」でそのまま実行します。

AppleScript
codeTempがAppleScriptの文なら
AppleScriptのメモ
codeFinalフィールドをそのまま実行

スクリプトステップ「AppleScriptを実行」で codeFinal フィールドを指定すればいいだけです。

codeFinalフィールドを指定するだけ

 

※ 以下、以前のバージョンでの「コピペ実行」について書いてます。現在は別の方法で行っています。この記事を書き直すことも考えましたが過去は過去としてとりあえず温存しております。


コピペで実行

ターミナルコマンドの場合はどうしましょう。コピペで実行します。

codeRun 画面
ターミナルのコマンド

 FileMakerでコード管理を作る前はどうしてましたか。メモ帳のコードをターミナルウインドウにコピペしていました。同じことをするだけです。

codeFinalをコピーしてから、ステップ「AppleScriptを実行」で以下のAppleScriptを指定します。

tell application "Terminal"
	activate
	tell application "System Events"
		key code 45 using {command down}
		key code 9 using {command down}
		key code 36 using {command down}
	end tell
end tell

ターミナルをアクティブにして新規ウインドウしてペーストしてリターンする AppleScript です。コマンドN、コマンドV、リターンのキーストロークを実行させているだけのアホみたいなスクリプトですね。でもこれで期待通りの動きをします。

※ リターンキーのキーコードはキーボード配列によって異なるようです。36はUSキーボードの場合。JISなら・・・ 何番だっけ? キーコードを調べるアプリで調べて、ここを修正してください。→ キーコードを調べるアプリ

キーコードがわかれば AppleScript の知識がなくてもショートカットを並べるだけでいろんな操作が簡単に自動化できます。

do script

余談になるかもしれませんが、コピペ実行の他、do script で書くという方法もあります。これは難易度が高くて素人が手を出すのは難しい。でも毛が生えた程度の素人に育つとちょっと使えるようになります。 エラーをなくすための素人の防衛としては、AppleScriptの中でターミナルを呼び出して do script を使うことです。直接シェルコマンドを送り込もうと考える人はすでに猛者なので放っておきます。
tell application "Terminal"
	do script "ここにコマンド"
end tell
基本、こう書きます。AppleScriptからターミナルを呼び出し、そこに do script “コマンド” を書きます。安全に実行できます。 実行スクリプトで使用しない みんな大好き置換のsubstituteを駆使して計算式で do script の形に変換することを試みました。

しかし、変換しようとしている元のシェルスクリプトは「ここにコマンド」で済むような単純なコードは少なくて、パスやオプションやパイプや ” ” や ‘ ‘ や > やいろんな要素が入り込んでいます。

実行スクリプトの賢いバージョンになる筈でしたが、結果諦めました。理解力もまったく足りなかったし。実行スクリプトの計算式で関数を駆使するよりも、そもそもcodeTempフィールドにdo scriptごと書けばいいじゃん。となりました。

do script - codeTemp
do script を codeTemp に書けばいい
現時点の結論として実行スクリプトは素で実行コピペで実行の二つあればいいということです。 (引き続き、do script を使いこなせるよう精進します)

  そんなわけで実行スクリプトが二種類できました。で、素で実行コピペで実行の二つの実行スクリプトをそれぞれボタンに割り当てて画面に並べますか。いやです。

二つの実行スクリプトを統合して真の実行スクリプトを作ります。codeTempに書かれた内容がAppleScriptなら素で実行、コマンドラインならコピペ実行と振り分けます。どうやって見分けるかというと、コード内容の部品やカテゴリーを利用します。

これで真の実行スクリプトができました。

自動カテゴリー

カテゴリーは人力で付与していくものというイメージがありますが、codeTempに書かれたテキストから自動で判断してレコードをカテゴライズするという手を使いました。

細かい条件は省略しますが、「カテゴリー自動計算」を行うことで「do Script」「AppleScript」「Command」「memo」とカテゴリー分類することができました。

実行スクリプトに戻って、条件分岐を「カテゴリーがAppleScriptまたはdoScriptなら素で実行、Terminalならコピペ実行」と振り分けます。これにて解決。

 


※ 以上、改訂前のバージョンについての話でした。現在のファイルでは、コピペで実行を採用していません。

結果を受け取る(結果フィールド)

codeTempに書くコードは実行するだけで終わりではなくフィードバックを得るところまで含みます。 例えばファイルの日付を取得するコードでは日付を受け取ります。「結果フィールド」という、結果を受け取るフィールドを作りました。

出力を指定するコード

どうやって受け取るか。を司るのはもちろん codeTemp に書くコードそのものです。コードを実行した結果の出力を指定します。

考えられる方法は三つ。FileMakerのフィールドに直接出力するか、ファイルに保存するか、クリップボードに格納するかです。

この件について、くどくど説明し始めるとまた長くなるので適当に済ませますが、まず「結果をFileMakerのフィールドに直接出力」はAppleScriptなら可能ですがややこしいのでパスしておきましょう。以前はずっとこれを使っていましたが。こんな風に書きます。

tell application "FileMakerの名前"
activate
set contents of field "結果フィールド"  of current record to 前段で仕込んだ結果の変数 as string
end tell

クリップボードへ出力

現在、AppleScriptだろうとシェルスクリプトだろうと、結果を取得するコードではすべてクリップボードに出力しています。そしてクリップボードの内容を結果を受け取るフィールドにペーストします。最後スクリプトステップ「貼り付け」するだけですから楽です。

クリップボードへの出力は、AppleScriptだとこんなかたち。

set the clipboard to 仕込んだ変数

ターミナルでは | で繋げて pbcopy です(エラー出力はちょっと別の繋げ方)

コマンド | pbcopy

結果をペースト

さてクリップボードに出力があることを前提に、結果をペーストするスクリプトを作ります。 基本スクリプトステップ「貼り付け」で結果フィールドを指定するだけです。ただしいろいろあります。

結果フィールド

結果フィールドをグローバルにしています。どんなテーブルであっても等しく結果を受け取れるからです。また、大抵の場合結果は「一時的な結果」に過ぎないからです。グローバルな結果フィールドは、コード実行を使う可能性があるすべてのレイアウトに配置します。画面外の見えないところでOK。「貼り付け」ステップはレイアウト上にフィールドがないと動きません。

結果の待ち時間

結構大事なポイントです。実行するコードによって、処理時間が変わります。瞬時に終わるものもあれば、随分待たされる処理もあるでしょう。

スクリプトでコード実行から結果ペーストを繋げてしまうと、処理が終わってない状態でクリップボードの内容をペーストしてしまって意味不明な結果に終わります。

これを回避するための秘策はループを使って小刻みにペーストを繰り返すことです。別のどこかで同じ仕組みを説明したことがありますが、流れはこうです。

事前に結果フィールドを空にしておく
その空の結果フィールドの内容を変数 $結果 に保存しておく

コードを実行させる(出力がクリップボードのコード)

Loop
  少し待ってから(一時停止.5秒とか)
  結果フィールドにペースト
  Exit loop if [ 結果フィールド ≠ $結果 ](異なればループ終わり)
   (出力がまだなら、結果フィールド = $結果 だから)
   (出力が完了なら、結果フィールド ≠ $結果 だから)
end Loop

実際には、ループをカウントし、一定数繰り返しても駄目ならエラーの可能性があるからキャンセルダイアログを用意しておくなどの措置を講じます。

この「結果をペースト」スクリプトと先ほどの「コード実行」スクリプトを組み合わせて「コード実行から結果取得までのスクリプト」としてまとめます。

以上、結果をペーストするスクリプトでした。

結果を得た後どのように利用するかは codeManager の知るところではありません。別のFMファイルで活用します。

CodeManager でのコード実行に一手間かけたというお話

このCodeManagerというファイル、最初は「コードのメモ、オマケで実行もできる」というだけのものでした。でも案配が良いのでいろんなFileMakerのファイルに組み込んで使うようになり、まるでアドオンみたいになってきました。

その使い方だとコードを呼び出すのが面倒なので、セルフリレーションを組んでグローバルな仮IDの入力によって目的レコードを呼び出す形になりました。

その流れから、実行するにはグローバルIDに目的レコードのIDを入力してから、同じくグローバルなcodeFinal(copy)を実行するという手順になります。

 


ということで、本稿はとりあえずここで一旦締めます。  

Download CodeManager_v2.zip

Mac専用です。 あらかじめいくつかのサンプルレコードが入っています。 管理>セキュリティ の拡張アクセス権で、AppleEventのところにチェックを入れておいたほうがいいかも。

 

コメント

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください