Mit der Hinweisfunktion können Sie das Verhalten einer Funktion global ändern. Eine Hinweisdefinition kann die ursprüngliche Funktion aufrufen.
(defadvice foo
(around foo-bar activate compile)
"Always set `qux' to t when running `foo'."
(let ((qux t))
ad-do-it))
Das cl
Paket enthält das flet
Makro zum lokalen Überschreiben einer Funktion.
(defun foo ()
"global")
(flet ((foo ()
"local"))
(some-code-that-calls-foo))
Das erlaubt keinen Verweis auf die ursprüngliche foo
Funktion. Was ist, wenn die lokale Überschreibung die ursprüngliche Funktion aufrufen muss?
(defun foo ()
"global")
(flet ((foo ()
(concat (foo) "+local")))
;; this will cause an infinite loop when (foo) is called
(some-code-that-calls-foo))
Dieser einfache Ansatz funktioniert aus gutem Grund nicht: Er (foo)
ist ein rekursiver Aufruf der lokalen Definition.
Was ist eine nicht umständliche Methode zum lokalen Überschreiben einer Funktion, mit der die ursprüngliche Funktion aus dem Überschreibungscode aufgerufen werden kann?
Anwendung: Affen-Patching eines vorhandenen Codes, in einem Fall, in dem foo
nicht global zurückgebunden werden sollte, der Code jedoch das Original aufrufen muss. Hier ist das neueste Beispiel, das ich wollte:
(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)))
Ich wollte buffer-file-name
lokal neu binden und das Original aufrufen buffer-file-name
. Ok, in diesem speziellen Fall gibt es eine Problemumgehung, bei der die buffer-file-name
Variable verwendet wird. Aber der Punkt meiner Frage hier ist die allgemeine Technik. Wie kann ich eine Funktion (hier buffer-file-name
) lokal binden, aber die globale Definition aus meiner Neudefinition aufrufen?
Dies ist für meine .emacs
, die ich weiterhin in Emacs 19.34 arbeite, sodass Lösungen, die Emacs 24.4 erfordern, nicht verfügbar sind. Ich bevorzuge zwar Lösungen, die mit lexikalischer Bindung sauber umgehen - aber beim Affen-Patching geht es von Natur aus um dynamische Bindung.
quelle
cl-letf
in Emacs 24.3 und früher verfügbar ist, aber hier ist eine verwandte FrageAntworten:
Speichern Sie die ursprüngliche Funktion (erhalten mit
symbol-function
) in einer lokalen Variablen undfuncall
rufen Sie das in dieser Variablen gespeicherte Funktionsobjekt auf. Umständlich, aber es funktioniert meistens.Dies funktioniert meistens , indem es das tut, was es tun soll, aber es kann in seltenen Fällen brechen. Da Emacs Lisp keine primitive Möglichkeit hat, die Funktionssteckplätze von Symbolen lokal zu definieren (nur variable Steckplätze mit
let
),flet
werden die Bindungen festgelegt und wiederhergestelltunwind-protect
. Wenn der Code stirbt, weil die Verschachtelung von Anrufen überschrittenmax-lisp-eval-depth
wurde oder wenn die Bindung während der Ausführung dieser Funktion geändert wird (z. B. weil Sie den Hinweis debuggen), kann der Funktionssteckplatz des Symbols möglicherweise nicht wiederhergestellt werden. Möglicherweise möchten Sie Vorsichtsmaßnahmen treffen, um zu verhindern, dass einige Funktionen versehentlich verloren gehen.Eine andere Methode besteht darin, eine Kopie der Funktion zu speichern. Dies hat den Vorteil, dass die ursprüngliche Funktion niemals verloren geht.
Dies wäre in diesem speziellen Fall in Ordnung, da
buffer-file-name
es sich um eine integrierte Funktion handelt, deren Rückprall unwahrscheinlich ist, die jedoch keine Neudefinitionen der globalen Funktion nachverfolgen würde (z. B. um dieser Funktion Ratschläge hinzuzufügen ).quelle
nadvice
Rezept dafür?