Leiningen keeps old defns - clojure

I have very strange Lein's behavior: it keeps loading unexisting old code.
There is src directory with something like src/service/api.clj and src/user.clj. All files under src/service are reloading, but lein totally ignores any changes in src/user.clj.
(ns user
(:require [ragtime.jdbc :as jdbc]
[ragtime.repl :as repl]))
...
(defn migrate []
(repl/migrate (load-config)))
Even if I delete migrate definition, REPL will have it in user namespace, lein will run it with lein run -m user/migrate after doing lein clean and will not load changes with (load-file "src/user.clj") too.
How to make it load my changes to user.clj ?

Lein only looks for code in source paths directories. If you don't have any specified then src is assumed. In your project.clj this would be the suggested entry:
:source-paths ["dev" "src"]
To be able to reload code from the REPL this will work for user.clj:
(ns user
(:require [clojure.tools.namespace.repl :refer (refresh refresh-all)]
[clojure.stacktrace]
[clojure.pprint :as pp]))
;;
;; To run open a REPL and:
;; (reset)
;; (core/migrate)
;; Repeat those two commands after every source code change you make
;;
(defn reset []
(refresh))
user.clj can go under the dev directory.
The answer to your question is I think that user.clj is supposed to be changed so infrequently that restarting the JVM/REPL is not an issue after you have made changes. Code that is being changed frequently should be under the src directory, and should not be named as namespace user. The main entry point code that you have typically goes in a file called core.clj. So you should put the contents of your user.clj file in the core namespace i.e. in a file called core.clj, which is placed under src.

Related

Distributing a simple library via clojars

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 \-))))

clojure classpath(?) troubles loading code and dependencies with leiningen

