Next: , Previous: , Up: Functions   [Contents][Index]


12.10 Advising Emacs Lisp Functions

他のライブラリーの関数定義を変更する必要があるとき、またはfoo-functionoのようなフックやプロセスフィルター(process filter)、または関数を値としてもつ任意の変数またはオブジェクトを変更する必要があるときには、名前つきの関数にはfsetdefun、フック変数にはsetq、プロセスフィルターにはset-process-filterのように、適切なセッター関数(setter function)を使用することができます。しかし、これらが以前の値を完全に破棄してしまうのが好ましくない場合もあります。

アドバイス(advice)機能により、関数にアドバイスすることにより、既存の関数定義に機能を追加できます。これは関数全体を再定義するより明解な手法です。

Emacsのアドバイスシステムは2つのプリミティブセットを提供します。コアとなるセットは、変数やオブジェクトのフィールドに保持された関数値にたいするものです(対応するプリミティブはadd-functionremove-functionです)。もう1つのセットは、名前つき関数の最上位のレイヤーとなるものです(主要なプリミティブはadvice-addadvice-removeです)。

たとえば、プロセスprocのプロセスフィルターの呼び出しをトレースするためには、以下を使用できます:

(defun my-tracing-function (proc string)
  (message "Proc %S received %S" proc string))

(add-function :before (process-filter proc) #'my-tracing-function)

これにより、そのプロセスの出力は、元のプロセスフィルターに渡される前に、my-tracing-functionに渡されるようになります。my-tracing-functionは元の関数と同じ引数を受け取ります。これを行った場合、以下のようにしてトレースを行わない振る舞いにリバートすることができます。

(remove-function (process-filter proc) #'my-tracing-function)

同様に、display-bufferという名前つきの関数の実行をトレースしたい場合は、以下を使用できます:

(defun his-tracing-function (orig-fun &rest args)
  (message "display-buffer called with args %S" args)
  (let ((res (apply orig-fun args)))
    (message "display-buffer returned %S" res)
    res))

(advice-add 'display-buffer :around #'his-tracing-function)

ここで、his-tracing-functionは元の関数のかわりに呼び出され、元の関数(加えてその関数の引数)を引数として受け取るので、必要な場合はそれを呼び出すことができます。出力を確認し終えたら、以下のようにしてトレースしない振る舞いにリバートできます:

(advice-remove 'display-buffer #'his-tracing-function)

上記の例で使用されている引数:before:aroundは、2つの関数が構成される方法を指定します(これを行うには多くの方法があるからです)。追加された関数も、アドバイス(advice)と呼ばれます。