noflet - Local function decoration
noflet is dynamic, local, advice for Emacs-Lisp code.
noflet also has an Emacs indentation function for flet like macros.
It's great for test code when you need to mock another function.
This is useful for definining functions that overide a base definition in some way. You get access to the original (before you re-defined it) function through a different name.
Use it like this:
(noflet ((find-file-noselect (file-name) (if (string-match-p "^#.*" file-name) (this-fn "/tmp/mytest") (this-fn file-name))) (expand-file-name (file-name &optional thing) (if (string-match-p "^#.*" file-name) (concat "/tmp" (file-name-as-directory (substring file-name 1))) (funcall this-fn file-name thing)))) (expand-file-name "#/thing"))
This specifies that two functions should be overridden:
- find-file-noselect is changed so that if the file-name begins with # a different file-name altogether is opened
- expand-file-name is changed so that if the file-name begins with # it's resolved via /tmp
In both cases this-fn is used to access the original function definition of these common Emacs functions.
noflet can also be used to decorate results, just like around-advice:
(noflet ((find-file (file-name &optional wildcards) (let ((result (funcall this-fn file-name wildcards))) (with-current-buffer result (setq some-buffer-local "special")) result))) (with-current-buffer (find-file "~/some-file") (message "buffer local var is: %s" some-buffer-local)))
This overrides find-file to set a local variable. There are surely better ways to do it than this but it illustrates the point.
Because we include a good indenting function we also include a lexical flet. It's just a wrapper for cl-flet.