枚举命名空间并在ClojureScript

时间:2015-05-06 15:32:13

标签: clojure namespaces clojurescript reagent

这可能实际上有点XY-problem,所以我会先尝试解释目标是什么。

我正在构建一个由一组Reagent组件组成的ClojureScript应用程序。它提供了一个用户界面,您可以在其中动态添加或删除UI元素。这些UI元素(组件)具有某种类型。例如Markdown组件is-a文本组件。每当向用户提供添加文本的选项时,我们会列出与类型+ descendants匹配的所有组件(在本例中为Markdown,可能还有其他组件)。

我编码的方式如下。 每个组件都在其自己的命名空间中,此命名空间包含一个返回新组件的构建器函数。在命名空间的根部,它还调用(derive :: type :: parent)

现在在一些不同的命名空间中,我们需要并在地图中枚举所有这些组件,如:

(ns app.components
  (:require
   [app.gui.markdown :as markdown]
   [app.gui.study-list :as study-list]))

(def all
  {markdown/t markdown/builder
   study-list/t study-list/builder})

/t指的是用于定义层次结构的名称空间限定关键字。我们使用all地图来提供面向用户的菜单的数据(可以添加哪些组件,按类型过滤)。

现在,你可以想象,这并不漂亮。因为它现在必须手动维护层次结构中所有类型的(可能)长列表。

相反,我会做类似(def all (components-of (descendants ::root)))的事情,但我不确定如何解决这个问题,因为我认为需要按名称查找变量(ClojureScript不支持)。

所以我的问题是:如何在ClojureScript中维护名称空间+ vars(动态)的地图或列表?

1 个答案:

答案 0 :(得分:3)

你不能动态地这样做,但据我所知,你的问题并不多。 ClojureScript宏可以反射回编译器 - 您可以轻松地使用cljs.analyzer.api命名空间来确定您需要哪些变量(通过var元数据或其他变量)并自动发出所需的运行时信息映射。这实际上与cljs.test/run-tests的工作方式非常相似。它使用编译器过滤掉所有名称空间中包含:test元数据的所有变量,并生成用于测试每个变量的代码。值得仔细研究cljs.test以了解如何做到这一点。