Clojure: 在特定命名空间中启动 REPL

7
我已经安装了boot-clj,希望能够在外部编辑器中编辑.clj文件,并分别从命令行REPL运行,以便我可以调用更改的函数。不需要特殊的重新加载命令。
另一个问题是我不想手动输入命令来包含命名空间 - 我想运行一个脚本,将我带入命名空间,这样我就可以立即调用现有的函数。
文件名称:
C:\dev\my-project\src\my_project\utils.clj

文件中的一些内容:

(ns my-project.utils
  (:require
    [clojure.string :as s]))

(defn my-range [start end]
  (take (- end start) (iterate inc start)))

我想直接进入REPL并输入(my-range 0 3),查看是否产生我想要的结果。
这个设置是什么?我需要运行哪个脚本文件?
我的理解是答案应该像这样:
(deftask dev-repl
  (set-env! …)
  (repl))
1个回答

9

在命令行中

您可以在命令行中实现这一点,而不需要创建build.boot文件:

在C:\dev\my_project中:

boot -r src repl -n my-project.utils
  • boot -r src:使用“资源路径”上的src 启动启动程序,资源路径是在JVM内可访问的目录集合。
  • repl -n my-project.utils 启动REPL,需要引用您的命名空间并进入它。

当REPL正在运行且在编辑了C:\dev\my_project\src\my_project\utils.clj之后,您可以像这样在REPL中重新加载它:

my-project.utils=> (require 'my-project.utils :reload)
nil

最简build.boot

另一种方法是创建文件C:\dev\my_project\build.boot并添加以下内容:

(set-env! :resource-paths #{"src"})

(deftask dev 
  "Run a development REPL"
  []
  (repl :init-ns 'my-project.utils))

然后,在 C:\dev\my_project 目录下:
boot dev

这将在您的命名空间中启动一个REPL,但需要更少的命令行配置,因为我们已经在build.boot中执行了配置,boot将自动评估。

注意:从Clojure REPL开始,无论使用哪个构建工具,只要它在JVM的类路径上,您都可以使用require函数来请求任何名称空间,并使用in-ns函数进入该名称空间。

带有自动重载功能的build.boot

最后,可以结合Boot的特性来实现以自动重新加载代码为导向的开发工作流程。

C:\dev\my_project\build.boot中:

(set-env! :resource-paths #{"src"})

(require '[boot.core :as core]
         '[boot.pod  :as pod])

(deftask load-ns
  "Loads the my-project.utils namespace in a fresh pod."
  []
  (let [pods (pod/pod-pool (core/get-env))]
    (core/with-pre-wrap [fileset]
      (pod/with-eval-in (pods :refresh)
        ;; We require indirectly here so that errors from my-project.utils have
        ;; proper line and column information.
        (require 'my-project.load-impl))
      fileset)))

(deftask dev
  "Watches source code and loads my-project/utils every time code changes."
  []
  (comp (watch)
        (load-ns)))

C:\dev\my_project\src\my_project\load_impl.clj 文件中:

(ns my-project.load-impl)

(require 'my-project.utils)

C:\dev\my_project\src\my_project\utils.clj 中:

(ns my-project.utils
  (:require
    [clojure.string :as s]))

(defn my-range [start end]
  (take (- end start) (iterate inc start)))

(println "In the code!")
(println "(my-range 0 10) = " (my-range 10 20))

回到命令提示符处,输入 boot dev。你应该会看到一些 println 输出,每次编辑并保存文件后,您都应该再次看到它,反映出您所做的任何更改。

太好了,谢谢 - 这将使我能够在不每次重新启动新JVM的情况下运行代码。我想知道 (require ...) 是否可以以某种方式被放在历史记录的最前面,这样只需要几个向上的按键就可以了,或者转换成像 r 这样的命令? - Chris Murphy
你可以在 REPL 中输入 Ctrl-r 来搜索命令历史记录。你也可以向你的命名空间中添加一个函数,并在 REPL 中调用它使用 (r):(defn r [] (require ...)) - Alan Dipert
我喜欢(r)技巧(即使它是一个特殊的重新加载命令)。有趣的是,如果我更改函数名称,旧函数仍然存在于命名空间中。 - Chris Murphy
我是 SO 的新手,不确定您是否收到通知,但我对我的答案进行了重大编辑。现在它包括自动重新加载设置的说明,我希望您会喜欢。 - Alan Dipert
是的,我看到了,谢谢。我的意思是你完美地回答了这个问题。我现在会使用(r)技巧,因为它基本上可以做我需要的事情,并且比真正的答案少了许多复杂的部分。 - Chris Murphy
如果您希望在构建软件时采用有纪律的方法,可以考虑采用Stuart Sierra的重新加载工作流。可在https://github.com/danielsz/system获取自动重新加载的引导任务。 - Daniel Szmulewicz

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