La función de asesoramiento permite modificar el comportamiento de una función a nivel mundial. Una definición de consejo puede hacer llamadas a la función original.
(defadvice foo
(around foo-bar activate compile)
"Always set `qux' to t when running `foo'."
(let ((qux t))
ad-do-it))
El cl
paquete proporciona la flet
macro para anular una función localmente.
(defun foo ()
"global")
(flet ((foo ()
"local"))
(some-code-that-calls-foo))
Eso no permite una referencia a la foo
función original . ¿Qué pasa si la anulación local necesita llamar a la función original?
(defun foo ()
"global")
(flet ((foo ()
(concat (foo) "+local")))
;; this will cause an infinite loop when (foo) is called
(some-code-that-calls-foo))
Este enfoque directo no funciona, por una buena razón: (foo)
es una llamada recursiva a la definición local.
¿Cuál es una forma no engorrosa de anular localmente una función, que permite llamar a la función original desde el código de anulación?
Aplicación: parchear algunos códigos existentes, en un caso en el foo
que no se debe rebotar globalmente, pero el código debe llamar al original. Aquí está el último ejemplo que he estado esperando:
(defadvice TeX-master-file
(around TeX-master-file-indirect-buffer activate compile)
"Support indirect buffers."
(flet ((buffer-file-name (&optional buffer)
(<global buffer-file-name> (buffer-base-buffer buffer))))
ad-do-it)))
Quería volver a unir buffer-file-name
localmente y llamar al original buffer-file-name
. Ok, en este caso específico, hay una solución alternativa, que es usar la buffer-file-name
variable. Pero el punto de mi pregunta aquí es la técnica general. ¿Cómo puedo vincular una función (aquí buffer-file-name
) localmente pero llamar a la definición global desde mi redefinición?
Esto es para mi .emacs
, que sigo trabajando en Emacs 19.34, por lo que las soluciones que requieren Emacs 24.4 están fuera. Sin embargo, prefiero soluciones que hagan frente a la unión léxica limpiamente, pero el parcheado de mono es inherentemente una unión dinámica.
fuente
cl-letf
esté disponible en emacs 24.3 y anteriores, pero aquí hay un Q&A relacionado: emacs.stackexchange.com/a/16495/221Respuestas:
Almacene la función original (obtenida con
symbol-function
) en una variable local y úselafuncall
para llamar al objeto de función almacenado en esa variable. Incómodo, pero en su mayoría funciona.Esto funciona principalmente , ya que hace lo que se supone que debe hacer, pero puede romperse en circunstancias excepcionales. Dado que Emacs Lisp no tiene una forma primitiva de definir localmente las ranuras de función de los símbolos (solo ranuras variables, con
let
),flet
establece los enlaces y los restauraunwind-protect
. Si el código muere porque se excedió el anidamiento de la llamadamax-lisp-eval-depth
, o si el enlace se modifica durante la ejecución de esta función (por ejemplo, porque está depurando el consejo), es posible que la ranura de función del símbolo no se restablezca. Es posible que desee tomar precauciones contra la pérdida accidental de algunas funciones.Otro método es almacenar una copia de la función. Esto tiene la ventaja de que la función original nunca se pierde.
Esto estaría bien en este caso específico, porque
buffer-file-name
es una función incorporada que es poco probable que se recupere, pero no rastrearía las redefiniciones de la función global (por ejemplo, para agregar consejos a esa función).fuente
nadvice
receta para lo mismo?