次: , 前: Simple Advice, 上: Advising Functions


16.2 アドバイス定義

アドバイス断片を定義するには、マクロdefadviceを使います。 defadviceの呼び出しはつぎのような構文です。 defundefmacroの構文を基にしていますが、 追加部分があります。

     (defadvice function (class name
                              [position] [arglist]
                              flags...)
       [documentation-string]
       [interactive-form]
       body-forms...)

ここで、functionはアドバイス対象となる関数 (やマクロやスペシャルフォーム)です。 以後、アドバイスする対象を単に『関数』と書きますが、 これにはつねにマクロやスペシャルフォームを含みます。

classはアドバイスのクラスを指定し、 beforeafteraroundのいずれかです。 事前アドバイス(before)は関数そのもののまえに実行されます。 事後アドバイス(after)は関数そのもののあとに実行されます。 包囲アドバイス(around)は関数自身の実行を包み込みます。 事後アドバイスと包囲アドバイスでは、 ad-return-valueに設定することで戻り値を変更できます。

— 変数: ad-return-value

アドバイスを実行しているとき、 関数の元定義の実行を完了したあとでは、この変数はその戻り値を保持する。 すべてのアドバイスを完了すると、最終的には、この値を呼び出し側へ返す。 事後アドバイスと包囲アドバイスでは、この変数に別の値を設定することで 戻り値を変更できる。

引数nameはアドバイスの名前であり、nil以外のシンボルです。 アドバイス名は、functionの特定クラスのすべてのアドバイス断片から 1つのアドバイス断片を一意に識別します。 名前でアドバイス断片を参照でき、 それを再定義したり有効にしたり無効にできます。

通常の関数定義の引数リストのかわりに、 アドバイス定義では異なる情報を必要とします。

省略可能なpositionは、指定したclassの 現在のアドバイスリストのどこに新たなアドバイスを置くかを指定します。 firstlast、あるいは、 0から数え始める位置を指定する数である必要があります (firstは0と等価)。 位置を指定しないとデフォルトはfirstです。 当該クラスの既存位置の範囲を超えている場合には、 先頭か末尾のどちらか近いほうになります。 既存のアドバイス断片を再定義する場合には、値positionは無視されます。

省略可能なarglistは、 アドバイスが使う引数リストを定義するために使います。 これは、アドバイスを実行するために生成される結合定義 (see Combined Definition)の引数リストになります。 その結果、アドバイスの式では、 引数の値を参照するためにこのリストの引数変数を使えます。

この引数リストは、関数の実際の呼び出し方を扱えるように、 もとの関数の引数リストと互換性がある必要があります。 2つ以上のアドバイス断片で引数リストを指定している場合、 すべてのアドバイスクラスの中で最初のもの(位置が最小のもの)を使います。

残りの要素flagsは、このアドバイス断片の使い方に関する情報を指定する シンボルです。 正しいシンボルとそれらの意味はつぎのとおりです。

activate
functionに対するアドバイスをただちに活性にする。 関数のアドバイスに対する変更は、当該関数のアドバイスを活性にすると 効果を持つようになる。 このフラグは、functionに対するこのアドバイス断片を定義した直後に そのようにすることを指示する。

functionが未定義(未定義のアドバイス(forward advice)と呼ぶ状況) であるとこのフラグにはなんの効果もない。 というのは、未定義関数のアドバイスは活性にできないからである。 しかし、functionを定義するとそのアドバイスは自動的に活性にされる。

protect
このアドバイス断片をそれよりまえに実行されるコードやアドバイスによる 非ローカル脱出やエラーに対して保護する。 保護したアドバイス断片は、 フォームunwind-protectの中に後始末として置かれ、 それよりまえに実行されるコードでエラーが発生したりthrowを使っても 実行される。 see Cleanups
compile
アドバイスの実行に使われる結合定義をコンパイルする。 activateとともに指定しないと、このフラグは無視する。 see Combined Definition
disable
このアドバイス断片を当初は無効にしておき、 のちに明示的に有効にしない限り使われない。 see Enabling Advice
preactivate
このdefadviceをコンパイルしたりマクロ展開したときに、 functionに対するアドバイスを活性にする。 これにより現在のアドバイスの状態に応じたアドバイス定義をコンパイルし、 必要に応じて使われるようになる。

このdefadviceをバイトコンパイルする場合にのみ意味を持つ。

省略可能なdocumentation-stringは、 このアドバイス断片の説明文字列になります。 functionに対するアドバイスが活性であると、 (documentationが返す)functionの説明文は、 関数の元定義の説明文字列とfunctionのアドバイスすべての説明文字列の 合成になります。

省略可能なinteractive-formは、 元関数の対話的ふるまいを変更するために指定します。 2つ以上のアドバイス断片でinteractive-formを指定している場合、 すべてのアドバイスの中で最初のもの(位置が最小のもの)が優先します。

空リストでもかまわないbody-formsは、アドバイスの本体です。 アドバイスの本体では、引数、戻り値、束縛環境を参照/変更したり、 いかなる種類の副作用を起こせます。

警告: マクロをアドバイスする場合、 マクロはプログラムのコンパイル時に展開されるのであって、 コンパイルしたプログラムの実行時に展開されるのではないことに注意。 アドバイスが使用するすべてのサブルーティンは、 バイトコンパイラがマクロを展開するときに必要になる。