如何动态地将所有源文件包含在clojure的文件夹中?

时间:2017-07-03 13:22:56

标签: clojure

我定义了一个函数图:

(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

1 个答案:

答案 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