Use an alternate eval with nrepl - clojure

I can pass clojure.main/repl a function that will be used to eval input (thanks to the :eval keyword). But how can I do this with nrepl? I read a bit about handlers but it quickly becomes hard and abstract to follow.
Also, since I mainly launch it with lein repl, is there a way to specify my eval in the project.clj file? :repl-options doesn't seem to accept the :eval keyword.

Take a look at the interruptible-eval middleware: https://github.com/clojure/tools.nrepl/blob/master/src/main/clojure/clojure/tools/nrepl/middleware/interruptible_eval.clj
You could make something similar and start the nrepl manually using the start-server function. Or there is a lein option for nrepl middlewares.

Related

lein uberjar taking forever

I want to create an uberjar of a leiningen app. My config is:
:uberjar {:omit-source true
:aot :all
:uberjar-name "myapp.jar"
:source-paths ["env/prod/clj" ]
:resource-paths ["env/prod/resources"]}
But upon doing lein uberjar, I find the the files in the project are being compiled, but the compilation is stuck on the file that contains most of the code, for ten minutes and counting. This file doesn't contain more than 140 lines.
TL;DR: never def side-effects
As stated in the comments:
... I just figured that this line: (defonce server (http/start-server server-handler {:port 8982})) is causing the hang.
Don't put stuff like that at top-level.
defonce only means it will not be re-def-ed once it's there (so in this case
it would prevent some "port already in use" error on reloading.
Ways out of that dilemma
Write a function, that starts this server. Then call that from your main. For
development you can run that function from the REPL or you can sprinkle some
reload/restart logic in your user-ns.
Another option could be using delay: it will only execute the code once it gets derefed.
The more "binding of resources" you have to deal with, the more some systematic
approach will give your application a better structure. E.g. take a look at:
weavejester/integrant
stuartsierra/component
tolitius/mount
So why is putting blocking things or side-effects in a def problematic?
The way the Clojure compiler works, is by actually "running" the code. So compile basically is:
enable generation byte code and write it out as .class files
load the namespace and "run" it
This means, that at compile time, the top level side-effects are executed.
Therefor blocking operations in a def, will block compilation (which is quite
obvious), or your CI server will fail to compile, because it can not connect to
the database etc.
A great explanation of how the code generation in Clojure works:
What Are All These Class Files Even About? And Other Stories - Gary Fredericks

Reloadable Clojure REPL

