emacs-noflet
emacs-noflet copied to clipboard
noflet - nic's overriding flet, for fleting functions for the purpose of decorating them
= 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.
=== Decorating results ===
{{{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.
=== Lexical version ===
Because we include a good indenting function we also include a lexical {{{flet}}}. It's just a wrapper for {{{cl-flet}}}.