From Spec to Test Suite in Common Lisp: Mustache
msnyder.infoFairly idiomatic code. Just minor nitpick.
To traverse directories use fad:walk-directory from CL-FAD. It takes a starting directory and a single-argument function, then traversing that directory recursively calling the function with each child as an argument.
I wrote this earlier to count what languages I've used in 2011, because I didn't trust my cursory examination with ls(1).
(let ((start-2011 (encode-universal-time 1 0 0 1 1 2011))
(lang-stat (make-hash-table :test #'equalp)))
(fad:walk-directory #p"~/hack"
(lambda (f)
(when (>= (file-write-date f) start-2011)
(when-let (type (string-trim "~" (pathname-type f)))
(incf (gethash type lang-stat 0))))))
(loop for k in (sort (hash-table-keys lang-stat) #'string-lessp)
do (format t "~a~10t~a~%" k (gethash k lang-stat 0))))I'm not a lisp pro (more like aspiring to be), but, for what it's worth, I think your use of eval is fine. It doesn't suffer from the "double evaluation" problem, and evaluation at compile time is actually what you want.
If you really want to get rid of eval in the macro, though, I suppose you could hard-code your loop to all-specs rather than attempt to supply the list as an argument. This would be contingent on all-specs being present in the compilation environment, via an eval-when or something.
That's a pretty neat article! I'm glad you wrote that up! (Didn't even notice the EVAL in there, until I saw wes-exp's comment: You can avoid it (if you want, seeing as this is example code) by not using a SPECS variable, and putting all-specs in the loop directly.