Saran untuk Emacs


14

Saya ingin sementara menimpa fungsi dalam sepotong kode.

Ambil, misalnya, yang berikut ini:

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

Apa yang tidak berhasil:

  • Ini. Akan jauh lebih bersih jika saya bisa menghindari secara manual mengaktifkan dan menonaktifkan saran dan mempercayai sifat single-threaded Emacs untuk mengurus hal-hal.
  • cl-letftidak akan membiarkan saya referensi fungsi asal, jadi saya tidak bisa mengimplementasikan hal-hal yang :filter-argsbiasanya dilakukan.
  • cl-flet tidak dapat mengesampingkan fungsi di fungsi lain.
  • nofletadalah paket eksternal, yang ingin saya hindari. (Juga melakukan lebih dari yang saya butuhkan)

Jawaban:


16

Tidak bisakah Anda menggunakan (cl-)letfsaat referensi sendiri fungsi aslinya?

Sesuatu seperti ini:

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



Anda juga dapat membungkus ini dalam makro jika Anda berencana untuk menggunakannya kembali:

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

Contoh di atas kemudian dapat ditulis ulang seperti berikut:

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

Terima kasih, ini persis apa yang saya cari. Satu-satunya hal yang saya ubah adalah gunakan cl-letf*untuk keduanya let.
PythonNut

Saya menambahkan versi makro yang hanya menggunakan satu letf*formulir untuk kedua binding.
François Févotte

Bagus! Saya mungkin menggunakannya jika saya akhirnya membutuhkan saran di banyak tempat.
PythonNut
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.