I have the following Java class:
public class Speak {
public static String greet() {
return "Hello! I am a human!";
}
}
I have compiled this to Speak.class
How do I now import it into the clojure repl and how do classpaths and namespaces fit in?
Thanks
With the standard clojure repl, the class file needs to be available on the classpath used to start the repl. Here's an example
java -cp pathToClojure\clojure.jar;.\src;.\lib;.\lib\* clojure.main %1
I have the src included for clojure source, the lib folder included for class files, and lib* included for classes included in jar files.
In this example, the Speak class can be included and used with:
user=> (import Speak)
Speak
user=> (Speak/greet)
"Hello! I am a human!"
This assumes that you have set up the classpath before starting the repl. If you want to add something to the classpath after the repl is started it's more complicated. Example code to do it can be found here
Related
I have 2 external Clojure files in my file system.(a.clj and b.clj)
/Users/e/.somedir/a.clj:
(ns a (:require [b]))
(b/printt)
/Users/e/.somedir/b.clj:
(ns b)
(defn printt [] (println "aaaa"))
The thing is I want to be able to load those files to my REPL(preserving dependency order)
If I load a.clj first I get this exception:
(clojure.main/load-script "/Users/e/.somedir/a.clj"):
CompilerException java.io.FileNotFoundException: Could not locate b__init.class or b.clj on classpath., compiling:(/Users/e/.somedir/a.clj:1:1)
If I load b.clj first there is no problem.
So how can I figure this dependency order out and load b.clj first, imagine that this is a complex dependency graph, are there any code examples?
P.S: I don't want to use leiningen or any other build tool(want to do it programmatically). There could be some kinda library/code snippet that shows me files that needed to get loaded in dependency order. How do build tools like leiningen achieve this thing? They do it in some way.
You don't need to load all the files, just the root file of your dependency tree. The other source files are loaded as needed. So if namespace A requires namespace B and namespace B requires namespace C, then you just:
(load "com/example/A.clj")
and B.clj and C.clj are loaded automatically.
Also, since you're not using a build tool, you'll need to be careful about a few things:
1) You need to make sure your source files folder structure mirrors your namespace declarations so an ns of 'com.example.A' should be in a folder structure like src/com/example/A.clj. If you don't Clojure has no way to know where a dependency is located in the file system.
2) A running Clojure REPL is initiated with a specific class path. If the 'src' folder above was not defined on the classpath, Clojure doesn't know about it. So be careful to add that folder to your classpath: java -jar clojure-1.9.0.jar -cp [need to include your src folder here] clojure.main
One last note, running without a build tool like Leiningen means you'll need to be an expert on java class paths and understanding Clojure's dependency model. That's a lot for someone trying to learn Clojure.
You say do not want to use lein or any other build tool, and that's fine. So you'd be better just to organize your code according to Deps & CLI Guide about the latest CLI tools released with Clojure 1.9.
Briefly, in your folder, create another src folder and put all the .clj files there. The system will find them automatically. For example:
└── your-project
├── deps.edn # your dependencies
└── src
└── a.clj
└── b.clj
Then, in the root of your project, just run clj, and the REPL will appear. There, you may require your modules as well.
Take a look at this article, it would really help.
This is easy if you set up your project using lein. Here is an example project fred. To create a simple project, just type:
> lein new app fred
> cd fred
> cp src/fred/core.clj src/fred/second.clj
It now looks like so:
fred
└── src
├── fred
├── core.clj
└── second.clj
with 2 source files core.clj and second.clj. Add your functions:
> cat src/fred/core.clj
(ns fred.core)
(defn aaa [& args]
(println "aaa - enter")
(println "aaa - exit"))
> cat src/fred/second.clj
(ns fred.second
(:require [fred.core :as fc]))
(defn bbb [& args]
(println "bbb - enter")
(fc/aaa)
(println "bbb - exit"))
Then, you can access both using lein repl:
> lein repl
Clojure 1.9.0
fred.core=> (aaa)
aaa - enter
aaa - exit
nil
fred.core=> (require '[fred.second :as fs])
nil
fred.core=> (fs/bbb)
bbb - enter
aaa - enter
aaa - exit
bbb - exit
nil
fred.core=>
You can also use the following variant to reload a namespace and its dependencies:
(require '[fred.second :as fs] :reload-all)
although this is not perfect and can get into a confused state (see How to reload a clojure file in REPL for more details).
I think I found the solution first of all I created dependency graph then I sorted namespaces in topological order so this is the thing I've been looking for a while. Now I can load Clojure files in that order(increasing dependency order).
For the development of a library I started from a lein project, invoked like so:
lein new mylib
if I call lein install now, I can access my library in other projects. But trying to immidiately test the functions I wrote failed:
lein repl
...
(dir mylib.core)
Exception No namespace: mylib.core found clojure.core/the-ns (core.clj:4008)
Do I have to add something to the project.clj file maybe?
In order to use a library you must cause the code to be loaded - that it be on the classpath is not sufficient.
You can do this easily in an ns declaration in a file of course, but in the repl it can be easier to use (require '[my-lib.whatever :as w]) after which one can call (w/foo) (w/bar) etc. as expected. You can also use (in-ns 'my-lib.whatever) in order to switch to the namespace, but this will not give you a good result unless you have previously used require or use or load-file etc. to get the definitions first.
Let's say you created a new library named clj-foo.
% lein new clj-foo
Start your repl.
% cd clj-foo
% lein repl
In the repl, load the main entry point to your library and switch to its namespace.
(load-file "src/clj_foo/core.clj")
(ns clj-foo.core)
Now you're in the clj-foo.core namespace, make sure to add back in the repl ns to get things like doc available.
(use 'clojure.repl)
That's it. You're all set to start calling functions in your library. Note that other library files will be available from the clj-foo.core namespace if they were loaded by namespace declaration at the top of clj_foo/core.clj. If not, then you'll need to invoke load-file with their path as well.
If you make changes in core.clj. You can invoke load-file again to pick up the new code. As you progress, you can use cider to facilitate loading of individual functions and files. But that's for another question. :)
You need to add a dependency to use your library from another project. To do this add a vector (a tuple-2) to the vector that is the value of the :dependencies key in the project.clj file. Here's an example:
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.clojure/core.async "0.2.371"]
[default-db-format "0.1.0-SNAPSHOT"]
[com.andrewmcveigh/cljs-time "0.3.14"]]
My own local library is called default-db-format. Its really no different to adding a dependency for com.andrewmcveigh/cljs-time.
As you say you can already do this, but are having trouble getting a REPL connection to the project of the library itself. When you go (in-ns 'some-path), you need the single quote in front of some-path. Note that some-path is a different thing to the name of your library.
Rather than use lein repl you can use the figwheel repl - if your project is setup with figwheel. My library has only one entry point and that is lein figwheel devcards. After that I had no problem going to a namespace and trying out a function:
cljs.user=> (in-ns 'default-db-format.core)
nil
default-db-format.core=> (check 1 2)
As noisesmith mentioned having a REPL in your IDE is the best setup. No fiddly typing just bring up pre-configured REPLs (per namespace) with the click of a button (or keystroke). Figwheel/Cursive setup instructions here.
I was also facing the same issue with the following configuration:
Leiningen 2.9.0 on Java 1.8.0_201 Java HotSpot(TM) 64-Bit Server VM
My file looks like this, and from the repl I desired to invoke the foo function
(ns cljtest.test
(:gen-class))
(defn foo [input]
(assoc {} "a" 123))
Both these approaches worked fine for me on the repl.
1)Switch to the appropriate name space:
cljtest.core=> (in-ns 'cljtest.test)
#object[clojure.lang.Namespace 0x90175dd "cljtest.test"]
cljtest.test=> (foo nil)
{"a" 123}
cljtest.test=>
2)Require the appropriate name space:
cljtest.core=> (require '[cljtest.test :as test])
nil
cljtest.core=> (test/foo nil)
{"a" 123}
cljtest.core=>
I am reading the documention on clojure.org about compilation, the last part gen-class examples. I do the examples and then when trying to run it as java app with: java -cp ./classes:clojure.jar clojure.examples.hello Fred in the terminal i get : Error: Could not find or load main class clojure.examples.hello. Can someone help?
Can someone introduce where to learn about gen-class and :gen-class, i find not much documentation on web
The command java -cp ./classes:clojure.jar tst.core from your base+system+user+dave is almost correct. The java.lang.NoClassDefFoundError: clojure/lang/IFn error is because the JVM cannot find the Clojure classes as there is no clojure.jar file in the base+system+user+dave directory, so you need to specify the correct path for the clojure.jar file.
As you are using lein, it downloads your project dependencies to your local repository. One of the dependencies will be Clojure itself, so assuming you are on iOS/Linux and that your lein project.clj has a dependency with clojure 1.7.0, the command to run from the base+system+user+dave directory will be:
java -cp ./classes:~/.m2/repository/org/clojure/clojure/1.7.0/clojure-1.7.0.jar tst.core
As this gets quite annoying once you have more than one dependency, I would suggest to use lein uberjar that will create a file in the target directory called your-project-name-standalone.jar that will have all required classes, so to run it from the command line go to the target directory and run something like :
java -cp tst-standalone.jar tst.core
To understand more about how the classpath works in the JVM, you can start with Wikipedia
I am learning clojure and already got an assignment.
I need to automate compile and build jar of the classes generated.
Within the clojure code, I need to compile another clojure code, write code to build the jar of the classes generated.
Here is my example.
even_test.clj
(ns clojure.sqe.examples)
(defn pair-test [test-fn n1 n2]
(if (test-fn n1 n2) "sucess" "failed"))
(println (pair-test #(even? (+ %1 %2)) 3 4)) ; -> pass
compile_test.clj
(ns clojure.sqe.examples
(:use clojure.test)
(:require [simple-check.core :as sc])
)
(compile 'clojure.sqe.examples.even_test)
;(println *compile-path*) => classes
;TO-DO - Write code to
;Build the jar for the compiled classes or from classes folder
; upload this jar to a service .
You need to 1. compile the code and then 2. create a JAR file containing the compiled code.
Clojure's compile function compiles code and puts the compiled class files (there can be more than one) under the directory specified by *compile-path*.
You will need to create a JAR file using JarOutputStream (and optionally a Manifest), and write all the files under *compile-path* into the JAR. You will have to massage the paths so that a file like target/repl/classes/clojure/sqe/examples.class is put into the JAR as clojure/seq/examples.class.
The lein jar command more or less does this, so you might want to look at its source code for details: https://github.com/technomancy/leiningen/blob/master/src/leiningen/jar.clj
Why you don't use Leiningen? It is the de facto for doing Clojure development. You can do a lot of things, such as compiling Clojure sources, compiling Java sources, run unit tests, generate POM files from porject.clj and of course, generating JAR files.
lein jar
Package up all the project's files into a jar file.
lein uberjar
Package up the project files and all dependencies into a jar file.
The error as shown on the Noir error page: java.io.FileNotFoundException: Could not locate boundaries/lat_long__init.class or boundaries/lat_long.clj on class path
The code that requires it:
(ns boundaries.views.boundary
(:use noir.core
hiccup.core
hiccup.page-helpers)
(:require
[boundaries.lat-long :as lat-long]
[noir.response :as resp]))
Why is it looking for lat_long instead of the specified lat-long? boundaries/lat-long.clj exists as well as the corresponding boundaries.lat-long namespace.
the JVM does not allow -s in class names so the Clojure compiler converts them to _s
the problem is most likely with the project.clj dependencies.
When diagnosing this sort of issue:
is the namespace available from the REPL?
does the .class file appear in the lib directory for the project?
re-run lein deps
You need to rename the boundaries/lat-long.clj to boundaries/lat_long.clj.
Note that you don't have to change the namespace name. The clojure convention is to use "-" for functions and namespace names.
From Stuart Sierra response at https://stackoverflow.com/a/4451693/151650: "It's a necessary workaround for Java interoperability."