问题
What I've Already Tried
(defmacro magic []
(slurp *file*))
This works fine in clojure, but not in clojurescript (atleast not with lein figwheel).
Original Question
I need the following to work in both Clojure and Clojurescript. I think a macro is the right solution, but I'm open to other techniques.
I want a way to read the current file as a string. For example,
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
this should then result in (being printed out)
(ns my-test
(:require blah))
(def foo 20)
(println (blah/magic))
If I only needed this to work in Clojure, I could do funny things with the current file and reading it at run time. However, I need this also to work in Clojurescript (and I don't want to setup some REST API to serve *.cljs files) -- thus, is there some way to do this at compile time via some macro?
Clarification
Suppose you wanted to write a "cheating quine" -- how would you do it? Probably something like (println (slurp *file*))
. Now, what's the problem? This doesn't work in clojurescript when running under lein figwheel.
回答1:
You need Reader Conditionals like this:
(defn build-list []
(list #?@(:clj [5 6 7 8]
:cljs [1 2 3 4])))
Please see the docs here:
http://clojure.org/guides/reader_conditionals
https://github.com/clojure/clojurescript/wiki/Using-cljc
UPDATE 1
If you want to modify the currently executing source code, you can always construct a string and use eval
:
(eval (read-string "(defn darth [] (println \"I have the ultimate power now...\" ))" ))
(darth)
;=> I have the ultimate power now...
However, since ClojureScript is compiled, I don't think there is any simple way of finding the source original source code, if that's what you're after.
UPDATE 2
It's an interesting problem. The closest I've come so are is something like this:
(ns clj.core)
(defmacro fred [& forms]
(doseq [f forms]
(println `~f)))
(fred
(+ 1 2)
(* 2 3)
)
(defn -main [& args])
with results:
> lein run
(+ 1 2)
(* 2 3)
回答2:
Very late to the party here but I had a similar problem and after a day of searching I found the ClojureScript counterpart to *file*
to be cljs.analyzer/*cljs-file*
.
You also need to be careful to create a macro-only namespace (with nothing but defmacro
s) for your macro and make that a .clj file. Furthermore, in my experience, that namespace had to be required with the (:require-macros [your-macro-ns])
rather than the normal (:require ...)
.
So the answer to your question would be
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 20)
(println (my-macro/compile-time-slurp-self))
It should be noted that, since slurp needs Clojure, this only works with the Clojure-based ClojureScript compiler, not the new bootstrapped compiler that, itself, runs on ClojureScript. From what I understand the latter is mostly used for browser-based REPLs and dev environments where Java is not available so as long as you're not building your code in the browser you should be fine.
来源:https://stackoverflow.com/questions/40229721/clojure-clojurescript-macro-to-read-code-of-current-file