Reputation: 2455
I define a map of functions:
(ns fs
(:require [folder/a :as a]
[folder/b :as b]
[folder/c :as c])
(def functions {:a a/f :b b/f :c c/f})
(doseq [[_ f] functions] (f))
Now I want to add more namespaces within the folder, and I don't want to modify the above code. How can functions
be dynamically populated with the f
from each namespace in a folder.
Upvotes: 1
Views: 89
Reputation: 10514
First some helpers:
(defn directory
"Get directory from path"
[path]
(clojure.java.io/file path))
(defn file-names
"Get file names of the files in the directory."
[files]
(map (fn [file] (.getName file)) files))
(defn namespace
"Remove the extension from the file name and prefix with folder-name"
[folder-name file-name]
(->> (clojure.string/split file-name #"\.")
(butlast)
(apply str)
(str folder-name ".")
(symbol)))
Then retrieve all namespaces from your folder, you need the path and the folder name:
(def namespaces
(let [names (->> "/path/to/your/folder-name"
directory
file-seq ;; Gets the tree structure of the directory
rest ;; Get rid of the the directory name
file-names)]
(map (partial namespace "folder-name") names)))
Next get the public functions in every namespace via ns-publics
:
(def functions
(->> namespaces
(map (juxt keyword (comp vals ns-publics)))
(into {})))
;; => prints {:namespace-key '(fn-a fn-b) :namespace-key2 '(fn-b fn-c)}
Note that this gets a list of all the public functions in a namesapce after the namespace keys.
We can execute the functions as follows:
(doseq [[_ ns-fns] functions
f ns-fns] (f))
Of course, this only works for functions that have an arity of zero. Otherwise you have to pass arguments to f
.
Upvotes: 1