수정하기 힘든 패키지에 있는 함수를 수정할 때 사용하는 advice
The advice feature lets you add to the existing definition of a function, by advising the function. This is a cleaner method than redefining the whole function.
Advising Functions (GNU Emacs Lisp Reference Manual) - gnu.org
기존 함수 호출 전, 호출 후, 혹은 기존 함수 호출까지 내가 책임질 수 있다. 조언(advice)이라니 재미있는 표현이다.
필요할 때
내가 컨트롤하지 못하는 함수를 수정해야 할 때, 유용하게 사용할 수 있다. 난 사용 중인 패키지의 특정 코드나 emacs 기본 함수 동작을 변경할 때, 주로 사용한다. 혹은 특정 함수가 호출된 후에 호출하는 hook이 없어서 advice를 사용한다. ’TODO 상태와 org-clock은 같이 움직인다’ 글에서 org-clock-in
함수가 호출됐을 때, 후속 작업으로 org todo 상태를 바꾸고 싶어서 advice를 사용했다.
기본적인 사용법
(defun awesome-func (&rest args)
(apply '+ args))
(awesome-func 1 2 3)
6
인자를 더하는 개쩌는 함수가 있다.
(defun advice-awesome-func (&rest args)
(message "called advice-awesome-func")
(* (apply args) 2))
(advice-add #'awesome-func :around #'advice-awesome-func)
:around
로 advice-awesome-func
조언 함수(advising function)를 추가한다. awesome-func
함수 호출 전에 메시지를 출력하고 결괏값에 2를 곱한다.
(awesome-func 1 2 3)
12
*Messages*
버퍼에 called advice-awesome-func
문자열을 출력하고 리턴값은 6이 아니라 12가 된다. awesome-func
는 손도 안 대고 동작을 변경했다. 조언(advice)은 이런 건가 보다. 실제 대상을 변경시키지는 못한다.
(advice-remove #'awesome-func #'advice-awesome-func)
advice-remove
로 조언 함수를 제거할 수 있다.
(awesome-func 1 2 3)
6
이제 원래 값이 나온다.
:around
이외의 방법
원래 함수 호출까지 책임지는 :around
가 가장 강력하다. 이걸로 다 문지르려고 하지 말고 방법이 여러 개 있으니 더 명확한 걸 사용하자. 코드를 읽는 데 도움이 된다.
:before
(defun advice-awesome-func-before (oldfunc &rest args)
(message "args: %S" args))
(advice-add #'awesome-func :before'advice-awesome-func-before)
(awesome-func 1 2 3)
6
함수 호출되기 전에 뭔가를 하고 싶으면 사용한다.
:after
(defun advice-awesome-func-after (oldfunc &rest args)
(apply '- args))
(advice-add #'awesome-func :after #'advice-awesome-func-after)
(awesome-func 1 2 3)
6
함수가 호출된 후에 뭔가를 하고 싶을 때, 사용한다. 리턴 값을 대체할 순 없다.
:filter-args
(defun advice-awesome-func-filter-args (args)
(mapcar (lambda(x) (+ x 1)) args))
(advice-add #'awesome-func :filter-args #'advice-awesome-func-filter-args)
(awesome-func 1 2 3)
9
:filter-args
키워드를 사용하면 인자가 리스트로 넘어온다. 조언 함수에서 인자를 rest& args
로 받으면 안 되고 args
로 받아야 리스트를 받는다. 그걸 처리하고 리스트로 리턴하면 이 값이 awesome-func
인자로 들어간다.
:filter-return
(defun advice-awesome-func-filter-return (args)
(format "return value: %S" args))
(advice-add #'awesome-func :filter-return #'advice-awesome-func-filter-return)
(awesome-func 1 2 3)
return value: 9
:filter-args
키워드가 인자를 수정한다면 :filter-return
키워드는 리턴 값을 수정한다.
그 외
:override
, :before-while
, :before-until
, :after-while
, :after-until
도 있다. 사용법은 3.11.3 Ways to compose advice - gnu.org 문서에서 볼 수 있다.
링크
- #orgmode TODO 상태와 org-clock은 같이 움직인다 - ohyecloudy.com
- Advice Combinators (GNU Emacs Lisp Reference Manual) - gnu.org
- Advising Functions (GNU Emacs Lisp Reference Manual) - gnu.org
C-x C-s C-x C-c