defproject Compiler Exception - clojure

I am working through the book Programming Clojure (Second Edition) by Stuart Halloway and Aaron Bedra. As instructed in the book, I edit and add code in the file project.clj (which was created by lein new pinger) so that it reads:
(defproject pinger "0.0.1-SNAPSHOT"
:description "A website availability tester"
:dependencies [[org.clojure/clojure "1.3.0"]])
(ns pinger.core
(:import (java.net URL HttpURLConnection)))
(defn response-code [address]
(let [conn ^HttpURLConnection (.openConnection (URL. address))
code (.getResponseCode conn)]
(when (< code 400)
(-> conn .getInputStream .close))
code))
I then try to load the file and get the following error:
user=> (load-file "src/pinger/project.clj")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: defproject
in this context, compiling:(C:\Documents and Settings\vreinpa\My Documents\Books\ProgrammingClojure\code\src\pinger\project.clj:1)
What am I doing wrong here?

You're not supposed to add any code to the project.clj outside of the defproject definition.
The real project code is supposed to go into the classpath (for instance, in the files generated by "lein new ..." in src)

Related

How do I compile and use a class defined with gen-class in the repl and/or tests?

Clojure noob. I'm unable to get a basic example with :gen-class working.
$ lein new app pizza-parlor
; project.clj
(defproject pizza-parlor "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [[org.clojure/clojure "1.10.1"]]
:main ^:skip-aot pizza-parlor.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
; src/pizza_parlor/Deliverator.clj
(ns pizza-parlor.Deliverator
(:gen-class))
(defn -deliver [pizza]
(println "pipin' hot"))
$ lein repl
pizza-parlor.core=> (require 'pizza-parlor.Deliverator)
nil
pizza-parlor.core=> (def d (pizza-parlor.Deliverator.))
Syntax error (ClassNotFoundException) compiling new at (/tmp/form-init10318668819087633543.clj:1:1).
pizza-man.Deliverator
pizza-man.core=> (import pizza-parlor.Deliverator)
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:435).
pizza-parlor.Deliverator
I've tried the :aot option in project.clj and run lein compile to generate classes in target/default, but I get the same error.
What is the correct way to define a Java class via gen-class and then use it in the repl alongside the rest of my project code, or a test that I can run with lein test?
You have to pay attention to your names/folders with a dash - in it.
A clojure namespace of "some-clojure-namespace" will correspond to "some_clojure_namespace" in java world (and in folder structure)
So in your particular case :
; src/pizza-parlor/Deliverator.clj
(ns pizza-parlor.Deliverator
should be in "pizza_parlor" folder so :
; src/pizza_parlor/Deliverator.clj
(ns pizza-parlor.Deliverator
And then
(ns pizza-parlor.Deliverator)
would correspond to a (java) import :
(import pizza_parlor.Deliverator)
(note the underscore here)
But as stated by #Alan Thompson you do not need to create classes and import them in clojure. You can require the namespace and call it like he described. You want to generate Java Class and import them mostly if you have to interop with a java lib or so.
You can also use gen-class directly to generate any Java class that you would need like, see many example here
You are misunderstanding how to execute a function in the REPL.
You do not need to "create a class" in Clojure. Just start up a repl and invoke a function. There are several choices:
(ns demo.core
; (:gen-class) ; uncomment to make runnable JAR file
)
(defn -main []
(println "main - enter")
)
As the comment says, you only need the (:gen-class) expression in the ns form if you want to create an executable JAR file.
Method 1: Switch to the desired namespace and run the function:
~/expr/demo > lein repl
demo.core=> (in-ns 'demo.core) ; single-quote is required
demo.core=> (-main)
main - enter
Method 2: Just invoke the function with a fully-qualified symbol:
~/expr/demo > lein repl
demo.core=> (demo.core/-main) ; no quote!
main - enter
This will only work with the "main" ns, identified by the expression
:main demo.core
in project.clj.
Method 3: Require the namespace, then invoke the function with a fully-qualified symbol:
> lein repl
demo.core=> (require 'demo.core) ; single-quote is required
demo.core=> (demo.core/-main)
main - enter
This will work for any namespace, even demo.core if the REPL places you in the user namespace.
Method #4: Build an executable uberjar
You must ensure that (:gen-class) is present in the (ns ...) form AND that you have :main demo.core in your project.clj. Then
~/expr/demo > lein uberjar
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT.jar
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar
~/expr/demo > java -jar /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar
main - enter
If you see an error message like this:
~/expr/demo > java -jar /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar
Error: Could not find or load main class demo.core
Caused by: java.lang.ClassNotFoundException: demo.core
then you forgot to include the (:gen-class) in the ns form.
Look here for more details on gen-class.
Update
If you really want to create a Java class from within Clojure code, you need the function gen-class , not the ns expression. See:
examples
reference guide
API docs
Update #2
Do you really need to generate a Java class from Clojure code? It might be easier to just write a Java class in a *.java source code file. Leiningen is perfectly able to compile mixed Clojure & Java source code into a single executable. This might be the easiest way to go.

Clojure: Cannot launch cider repl with boot

I have the following build.boot file,
(set-env!
:resource-paths #{"src"}
:dependencies '[[me.raynes/conch "0.8.0"]
[boot.core :as boot]])
(task-options!
pom {:project 'myapp
:version "0.1.0"}
jar {:manifest {"Foo" "bar"}})
(boot/deftask cider "CIDER profile"
[]
(require 'boot.repl)
(swap! #(resolve 'boot.repl/default-dependencies)
concat '[[org.clojure/tools.nrepl "0.2.12"]
[cider/cider-nrepl "0.15.0"]
[refactor-nrepl "2.3.1"]])
(swap! #(resolve 'boot.repl/default-middleware)
concat '[cider.nrepl/cider-middleware
refactor-nrepl.middleware/wrap-refactor])
identity)
following this documentation: https://github.com/boot-clj/boot/wiki/Cider-REPL
However, upon doing cider-jack-in I get the error "refusing to run as root. set BOOT_AS_ROOT=yes to force.", and yet after doing export BOOT_AS_ROOT=yes, I get the same error. What's wrong?
This wiki page is super outdated, so I don't recommend following it. I'd be best to read CIDER's documentation instead.
Just make sure you're using Boot 2.8.3. You don't really need any special CIDER profile. Just create a Boot project, open a file from it in CIDER and do M-x cider-jack-in-clj.

How to Run Jetty Example with Ring in Clojure

I am following along with this example on creating a simple web service in Clojure using ring and jetty.
I have this in my project.clj:
(defproject ws-example "0.0.1"
:description "REST datastore interface."
:dependencies
[[org.clojure/clojure "1.5.1"]
[ring/ring-jetty-adapter "0.2.5"]
[ring-json-params "0.1.0"]
[compojure "0.4.0"]
[clj-json "0.5.3"]]
:dev-dependencies
[[lein-run "1.0.0-SNAPSHOT"]])
This in script/run.clj
(use 'ring.adapter.jetty)
(require '[ws-example.web :as web])
(run-jetty #'web/app {:port 8080})
And this in src/ws_example/web.clj
(ns ws-example.web
(:use compojure.core)
(:use ring.middleware.json-params)
(:require [clj-json.core :as json]))
(defn json-response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/json"}
:body (json/generate-string data)})
(defroutes handler
(GET "/" []
(json-response {"hello" "world"}))
(PUT "/" [name]
(json-response {"hello" name})))
(def app
(-> handler
wrap-json-params))
However, when I execute:
lein run script/run.clj
I get this error:
No :main namespace specified in project.clj.
Why am I getting this and how do I fix it?
You're getting this error because the purpose of lein run (according to lein help run) is to "Run the project's -main function." You don't have a -main function in your ws-example.web namespace, nor do you have a :main specified in your project.clj file, which is what lein run is complaining about.
To fix this, you have a few options. You could move the run-jetty code to a new -main function of the ws-example.web function and then say lein run -m ws-example.web. Or you could do that and also add a line :main ws-example.web to project.clj and then just say lein run. Or you could try using the lein exec plugin to execute a file, rather than a namespace.
For more info, check out the Leiningen Tutorial.
You have to put that (run-jetty) stuff into a -main somewhere and then add it to the project.clj like
:main ws-example.core)
From lein help run:
USAGE: lein run -m NAMESPACE[/MAIN_FUNCTION] [ARGS...]
Calls the main function in the specified namespace.
So, you would need to put your script.clj somewhere on the project source path and then call it as:
lein run -m script

command line arguments with leiningen

I have recently started out with clojure, and I am using leiningen to create a small project. I am having troubles in getting leiningen to behave with command line arguments. The following is my src/project/core.clj
(ns project.core
(:gen-class))
(defn -main [& args]
(println (apply str args)))
and my project.clj
(defproject project "1.0.0-SNAPSHOT"
:description "FIXME: write"
:main project.core
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]])
Now when I run lein run arg1 arg2, it gives me this error:
Exception in thread "main" java.lang.Exception: Unable to resolve symbol: arg1 in this context (NO_SOURCE_FILE:1)
at clojure.lang.Compiler.analyze(Compiler.java:5205)
at clojure.lang.Compiler.analyze(Compiler.java:5151)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3057)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:5371)
at clojure.lang.Compiler.analyze(Compiler.java:5190)
at clojure.lang.Compiler.analyze(Compiler.java:5151)
at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:4670)
at clojure.lang.Compiler$FnMethod.parse(Compiler.java:4328)
at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3173)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:5367)
at clojure.lang.Compiler.analyze(Compiler.java:5190)
at clojure.lang.Compiler.eval(Compiler.java:5421)
at clojure.lang.Compiler.eval(Compiler.java:5415)
at clojure.lang.Compiler.eval(Compiler.java:5391)
at clojure.core$eval.invoke(core.clj:2382)
at clojure.main$eval_opt.invoke(main.clj:235)
at clojure.main$initialize.invoke(main.clj:254)
at clojure.main$null_opt.invoke(main.clj:279)
at clojure.main$main.doInvoke(main.clj:354)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at clojure.lang.Var.invoke(Var.java:369)
at clojure.lang.AFn.applyToHelper(AFn.java:165)
at clojure.lang.Var.applyTo(Var.java:482)
at clojure.main.main(main.java:37)
Caused by: java.lang.Exception: Unable to resolve symbol: arg1 in this context
at clojure.lang.Compiler.resolveIn(Compiler.java:5677)
at clojure.lang.Compiler.resolve(Compiler.java:5621)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:5584)
at clojure.lang.Compiler.analyze(Compiler.java:5172)
... 23 more
However, if I do a lein uberjar and then do java -jar project-1.0.0-SNAPSHOT-standalone.jar arg1 arg2, I get the correct output.
arg1arg2
It isn't very comfortable to have to create the uberjar to run it every time while development, is there a better way?
This looks like it's caused by a bug that's been fixed in git. The fix will be in 1.4.2, which should be out in a few days. In the mean time, you can use workarounds discussed here: http://groups.google.com/group/clojure/msg/a8160b23a5019a12
From lein-run: "Args will be passed on as *command-line-args*"
So you will have to use those. The example on the site shows how. If you now what arguments you are passing you an also use :run-aliases to specify those in your project.clj. Again, the mentioned site has all the information.
My sample project.clj
(defproject addressbook "1.0.0-SNAPSHOT"
:description "FIXME: write"
:main addressbook.core
:run-aliases {:addressbook [addressbook.core -main "arg1"]}
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]]
:dev-dependencies [[lein-run "1.0.0"]])
And the test code:
(ns addressbook.core
(:gen-class))
(defn -main [& [args]]
(if args (println args)))
Both "lein run addressbook foo" as "lein uberjar" work for me.

