This question already has answers here:
how to load ns by default when starting repl
(2 answers)
Closed 7 years ago.
I'm new to Clojure so this could very well be an easy question. I'm having an issue with the REPL while using Leiningen.
Previously, I had created an app project while following a tutorial. When I would launch the REPL using lein repl with that project, it would always put me in the project's core namespace automatically. Even though I was in that namespace, I could still access built-in resources e.g. (doc build-in-function-name), etc.
Now, I've created another non-app project and I seem to have lost this autoloading capability. I'm now being put into a user namespace by default. Also, when I try to get access to my project's core namespace by doing (in-ns 'project.core), I lose access to build-in functions like doc.
Can anyone explain what's going on here?
in-ns does not load code. It switches to an ns, creating it if needed. It also does not do the default ns setup (eg. referring clojure.core). The proper way to load a namespace from code in the repl is with require (require 'some.ns), which can then be followed by (in-ns 'some.ns) if it succeeds.
You can use the :repl-options {:init-ns some.ns} option in project.clj to specify the namespace that leiningen should auto-load into your repl. When it's up to me I do not use this option, because it prevents me from having a usable repl if there is any bug that prevents my code from loading.
Related
I'm using Austin to set up a browser-connected REPL, and following the example of its sample project, which uses Enlive to add the REPL script to the page.
Now I'd like to deploy my app, but I don't wan't Austin or my REPL to be on the page in production. What's the intended way to use the REPL only in development?
Is there a way to use Enlive as a middleware I could use in development and not in production?
There's almost always something that uniquely distinguishes a production environment from :dev that you can use as a conditional: if in :dev, inject the result of (browser-connected-repl-js); if not, don't.
If your deployment environment doesn't have such a property, I'd suggest adding one, as this sort of "only in environment X" use case is pretty common for a lot of things.
On the other hand, if you're looking to avoid having Austin and its dependencies included in your production-targeted builds entirely without changing any of your code that uses browser-connected-repl-js, one solution might be to simply dummy up the relevant Austin namespace, e.g.:
(ns cemerick.austin.repls)
(defn browser-connected-repl-js [& _] "")
Put that in cemerick/austin/repls.clj in a directory that is included in your project.clj's non-:dev profile:source-paths. Now your code will deploy to production without Austin and its dependencies, and your code will transparently call the above dummy function (injecting nothing into your page(s)).
Hi I have some helper fns I want to load into the user ns for a lein repl on startup across all my projects.
What's the recommended way to do this as lein plugin?
Failing that I tried to make a ~/lein/user.clj and to my surprise that did't work? $Project/user.clj works fine but I don't want to copy to each project.
Take a look at vinyasa, which allows you to do exactly that.
In my clojurescript code I have the following:
(defn onload [] (repl/connect "http://localhost:9000/repl"))
(set! (.-onload js/window) onload)
The Clojurescript repl is very useful in development, but I am hesitant to leave it in the code during production. What is the cleanest way to have the above code present during development (simple compilation), but absent during production (advanced compilation)?
The modern-cljs tutorial actually describes exactly how to solve this here.
Hope that helps!
Unfortunately there aren't currently any well defined ways to do conditional compilation in ClojureScript.
You could add configuration variables to control whether to start a REPL in a variety of ways, but one quick and easy way would be to get the hostname of the current page, and only invoke repl/connnect if it was "localhost" or whatever other domains you're using for development work.
I think a combination of lein2 profiles and cljsbuild src-paths munging can do the trick. eg, create a namespace that simply loads your repl, and exclude it with a profile run for the final compile (possibly might need to create a dummy namespace in another src-path directory).
Sorry for the long post, but this forum always asks for use cases :-).
I am frequently called upon to write utility applications (GUI and command line) for my organization. I most commonly write these in Java and more recently Scala.
The "philosophy" in Clojure (and other Lisps) seems to center around the REPL, and I have to agree that it makes a nice development environment, but I obviously cannot produce utilities that require that the users "Install Clojure and Clojure-contrib, then unzip the utility into a directory on your hard drive, start Clojure from the command line using the following classpath, ...". The users do not care that the utility is written in Clojure. They just want to point and click or, at most, type "java -jar Utility.jar -?" on the command line.
My question centers around compilation and separating the application into many namespaces/files.
I know that the main method must be in a Clojure file that includes the (gen-class...) command (or the :gen-class clause on the ns command). Do I do the same for the additional Clojure files, or should they be left as a source code that is packed in the JAR and loaded by the main file? How about testing the additional files from the REPL during development?
I have been using leiningen, cake, and maven to build self-contained JARs (containing unpacked clojure.jar, clojure-contrib.jar, and commons-cli.jar files), but so far I have been writing my code in the same file as the main method.
It's up to you whether you AOT-compile your .clj into .class or let Clojure do it dynamically at runtime. In general, I find it's easier during development to avoid AOT and just use AOT as a performance booster for cases where the cost of compiling your .clj on the fly doesn't make sense (limited environments like Google App Engine or utilities where startup time is critical). For server processes that will run for a long time, there is not much advantage in AOT-compiling.
There are a number of complexities around using AOT classes at dev times that are specific to different dev environments.
One down-side of AOT is that your compiled classes might be incompatible with a future version of Clojure and that is more likely than your clj files being incompatible. That may become more important over time.
When it comes to the separation, I'd keep them in separate namespaces/files:
One for the :gen-class namespace, containing -main and all the other Java-like things.
The other namespace for all the functions.
Ideally, your main should contain just the call to a function from the other namespace, or perhaps some logics for evaluating or repacking of the args.
Your question seems quite similar to the separation between logics code and ui code. You could see the namespace with :gen-class as just an interface provided by your program to Java code, nothing more.
When it comes to the utilities (like command-line, or Swing apps, etc.), there's a trouble with Java in general because of the JVM start time.
Now, you could solve this by making a server app run the REPL in the background all the time, and say, somehow receive an s-expr to be evaluated, and return the result. This could be done as a simple web application which receives an s-expr as URL parameter, and returns the result. Now, with this you could make all utilities in plain old Java, or even bash using wget, since all you'd have to do is access an URL (assuming that server with repl is running in background).
There's a good chance that something like this already exists, so if anyone knows - comments are more than welcome.
Oh, and another thing, the port where repl webapp is exposed would probably have to be closed to the outside world, to prevent Clojure-injections :D
I occasionally get this problem, and generally work around it, but it's rather frustrating.
I have all of Incanter (check it out if you don't know it: it's superb) on my classpath. I try to import it (through a Slime REPL) like this: user> (use 'incanter.core), but fail.
Doing this: user> (use 'clojure.contrib.def) works just fine, and this file is in the same place–on my classpath.
Regardless, the error isn't anything about classpath: it's this:
Don't know how to create ISeq from: clojure.lang.Symbol
[Thrown class java.lang.IllegalArgumentException]
You can see my entire terminal here (a screenshot.)
I don't know what's going on here, and it's really frustrating, as I really would like to use Incancter, and I can from the Incanter binary's REPL. I definitely don't want to develop from that–and this should work.
Any help would be much appreciated.
EDIT:
It appears as though Incanter requires Clojure 1.2, and lein swank gives me Clojure 1.1. This might be the cause of my problems: if so, is there a way to continue to use Swank & Lein with Clojure 1.2?
Thanks again!
EDIT:
Apparently if you start using Clojure-1.1 and lein swank, you're stuck with it unless you make a new project.
If future people have this problem, this article helped me out, but also, at least for me, you must start a new lein project if you had begun it using leink swank and Clojure-1.1. Simply changing your project.clj file and then lein swanking again doesn't work.
Yes, you can use Leiningen and swank-clojure with Clojure 1.2. You might need to use a recent version of Leiningen (I'm not sure if a certain old limitation affected lein repl only or was it lein swank as well; anyway, try the 1.2-RC2 which you'll find in the downloads section on GitHub). You will also need to use a recent-enough swank-clojure; I use a bleeding edge checkout myself, get yours here.
Other than that, simply use 1.2 jars for Clojure and contrib. (Lein uses it's own Clojure, separate from the one used for lein swank, for its internal workings and you never need to care about it; swank-clojure has no AOT'd namespaces and doesn't particularly care about the Clojure version, except once in a (long!) while something breaks, a patch is applied and joy is restored.)
I hope the above helps, but if it doesn't: your problem description is not entirely sufficient for me to get a clear picture of what is happening. Could you add information on what it means for "all of Incanter" to be on your classpath (do you mean the jars? sources? where do you get them? how do you set your classpath?). Without knowing this, it'll be hard to replicate your setup to try to track down the source of the problem.
Of course if bumping some versions fixes things, please disregard my current confusion. ;-)