I often have to manipulate keywords and symbols. A symbol name needs
a string appended in a macro, a keyword uses underscores instead of
dashes.
In order to do this, I usually transform them into a string, do some
manipulation, and then turn the result back into a keyword/symbol.
This pattern shows up enough that I created the multimethod below
(defmulti modify (fn [& args] (class (second args))))
(defmethod modify clojure.lang.Keyword
[f k] (keyword (f (name k))))
(defmethod modify clojure.lang.Symbol
[f s] (symbol (f (name s))))
(defmethod modify :default
[f s] (f s))
What this lets me do is use a string library to manipulate keywords/
symbols. For example
;wraps .toLowerCase
user=>(downcase "ABC")
"abc"
;Expected behavior w/strings
user=>(modify downcase "ABC")
"abc"
user=>(modify downcase :ABC)
:abc
user=>(modify downcase 'ABC)
abc
As you can see, it works on both keywords & symbols without missing a
beat. Now, let's take it a step further:
(defn super-downcase [input]
(modify downcase input))
user=>(super-downcase "ABC")
"abc"
user=>(super-downcase :ABC)
:abc
user=>(super-downcase 'ABC)
abc
super-downcase works on all three types, and we now have a new layer
of abstraction in our string function. Add some macro-fu, et voila -
a unified string/keyword/symbol library.
You can play with the code here:
http://github.com/francoisdevlin/devlinsf-clojure-utils
Check the lib.sfd.str-utils namespace. Feel free to use the idea as
you see fit.
Hope this helps,
Sean