我定义了一个函数图:
(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))
现在我想在文件夹中添加更多名称空间,我不想修改上面的代码。如何使用functions
从文件夹中的每个命名空间动态填充f
。
答案 0 :(得分:1)
首先是一些助手:
(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)))
然后从您的文件夹中检索所有名称空间,您需要路径和文件夹名称:
(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)))
接下来通过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)}
请注意,这会获取名称空间键后名称空间中所有公共函数的列表。
我们可以执行以下功能:
(doseq [[_ ns-fns] functions
f ns-fns] (f))
当然,这仅适用于arity为零的函数。否则你必须将参数传递给f
。