Вся необходимая информация включена в 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, за исключением того, что он помогает байтам компилятору определить символы, имена функций и , таким образом , чтобы выявить недостающие функции (например , из - за опечатки).
M-x report-emacs-bug. Некоторые разработчики иногда предпочитают разрабатывать, а не документировать. ;-) Важно, чтобы Emacs документировал сам.