2014-01-12 128 views
2

从REPL(Cloure 1.4.0)我试图使用source宏来显示我的功能把定义 - 但它与“未找到源”为什么'源'不工作?

回复我可以source使用source本身喜欢这个(并可以看到它使用source-fn) - 但不知道为什么它不喜欢我的defn x[] "hello"函数定义?

user=> (source source) 
(defmacro source 
    "Prints the source code for the given symbol, if it can find it. 
    This requires that the symbol resolve to a Var defined in a 
    namespace for which the .clj is in the classpath. 

    Example: (source filter)" 
    [n] 
    `(println (or (source-fn '~n) (str "Source not found")))) 
    nil 


    user=> (defn x[] "hello") 
    #'user/x 
    user=> (source x) 
    Source not found 
    nil 
    user=> 

回答

6

source只能得到类路径中可用的源文件中定义的函数源。它不适用于在REPL中定义的函数。

更确切地说,source作品通过查找其参数命名的VAR,检查对无功的元数据映射是否包括源信息(一切都是工作需要:file:line键),查找命名的文件元数据映射,打开文件(作为类路径上的资源),跳过很多行,最后将文本返回到下一个表单后面;详情请参见(source clojure.repl/source-fn)

因此,它可以用于存储在Vars中的东西 - 比如函数和宏 - 在源文件的顶层定义,它仍然存在于类路径中。它不适用于没有存储在Vars中的事物,也不适用于存储在其类别路径中不存在其后备源的Vars中的事物。后一种情况在AOT编译和REPL定义的情况下是可能的。

+0

那么有没有找到in-REPL定义函数(等)的'源'的方法?例如,如果我只是在REPL上编写代码,但想保存我的工作(就目前的情况而言) - 那可能吗? – monojohnny

4

source使用函数元数据来查找定义该函数的文件。然后它读取该文件以查找函数定义,将其转换为字符串并将其返回。

总之,(来源源)正在做这样的事情

user> (-> (resolve 'source) 
      meta 
      :file) 
"clojure/repl.clj" 

在REPL中定义的函数的元数据将不包含一个有效的源文件。

user=> (meta (resolve 'x)) 
{:arglists ([]), :ns #<Namespace user>, :name x, :column 1, :line 1, :file "NO_SOURCE_PATH"} 

您可以在source-fn函数中看到完整的工作方式。

+0

谢谢 - 我被撕裂选择哪个答案被接受,因为他们都非常丰富!否则,我会投票支持!干杯。 – monojohnny