nadviceを使用するにはどうすればよいですか?


29

私の設定にはアドバイスがたくさんあり、新しい光沢のあるミニマリストのnadvice.elパッケージについて聞いています。

私はマニュアルを検索し、ソースを読みましたが、私は率直に認めます

ここの誰かがガイドを教えてくれたり、古いスタイルのアドバイスを移植する方法を教えてもらえますか?


7
質問の+1。マニュアルを検索しても必要なものが見つからない場合は、(doc)バグレポートを提出することを検討してくださいM-x report-emacs-bug。一部の開発者は、文書化よりも開発を好む場合があります。;-) Emacs自体を文書化することが重要です。
ドリュー

2
マニュアルには実際にそのセクションがあります。(info "(elisp)古いアドバイスの移植")を参照してください。ただし、何らかの理由で詳細なインデックスに記載されていません。
wasamasa


3
nadvice私の設定から使用するいくつかの例::after:filter-return:around:before-until
Kaushal Modi

1
@wasamasaこのセクションは完全にはほど遠いと思います。もっと複雑なアドバイスがいくつかあります(たぶん1つだけでしょう)。ここでそれぞれについて質問する必要がありますか?
PythonNut

回答:


22

必要なすべての情報が含まれC-h f add-functionており、その中にあるメカニズムを説明していadvice-addます。

基本的に、新しいアドバイスシステムC-h f add-functionは、WHERE 引数の選択に応じて、関数の現在の定義をの表に記載されている関数で置き換えるように機能し ます。

:aroundオプション付きの例

最も一般的なケースは:aroundオプションであるため、その例を示します。(おそらくWHERE、可能であれば専用のパラメーターを使用することをお勧めしますが、同等の:around機能で他のものをすべて置き換えることができ ます)。

ちょうど例として、呼び出されるたびfind-fileprintその使用法をデバッグし、引数リストにしたいとしましょう。あなたは書くことができます

(defun my-find-file-advice-print-arguments (old-function &rest arguments)
  "Print the argument list every time the advised function is called."
  (print arguments)
  (apply old-function arguments))

(advice-add #'find-file :around #'my-find-file-advice-print-arguments)

この新しい実装では、アドバイスに必要なすべてのものが引数として渡されます。ad-get-args引数は通常の関数の引数としてアドバイス関数に渡されるため(WHEREそれが意味をなす引数の場合)、不要になり ます。アドバイスが引数として関数と引数を取得するad-do-itため、不要になる:aroundため(ad-do-it)、次の形式に置き換えられます。

(apply old-function arguments)

または引数に名前を付けたとき

(funcall old-function first-arg second-arg)

魔法のフォームが含まれていないので、よりクリーンです。引数を変更するには、変更した値をに渡すだけOLD-FUNCTIONです。

その他のWHERE

のdocstringにadd-functionは、すべてのアドバイスプレース(または「コンビネーター」)とそれらの同等物のテーブルが含まれ、アドバイスされた機能とlambda同等の動作に関して機能を説明します。

`:before'       (lambda (&rest r) (apply FUNCTION r) (apply OLDFUN r))
`:after'        (lambda (&rest r) (prog1 (apply OLDFUN r) (apply FUNCTION r)))
`:around'       (lambda (&rest r) (apply FUNCTION OLDFUN r))
`:override'     (lambda (&rest r) (apply FUNCTION r))
`:before-while' (lambda (&rest r) (and (apply FUNCTION r) (apply OLDFUN r)))
`:before-until' (lambda (&rest r) (or  (apply FUNCTION r) (apply OLDFUN r)))
`:after-while'  (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r)))
`:after-until'  (lambda (&rest r) (or  (apply OLDFUN r) (apply FUNCTION r)))
`:filter-args'  (lambda (&rest r) (apply OLDFUN (funcall FUNCTION r)))
`:filter-return'(lambda (&rest r) (funcall FUNCTION (apply OLDFUN r)))

(cited from `C-h f add-function')

ここで、FUNCTIONはアドバイス関数であり、OLDFUNはアドバイスが追加される関数です。一度にすべてを理解しようとするのではなく、WHERE適切に聞こえる記号を選択して、その記号を理解してください。

または、単に使用します:around。すべてに特化したWHEREs を使用することの唯一の利点 は、アドバイスのdocstringを読む前に:around調べることでもう少し情報が得られることですC-h f ADVISED-FUNCTION。アドバイスを含むコードを公開する予定がない限り、おそらく重要ではありません。

名前付きアドバイス関数

多くの利点を提供するため、名前付き関数をアドバイスとして使用することをお勧めします(フックの名前付き関数の使用にも適用されるものもあります)。

  • 次のように表示されC-h f find-fileます

    :around advice: `my-find-file-advice-print-arguments'
    

    アドバイス関数の定義へのリンク。通常は、関数が定義されたファイルへのリンクが含まれています。アドバイスがlambdaフォーム内で直接フォームとして定義されていた場合、advice-add docstringはインラインで表示され(長いdocstringの混乱?)、どこで定義されたかを示すものはありません。

  • アドバイスを削除するには

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • advice-add古いバージョンを再実行したり危険にさらしたりせずに、アドバイスの定義を更新できます (advice-add変更された状態で実行 lambdaすると、古いアドバイスの更新としてではなく、新しいアドバイスとして認識されます)。

補足説明この#'function表記法は'function、バイトコンパイラーがシンボルを関数名として識別し、欠落している関数(タイプミスなど)を識別するのに役立つことを除いて、基本的にに相当し ます。


あたりとして議論私はそれがあるべき..ハッシュ引用符は、すべての引数に、ここで使用されるべきではないスティーブン・モニエとしていた(advice-add 'find-file :around #'my-find-file-advice-print-arguments)と同様に(advice-remove 'find-file #'my-find-file-advice-print-arguments)
カウシャルモディ

advice-addボーダーケースだと思います。個人的には、' ↔ #'区別は主に関数名のタイプミスを識別するのに役立つと考えているため、ここではおそらく、アドバイスが追加されるまでに関数が定義されることを期待するかどうかに依存します。
kdb

@kdb私は最終的に自分でこれを見つけました(のドキュメントに遭遇した後add-function)。ドキュメントがそれをより明確にしたいです。私はそれのためにパッチを作成することを期待するかもしれません。
PythonNut

@kdb「C-h f find-fileではなく、で表示されC-xますか?
-Peeja

@Peejaはい、修正しました。
kdb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.