Tips ’n’ Tricks (パート3)

私がお気に入りだったFileMaker Hacksの3年前の記事の続編が年末に公開されたので、さっそくご紹介します。
というわけで、本年もよろしくお願いします。
(2019/1/21追記: 元記事のTip #6を訂正いただき、合わせて訳を更新しました。)


FileMaker Hacks logo

Tips ’n’ Tricks, part 3

(元記事はこちら)

Kevin Frank
2018/12/30

このFileMaker Hacksでtips ‘n’ tricksの記事を最後に掲載してからもう3年が経ちました。その間に、私の使い古した道具袋にはまたいくつか新しいチップスが溜まってきました(この手の記事が好きな方には、パート1パート2も参照することをお勧めします)。その中のいくつかははっきりとした答えがなく、他の一つはとても基本的なものです。理想的には、あらゆるレベルの専門知識を持つ開発者が、何らか役に立った(または議論する価値がある)と思っていただければ幸いです。

Corn WalkerがいつかのDevConのセッションの初めに、「私は算数の授業を真剣に聞いていた子供みたいなものです」と言っていたのを思い出します。同じような意味で、賢い人が苦労して手に入れた知恵を共有してくれるときには、私は注意をして聞くようにしています。以下に紹介するチップスの中のいくつは、そのような人々から提供されたものであり、それらには正しい出典を示すようにしました。

Tip #1: これらの関数のうちの一つは、他とは異なる

FileMaker関数の多くは1つ以上の引数を必要とします。例えばSum()やEvaluate()など。引数を必要としないものもあります。例えばRandom。そして引数がオプションである(引数を取る場合も取らない場合もある)関数が一つだけあります。かっこがない場合はこんな感じです。

Function

かっこがつく場合は以下のようになります。

Function ( 引数 )

さて、この関数は何でしょうか? (答えは、この記事の最後にあります。)

Tip #2: ある区切り文字の、直感的でない挙動

ある同僚が最近、UUIDを評価する際のWordCount関数に「バグがある」と発言しました。実際にはWordCountは設計どおりに動作します。それについてはこの後説明しますが、その前に彼の主張を以下に示しておきます。以下のような式があるとします。

wc expression.png

2つ目のハイフンの数が常に一定(4)であるにも関わらず、WordCount(x)は異なる値を返すことがあります。

wordcount-four-up.png

一体何が起こっているのでしょうか? 以下のナレッジベースの項目(FileMaker Proでの単語の区切り文字)は、全体をよく読むことが重要です。

以下の部分が、一見おかしく見えるWordCountとUUIDの掛け合わせで起きる挙動の原理を説明しています。

FileMaker Pro 7以降では、左右の文字が数字でなければハイフン、コロン、およびスラッシュが単語の区切り文字として扱われます。

Tip #3: 関連フィールドを編集するとき、親レコードは開かれるか?

答えは…状況によります。まず最初に、親と子のテーブル間で「レコード作成を許可」を有効化/無効化することがこの問題の決定要因になると考えるかもしれません。しかしこれは、本件には影響を与えません (読者の皆さんが実際に試して、この主張の証明または反論をしていただけることを期待したいと思います)。

簡単な実験をしてみましょう。編集可能なポータルを持つ、適当なデータベースを何か見つけてきてください (あるいは私の過去の投稿に含まれていたWinery JSONファイルを使用してください)。まずフィールド以外をどこかクリックして、データビューアの[監視]タブで、開いているレコード数が0であることを確認します。

2018-12-30_13-51-26

次に、いずれかのポータル行のいずれかの値を編集し、データビューアで[更新]をクリックします。

2018-12-30_13-52-28

つまり「関連フィールドを編集する場合に親レコードは開かれるか」という質問に対する答えは、「はい手動で編集を行う場合には」となります。同じ操作をスクリプトで実行するとどうなるでしょうか?

2018-12-30_14-07-01

確認してみましょう。

2018-12-30_14-15-00

私の弟が、ポーカーで配られたばかりの手札を見た瞬間によく言ったものです。「すごい! というか…興味深い」

ヒント#4:Self-ish(自己中心)がいい場合もある

あるフィールドが、空間的な制約のためにすべての内容を表示できない場合には、以下のようにポップアップヘルプを設定してください。

2018-12-30_12-57-45

こうすれば、ユーザがフィールドをクリックしなくても、ブラウズモードでフィールド内容の全体を表示できます。

2018-12-30_12-59-17.png

ポップアップヘルプにSelfを使うこと(元となるフィールド名を指定するのと比較して)の利点の一つは、必要があれば、一度に多数のフィールドに一括で設定できることです。

Tip #5: Self-ish(自己中心)について パート2

経験を積んだ開発者であれば誰でも、慎重に設計された自分のシステムにゴミを入れることに成功した「賢い」ユーザに、何度か遭遇したことがあるものです。たとえば、Webページからコピーされた奇妙にフォーマットされたデータを貼り付けられたり、または改行記号や、前や後ろに不要な空白を入力されたり、という場合があります。理想的には、そもそもシステムにゴミが入らないように設計することで、上のような間違った振る舞いを未然に防ぐことが大事です。

方法は次のとおりです。ユーザがデータを入力できるすべてのテキストフィールドで、次のような計算式を使用します。一つ前のチップスと同じように、この方法のいいところは移植性です。つまり、どのテキストフィールドにも適用できます。

YourCustomFunction ( Self )

まず最初はRay CologonTrim4です。これは前や後ろにある「空白」(通常のスペース、非分割(non-breaking)スペース、タブ、改行記号)を取り除きます。一般的なルールとして、連続したスペースや文字修飾もしたくありません。そしてほとんどの場合、改行記号はまったく使用したくありません。必要に応じて微調整する必要があるかもしれませんが、以下に汎用的に使えるカスタム関数を示します。Ray博士のTrim4をベースにしていて、私はcfZapと呼んでいます。

2018-12-30_15-08-50.png

Tip #6: 空(から)のフィールドを検索するときに=を使ってはいけない

Russell Watson (別名 MrWatson)がdotFMPで6月に指摘したように、多くの開発者は空(から)のフィールドを検索するために反射的に=を使っています。そして、ほとんどの場合これは正しく動作します。しかし例外的に、誤検出、つまり実際には空ではないフィールドを返してしまう特別な状況があります。それは、フィールドに複数の改行記号だけが入っている場合です。

ベストプラクティスとして、空のフィールドを検索する場合は==を使いましょう。

Tip #7: 大きなテキストブロックをインクリメンタルに作成する、より高速な方法

上のチップスだけでは飽き足らず、Russell Watsonは昨年8月にFileMaker Communityフォーラムにこのチップスを投稿し、FileMaker界に衝撃波を与えました。文字列の連結に「計算結果を挿入」を使用する

しかしながら最近のやり取りを見ていると、このチップスの公開後も、多くの開発者はこの手法に気づいていないようです。ここで私がそれをわざわざ指摘する理由は、ある状況が発生したときに、開発者ならこれを自分のテクニックの引き出しにぜひ入れておいた方がいいと思うからです。その状況とは以下のような場合です。

  • ループでテキストを足しながら、大きなテキストブロックを作成している
  • 既存のブロックの末尾に新しい文字列を追加している
  • 注意: そのブロックが、あなたが利益を享受できるほど、十分大きい

数ヶ月前にFaux Subsummaries via JSON + Virtual Listを公開したとき、私は意図せずに「burying the lead(強調するポイントを間違える)」 という罪を犯しました。以下の内容のステップ(“Method A”スクリプトとなったもの)を特徴とするデモファイルを用意したことによって…

方法-a

…これはWatsonのアプローチを試す好機のように思えたので、スクリプトを複製し、4つの強調表示されたステップを次のように変更しました。

method-b.png

そしてその結果は、MrWatsonの奇跡の特効薬が確かに受け入れるに値ある、という説得力のある証拠を示しています。

method-results.png

Tip #8: 誰がレコードをロックしているかをプログラムで判定する

ここで紹介するのはFileMaker Community forumにDavid Headが投稿したチップスです。FM16以降で使用できるGet ( 最終外部エラー詳細 )関数は、レコードをロックしたユーザのアカウント名とユーザ名の両方を返します。FM16の前までは、この情報にはアクセスできませんでした。

Tip #9: PSOSスクリプトの結果に対する文字数制限を回避する

PSOSの引数と結果の文字数が100万文字に制限されていることをご存知ですか? サーバ上で大量のデータを生成し、それをクライアントに転送する必要がある場合は、Fabrice NordmannとAndries Heylenによるこのすばらしいテクニックをチェックしてください。dotFMP Developer Challenge

転送用テーブルを使用してサーバとクライアントの間で大量のデータを移動させるという考え方自体は目新しいものではありません。しかし彼らの手法は、単にテキストフィールドにデータを挿入するのではなく、オブジェクトフィールドとテキストファイルを使用するという点で、非常に強力です。では何がそんなに強力なのでしょうか? 答えはパフォーマンスです。WAN経由では驚くほど高速です。

Tip #10: CustomListを使ってJSONの機能を拡張する

CustomListがJSONを強化する無数の方法についてすべて説明するには、一つのブログ記事全体あるいはシリーズ連載が必要かもしれません (JSONに限らず、SQLあるいはほとんどすべてのこと…私がそれを知ってからは飼っている猫たちさえ私にやさしくなりました)。しかし今回は、オンラインフォーラムの1つで出てきた一つの課題に焦点をあてたいと思います。

変数$dataに以下のJSONが割り当てられているとします。

JSONデータ

特定のキーに一致するすべての値をリスト化する関数はあるでしょうか? たとえば3つの”name”というキーのエントリに対応する値のリストを取得することはできるしょうか? 驚いたことに、これを可能にするネイティブのJSON関数はありません。もちろん、スクリプトを使ってループ内でJSONGetElementを使用してリストを作成することはできます。ですが、CustomListを使用すると、次のように一回の関数呼び出しでこれを実行できます。

Let ( [
   a = JSONListKeys ( $data ; "bakery.product" ) ;
   x = ValueCount ( a ) 
] ;

CustomList ( 1 ; x ; 
   "JSONGetElement ( $data ; \"bakery.product[\" & [n]-1 & \"]name\" )" 
)

)

結果:

Donuts
Chocolate Cake
Baguette

Tip #1の答え

Tip #1に戻ると、答えの関数はWindowNamesです(かっこの変則的な配置に注意してください)。

WindowNames {(ファイル名)}

この関数はオプションでファイル名を引数として取ります。ファイル名を引数としてとる他の多くの関数と同じように、空のダブルクォーテーション( “” )はGet( ファイル名 )と同義になります。オプションのファイル名の引数を空白のままにすると、 すべてのファイルのすべての表示ウィンドウと非表示ウィンドウが、少なくとも一度画面に描画されていれば(言い換えれば、すべての表示ウィンドウと、「ウィンドウ>表示」サブメニューで表示される、かっこで囲まれていないウインドウが)、リスト化されます。

この知識が役に立ちそうな場面: 複数のファイルからなるソリューションで、現在のファイルの”レポート”ウィンドウを閉じることを意図した次のスクリプトステップを考えます。

変数を設定 [ $x ; "Reports" ]
If [ not IsEmpty ( FilterValues ( WindowNames ; $x ) ) ]
   ウインドウを選択 [ $x ; 現在のファイル ]
   ウインドウを閉じる [ 現在のウインドウ ]
End If

現在のファイルで上記の手順を実行し、たまたま現在のファイルに”Reports”という名前の開いたウィンドウがなく、別のファイルに属する”Reports”という名前の開いたウィンドウがある場合…

  • If内の式は真と評価される
  • “ウインドウを選択”ステップが失敗する (“Reports”が現在のファイルにないため)
  • “ウインドウを閉じる”ステップが、現在のファイル内でスクリプトが呼び出されたウィンドウを(それが何であれ)閉じる

以下の一つ目の赤字の変更部分が、これを起こらないようにします。その上で、安全に実行するため、閉じるウィンドウを明示的に指定します。

変数を設定 [ $x ; "Reports" ]
If [ not IsEmpty ( FilterValues ( WindowNames ( "" ) ; $x ) ) ]
   ウインドウを選択 [ $x ; 現在のファイル ]
   ウインドウを閉じる [ 名前: $x ; 現在のファイル ]
End If

 

Leave a Reply