Previous: , Up: Emacs Lisp関数にたいするアドバイス   [Contents][Index]


13.11.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-advicead-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を変更することによりリターン値を変更できますが、新しい:afterは変更できないので、そのようなafterを移行するときは、かわりにそれらを新しいアドバイス:around:filter-returnに変更する必要があるでしょう。