Problem using redis-clojure with Leiningen

Hey, I'm new to Clojure and Leiningen and a bit stuck. I've managed to setup a project with Leiningen. I'm able to compile it into an uberjar and run the repl. I've also managed to load a dependency named aleph to run a simple concurrent webserver.
The next step for me is to use redis-clojure to access redis. But here I'm stuck. This is my project.clj:
(defproject alpha "0.0.1-SNAPSHOT"
:description "Just an alpha test script"
:main alpha.core
:dependencies [[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
[aleph, "0.1.2-SNAPSHOT"]
[redis-clojure "1.2.4"]])
And here is my core.clj: Note that I only added the line (:requre redis) according to the example from redis-clojure.
(ns alpha.core
(:require redis)
(:gen-class))
(use `aleph.core 'aleph.http)
(defn alpha [channel request]
(let [] (enqueue-and-close channel
{:status 200
:header {"Content-Type" "text/html"}
:body "Hello Clojure World!"}))
(println (str request)))
(defn -main [& args]
(start-http-server alpha {:port 9292}))
When I try to run lein repl this happens:
java.io.FileNotFoundException: Could not locate redis__init.class or redis.clj on classpath: (core.clj:1)
Yes, I have run lein deps and the redis-clojure jar is available in my lib directory. I'm probably missing something trivial, but I've been at this issue for a few hours now and not getting any closer to a solution. Thanks!
Namespace redis does not exist. I suppose you need
(:require [redis.core :as redis])
A way to check for available namespaces:
(use 'clojure.contrib.find-namespaces)
(filter #(.startsWith (str %) "redis") (find-namespaces-on-classpath))
This works with more current versions of Clojure, in this example it finds the names of all namespaces that contains the sub string "jdbc":
(map str
(filter
#(> (.indexOf (str %) "jdbc") -1)
(all-ns)))
The result is a sequence, in example:
=>
("clojure.java.jdbc")