Spec-Zone.ru › Elisp

Адаптация кода, использующего старые defadvice

Множество кода использует старый механизм defadvice, который в значительной степени устарел из-за нового 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. Новый механизм избавляется от этого различия.

Советы, подобные:

(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.

Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Porting-Old-Advice.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API