2013-04-10 8 views
7

Angenommen es eine Beispielfunktion in einer Bibliothek (diese Frage ist Voraussetzung dafür ist, in dieser Bibliothek alle Definitionen geändert, so etwas wie „read only“ werden können) definiert ist:, wie eine Funktionsdefinition ändern gnädig

(defun sample() 
    (foo) 
    (bar) 
    (baz)) 

I wollen diese Bibliothek verwenden, aber die Funktion sample kann meine Anfrage nicht überein, was ich will, ist:

(defun sample() 
    (foo) 
    (when condition 
    (bar)) 
    (baz)) 

Jemand hat mir gesagt defadvice zu verwenden, aber ich bemerkte, dass defadvice nur Code vor oder nach dem einfügen Anrufungen von sample, wie:

(before-advice ...) 
(sample) 
(after-advice ...) 

es die Definition von sample selbst nicht ändern kann. Also, wie kann ich das gnädig erreichen? Sollte ich selbst eine sample umschreiben, genannt my-sample oder sample2?

+1

Während Sie eine sehr klare Beschreibung des Problems geben hat, wenn man die aktuelle Situation geben und Funktion, die Sie außer Kraft setzen möchten, könnten andere Optionen eröffnen. –

+0

@TreyJackson Die tatsächliche Situation ist ein wenig komplex zu beschreiben, was ich oben geschrieben habe, ist die einfachste, aber die beste Beschreibung dieser Situation, aber jetzt bekomme ich die Antwort, danke. :-) –

Antwort

5

der sds Antwort funktioniert, außer dass Sie vermutlich wollen nur bar Beratung, wenn sample ausgeführt wird, so dass Sie Probe beraten bräuchten sowie zum Aktivieren und Deaktivieren des Hinweises für bar. Mein with-temporary-advice Makro erleichtert dies:

(defmacro with-temporary-advice (function class name &rest body) 
    "Enable the specified advice, evaluate BODY, then disable the advice." 
    `(unwind-protect 
     (progn 
     (ad-enable-advice ,function ,class ,name) 
     (ad-activate ,function) 
     ,@body) 
    (ad-disable-advice ,function ,class ,name) 
    (ad-activate ,function))) 

(defadvice bar (around my-conditional-bar disable) 
    ;; This advice disabled by default, and enabled dynamically. 
    (when condition 
    ad-do-it)) 

(defadvice sample (around my-sample-advice activate) 
    "Make execution of `bar' conditional when running `sample'." 
    (with-temporary-advice 'bar 'around 'my-conditional-bar 
    ad-do-it)) 

Beachten Sie, dass, wenn bar auch auf andere Weise aufgerufen wird, während sample ausgeführt wird, die Beratung als auch für die Anrufe gelten, so dass Sie für dieses Konto sollte, wenn es eine Möglichkeit ist.

Alternativ können Sie auch flet verwenden, um bar bei Bedarf neu zu definieren. Dies unterliegt selbstverständlich dem gleichen Vorbehalt wie die erste Lösung.

(defadvice sample (around my-sample-advice activate) 
    "Make execution of `bar' conditional when running `sample'." 
    (if condition 
     ad-do-it 
    (flet ((bar() nil)) 
     ad-do-it))) 

Das viel einfacher zu lesen ist, aber aus Gründen, die ich nicht verstehen flet ist, wie von Emacs 24.3, nicht mehr dafür. Sein Docstring schlägt vor, stattdessen cl-flet zu verwenden, aber da cl-flet lexikalische Bindung verwendet, wird das nicht wirklich funktionieren. So gut ich es beurteilen konnte, es klang wie flet ist eigentlich nicht weg, aber die aktuelle Empfehlung scheint zu sein, stattdessen Rat zu verwenden.

Beachten Sie auch, dass, wenn innerhalb bar, das unerwünschte Verhalten auf einigen Variable abhing, dann wäre es besser, eine let Bindung an diese Variable zu verwenden, anstatt der flet auf die Funktion zu binden.

Edit:

Diese Ansätze machen es schwieriger, zu sehen, was, natürlich geschieht. Abhängig von der genauen Situation, ist es möglicherweise besser, einfach die sample Funktion neu zu definieren, um das zu tun, was Sie wollen (oder eine my-sample Funktion zu schreiben, um an ihrer Stelle aufzurufen, wie Sie vorgeschlagen haben).

+0

Ein Schlüssel-Tipp für mich ist genug, aber Sie gaben mir mehr als ich wollte, wirklich wirklich danke für Ihre ausführliche Antwort. :-) –

+0

Es gibt dflet, die flet für neuere Emacs-Versionen bietet: https://github.com/sigma/el-x – tkf

+0

Ich glaube, Sie sollten 'unroll-protect' in diesem Makro verwenden. – Svante

3

sollten Sie Funktion beraten bar stattdessen mit einem around Rat:

(defadvice bar (around my-condition) 
    (when condition 
    ad-do-it)) 
+0

Oh, danke, mein Gedanke ist so starr, dass ich nicht weiß, dass ich "Bar" raten könnte, um das Ziel zu erreichen. –

4

Andere haben bereits gute Antworten zur Verfügung gestellt, aber da einige über flet ‚s Schande beschweren, werde ich zeigen, was ich verwenden würde:

(defvar my-inhibit-bar nil) 
(defadvice bar (around my-condition activate) 
    (unless my-inhibit-bar ad-do-it)) 
(defadvice sample (around my-condition activate) 
    (let ((my-inhibit-bar (not condition))) 
    ad-do-it)) 

Schauen Sie MA! Nein flet und keine hässliche aktivieren/deaktivieren! Und wenn Sie C-h f bar es klar sagen, dass es mehr als das Auge trifft. Ich würde auch tatsächlich nutzen die neue advice-add statt:

(defvar my-inhibit-bar nil) 
(defun my-bar-advice (doit &rest args) 
    (unless my-inhibit-bar (apply doit args))) 
(advice-add :around 'bar #'my-bar-advice) 
(defun my-sample-advice (doit &rest args) 
    (let ((my-inhibit-bar (not condition))) 
    (apply doit args))) 
(advice-add :around 'sample #'my-sample-advice) 
+0

Mein Instinkt war, dass es hässlich ist, etwas dauerhaft empfohlen zu bekommen, wenn es nur selten gebraucht wird, aber größere Transparenz ist hier ein offensichtlicher Gewinn, und wenn man diese Art von 'Hemmungs'-Test schreibt, erscheint die Permanenz viel vernünftiger. Ich mag auch sehr, dass die neue Ratgeber-Bibliothek "defun" verwendet, da wir tatsächlich 'find-function' darauf verwenden können! Das wird eine enorme Verbesserung sein. Ich hoffe immer noch, dass 'flet' * langfristig in Emacs bleiben wird, aber ich kann die Vorteile Ihres Ansatzes hier sehen. – phils

+0

Ich bin froh, dass Ihnen die neue Beratungsstelle gefällt. Hoffentlich wird 'flet' irgendwann verschwinden, aus Gründen der Rückwärtskompatibilität sollten Sie für mehrere Jahre in Sicherheit sein. Beachten Sie, dass 'cl-letf' nicht auf dem Weg nach draußen ist, also ist es auch eine Alternative, obwohl es etwas verbaler ist als' flet'. – Stefan

Verwandte Themen