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

(ここに見られるように、1 つまたは複数のキーを に設定するだけの場合は、メタデータの完全なマップを指定する必要もありませんtrue。)

于 2013-11-06T12:51:31.120 に答える