I am trying out the function (starts-with?) shown here: https://clojure.github.io/clojure/clojure.string-api.html and when I try to use it I get Unable to resolve symbol: starts-with? in this context error message . I modified my project dependencies too by specifying :dependencies [[org.clojure/clojure "1.8.0"]] but that didn't seem to help.
You may have forgotten to require the namespace ? See the example below:
(ns simple.strings
(:require [clojure.string :as str]))
(str/starts-with? "hello, world" "hello")
; true
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.
I am pulling my hair out trying to resolve the following error:
Exception in thread "main" java.io.FileNotFoundException: Could not locate composer/midi/short_message__init.class or composer/midi/short_message.clj on classpath: , compiling:(events.clj:12:1)
The reference to short-message is in the namespace declaration of events.clj:
(ns composer.ui.events
(:use [seesaw core border chooser])
(:require [composer.midi
[io :as io]
[time :as time]
[player :as player]
[short-message :as short]]))
And here is the namespace declaration of short-message itself in short-message.clj:
(ns composer.midi.short-message
(:require [composer.algorithm.transform :refer :all]
[composer.algorithm.markov.transform :refer :all]
[composer.midi [io :refer :all] [message :as message]]))
short-message is in the same directory as all other files in composer.midi, and yet this seems to be the only one that is resulting in an issue. Indeed, after verifying the target directory in my project, this is the only namespace which doesn't seem to contain a corresponding class file. I thought it could be an error with the code, but if I try to load the file with (load-file "src/composer/midi/short-message.clj") at the REPL I don't have any issues.
Your comment is right. In clojure dashes in namespaces correspond to underscore in filenames. So your file name should be short_message.clj as you found.
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
I would really like to use Korma for my project, but every time I try to test it in my REPL, it throws the following error:
core=> (require 'korma.db)
FileNotFoundException Could not locate clojure/java/jdbc/internal__init.class or clojure/java/jdbc/internal.clj on classpath: clojure.lang.RT.load (RT.java:432)
I have the following in my 'core' namespace:
(ns core
(:require [clojure.java.jdbc :as sql]))
and the following in my project.clj:
(defproject wknd "1.0.0-SNAPSHOT"
:description "weekend side project"
:dependencies [[org.clojure/clojure "1.4.0"]
[org.clojure/clojure-contrib "1.2.0"]
[org.xerial/sqlite-jdbc "3.7.2"]
[org.clojure/java.jdbc "0.2.2"]
[korma "0.3.0-beta9"]]
:dev-dependencies [[org.clojars.scott/lein-nailgun "1.1.0"]])
I am just starting out on clojure and have no idea why I'm getting this error. I've searched around and couldn't find similar issues elsewhere.
From the author:
Korma hadn't been upgraded to the latest JDBC since the reorganization
of it. Try beta11, should be fixed.
Cheers, Chris.
and this error disappeared for me.
I wrote a small namespace to do some database operations and I would like to use it from within another namespace. Normally having the files in the same directory and then doing
(ns program (:require [other-ns :as other]) (:gen-class))
would be all that's necessary. However this doesn't work in Clojure CLR, compiler complains about not knowing about other-ns. So what is the proper method of doing this? Having a seperate assembly for every namespace?
[EDIT] Another example
another.clj
(ns another)
(defn hello [name] (str "Hello " name))
program.clj
(ns program
(:require [another :as a])
(:gen-class))
I load up program.clj in the repl and get this message:
FileNotFoundException Could not locate another.clj.dll or another.clj on load path. clojure.lang.RT.load (d:\work\clojure-clr\Clojure\Clojure\Lib\RT.cs:3068)
I created two files in the same directory filea.clj and fileb.clj. Here's filea.clj:
(ns filea)
(defn hi []
(println "hi from filea"))
Here's fileb.clj:
(ns fileb
(require [filea :as a])
(:gen-class))
(defn -main []
(println "hi from fileb")
(a/hi))
I then changed into the directory where these files live and ran:
C:\temp\multi-ns>clojure.compile fileb
Compiling fileb to . -- 59 milliseconds.
And when I ran it I saw:
C:\temp\multi-ns>c:\Tools\clojure-clr-1.3.0-Debug-4.0\fileb.exe
hi from fileb
hi from filea
Are you using vsClojure or writing your code outside of VS?