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это внешний пакет, который я хотел бы избежать. (Также делает гораздо больше, чем мне нужно)
PythonNut
источник

Ответы:

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
Я добавил макро-версию, которая использует только одну letf*форму для обеих привязок.
Франсуа Февот
Ницца! Я мог бы использовать его, если мне понадобится совет во многих местах.
PythonNut