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


12.10.4 古いdefadviceを使用するコードの改良

多くのコードは古いdefadviceメカニズムを使用しており、これらの大半はadvice-addによって陳腐化しました。advice-addの実装とセマンティックは非常にシンプルです。

古いアドバイスは以下のようなものです:

(defadvice previous-line (before next-line-at-end
                                 (&optional arg try-vscroll))
  "Insert an empty line when moving up from the top line."
  (if (and next-line-add-newlines (= arg 1)
           (save-excursion (beginning-of-line) (bobp)))
      (progn
        (beginning-of-line)
        (newline))))

新しいアドバイスメカニズムを使用すれば、これを通常の関数に変換できます:

(defun previous-line--next-line-at-end (&optional arg try-vscroll)
  "Insert an empty line when moving up from the top line."
  (if (and next-line-add-newlines (= arg 1)
           (save-excursion (beginning-of-line) (bobp)))
      (progn
        (beginning-of-line)
        (newline))))

これが実際のprevious-lineを変更しないことは明確です。古いアドバイスには以下が必要です:

(ad-activate 'previous-line)

一方、新しいアドバイスメカニズムでは以下が必要です:

(advice-add 'previous-line :before #'previous-line--next-line-at-end)

ad-activateはグローバルな効果をもつことに注意してください。これは、指定された関数にたいして、アドバイスのすべての断片を有効にします。特定のアドバイスだけをアクティブ、または非アクティブにしたい場合、ad-enable-advice、またはad-disable-adviceにより、有効または無効にする必要があります。新しいメカニズムではこの区別はなくなりました。

以下のようなaroundのアドバイスがあるとします:

(defadvice foo (around foo-around)
  "Ignore case in `foo'."
  (let ((case-fold-search t))
    ad-do-it))
(ad-activate 'foo)

これは以下のように変換できます:

(defun foo--foo-around (orig-fun &rest args)
  "Ignore case in `foo'."
  (let ((case-fold-search t))
    (apply orig-fun args)))
(advice-add 'foo :around #'foo--foo-around)

アドバイスのクラスについて、新たな:beforeは、古いbeforeは完全に等価ではないことに注意してください。なぜなら古いアドバイス内では、(たとえばad-set-argを使って)その関数の引数を変更できそれは元の関数が参照する引数値に影響します。しかし新しい:beforeは、setqを通じてアドバイス内の引数をし、その変更は元の関数からの参照に影響しません。この振る舞いにもとづいてbeforeアドバイスを移行するときは、代わりにそれを新たなアドバイス:aroundまたは:filter-argsに変更する必要があるでしょう。

同様に、古いafterアドバイスは、ad-return-valueを変更することによりreturn値を変更できますが、新しい:afterは変更できないので、そのようなafterを移行するときは、かわりにそれらを新しいアドバイス:aroundまたは:filter-returnに変更する必要があるでしょう。