在ClojureScript中列举命名空间并动态加载它们

4

这实际上可能是一个XY问题,所以我将首先尝试解释目标。

我正在构建一个ClojureScript应用程序,它由一组Reagent组件组成。它提供了一个用户界面,您可以动态添加或删除UI元素。这些UI元素(组件)具有特定类型。例如,Markdown组件文本组件。每当用户被呈现添加文本的选项时,我们列出所有与类型+后代匹配的组件(在这种情况下为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中动态地维护命名空间+变量的映射或列表?


1
也许宏会有帮助?或者使用.cljc的技巧? - Michiel Borkent
1个回答

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

谢谢,这非常有帮助!看起来我将能够从cljs.test中提取相关部分。我还没有完全意识到clj和cljs之间的宏互操作性。 - JoelKuiper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接