Clojure + Clojurescript:读取当前文件代码的宏
Clojure + Clojurescript: Macro to read code of current file
我已经尝试过的
(defmacro magic []
(slurp *file*))
这在 clojure 中工作正常,但在 clojurescript 中不行(至少不能用 lein figwheel)。
原问题
我需要以下内容才能在 Clojure 和 Clojurescript 中工作。我认为宏是正确的解决方案,但我对其他技术持开放态度。
我想要一种将 当前 文件作为字符串读取的方法。例如,
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
这应该会导致(被打印出来)
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
如果我只需要它在 Clojure 中工作,我可以对当前文件做一些有趣的事情并在 运行 时间读取它。但是,我也需要它在 Clojurescript 中工作(而且我不想设置一些 REST API 来服务 *.cljs 文件)——因此,有没有办法在编译时通过一些宏来做到这一点?
澄清
假设你想写一个 "cheating quine" -- 你会怎么做?可能类似于 (println (slurp *file*))
。现在,问题是什么?当运行在 lein figwheel 下时,这在 clojurescript 中不起作用。
你需要 Reader 这样的条件:
(defn build-list []
(list #?@(:clj [5 6 7 8]
:cljs [1 2 3 4])))
请在此处查看文档:
http://clojure.org/guides/reader_conditionals
https://github.com/clojure/clojurescript/wiki/Using-cljc
更新 1
如果要修改当前执行的源代码,可以随时构造一个字符串,使用eval
:
(eval (read-string "(defn darth [] (println \"I have the ultimate power now...\" ))" ))
(darth)
;=> I have the ultimate power now...
但是,由于 ClojureScript 是经过编译的,我认为没有任何简单的方法可以找到原始源代码,如果那是您想要的。
更新 2
这是一个有趣的问题。我最接近的是这样的:
(ns clj.core)
(defmacro fred [& forms]
(doseq [f forms]
(println `~f)))
(fred
(+ 1 2)
(* 2 3)
)
(defn -main [& args])
结果:
> lein run
(+ 1 2)
(* 2 3)
这里的聚会已经很晚了,但我遇到了类似的问题,经过一天的搜索,我发现 *file*
的 ClojureScript 对应项是 cljs.analyzer/*cljs-file*
。
您还需要小心地为您的宏创建一个仅限宏的命名空间(除了 defmacro
s 之外什么都没有)并将其制作为 .clj 文件。此外,根据我的经验,(:require-macros [your-macro-ns])
必须需要该名称空间,而不是正常的 (:require ...)
.
所以你的问题的答案是
my_macro.clj
(ns my-macro)
(defmacro compile-time-slurp-self []
(slurp cljs.analyzer/*cljs-file*))
main.cljs
(ns main
(:require-macros [my-macro]))
(def foo 420)
(println (my-macro/compile-time-slurp-self))
应该注意的是,由于 slurp 需要 Clojure,因此它仅适用于基于 Clojure 的 ClojureScript 编译器,而不适用于本身在 ClojureScript 上运行的新的自举编译器。据我了解,后者主要用于基于浏览器的 REPL 和 Java 不可用的开发环境,因此只要您不在浏览器中构建代码就可以了。
我已经尝试过的
(defmacro magic []
(slurp *file*))
这在 clojure 中工作正常,但在 clojurescript 中不行(至少不能用 lein figwheel)。
原问题
我需要以下内容才能在 Clojure 和 Clojurescript 中工作。我认为宏是正确的解决方案,但我对其他技术持开放态度。
我想要一种将 当前 文件作为字符串读取的方法。例如,
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
这应该会导致(被打印出来)
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
如果我只需要它在 Clojure 中工作,我可以对当前文件做一些有趣的事情并在 运行 时间读取它。但是,我也需要它在 Clojurescript 中工作(而且我不想设置一些 REST API 来服务 *.cljs 文件)——因此,有没有办法在编译时通过一些宏来做到这一点?
澄清
假设你想写一个 "cheating quine" -- 你会怎么做?可能类似于 (println (slurp *file*))
。现在,问题是什么?当运行在 lein figwheel 下时,这在 clojurescript 中不起作用。
你需要 Reader 这样的条件:
(defn build-list []
(list #?@(:clj [5 6 7 8]
:cljs [1 2 3 4])))
请在此处查看文档:
http://clojure.org/guides/reader_conditionals
https://github.com/clojure/clojurescript/wiki/Using-cljc
更新 1
如果要修改当前执行的源代码,可以随时构造一个字符串,使用eval
:
(eval (read-string "(defn darth [] (println \"I have the ultimate power now...\" ))" ))
(darth)
;=> I have the ultimate power now...
但是,由于 ClojureScript 是经过编译的,我认为没有任何简单的方法可以找到原始源代码,如果那是您想要的。
更新 2
这是一个有趣的问题。我最接近的是这样的:
(ns clj.core)
(defmacro fred [& forms]
(doseq [f forms]
(println `~f)))
(fred
(+ 1 2)
(* 2 3)
)
(defn -main [& args])
结果:
> lein run
(+ 1 2)
(* 2 3)
这里的聚会已经很晚了,但我遇到了类似的问题,经过一天的搜索,我发现 *file*
的 ClojureScript 对应项是 cljs.analyzer/*cljs-file*
。
您还需要小心地为您的宏创建一个仅限宏的命名空间(除了 defmacro
s 之外什么都没有)并将其制作为 .clj 文件。此外,根据我的经验,(:require-macros [your-macro-ns])
必须需要该名称空间,而不是正常的 (:require ...)
.
所以你的问题的答案是
my_macro.clj
(ns my-macro)
(defmacro compile-time-slurp-self []
(slurp cljs.analyzer/*cljs-file*))
main.cljs
(ns main
(:require-macros [my-macro]))
(def foo 420)
(println (my-macro/compile-time-slurp-self))
应该注意的是,由于 slurp 需要 Clojure,因此它仅适用于基于 Clojure 的 ClojureScript 编译器,而不适用于本身在 ClojureScript 上运行的新的自举编译器。据我了解,后者主要用于基于浏览器的 REPL 和 Java 不可用的开发环境,因此只要您不在浏览器中构建代码就可以了。