名前/値のペアを引数とデータの保存に使用する

2014/11/26~28に開催されたFileMakerカンファレンス2014に参加して、いろいろな知見を得ることができました。
面白かったセッションの一つが、寿商会 深澤真吾さんのファイルのモジュール化に関するものでした。お話の中で、スクリプト間で複数の引数をやりとりする手法の元ネタの英文記事が紹介されていたので、さっそく読んでみました。
執筆者のNickさんの了解が得られたので、以下に私の拙訳を掲載します。


goya

名前/値のペアを引数とデータの保存に使用する
( Using name / value pairs for parameters and storing data. )

Nicholas Orr
2009/9/21

fp7のファイル形式に変更されてからFileMakerに追加されたもっとも優れた機能のひとつが、スクリプトに引数を渡したり、その結果を戻り値として取得できるようになったことです。これには取得関数の Get ( スクリプト引数 )Get ( スクリプトの結果 ) を使用します。ところが、コーディングを進めていくとすぐに重大な見落としに気付くでしょう。引数や結果をひとつしか持つことができず、複数の名前付きパラメータを使ってスクリプトを定義することができないのです。しかもFileMakerのターゲット市場を考えれば、近いうちにこの仕様が変更されるということはなさそうです。もしコードをモジュール化して、引数に基づいていろいろな振る舞いをさせたい場合には、スクリプト引数のひとつのテキスト文字列の中で、複数の変数を確実に処理するためのなんらかの方法を考えなくてはいけません。

これがなぜ便利なのかよくわからないという方は、例えば「新規ユーザ作成」スクリプトに名前、住所、電話番号を渡して、それぞれの値を対応するフィールドに挿入するというような場合を考えてみれば、その有用性が明らかでしょう。

これに似たことを他の人たちがいろいろな方法で行っているのを見てきましたが、ここでは我々のやり方の概略とその考え方を紹介します。まずいくつかの選択肢を示します。

1行ごとに1つの値を持つ

これは単純な規則の場合はうまくいくかもしれませんが、値自体の中に改行が入っているととたんに破綻し、そうでなくてもコードがかなりわかりにくくなります。例えば7番目の値だけを渡したいという場合、「¶¶¶¶¶¶値」という形式になりますが、なぜそのようになっているか自明でなく、コードを読み解くだけではわかりません。GetValue ( Get ( スクリプト引数 ) ; 7 ) も同じ問題があり、これが何を意味していてなぜそうなっているのかがわかりません。

引数にXMLを使用する

これは面白いアイデアです。XMLはよく知られた標準であり、理解しやすいという利点があります。またエンコード/デコードの方法や、引数の名前にどんな値を使用できるかがあらかじめ仕様に含まれています。

しかしこれらの引数がFileMakerの外から設定されたり取得されたりすことはない(原注: ただし最近はWebサービスで利用されている場合が増えているが)ので、余分なコードが増えてしまうことによって標準的なFileMakerプログラマにとって引数が理解しにくいものにならないよう考慮する必要があります。

名前/値のペア

この方法は、単に値のリストを次のように持つだけです。

name1=value1
name2=value2

我々はこの形式を使っています。これによって、パラメータ変数のセットを無限に持つことができ、自由に設定や取得ができます。区切り文字をエスケープすることにより、どんな値も扱うことができます。機械可読性を考慮したXMLなどと比較して、人間が読みやすいという利点もあります。

名前によって値を取得・設定するので、操作の対象が何であるかが直感的にわかります。たとえば、

GetScriptProperty ( "Contact Name" )

このコードを見れば何を取得しようとしているかは明らかです。これらの名前/値ペアの取得と設定のために、我々が使っている2つの主要なカスタム関数があります。我々はそれらを「Properties」と呼んでいます。1つ目を以下に示します。

SetProperty ( Name ; Value )
---
Trim ( Substitute ( Name ; [ ¶ ; "" ] ; [ "=" ; "" ] ) ) & "=" & Substitute ( Value ; [ "\\" ; "\\\\" ] ; [ "¶" ; "\r" ] ) & ¶

そして、値を取得するためのもう1つの関数です。


GetProperty ( propertyList ; propertyName )
---
Case ( IsEmpty ( propertyList ) ; "" ;
Let ( [
first = GetValue ( propertyList ; 1 ) ;
eq = Position ( first ; "=" ; 1 ; 1 ) ;
firstName = Trim ( Left ( first ; eq - 1 ) ) ] ;
Case (
firstName = Trim ( Substitute ( propertyName ; [ ¶ ; "" ] ; [ "=" ; "" ] ) ) ;
Substitute ( Middle ( first ; eq + 1 ; Length( first ) - eq ) ; [ "\\\\" ; "\\" ] ; [ "\r" ; ¶ ] ) ;
GetProperty ( RightValues ( propertyList ; ValueCount ( propertyList ) - 1 ) ; propertyName )
) ) )

呼び出したスクリプトの引数を設定(Set)して、その後でスクリプトの中で必要になったときに取得(Get)します。

さらに追加で、スクリプト引数と結果を取得するためのショートカット用のカスタム関数も作りました。


GetScriptProperty ( propertyName )
---
GetProperty ( Get ( スクリプト引数 ) ; propertyName )


