(ns secretary.core)
(defn -main
[& args]
(println args "Hello, World!"))
lein run 1 2 3
(1 2 3) Hello, World!
But I want it keep in REPL. Not exit.
Try this:
(ns demo.core )
(defn -main
[& args]
(println "Got:" args ))
with the above code:
> lein repl
Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Compiling 2 source files to /home/alan/expr/demo/target/default/class-files
nREPL server started on port 46184 on host 127.0.0.1 - nrepl://127.0.0.1:46184
REPL-y 0.4.3, nREPL 0.6.0
Clojure 1.10.1
Java HotSpot(TM) 64-Bit Server VM 13+33
demo.core=> (ns demo.core)
nil
demo.core=> (-main 1 2 3)
Got: (1 2 3)
demo.core=> (+ 3 4)
7
demo.core=>
So, you start the REPL first, then call a function (even -main). You are still in the REPL when finished.
P.S. Although, my personal favorite, is to use the lein test-refresh
plugin and write your experiments in unit-test style using your favorite editor.
Related
How do I start an nREPL from the clj command?
I can't run my project using Lein or Boot because I have an unbalanced paren somewhere, and the reader complains `java.lang.RuntimeException: read-cond starting on line 13 requires an even number of forms.
Things are easier now than they were when the question was posted:
$ clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "0.5.3"}}}' -m nrepl.cmdline
More details here.
Wrote a gist on how to do this:
clj -Sdeps '{:deps {org.clojure/tools.nrepl {:mvn/version "0.2.12"}}}'
Clojure 1.9.0
user=> (use '[clojure.tools.nrepl.server :only (start-server stop-server)])
nil
user=> (defonce server (start-server :port 7888))
#'user/server
Now you can connect to port 7888 using your remote REPL client. There is probably a way to do this in one line.
Suppose that I have implemented a few functions for some personal calculation at work. I'd like to build a .jar (uberjar) that my colleagues would use too in a REPL, like:
megacorpcalcs.core=> (+ 2 2)
4
megacorpcalcs.core=> (salary 8 0.4)
666$
What code should I type for a REPL to start when the .jar launches?
EDIT: after your comments I've split this answer into 2
1. Running your uberjar with a REPL
Create your uberjar, and start it with:
java -cp /path/to/your/application-X.Y.Z-standalone.jar clojure.main -i #your_application/foo.clj -r
I had to add the -i parameter and point it to one of my clj files in order to get any of my classes in the project to actually load in the repl. There may be a better way to do this, but I haven't found it yet. Without it, you get a standard clojure repl but your application isn't loaded.
Note, you need the # symbol so that it loads from the jar file relative to the classpath (i.e from root of jar).
This should start a repl which you can change namespace and run your application functions in.
Additionally, you can install rlwrap and prepend the java command with it so you can use history and arrow keys sanely.
2. Embedding a REPL server in your application to connect to from another client
You can embed your own repl on startup of your application (e.g. a simple main that just starts a repl instance), and then your users can run your jar file, and separately connect to it with their choice of tool (cider-jack-in, 'lein repl connect ...')
The simple version of this is:
(start-server :port 7890 :handler cider-nrepl-handler)
Substitute the port you want, see below for the appropriate namespaces to import.
Here is a more complete example:
(ns your-app.server
(:gen-class)
(:require [cider.nrepl :refer (cider-nrepl-handler)]
[clojure.tools.nrepl.server :refer [start-server]]))
(def repl-server (atom nil))
(defn create-nrepl-server!
[repl-port]
(println (format "starting nrepl server on port %d" repl-port))
(reset! repl-server (start-server :port repl-port :handler cider-nrepl-handler)))
(defn -main []
;; ...
(let [repl-port 7890]
(create-nrepl-server! repl-port)
(spit ".nrepl-port" repl-port)))
You'll need the following in your project.clj file
:plugins [[cider/cider-nrepl "0.10.0"]] ;; or whatever version you prefer
:dependencies [[org.clojure/tools.nrepl "0.2.12"]]
Once connected to your custom repl, standard rules apply, just change namespace and call your functions.
Following http://www.webnoir.org/ instructions to create a new project - I ran lein uberwar - this generates a single (executable) jar - however it is not able to find the main class as mentioned in the manifest - no class file found.
The app runs run with "lein run".
Is the uberjar meant to be able to run this way (I expect it launches an embedded jetty?)
FYI Jar produced with lein uberjar fails on NoClassDefFoundError is similar - but out of date (this is with a newer version of leiningen where that specific bug is fixed).
The trick is to add gen-class to server.clj
(ns myproject.server ... (:gen-class))
For example:
I've just deployed using lein uberjar, and I have the following:
In my project.clj:
:main myproject.server
In my server.clj:
(ns myproject.server
(:require [noir.server :as server]
[myproject.views.common]
[myproject.views.index])
(:gen-class))
(server/load-views "src/myproject/views/")
(defn -main [& m]
(let [mode (keyword (or (first m) :dev))
port (Integer. (get (System/getenv) "PORT" "8080"))]
(server/start port {:mode mode
:ns 'myproject})))
require the views at the top
gen-class
load-views
Now it works fine to java -jar myproject-standalone.jar.
Today I noticed something odd. When I'm not "in" a project (that is, the shell is not in a clojure project's directory), I can use exit to exit the REPL:
shell$ lein repl
REPL started; server listening on localhost port 43712
user=> (+ 3 4)
7
user=> (exit)
shell$ echo '<span>not in <s>kansas</s>clojure anymore</span>'
When I'm "in" a project (that is, the shell is in a clojure project's directory), I can't use exit:
shell$ cd my_clojure_project
shell$ lein repl
REPL started; server listening on localhost port 69237
user=> (* 8 4)
32
user=> (exit)
java.lang.Exception: Unable to resolve symbol: exit in this context (NO_SOURCE_FILE:2)
user=>
What is the issue here?
Clojure version (for both examples):
user=> (clojure-version)
"1.2.1"
Leiningen version (for both examples):
shell$ lein -v
Leiningen 1.6.1 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM
It appears to be because the leiningen.core namespace isn't available when there is a project. More specifically, when there is a project, your project's code is evaluated in a separate ClassLoader with only your project on the classpath. Therefore none of Leiningen's functions are available.
The Leiningen 2 REPL doesn't have this problem.
I'm feeling slightly silly here, but I can't get Clojure Hello World to compile.
Directory structure:
hello-world/
clojure-1.1.0.jar
build/
classes/
src/
test/
hello.clj
hello.clj:
(ns test.hello
(:gen-class))
(defn -main [& args]
(println "Hello" (nth args 0)))
Interaction:
$ cd hello-world
[hello-world]$ java -cp ./clojure-1.1.0.jar:./build/classes:./src clojure.main
Clojure 1.1.0
user=> (require 'test.hello)
nil
user=> (test.hello/-main "there")
Hello there
nil
user=> (compile 'test.hello)
java.io.IOException: No such file or directory (hello.clj:2)
user=> *compile-path*
"classes"
user=> (doseq [p (.split (System/getProperty "java.class.path") ":")] (println p))
./clojure-1.1.0.jar
./build/classes
./src
nil
So I can load and call the file from the REPL, but it doesn't compile.
According to clojure.org, compilation needs
namespace must match classpath-relative file path - check
*compile-path* must be on the classpath - check
:gen-class argument to the ns form - check
I found this post from a year back, as far as I can tell I'm doing exactly the same, but it doesn't work.
What am I missing?
System: OS X 10.6, Java 1.6.0, Clojure 1.1
Got it, there's a fourth requirement:
*compile-path* is resolved relative to the JVMs working directory, normally the directory where java is started. Or by REPL: (System/getProperty "user.dir"),
So this works:
user=> (set! *compile-path* "build/classes")
"build/classes"
user=> (compile 'test.hello)
test.hello
Why you don't use Leiningen? It's much easier to use it, than compile code manually. You can use my article about it as introduction...
To run clojure file
clojure filename.clj