Как я могу использовать nadvice?

29

Мой конфиг полон советов, и я продолжаю слышать о новом блестящем минималистском nadvice.elпакете.

Я искал руководства, и я прочитал источник , но я открыто признаю: я все еще не знаю, как на самом деле его использовать.

Может ли кто-нибудь здесь указать мне на руководство или подсказать, как начать переносить мой совет в старом стиле?

PythonNut
источник
7
+1 за вопрос. Если вы искали руководства и не нашли то , что вам нужно, пожалуйста , рассмотреть вопрос о подаче (DOC) сообщение об ошибке: M-x report-emacs-bug. Некоторые разработчики иногда предпочитают разрабатывать, а не документировать. ;-) Важно, чтобы Emacs документировал сам.
Дрю
2
В этом руководстве есть раздел, см. (Info "(elisp) Портирование старых советов") . Это не перечислено в подробном индексе по любой причине все же.
Васамаса
3
Несколько примеров использования nadviceиз моей конфигурации: : после того, как , : фильтр обратного , : вокруг , : до того , пока
Kaushal Моди
1
@wasamasa Боюсь, что этот раздел далеко не полный. У меня есть несколько советов (может быть, только один, мы увидим), которые являются более сложными. Должен ли я просто задать вопрос для каждого здесь?
PythonNut

Ответы:

22

Вся необходимая информация включена в C-h f add-functionкоторые описывает основной механизм advice-add.

Новая система рекомендаций в основном действует как замена текущего определения функции на функцию, описанную в таблице, в C-h f add-functionзависимости от вашего выбора WHERE аргумента, только для того, чтобы отслеживать, какое поведение было определено в каком исходном файле.

Пример с :aroundопцией

Наиболее общий случай - это :aroundвариант, поэтому я приведу пример для этого. (Возможно, лучше использовать выделенные WHEREпараметры, когда это возможно, но вы можете заменить все остальные эквивалентными :aroundфункциями).

В качестве примера, скажем, вы хотите отладить некоторое использование find-file и хотите printкаждый раз вызывать его список аргументов. Вы могли бы написать

(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ценности

Строка документации 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 над :aroundвсем является то, что вы получаете немного больше информации от поиска до C-h f ADVISED-FUNCTION прочтения строки документа. Если вы не планируете публиковать код, содержащий рекомендации, это, вероятно, не имеет значения.

Названные функции совета

Я рекомендую использовать именованные функции в качестве совета, поскольку это дает много преимуществ (некоторые из них также применимы к использованию именованных функций для ловушек):

  • Это проявляется C-h f find-fileкак

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

    ссылка на определение функции совета, которая, как обычно, содержит ссылку на файл, в котором она была определена. Если бы совет был определен как lambdaформа непосредственно в advice-add форме, строка документа была бы показана встроенной (беспорядок для длинных строк документации?), И ничто не указывало бы, где это было определено.

  • Вы можете удалить совет с

    (advice-remove #'find-file #'my-find-file-advice-print-arguments)
    
  • Вы можете обновить определение рекомендации, не повторяя advice-addи не рискуя сохранять старую версию активной (поскольку работа advice-addс измененной версией lambdaбудет распознаваться как новая рекомендация, а не как обновление старой).

Боковое замечание#'function обозначение в основном эквивалентно 'function, за исключением того, что он помогает байтам компилятору определить символы, имена функций и , таким образом , чтобы выявить недостающие функции (например , из - за опечатки).

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