I just started playing with clojure, and I have a question.
I create a folder called testingclojure in ~/ and it contains a file called core.clj which has a simple function like this:
(ns testingclojure.core)
(defn greetings
[{:keys [name age]}]
(format "Hello my name is %s and I'm %s years old" name age))
So the filepath is: ~/testingclojure/core.clj
Meanwhile I'm in ~/, and I want to use it in repl, so I type:
(use '[testingclojure [core :as c]])
Unfortunately, I got an error, something like "Could not locate testingclojure/core.clj". How to solve this problem?
How do you invoke the repl?
Are you using leiningen or just the clojure jar?
You need to include the current folder
if you are using the clojure jar
java -cp [path to clojure jar];.; clojure.main
if you are using leiningen place your code in the src folder or use the src directive in your project.clj to point it to the right source folder.
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).
I have implemented a hyphenation algorithm (at namespace hyphenator-clj.core), defined it as org.clojars.nikonyrh.hyphenator-clj 0.1.0 at defproject and pushed it to Clojars. Uberjar seems to have files like core__init.class, core.clj and core.class.
However when I try to use it as a dependency on an other project I get this error:
$ lein uberjar
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.pom from clojars
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.jar from clojars
Compiling example.core
java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
...
Must I change my project's folder structure so that it matches the expected org/clojars/nikonyrh/hyphenator_clj__init.class, or can I somehow override the current behavior? If there is a good tutorial about this out there I would be happy to read it.
Basically I would like to get this example project to work. project.clj:
(defproject example "0.0.1-SNAPSHOT"
:description ""
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojars.nikonyrh.hyphenator-clj "0.1.0"]]
:javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
:aot [example.core]
:main example.core)
src/example/core.clj:
(ns example.core
(:require [org.clojars.nikonyrh.hyphenator-clj :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
I'm suspecting I also have the english.txt in a wrong directory, as it isn't contained in the uberjar but resource files are an other topic.
You would probably be better off not using a hyphen in the namespace hyphenator-clj. Why not just use hyphenator? But if you do I suspect that the name of the directory should have an underscore in it rather than a hyphen, so be: hyphenator_clj.
If fixing that issue doesn't help then another thing to look out for, which I can't see from your question, is where exactly is core.clj in the directory structure, and does the project.clj reflect that? For instance is the path for the namespace hyphenator-clj.core in a src directory off the root of your project? The root of your project being defined as where the project.clj is located.
Something else that would be good to see in the question is whether you can get the program to work just locally, without having packed it up into an uberjar and shipped it to clojars. My guess would be that it does work locally, but it would help for that to be stated.
Okay taking a look at your links now. You might like to read a working project deployed to clojars, that has hypens in its name, for instance here. The first difference you might notice is the project name you use is rather long: org.clojars.nikonyrh.hyphenator-clj. It should just be hyphenator-clj. Also I would recommend having an identifier ending in "-SNAPSHOT" as that project does.
But taking a look at the bigger picture, a great idea you suggested in the comments is to test without Clojars being in the mix at all. To do this use lein install on the library you want to use from another lein project.
Ahaa at least I understand the process a bit better now, basically my require has to match the structure of the used JAR file, which may be very different from the project's name. For example cc.qbits/spandex is actually required as qbits.spandex.
The english.txt dependency was fixed by moving it to resources folder, deploying the new version to Clojars and importing the dependency as it exists in the JAR:
(ns example.core
(:require [hyphenator-clj.core :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
Assume there is two files inside my clojure project, one clj and the other is txt.
Is there a way to know the path (as a string) of the txt file from the clj file?
There is:
(System/getProperty "user.dir")
or
(-> (java.io.File. ".") .getAbsolutePath)
But this gives where the current directory. The one that includes the clj file, the one the code is written in.
But how to know the path of the txt file?
The purpose is to write into this txt file from the clj file.
Thank you.
In Java and therefore Clojure you can find files on the CLASSPATH. For example, in Java it is common to put things like log4j.properties at the top of your CLASSPATH (e.g., in the classes directory) and then you can reference the file in your Clojure (or Java) code with:
(java.io.File. "log4j.properties")
Are you using and running your app with Leiningen? If so, you can create a directory at the top level and put files there. For example, if you have a config file you can have a "conf" dir with a properties files:
my-lein-proj$ ls
conf doc project.clj README.md src target test
Suppose you put a myproj.conf file in the conf directory and you want to read from it in your Clojure code. Then you can just do:
(slurp "conf/myproj.conf")
The Clojure library local-file allows you to get your current project's directory with local-file/project-dir. As long as you know where in your project the file you want to access is, you should be able to find it this way.
This gives where the current clj file, the one that this code is
written in.
No, it doesn't.
It gives the current directory.
Did you take into account that one can run clojure scripts that are not in the current directory?
if your file structure is something similar to this:
config | src | target | test
you have a config inside config directory, in our case let's assume its java.config and you are trying to read this file inside core.clj in src directory you can also use clojure.java.io/reader method
for example:
(clojure.java.io/reader "config/java.config")
you can run below commands in the repl to see the contents of the file
(slurp (clojure.java.io/reader "config/java.config")
if you are interested in reading the contents of the file line by line you combine above function with with-open method and read line by line:
(with-open [word (clojure.java.io/reader "config/java.config")]
(loop [c (.read word)]
(if (not= c -1)
(do
(print (char c))
(recur (.read word))))))
I'm working through "Clojure in Action", and I have been instructed to create a file "in a folder named chapter08 within your source directory" and try to require it.
I created the following files (tried both - and _ delimited)
~/clojure-1.4.0$ ls src/chapter08/
date-operations-spec.clj date_operations.clj
date-operations.clj date_operations_spec.clj
I tried to require in the REPL using code from the book, but keep failing:
~/clojure-1.4.0$ java -cp clojure-1.4.0.jar clojure.main
Clojure 1.4.0
user=>
(ns chapter08.date-operations-spec
(:use chapter08.date-operations)
(:use clojure.test))
FileNotFoundException Could not locate chapter08/date_operations__init.class or chapter08/date_operations.clj on classpath: clojure.lang.RT.load (RT.java:432)
use leiningen which has become the ubiquitous tool for managing such things since Amit published that excellent book. I just spent longer writing this than the time required to setup leiningen.
then run lein new chapter8.
copy the file to chapter8/src/chapter8/
Run lein repl
Using plain java to start clojure is a pain in the neck. For instance, your java -cp ... call will not put ./src on the classpath . Please just use leiningen.
I'm a beginner with clojure, only starting it yesterday.
I have gathered that a simple way to create a standalone app is with leiningen lein new foo.
I tried to create a hello world test project with leiningen. I added :main and :aot directives to project.clj, added :gen-class to the core.clj file and tried lein run, but I get errors about class definition not found.
Exception in thread "main" java.lang.NoClassDefFoundError:
Caused by: java.lang.ClassNotFoundException:
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
The core.clj file
(ns test.core
(:gen-class))
(defn -main [& args] (println "Hello main"))
And the project.clj file
(defproject test "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:main test.core
:aot [test.core]
:dependencies [[org.clojure/clojure "1.2.1"]])
Edit: After further testing, it seems like copying the project to my desktop works as is, which I think points to that the environment on my laptop is somehow borked, but I don't know how.
The environment on desktop is clojure from repositories and leiningen from AUR. On laptop the clojure is from clojure.org and leining is from github.
[UPDATE April 2013]
Leiningen 2, which has been officially released for some time, includes the concept of project templates. By default, Leiningen provides an app template that provides what you need out of the box. Try:
lein new app my-project
You will see that Leiningen creates the familiar project template, but also includes:
The default namespace of my-project.core as the :main entry in your project.clj file
The :gen-class form in the namespace declaration of my-project.core
A default -main function in the my-project.core namespace
For those who cannot yet use Leiningen 2, the lein-newnew plugin provides an equivalent experience under Leiningen 1.
[/UPDATE]
To build a project that, when run, prints "Hello World!", you'd do as follows (revision of your process above):
Setup
lein new my-project
cd my-project
lein deps
You should now have a basic structure in place and the Clojure jar in your lib folder.
Write a Function
Now edit src/my_project/core.clj with your editor of choice, adding the following below the (ns ...) form:
(defn -main []
(println "Hello World!"))
This function is inside your my-project.core namespace. To ensure this gets run as your main, let's add a gen-class parameter to your namespace definition at the top, so that it now looks like this at the top of core.clj:
(ns my-project.core
(:gen-class :main true))
So all together, your core.clj file looks like this:
(ns my-project.core
(:gen-class :main true))
(defn -main []
(println "Hello World!"))
Configure it as the Main Function
Once you've got src/my_project/core.clj edited as above, you need to tell Leiningen (the build tool) where the "main" function for your project lives. Here's an example defproject form that does this:
(defproject my-project "1.0.0-SNAPSHOT"
:description "My Project"
:dependencies [[org.clojure/clojure "1.2.1"]]
:main my-project.core)
Now the -main function inside my-project.core becomes the entry-point for your program.
Run It
You can now have two options for running this project:
Use lein run at the command-line while at the root of your my-project project
Create a standalone jar file by running lein uberjar. You can then run the resultant jar file by running java -jar my-project-1.0.0-SNAPSHOT-standalone.jar
Figured it out. I had the latest leiningen from git, which was borked somehow. I checked out the 1.6.1 tag and ran self-install, and now it works.
I missed it, You named your project test, you can't do that change the name to something else it will work.
You say above
lein new foo
what you mean is
lein new test