3

假设我已将特定元数据添加到我的变量中:

(defn ^:run-at-startup init []
  (prn "Initializing...")
  :done)

(meta (var init))
; {:arglists ([]), :ns #<Namespace user>, :name init, :end-column 34, 
; :run-at-startup true, :column 1, :line 5, :file "NO_SOURCE_FILE", :end-line 5}

然后我想查找包含它的所有变量(跨不同的命名空间)。是否可以?

这就是为什么。我的应用程序包含几个必须在启动时初始化的模块。可以添加新模块并删除现有模块(当然不是在运行时),并且必须在不知道模块的任何细节的情况下调用它的初始化程序。我想将元数据添加到初始化程序,然后查找并调用。

我想知道是否有更好的方法。

4

1 回答 1

3

因此,如果您require的所有命名空间都包含您的非私有初始化程序,all-ns则能够检索这些命名空间的列表。如果您不知道存在哪些名称空间,您可以使用例如tools.namespace来查找。

以下函数查找包含某个元数据键设置为的所有变量true,返回变量值的序列。

(defn find-by-var-meta
  [metadata-flag]
  (->> (all-ns)
       (mapcat ns-publics)
       (keep
         (fn [[_ v]]
           (when (-> v meta metadata-flag)
             (var-get v))))))

然后可以遍历生成的 seq,并且可以调用作为函数的所有内容。所以,在你的情况下,这应该是这样的:

(require '[my.namespace.initializers a b c])
(find-by-var-meta :run-at-startup) ;; => seq of initializers from the above ns.

并快速检查 REPL:

(defn ^:run-at-startup add-one [x] (inc x))    ;; => #'user/add-one
((first (find-by-var-meta :run-at-startup)) 5) ;; => 6

(如此处所示,如果您只想将一个或多个键设置为 ,则也不需要为元数据指定完整映射true。)

于 2013-11-06T12:51:31.120 回答