Emacs laisse des conseils


14

Je voudrais remplacer temporairement une fonction dans un morceau de code.

Prenez, par exemple, ce qui suit:

(defun nadvice/load-quiet (args)
  (cl-destructuring-bind
      (file &optional noerror nomessage nosuffix must-suffix)
      args
    (list file noerror t nosuffix must-suffix)))

(defun nadvice/idle-require-quiet (old-fun &rest args)
    (advice-add 'load :filter-args #'nadvice/load-quiet)
    (apply old-fun args)
    (advice-remove #'load #'nadvice/load-quiet))

(advice-add 'idle-require-load-next :around #'nadvice/idle-require-quiet)

Ce qui ne fonctionne pas:

  • Cette. Il serait beaucoup plus propre si je pouvais éviter d'activer et de désactiver manuellement les conseils et de faire confiance à la nature à un seul thread d'Emacs pour prendre soin des choses.
  • cl-letfne me laisse pas référencer la fonction d'origine, donc je ne peux pas implémenter des choses qui :filter-argsferaient normalement.
  • cl-flet ne peut pas remplacer les fonctions dans d'autres fonctions.
  • nofletest un package externe, que j'aimerais éviter. (Fait également beaucoup plus que ce dont j'ai besoin)

Réponses:


16

Ne pourriez-vous pas utiliser vous- (cl-)letfmême le référencement de la fonction d'origine?

Quelque chose comme ça:

;; Original function
(defun my-fun (arg)
  (message "my-fun (%s)" arg))


;; Standard call
(my-fun "arg") ;; => my-fun (arg)


;; Temporary overriding (more or less like an around advice)
(let ((orig-fun (symbol-function 'my-fun)))
  (letf (((symbol-function 'my-fun)
          (lambda (arg)
            ;; filter arguments
            (funcall orig-fun (concat "modified-" arg)))))
    (my-fun "arg")))
;; => my-fun (modified-arg)


;; The overriding was only temporary
(my-fun "arg") ;; => my-fun (arg)



Vous pouvez également envelopper cela dans une macro si vous prévoyez de le réutiliser:

(defmacro with-advice (args &rest body)
  (declare (indent 1))
  (let ((fun-name (car args))
        (advice   (cadr args))
        (orig-sym (make-symbol "orig")))
    `(cl-letf* ((,orig-sym  (symbol-function ',fun-name))
                ((symbol-function ',fun-name)
                 (lambda (&rest args)
                   (apply ,advice ,orig-sym args))))
       ,@body)))

L'exemple ci-dessus peut ensuite être réécrit comme suit:

(defun my-fun (arg)
  (message "my-fun (%s)" arg))


(my-fun "my-arg")

(with-advice (my-fun
              (lambda (orig-fun arg)
                (funcall orig-fun (concat "modified-" arg))))
  (my-fun "my-arg"))

(my-fun "my-arg")

Merci, c'est exactement ce que je cherchais. La seule chose que je changerais serait d'utiliser cl-letf*à la fois l' letart.
PythonNut du

J'ai ajouté une version macro qui utilise un seul letf*formulaire pour les deux liaisons.
François Févotte

Agréable! Je pourrais l'utiliser si je finis par avoir besoin des conseils dans beaucoup d'endroits.
PythonNut
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.