I'm a Clojure and JVM beginner, and the build tools are a bit confusing to me, so forgive the stupidity I'm about to carry out. I don't actually know what a "classpath" is... I just want a Lisp with lots of libraries!
But I'm trying to do a write a simple little bit of text-mining code in Clojure, and I don't seem to be able to get things working.
There are two problems, and I think they're related, both probably to this classpath thing from javaland that none of the introductory Clojure books seem to explain.
I started the project with lein new and my project.clj has the following dependencies:
:dependencies [[org.clojure/clojure "1.6.0"]
[clj-fuzzy "0.1.8"]
[snowball-stemmer "0.1.0"]
[net.mikera/core.matrix "0.50.0"]])
and the relevant ns call from my core.clj is as follows:
(ns blabber.core
(:require
[clojure.string :refer [lower-case split]]
[clojure.walk :refer [keywordize-keys]]))
My directory structure is the default setup leiningen uses for a new library.
First problem:
I gather from this prior SO that if things are set up right, I shouldn't need to call (load-file "src/blabber/core.clj") in the repl before calling (use 'blabber.core) in order to get at code I just wrote. (I'm firing up the lein repl from the src/blabber directory in bash). But when I fire up the repl, use fails unless I call load-file first. So does that mean my classpath is set up wrong somehow? And how does one fix such a thing?
Second problem:
Ok, so now I'm trying to actually use core.matrix. First line of my core.clj changed to:
(ns blabber.core
(:require
[clojure.string :refer [lower-case split]]
[clojure.walk :refer [keywordize-keys]]
[clojure.core.matrix :refer [dataset]]))
When I first started the repl with this project.clj but without the :require to core.matrix, leiningen happily fetched core.matrix: Retrieving net/mikera/core.matrix/0.50.0/core.matrix-0.50.0.jar from clojars
However, after including the :require to core.matrix in the actual code and starting up the repl again, at the repl I call (load-file "src/blabber/core.clj"), and get the following error:
CompilerException java.io.FileNotFoundException: Could not locate clojure/core/matrix__init.class or clojure/core/matrix.clj on classpath: , compiling:(/Users/pauliglot/github/blabber/src/blabber/core.clj:1:1)
I'm using Leiningen 2.5.1 on Java 1.8.0_45. And I'm just following the getting started guide for core.matrix.
So what happened? Why can't the JVM find any of my stuff? Save me? Thanks!
If it helps, here's a dump of the output of lein classpath
/Users/pauliglot/github/blabber/test:/Users/pauliglot/github/blabber/src:/Users/pauliglot/github/blabber/dev-resources:/Users/pauliglot/github/blabber/resources:/Users/pauliglot/github/blabber/target/classes:/Users/pauliglot/.m2/repository/clj-fuzzy/clj-fuzzy/0.1.8/clj-fuzzy-0.1.8.jar:/Users/pauliglot/.m2/repository/snowball-stemmer/snowball-stemmer/0.1.0/snowball-stemmer-0.1.0.jar:/Users/pauliglot/.m2/repository/org/clojure/tools.macro/0.1.5/tools.macro-0.1.5.jar:/Users/pauliglot/.m2/repository/clojure-complete/clojure-complete/0.2.3/clojure-complete-0.2.3.jar:/Users/pauliglot/.m2/repository/org/clojure/google-closure-library-third-party/0.0-20140226-71326067/google-closure-library-third-party-0.0-20140226-71326067.jar:/Users/pauliglot/.m2/repository/com/google/protobuf/protobuf-java/2.4.1/protobuf-java-2.4.1.jar:/Users/pauliglot/.m2/repository/org/clojure/google-closure-library/0.0-20140226-71326067/google-closure-library-0.0-20140226-71326067.jar:/Users/pauliglot/.m2/repository/org/mozilla/rhino/1.7R4/rhino-1.7R4.jar:/Users/pauliglot/.m2/repository/org/json/json/20090211/json-20090211.jar:/Users/pauliglot/.m2/repository/net/mikera/core.matrix/0.50.0/core.matrix-0.50.0.jar:/Users/pauliglot/.m2/repository/com/google/javascript/closure-compiler/v20131014/closure-compiler-v20131014.jar:/Users/pauliglot/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar:/Users/pauliglot/.m2/repository/org/clojure/clojurescript/0.0-2202/clojurescript-0.0-2202.jar:/Users/pauliglot/.m2/repository/args4j/args4j/2.0.16/args4j-2.0.16.jar:/Users/pauliglot/.m2/repository/org/clojure/tools.nrepl/0.2.6/tools.nrepl-0.2.6.jar:/Users/pauliglot/.m2/repository/com/google/guava/guava/15.0/guava-15.0.jar:/Users/pauliglot/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar:/Users/pauliglot/.m2/repository/org/clojure/tools.reader/0.8.3/tools.reader-0.8.3.jar:/Users/pauliglot/.m2/repository/org/clojure/data.json/0.2.3/data.json-0.2.3.jar
Edit
Here's the directory tree:
| blabber
|-doc
|-resources
|-src
|---blabber
|-target
|---classes
|-----META-INF
|-------maven
|---------blabber
|-----------blabber
|---stale
|-test
and all my code is in blabber/src/blabber/core.clj
A classpath is a Java concept; Leiningen should set up the classpath correctly. What I suspect is that there's a mismatch between the directories, filenames, or namespace declarations. The file path should be <name passed to 'lein new'>/src/blabber/core.clj. It wasn't clear from what you wrote whether that's the case. Try running lein deps first, too, but you shouldn't need to do that. This and lein repl are usually run from the directory, i.e. the project root directory. You might need :source-paths or :main in project.clj, but I don't think so.
(use 'clojure.core.matrix) should work. Works for me, e.g. with
(defproject blabber "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[net.mikera/core.matrix "0.50.0"]]).

access library functions in leiningen REPL

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=>

Locating Clojure Browser Dom

I am using the following namespace for a graphics demo
(ns foo.core
(:use [clojure.browser.dom :only [get-element]]))
However, I return a File not found exception for clojure browser dom in the classpath.
Clojurescript has been pulled, and is contained within the file I cd into. But is not contained in the file I am trying to load, after having accessed the REPL.
Is clojure.browser.dom out of date? Or, am I missing something within the implementation?
Edit
I have not included the dependency for this file.
That namespace is correct:
https://github.com/clojure/clojurescript/blob/master/src/cljs/clojure/browser/dom.cljs
Maybe the problem is the ns form? Try
(ns foo.core
(:require [clojure.browser.dom :refer [get-element]]))
Also, just in case, be sure to name your file .cljs and restart the cljsbuild compiler, just in case.

Standalone clojure app

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