Reflection 在运行时导入脚本

Reflection 在运行时导入脚本,reflection,import,clojure,namespaces,runtime,Reflection,Import,Clojure,Namespaces,Runtime,我正在使用Clojure编写一个小型测试框架 (ns pvt.core.runner (use [pvt.tests.deployment] [pvt.tests.files] [pvt.tests.jms])) (defn- run-test [test-name] {test-name (test-and-log test-name)}) (defn- run-all-tests-in-namespace [namespace-name] (

我正在使用Clojure编写一个小型测试框架

(ns pvt.core.runner
  (use 
    [pvt.tests.deployment]
    [pvt.tests.files]
    [pvt.tests.jms]))

(defn- run-test
  [test-name]
  {test-name (test-and-log test-name)})

(defn- run-all-tests-in-namespace
  [namespace-name]
  (map
    run-test
    (vals (ns-publics (symbol namespace-name))))
  )

(defn run-all-tests
  [namespace-list]
  (map run-all-tests-in-namespace namespace-list))
My
run all tests
函数接受clojure脚本列表,加载这些脚本中的所有公共函数并运行它们。这很好,只是我必须实际导入这些脚本。我像这样调用我的函数
(运行所有测试[“pvt.tests.deployment”“pvt.tests.files”“pvt.tests.jms”])
,但这只有在我导入这些脚本(如代码摘录开头所示)时才有效。这是不好的,因为我不知道谁将调用runall测试,以及将使用什么参数

我想知道是否有办法在运行时导入这些脚本。我已经知道每个脚本的名称空间,所以我有所有必需的信息。这能做到吗?
谢谢

是的,您可以使用
加载文件
从任意文件路径导入Clojure源文件。如果源文件包含名称空间声明,那么这些名称空间现在可用于Clojure应用程序(框架)

显然,至少您必须编写一些代码,从命令行获取Clojure源文件的名称,或者指向源文件所在的目录。然后代码将使用
(加载文件)
加载文件

您声明的问题是,您希望在不预先知道名称空间名称的情况下从名称空间执行一些测试。有两种方法可以实现这一点:

1)使用命名约定。

user=> (load-file "/home/noahlz/foo.clj") 
#<Var@1e955d29: #<core$foo foo.test.core$foo@48a7a9bd>>
user=> (filter #(re-matches #".*\.test\..*" %) (map str (all-ns)))
("foo.test.core")
在REPL,您可以通过编程方式获取以下信息:

user=> (load-file "foo.clj")

user=> (filter (fn [[n m]] (:my-framework-tests m)) 
               (map #(vector (str %) (meta %)) (all-ns)))
(["foo.test.core" {:my-framework-tests true, :doc "some documentation"}])
现在您有了一个名称空间列表,这些名称空间被标记为包含自定义测试框架的测试。您甚至可以在名称空间函数中使用元数据,以避免这些函数也需要命名约定

可能有一种更简洁的方法来获取具有特定元数据的名称空间(如果有人知道,请务必注释!)

另外一个重要的注意事项:我正在加载任意文件来证明这是可能的,买你真的应该考虑下面的约定,接着是LeInEnen,Maven或其他构建框架。例如,请参见


祝你好运

谢谢你帮助我。我设法找到了我要找的东西。其实比我想象的要简单。不知道
use
实际上是一个函数。现在,我只需这样做:

(defn- run-all-tests-in-namespace
  [namespace-name]
  (use (symbol namespace-name))
  (map
    run-test
    (vals (ns-publics (symbol namespace-name))))
  )

我从名称空间名称创建一个符号,然后将其传递给
use
函数。很好

名称空间是一等公民。我看不出你有什么问题。请看:名称空间是一流的公民,但是实现sebi所需的技术对于初学者来说可能并不那么明显。请查看我的答案并做出适当的评论(特别是关于我如何映射和过滤名称apce的任何反馈)。您的答案非常好且全面,但我猜所需的只是在函数内部调用(使用…)。OP的回答证实了这一点。1)
使用
现在被广泛劝阻。2) “这只在我导入这些脚本(如代码摘录开头所示)时有效。这不好…”-OP不想在源代码中硬编码名称空间名称,这就是我的回答。哈,真的吗?您的问题说明您正在创建一个框架,不想硬编码名称空间名称。我不想。run all tests是一个公共方法,它将从调用方接收名称空间名称。好吧,您应该更喜欢
(require)
:请参考[test fns…]
:-我认为您不是真的想使用
使用

(defn- run-all-tests-in-namespace
  [namespace-name]
  (use (symbol namespace-name))
  (map
    run-test
    (vals (ns-publics (symbol namespace-name))))
  )