使用Clojure REPL函数的最佳实践是什么?

3
我在编写Clojure源代码时,经常会键入 (ns user) 并重复按下 C+c M+n。问题在于我经常使用像 sourcedoc 这样的函数,它们在 clojure.repl 中,并且我不想将其 :require 到我的命名空间中。有经验的Clojurians 在这种情况下该怎么做呢? 澄清:我知道Clojure的命名空间是如何工作的。我想实现的是能够在REPL中调用 (source myfunc)(doc myfunc) 等函数,而无需在每个命名空间中都使用完全限定名,并且无需从clojure.repl 中要求这些函数。

1
我的工作流程中,我喜欢保留一个单独的源文件来保存我的user命名空间及其所有依赖项。例如,当我不使用Component时,我的dev/user.clj文件通常看起来像这样:(ns user (:require [clojure.pprint :refer [pprint]] [clojure.repl :refer [doc source]])) - Sam Estep
2
你提到了 C-c M-n。如果你在 Emacs 中使用 CIDER,那么 M-. 相当于 source。而 C-d d d 则是 doc。如果光标已经在 myfunc 上了,你就不需要再输入它了。 - Greg Hendershott
2个回答

4
感谢您澄清您的需求。
Leiningen有一个称为:injections的功能,您可以与vinyasa结合使用来实现此效果。如果您在Leiningen配置文件中添加以下内容:

~/lein/profiles.clj:

{:user {:plugins []
        :dependencies [[im.chit/vinyasa "0.1.8"]]
        :injections [(require 'vinyasa.inject)
                      (vinyasa.inject/inject
                       'clojure.core '>
                       '[[clojure.repl doc source]
                         [clojure.pprint pprint pp]])]}}

因为这个代码在你的profiles.clj文件中,所以只会影响你自己。其他在这个项目上工作的人不会受到影响。
因为注入到clojure.core可能有些可疑,所以我遵循vinyasa作者的建议并将其注入到一个名为“.”的命名空间中,该命名空间由我在每个项目中创建的配置文件创建。这个命名空间始终存在,这使得即使在尚未引用clojure.core的新创建命名空间中,这些函数也可以正常工作。

我的~/.lein/profiles.clj:

{:user
  {:plugins []
   :dependencies [[spyscope "0.1.4"]
                  [org.clojure/tools.namespace "0.2.4"]
                  [io.aviso/pretty "0.1.8"]
                  [im.chit/vinyasa "0.4.7"]]
   :injections
   [(require 'spyscope.core)
    (require '[vinyasa.inject :as inject])
    (require 'io.aviso.repl)
    (inject/in ;; the default injected namespace is `.`

               ;; note that `:refer, :all and :exclude can be used
               [vinyasa.inject :refer [inject [in inject-in]]]
               [clojure.pprint :refer [pprint]]
               [clojure.java.shell :refer [sh]]
               [clojure.repl :refer [doc source]]
               [vinyasa.maven pull]
               [vinyasa.reflection .> .? .* .% .%> .& .>ns .>var])]}}

这是这样工作的:
hello.core> (./doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil
hello.core> (in-ns 'new-namespace)
#namespace[new-namespace]
new-namespace> (./doc first)
nil
new-namespace> (clojure.core/refer-clojure)
nil
new-namespace> (./doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil

1
为了实现这个目标,你可以使用vinyasa库,特别是它的inject功能。基本上,你需要将clojure.repl命名空间中所需的函数添加到clojure.core命名空间中。之后,你就不需要显式地要求它们了。请参见以下内容:
user> (require '[vinyasa.inject :refer [inject]])
nil

;; injecting `source` and `doc` symbols to clojure.core
user> (inject '[clojure.core [clojure.repl source doc]]) 
[]

;; switching to some other namespace
user> (require 'my-project.core)
nil
user> (in-ns 'my-project.core)
#namespace[my-project.core]

;; now those functions are accessible w/o qualifier
my-project.core> (doc vector) 
-------------------------
clojure.core/vector
([] [a] [a b] [a b c] [a b c d] [a b c d e] [a b c d e f] [a b c d e f & args])
  Creates a new vector containing the args.
nil

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