How to compile ClojureScript inside Clojure - clojure

I want to compile ClojureScript inside Clojure and am having some problems. I would like to do something like this:
(def x '(map (fn [n] (* n n n)) [1 2 3 4]))
(cljs->js x)
where cljs->js returns JavaScript code. I guess Himera does something similar (first reading ClojureScript from a string), but I don't know enough about ClojureScript to figure it out.
Is there are simple solution to this?

Have you look at the Himera code? Here is where the code sent by the UI is compiled, which basically calls the cljs.compiler from the clojurescript project. Note that Himera is probably a lot more complex than what you are asking for, probably you just need to get the "compilation" function working

once you have the clojurescript dependencies sorted out (which is it's own question) then you can just call the clojurescript emit function. this is used in the Clutch project (couchdb for clojure+clojurescript). it basically looks like this:
(js/emit (aget doc "_id") nil)

Related

How do I require clojure.java.io with lein exec?

I am totally new to clojure. I would like to start writing simple scripts, and I came across lein-exec as a means of doing so even if a script contains dependencies. Although I can run an example I found online, I don't know how to require clojure.java.io.
(require 'leiningen.exec)
;places the dependency on the classpath
(leiningen.exec/deps '[[enlive/enlive "1.1.4"]])
(require '[net.cgrand.enlive-html :as html])
How would I require something like clojure.java.io using lein exec?
EDIT: adding more detail
(require 'leiningen.exec)
(leiningen.exec/deps '[[clojure.java.io]])
(require 'clojure.java.io)
(defn Example []
(.exists (clojure.java.io "Example.txt")))
(Example)
gives me
Caused by: java.lang.IllegalArgumentException: Provided artifact is missing a version: [clojure.java.io]
and this
(require 'leiningen.exec)
;(leiningen.exec/deps '[[clojure.java.io]])
(require 'clojure.java.io)
(defn Example []
(.exists (clojure.java.io "Example.txt")))
(Example)
gives me
Caused by: java.lang.ClassNotFoundException: clojure.java.io
Well, personally, I'd recommend using inlein instead of lein-exec for doing scripting with Clojure:
http://inlein.org/
https://github.com/hypirion/inlein
I find it nicer, and it uses standard lein dependency map for defining your dependencies.
Secondly, this: (require 'clojure.java.io) IS the right way to require clojure.java.io. That namespace is included with Clojure itself, so you don't need to declare an additional dependency on any other library to use it.
Your problem is that you are not using it correctly:
(.exists (clojure.java.io "Example.txt"))
In the above code, you are calling clojure.java.io as if it was a function, but it is not a function, it is a namespace. You need to choose a function inside of it to call, such as the file function. If this was java, you could kinda think of the namespace as the class, and the function as a method on the class. If you do:
(.exists (clojure.java.io/file "Example.txt"))
It should work now. Notice how in Clojure, the syntax is: namespace/function. This is different the some other languages like Java or Python, where you would have: some.location.class.method instead, basically the function is also separated by a .. This is not the case in Clojure, in Clojure, the function part is separated by a /.

Reading thousands of files in clojure

I'm working on a script that needs to read tens of thousands of files from the disk. I'm trying to understand the best way to do this. I've run into a problem when I use map to do this using two packages clj-glob and clojure-mail:
(def sent-mail-paths
(->> (str maildir-path "/*/_sent_mail/*")
(glob) ;; returns files using clojure.java.io/as-file
(map str) ;; i just want the paths
))
(def msgs
(->> sent-mail-paths ;; 30K + paths
(map mail/file->message)))
where the glob function in the first block comes from clj-glob and uses as-file to return a set of file objects (see here). I only want the path strings, so I do (map str). The mail/file->message function in the second block uses with-open along with the java FileInputStream class to read the files (see here).
The trouble I am encountering is that this code causes an error the moment I try to process the files in the resulting lazy sequence by doing evensomething like:
(count msgs)
The error is:
(Too many open files in system)
The only way I've been able to get the job done here is to use doseq:
(def msgs (->> list-of-paths ;; 30K+ paths
(map mail/file->message)))
(def final (atom []))
(doseq [x result]
(swap! final conj (mail/file->message x)))
My question is whether this is the best (only?) way to accomplish this process without opening thousands and thousands of files at once? I don't fully understand why I can't use the lazy sequence that is returned by map. Why does that end up opening tons of files.
One thing, incidentally, that I noticed is that clj-glob, which is not a well-maintained package, does not use with-open when it calls as-file...
Even if you open/close the files correctly, there's a chance that during the execution of the program you hit an internally defined limit on the number of file descriptors that you program can have (this is common on long-lived programs such as microservices).
You can read here on how to look up what that limit is currently and how to increase it: https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

Cider debug -- how to evaluate stuff while debugging

Cider debug instructions tell me I can press e to evaluate something while debugging. This gives me a little one-line space in Emacs mini-buffer at the bottom.
Is there a way to switch to the full REPL while in the middle of
debugging a function, with access to all the locals, etc.? Currently
the REPL is hung/frozen while debugging. I'm thinking of something in
the style of how PyCharm or Matlab allow full REPL while in the middle of something.
It does appear that the jacked-in REPL is tied up during debugging.
But there are a few options available through the debugger that may
give you nearly as much as you'd get out of the REPL. A handy one is
to inject a new value for the result you're about to produce.
So you're actually changing the data on-the-fly.
You can inspect the full list of local vars with l. Then see more
about a var with inspect and specifying which.
You can also eval to enter an arbitrary expression just like
you would in the REPL (as you've mentioned). That seems to be a
single-line full REPL, with history, editing, etc. Is there something
you'd want to do in the REPL that you can't do with e or discover
with l or p?
One thing I find really frustrating is that I can't edit a function while the debugger is stoped at the said function, then edit it and re run it with the initial arguments. In cider, if you try to edit a function being debugged, emacs will open the bebugger in a new buffer with the original code. Alternatively, you have the e command that evals things in the minibuffer, which I don't think is a great experience. The closest I came to this is the following:
Imagine you have some function that crashes and you need to debug:
(defn some-fn
[complex-data more-data]
; block of code with some bug
)
I'll create atoms in the namespace and set the value inside the given function:
(def c (atom nil))
(def d (atom nil))
(defn some-fn
[complex-data more-data]
(reset! c complex-data)
(reset! d more-data)
; block of code with some bug
)
Then I'l just iterate on some-fn using the args I now have available in the namespace.
(some-fn #c #d)
I think it's a much better approach than using the eval command and the minibuffer from the cider debugger.

Import Record Type in Clojure/ClojureScript

Is there any way to import a record type, that works in Clojure as well as ClojureScript?
As far as I can tell it's (ns x (:import y [A B])) for Clojure, (ns x (:require y :refer [A B])) for ClojureScript, and each is invalid for the respective other.
Ignoring the specifics on the syntax of requiring records, there are two main ways to write ns declarations (or any platform specific code) for multiple Clojure variants while sharing the majority of your code.
CLJX is a Clojure preprocessor that runs before the Clojure compiler. You write platform specific code prefixed with #+clj or #+cljs in a .cljx file. It can run on pretty much any Clojure code, and will spit out multiple platform specific files which the respective Clojure Compilers can handle.
Reader Conditionals are a feature in Clojure 1.7 and are available in recent releases of ClojureScript. This is similar in spirit to cljx, but is integrated into the Clojure Compiler. You write code with reader conditionals like #?(:clj 1 :cljs 2) in files with a .cljc extension.
Now back to your specific question, you can achieve this with Reader Conditionals like so:
(ns myapp.music-store
(:require #?(:clj [myapp.cool-music]
:cljs [myapp.cool-music :refer [Vinyl]]))
#?(:clj
(:import [myapp.cool_music Vinyl])))
I wrote a longer blog post about this too: Requiring records in Clojure and ClojureScript

Can I conditionally compile clojure / clojurescript?

Is there a way to in clojure / clojurescript to conditionally compile something depending on whether you're compiling to JVM bytecode of Javascript?
I am writing a small game in ClojureScript but want to keep the majority of the code platform neutral so I can convert to Clojure at some point. I also find that compiling in Clojure is better for finding errors in my code.
I have this working fine by having a directory of clj files that cljsbuild converts to cljs using crossovers.
Where I've come unstuck is trying to use core.async in my clj files. This is needed for cljs:
(ns gaz.system
(:require-macros [cljs.core.async.macros :refer [go]])
(:require
[cljs.core.async]))
While this is needed for clj to work
(ns gaz.system
(:require
[core.async ]))
I'd love to have one file with some form conditional require depending on how it's being compiled. Is that possible at all?
Con
Have a look at cljx. It let's you prefix s-expressions with e.g. #+clj or #+cljs to create different code for Clojure and Clojurescript.
Also, though I have not tried it so far, there is lein-dalap which seems to rely on pure, compilable Clojure to generate Clojurescript.