clojure version: 1.8.0
leiningen version: 2.7.1
jdk version: 1.8.0_101
When I require a library, say reagent(has added in the project dependencies), in the lein repl:
user=> (require '[reagent.core :as r])
nil
The output is nil, which I think it means success. But when I use the r,say (r/atom 3), the repl throw an error says:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: r in
this context, compiling: (/private/var/folders/_y/n3ym4ftj2ld9tl471g_kcv_00000gn/T
/form-init1002540725014588615.clj:1:4923)
That seems strange.
Anyone has some idea?
By the way, I can require java and clojure library.
Probably you are trying to use ClojureScript library: reagent within the Clojure REPL. Finding the cause to error is not that useful since Clojure and ClojureScript are suppose to run in very different environments, JVM and JavaScript respectively. But same attempt will succeed in ClojureScript context.
As a test, create a ClojureScript project based on figwheel template.
lein new figwheel rtest
cd rtest
Add the regent dependency in project.clj
:dependencies [[org.clojure/clojure "1.8.0"]
[reagent "0.6.0"] ; only add this line
Run the project
rlwrap lein figwheel
You will be connected to the browser repl automatically. Otherwise browse to http://localhost:3449/index.html to get connected.
Now you can retry what you did.
cljs.user=> (require '[reagent.core :as r])
nil
cljs.user=> (type r/render-component)
#object[Function "function Function() { [native code] }"]
Related
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.
If I add the following require:
(ns project.core
(:require
[compojure.route :as route])
(:gen-class))
(defn -main [& {:as args}]
(println "hello"))
an do
lein run
I get
Syntax error macroexpanding clojure.core/ns at (ring/util/mime_type.clj:1:1).
((require [clojure.string :as str])) - failed: Extra input spec: :clojure.core.specs.alpha/ns-form
is there a way I can get
"compojure.route not found; not defined; or whatever" e.g. something meaningful?
if I remove it it works fine. e.g. it says Hello
using Leiningen 2.9.4 on Java 14.0.1 OpenJDK 64-Bit Server VM
The project you are using is using very old dependencies. Clojure spec (introduced "recenlty") added macro/compile time checks and the mentioned file there triggers it.
compojure.route actually is found and it then requires its transitive deps. And while going down the chain ring.util.mime-type is required and the version you are using is not ready for current Clojure versions.
Your best bet here is to upgrade your deps. E.g. if you are following a book or if you are using a template this things can happen. If you have lein-ancient installed, it can attempt the update for you. Otherwise your best bet is to start in your project.clj and compare versions (e.g. check clojars).
If the problem still persists, have a look at lein deps :tree and see what is going on with the transtive deps.
As exercise to gain experience with ClojureScript I am writing a LightTable Plugin and I find no way to successfully use any standard library, I read the official documentation and even updated it to reflect latest changes regarding paths etc.. I followed this video and read the whole thread on the google group trying the proposed solutions, even working with the latest github source without luck.
I tried including core.async or cljs.http (I know the embedded nodejs alternative, just as example) following the proposed workflow by Irakli on the Google discussion. Simplest possible scenario:
$ lein version
Leiningen 2.5.0 on Java 1.7.0_55 Java HotSpot(TM) 64-Bit Server VM (Mac OS X 10.9.5) and LT latest (0.7.2)
$ lein new lt-plugin sample
plugin project.clj->
(defproject sample "0.0.1"
:dependencies [[org.clojure/clojure "1.5.1"]
[cljs-http "0.1.20"]
])
core file
(ns lt.plugins.sample
(:require [lt.object :as object]
[lt.objs.tabs :as tabs]
[lt.objs.command :as cmd]
[cljs-http.client :as http]
)
(:require-macros [lt.macros :refer [defui behavior]]))
(defn get-users
""
[]
(let [response (http/get "https://api.github.com/users" {:with-credentials? false})]
(prn (:status response))
(prn (map :login (:body response))))) ; evaluated correctly
(get-users) ; loads of errors like
WARNING: Referred var clojure.string/split does not exist at line 1 file:/Users/jaime/.m2/repository/noencore/noencore/0.1.16/noencore-0.1.16.jar!/no/en/core.cljs
I run lein deps, save, reload behaviours, restart, refresh plugin lists... all possible combinations tried, with the plugin folder within ~/Library/Application Support/LightTable/plugins or outside.
Should I download the jars and put them manually into a lib folder? I guess lein deps is not working as I expect
Yes currently seems that Cljs native or Cljx for that matter, doesn't resonate well with the LightTable UI.
Trying https://github.com/swannodette/om/wiki/Basic-Tutorial you'll find that it doesn't take much. You can create a LT keybinding to open browser tab, navigate to project folder index.html and make another for reloading (as autoreload is a work in progress I think). Then another tab with the Cljs file while you have the cljsbuild auto running, refresh browser and changes should be witnessed.
I try to get started with ClojureScript using the chestnut leiningen template which combines piggyback, figwheel and weasel. After upgrading my leiningen installation to 2.5.0, I can start the clojure repl, but after issuing the recommended run and browser-repl commands, I run into a cryptic error. There seems to be a core.async issue as well, which I don't know whether it's related.
chestnut-borked.server=> (run)
2014-10-07 12:38:06.506:INFO:oejs.Server:jetty-7.6.13.v20130916
2014-10-07 12:38:06.545:INFO:oejs.AbstractConnector:Started SelectChannelConnector#0.0.0.0:10555
Starting figwheel.
Starting web server on port 10555 .
#<Server org.eclipse.jetty.server.Server#6cdd377c>
Compiling ClojureScript.
Figwheel: Starting server at http://localhost:3449
Figwheel: Serving files from '(dev-resources|resources)/public'
Compiling "resources/public/js/app.js" from ["src/cljs"]...
WARNING: Use of undeclared Var cljs.core.async/do-alts at line 62 file:/home/schauer /.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async/impl/ioc_helpers.cljs
WARNING: Bad method signature in protocol implementation impl/Handler lock-id at line 214 file:/home/schauer/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async.cljs
WARNING: Use of undeclared Var cljs.core.async.impl.protocols/lock-id at line 217 file:/home/schauer/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async.cljs
WARNING: Use of undeclared Var chestnut-borked.dev/put! at line 14 src/cljs/chestnut_borked/dev.cljs
[... some warnings removed after first answer ...]
WARNING: Bad method signature in protocol implementation impl/Handler lock-id at line 214 resources/public/js/out/cljs/core/async.cljs
WARNING: Use of undeclared Var cljs.core.async.impl.protocols/lock-id at line 217 resources/public/js/out/cljs/core/async.cljs
Successfully compiled "resources/public/js/app.js" in 21.377 seconds.
notifying browser that file changed: /js/app.js
notifying browser that file changed: /js/out/goog/deps.js
notifying browser that file changed: /js/out/chestnut_borked/core.js
notifying browser that file changed: /js/out/chestnut_borked/dev.js
Besides from the warnings, so far, so good -- Jetty seems to have started successfully. However, when I try to start the browser-repl, I run into an error and the connection seems to be broken:
chestnut-borked.server=> (browser-repl)
WARNING: Bad method signature in protocol implementation impl/Handler lock-id at line 214 file:/home/schauer/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async.cljs
ArityException Wrong number of args (0) passed to: compiler/with-core-cljs clojure.lang.AFn.throwArity (AFn.java:429)
chestnut-borked.server=> (browser-repl)
java.io.IOException: No client connected to Websocket
at weasel.repl.server$send_BANG_.invoke(server.clj:25)
at weasel.repl.websocket$send_for_eval_BANG_.invoke(websocket.clj:130)
at weasel.repl.websocket$websocket_eval.invoke(websocket.clj:109)
at weasel.repl.websocket.WebsocketEnv._evaluate(websocket.clj:34)
at cljs.repl$evaluate_form.invoke(repl.clj:113)
at cemerick.piggieback$cljs_eval$fn__5152.invoke(piggieback.clj:115)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
[...]
UPDATE: After the input from lnmx, it's becoming clear that weasel isn't functioning properly. If I take a look at the JS elements that the browser sees, the dev script apparently doesn't get loaded and neither is the repl.js from weasel, although there are goog.addDependency calls for them in app.js.
Chestnut 0.5.0 has been released now. It contains an updated ClojureScript which should fix the issue with Weasel (the browser-connected REPL), as well as several other improvements.
I had some success with chestnut 0.5.0, but some changes were needed. I am new to Clojure so I may be missing something -- anyway, here's what I found:
It looks like the README file for chestnut describes the usage of version 0.5.0, but that version is not available on clojars as of today.
So, per the README, I installed from a local copy:
git clone https://github.com/plexus/chestnut.git
cd chestnut
lein install
...and created a new project:
lein new chestnut tree
Attempting to compile the cljs with lein cljsbuild once produced the Bad method signature warning related to lock-id. So, I started by adding the latest core.async to project.clj under :dependencies
[org.clojure/core.async "0.1.346.0-17112a-alpha"]
Then there were some errors related to undefined core.async functions, so I fixed the requires in src/cljs/tree/core.cljs:
(ns tree.core
(:require [tree.dev :refer [is-dev?]]
[cljs.core.async :refer [chan <!]]
[om.core :as om :include-macros true]
[om.dom :as dom :include-macros true])
(:require-macros [cljs.core.async.macros :refer [go alt!]]))
and src/cljs/tree/dev.cljs:
(ns tree.dev
(:require [figwheel.client :as figwheel :include-macros true]
[cljs.core.async :refer [put!]]
[weasel.repl :as weasel]))
The next issue is that tree.dev needs a reference to the re-render-ch owned by tree.core. So I wrapped the "dev mode" setup into a function called from tree.core (src/cljs/tree/core.cljs):
(defonce re-render-ch (chan))
(when is-dev?
(tree.dev/setup re-render-ch))
...and implemented in tree.dev (src/cljs/tree/dev.cljs):
(def is-dev? (.contains (.. js/document -body -classList) "is-dev"))
(defn setup [re-render-ch]
(when is-dev?
(enable-console-print!)
(figwheel/watch-and-reload
:websocket-url "ws://localhost:3449/figwheel-ws"
:jsload-callback (fn []
(println "reloaded")
(put! re-render-ch true)))
(weasel/connect "ws://localhost:9001" :verbose true)))
With those changes, I can start lein repl, (run) and (browser-repl) OK.
During (run) I get this error:
ArityException Wrong number of args (0) passed to: compiler/with-core-cljs
(not sure where this is coming from). However, if I edit tree/src/cljs/tree/core.cljs and add
(reset! app-state {:text "Hello There?"})
the change is compiled automatically and shows up in the browser shortly after I save the file.
Per the comment, this still doesn't fix the browser-repl. For that I had to get a local copy of weasel, and hack src/clj/weasel/repl/websocket.clj ~line 88:
- (cmp/with-core-cljs)
+ (cmp/with-core-cljs {} (fn [] (println "foo")))
It seems to be related to an API change in the cljs compiler. With that, I can (browser-repl) without any warnings, and (do (js/alert "Hello world!") 42) produces an alert in the browser.
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.