How to create a REPL for Clojure for which the code is reloadable?
I can create a new project, and get a REPL up and running:
lein new app stack
cd stack
lein repl
(-main)
Doing the above should get you "Hello, World!".
I would like to stay in the REPL, change the code to println "Howdy partner!", and then just (-main) again. Either auto-reloading or (perhaps even better) simple manual reloading (for instance with a command like (r)) would make the environment complete.
It seems with lein I'm already getting into the right namespace (any namespace but the user namespace from which you then have to (in-ns 'some-ns) is the right namespace!). The only unanswered part is code reloading - either manual or auto.
As it happens I previously asked how to do this with boot.
For manual reloading you can use the same trick as posted in the boot answer, which is to have a function that does the reloading for you:
(defn r [] (require 'stack.core :reload))
Once the above function is part of the stack.core namespace, you can call it from the REPL. Pretty simple - the namespace stack.core has a function in it which reloads itself.
Make code changes from the editor, reload with (r), then run again...
There's also the lein-autoreload plugin for automatic reloading.

Leiningen, repl, uberjar: Unable to resolve symbol, No such var

While my lein new app project runs merrily inside the Light Table, lein uberjar won't work. Curiously, it behaves exactly like a classic Pascal compiler: it can't resolve references ahead of definitions. Another curiosity: yesterday it worked. I am not aware of fooling with anything sensitive.
Google says that the subj symptoms are quite commonplace; I tried whatever helped other people in the same (?) plight, but to no avail. By the way, usually they blame it on software bugs: "get the latest version of Leiningen and Clojure". I've got 2.5.0 and 1.6.
The project (main file) is here: https://github.com/Tyrn/pcc/blob/master/src/pcc/core.clj
As it is, parsed-args can't be resolved inside build-album; if I move the -main function to the top of the file, 'No such var' happens to cli-options inside -main. No amount of fiddling with explicit use of namespaces makes any difference.
Again, inside the Light Table everything runs fine.
Using def inside of a function is not idiomatic, especially if there is no reason to have it as a global variable. Just pass it as a function parameter:
(let [parsed-args (parse-opts ...)]
...
(build-album parsed-args))
If you really need global state, you can use e.g. a promise (alternatively, an atom):
(defonce parsed-args (promise))
...
(deliver parsed-args (parse-opts ...))
However, Clojure files are read from top to bottom, and yes, functions not having access to bindings introduced later in the file is by design. You can use declare to tell the parser what to expect:
(declare ^:dynamic *parsed-args*)
(defn build-album ...)
(def ^:dynamic *parsed-args* ...)
...
(binding [*parsed-args* (parse-opts ...)]
(build-album))
TL;DR: If not necessary, avoid global state; if necessary, minimize it.

Is there a way to inject a method into clojure.core at lein repl startup?

the :injections keyword is really useful. However, I am hoping to dynamically install a couple of functions in core for debugging purposes. How can this be done?
:injections [(require 'spyscope.core)
(use '[cemerick.pomegranate :only (add-dependencies)])
(use '[clojure.tools.namespace.repl :only (refresh)])]
Ideally, I would want refresh to stay around to that I can use it everywhere
You could use intern for this purpose, although I suspect there might be a better way to have debugging functions available all the time. I've used intern with clojure.core the times that I wanted to mess around with existing functions to learn stuff, but injecting functions in other namespaces feels too hackish.
(intern 'clojure.core 'refresh (fn [] (println "refreshed!"))
(ns another-ns)
(refresh)
;=> refreshed!
And in your project.clj you can use the :repl-options key, specifically :init. This, though, depends on the workflow you have in mind, since the function will not be available in all the namespaces that already exist when the REPL fires up, because they all have already refered the public vars in clojure.core.
You could however, call (clojure.tools.namespace.repl/refresh) once, when the REPL starts, to get all namespaces reloaded and then the function should be available from then on. I just tried the following and it seems to work:
:repl-options {:init (do (require 'clojure.tools.namespace.repl)
(intern 'clojure.core 'refresh clojure.tools.namespace.repl/refresh)
(clojure.tools.namespace.repl/refresh))}

Enclojure REPL can't find dependent clj file on Load

I have a problem with the Enclojure REPL and using clojure modules from it. The Load/Change REPL to file/ns works fine with an isolated clojure file, but breaks with a file which has references to another clojure file which I try to use from my project.
Here are the exact steps:
Create a new project.
Create a clojure module foobar.clj (namespace com.acme.foobar)
Define a function which returns a value in foobar.clj:
(ns com.acme.foobar
(:use com.acme.othermodule))
(defn myfunc1 []
"a")
Open a Netbeans IDE REPL
From foobar.clj's context menu select:
Change REPL to file/ns
Load
From REPL call the (myfunc1) function. This works just fine:
com.acme.foobar=> (myfunc1)
"a"
The problems start when when I try to refer to other files from foobar. Here's what I do:
Create a new clojure module othermodule.clj
(ns com.acme.othermodule)
(defn fromothermodule []
"b")
Now try to call this from foobar.clj:
(defn myfunc2 []
(fromothermodule))
From othermodule.clj's context menu I select:
Change REPL to file/ns
Load
To make the REPL realize that there is new module it should be able to run.
I do same things things to foobar.clj which now refers to othermodule.clj, but I get:
CompilerException java.io.FileNotFoundException: Could not locate com/acme/othermodule__init.class or com/acme/othermodule.clj on classpath: (NO_SOURCE_FILE:50)
com.acme.foobar=>
This error message comes from both "Change REPL to file/ns" and "Load"
What am I missing? Should I do some other tricks to make this happen? Even the desperate measure of Run->Clean and Build the main project doesn't help (that would of course make the REPL business pretty painful anyway).
I am using NetBeans 6.7.1 and enclojure-plugin-2009-11-3.nbm.
Got the right solution from Eric Thorsen in the google group:
There are three ways to create the REPL from window-menu. Don't use any of those, instead right
click on the Project and "Start Project REPL". Now the paths are set up accordingly.
My first recommendation is to move from NetBeans/Enclojure to IDEA/La Clojure. JetBrains recently created an open source version of their IDE, and the Clojure plugin works fine in it. Since discovering this, I ditched NetBeans and Enclojure. I find La Clojure a pleasure to work in, but of course your mileage may vary.
Back from when I did this in NetBeans, I seem to remember Enclojure source code resides in a subdirectory called "lib". I think I solved a similar problem by fiddling with directory prefixes on the name of the file to load. Probably something like "../lib/YourName". I managed this by trial and error, so I can't relate the exact rules and syntax.
Two things that might help:
You can run something like (println (System/getProperty "java.user.dir")) to find out where Clojure thinks it's executing from.
You could start, as I did, with using an absolute path until you find your way to the correct directory name. Something like "/home/carl/NetbeansProjects/MyProject/lib/myfile.clj" .