GetResultProperty ( propertyName )
---
GetProperty ( Get ( スクリプトの結果 ) ; propertyName )

です。
GetScriptProperty ( "Name" ) で「Name」という名前のスクリプト引数を取得でき、とても簡単です。

利点

このような書き方を選択する理由としては、10個の属性を設定しなくてはいけない場合でも対応できるという点があります。たとえば「新規コンタクト先を作成」というスクリプトが、10個のフィールドを設定するとします。その場合に、10個のうちの何個でもどのような順番でも渡すことができます。基本的なスクリプトの呼び出しは1つの名前付き属性を呼び出すだけで、別の場所から呼び出す場合は10個すべて、あるはそのうちの5個だけかもしれません。

スクリプトの最初の行に、コメントでスクリプトがとる引数に関する説明を入れるようにしているので、スクリプトを呼び出したいときは、あなたはそのスクリプトを開いて最初のコメント行から引数をコピーし、引数を設定する場所にそれを貼り付けます。たとえば、コメントが以下のようになっていたら、

Parameters :
SetProperty ( "Name" ; Value ) &
SetProperty ( "ContactID" ; Value ) &
SetProperty ( "Status" ; Value )

この3行をコピーしてValueの部分を変更するだけで、すぐに使い始めることができます。

もう1つのボーナスとして、スクリプトを入れ子にしている場合、既存の引数を変更することなく値に追加する、あるいは非常に簡単に値を上書きすることができます。

たとえば「新しい請求書を作成」というスクリプトがあって、コンタクトIDなどのいくつかの引数とともにそのスクリプトを呼び出して値を設定したら、それがさらに「新しい請求書明細行を作成」スクリプトを呼び出して、請求書の1行目の項目を設定します。最初のスクリプトの呼び出しの引数は次のようになります。

SetProperty ( "ContactID" ; Value ) &
SetProperty ( "Item Description" ; Value )

「新しい請求書を作成」スクリプトは、それ自体は「ContactID」という引数しか使わず、あとは「新しい請求書明細行を作成」スクリプトをGet( スクリプト引数 )とともに呼び出して引数を引き継ぐだけで、請求書明細行スクリプトは必要な「項目の詳細情報」を取得することができます。

また、それをさらに賢くすることができます。引数を増やすことができるので、次のようにして「新しい請求書を作成」スクリプトが「新しい請求書明細行を作成」スクリプトを呼び出します。

SetProperty ( "InvoiceID" ; Value ) &
Get ( スクリプト引数 )

これで取得した値をそのまま引き継いで、さらに自分の引数を追加します。

さらに値は後で設定されたものから順に取り出されるため、値を上書きすることが可能です。次のようにして、詳細情報を修正することができます。

SetProperty ( "InvoiceID" ; Value ) &
SetProperty ( "Item Description" ; NewValue ) &
Get ( スクリプト引数 )

「新しい請求書明細行を作成」スクリプトが「項目の詳細情報」を取得しようとすると、代わりにNewValueを返します。

さらに

我々がこれを使い始めた興味深い適用先の一つは、「新規レコードを作成」スクリプトがあって、かつそのスクリプトが新規レコードの複数フィールドを設定する必要があるというものでした。名前付き引数というこの考え方に一つ欠点があるとしたら、名前を正しく取得しなくてはいけないという点です。設定したものと違う名前を取得した場合、値は見つからず空の結果を得ます。

しかしFileMaker 10で特別な新しい関数が追加されました。

GetFieldName ( field )

これで何ができるかというと、引数の名前をフィールドそのものの実際の名前にすることができます。それによって、名前をいちいち書く必要がなく、テーブルのフィールド名が変更されてもスクリプトは動き続けます。つまり、属性を次のように設定(Set)できます。

SetProperty ( GetFieldName ( table::field ) ; Value )

そしてこれは現在のコンテキストに関係なく動作します。幸いなことに、GetFieldName関数は現在のコンテキストからアクセスできるフィールドを使用することを要求しません。そうすると、スクリプト引数を取得するための方法は当然、「フィールド設定」スクリプトステップで以下の式を使用する方法になります。

GetScriptProperty ( GetFieldName ( field ) )

しかしさらに簡単な方法があります。以下の計算値自動入力をフィールド自体に定義します。

GetScriptProperty ( GetFieldName ( Self ) )

つまり「フィールド設定」スクリプトステップを使わずに、100個の別々のフィールドにそれぞれ別の値を設定するスクリプトを呼ぶことができるということです。そして、ユーザが作成したレコードやこの自動レコード生成のプロセスの外には悪い影響をいっさい与えません。

便利だと思いませんか?

そして、この方法はスクリプト引数に使えるだけでなく、複数の値を格納する用途でどこでも使うことができます。たとえばDavid Headによるこの例( Metadata for your FileMaker Pro records [訳注: 翻訳の公開時点ではリンク先は見つかりませんでした] )では、1つのレコードについてのすべてのメタデータを1つのフィールドに保存することができ、各メタデータをわかりやすく管理できます。そのため、例えば作成日付と修正日付を混同するというようなこともないでしょう。

(翻訳終わり)



なお、2009年に書かれたこの記事で紹介された手法の改良版が、ダウンロードできるサンプルファイルとともに
2011年の記事で公開されています。

Leave a Reply