Emacs束手无策的建议


14

我想在一段代码中临时重写一个函数。

例如,以下内容:

(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)

什么不起作用:

  • 这个。如果我可以避免手动启用和禁用建议,并相信Emacs的单线程性质来处理事务,那将更加干净。
  • cl-letf不会让我引用原始函数,因此我无法实现:filter-args通常会执行的操作。
  • cl-flet 无法覆盖其他功能中的功能。
  • noflet是一个外部软件包,我想避免。(做的比我需要的要多得多)

Answers:


16

(cl-)letf自己引用原始功能时不能使用吗?

像这样:

;; 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)



如果您打算重复使用它,也可以将其包装在宏中:

(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)))

然后可以像下面这样重写上面的示例:

(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")

谢谢,这正是我想要的。我唯一要更改的是同时使用cl-letf*两个let
PythonNut 2015年

我添加了一个宏版本,该版本仅对letf*两种绑定使用一种形式。
弗朗索瓦Févotte

真好!如果最终在很多地方需要建议,我可能会使用它。
PythonNut
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.