I am sharing a namespace among all my ring routes in order to keep each route in its own file, so I have a file routes/core.clj that contains:
(ns test-proxy.routes.core)
;; Some utility functions
Then I start each route handler file like this:
(in-ns 'test-proxy.routes.core)
;; rest of the code
When I start the server, it works perfectly.
But when I make a change in any of the files and reload the page in the browser, I get the following error:
Caused by: java.lang.Exception: Found lib name 'test-proxy.routes.core'
containing period with prefix 'quote'. lib names inside prefix lists
must not contain periods
If I restart the server manually (lein ring server), all works as expected again, but as soon as I make another change in the code base, it fails with the same error. It definitely looks related to the way I'm using namespaces, but what gets me is that it works without a problem when I restart the server.
If I unquote the namespace to (in-ns test-proxy.routes.core) like the error seems to suggest, the server doesn't even start:
Syntax error (ClassNotFoundException) compiling at (diplomat/routes/docs.clj:1:1).
test-proxy.routes.core
in-ns is only meant to be used when at the REPL.
It is fine to divide up your functions any way you want. Just use the fully-qualified name like some.ns.of.mine/my-fn when you reference the function from any other namespace.
Of course, you can always use a namespace alias like:
(ns some.other.ns.of.mine
(:require [some.ns.of.mine :as snom])) ; define namespace alias
....
(snom/my-fn ...) ; invoke the fn
Be sure to also see How to ns
Related
I'm using tools.namespace to provide smart reloading of namespaces on the REPL. However, when calling refresh or refresh-all, it throws an error.
user=> (require '[clojure.tools.namespace.repl :as tn])
user=> (tn/refresh)
:reloading (ep31.common ep31.routes ep31.config ep31.application user ep31.common-test ep31.example-test)
:error-while-loading user
java.lang.Exception: No namespace: ep31.config, compiling:(user.clj:1:1)
And it seems to end up in this weird state where (require ep31.config) works without an error, but afterwards the namespace isn't actually defined.
I kind of figured this out, this seems to be a combination of circumstances
there were AOT compiled classes left in target/classes from doing lein uberjar previously
tools.namespace doesn't function correctly when loaded namespaces are AOT compiled
target/classes is by default on the classpath
So long story short, if you did a jar/uberjar build before, then remove target/ and things should start working again.
The question I haven't been able to solve yet is why target/classes is on the classpath to begin with. I'm suspecting it's being added by Leiningen, but haven't found yet where or why it's happening.
I learned this the hard way, documentation for :target-path says (https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L309-L313):
;; All generated files will be placed in :target-path. In order to avoid
;; cross-profile contamination (for instance, uberjar classes interfering
;; with development), it's recommended to include %s in in your custom
;; :target-path, which will splice in names of the currently active profiles.
:target-path "target/%s/"
I guess there has to be legacy reasons that :target-path "target/%s/" isn't the default.
in my Clojure library testlib, i've got a namespace with a :gen-class directive that looks like this:
(ns com.some_long_path.NewClass
(:import (java.util List ArrayList))
(:gen-class
:name com.some_long_path.NewClass
:methods [^{:static true} [getValues [String] java.util.List]]
)
(:require
[testlib.core :refer [var1 var2]]))
(defn getValues [^String]
(java.util.ArrayList. [3 5]))
If i try to import this class inside another namespace in the testlib project (after invoking compile), i can invoke getValues method without errors.
However, if i lein install, include testlib in another project jartest, and then use it in a test namespace below
(ns jartest.core
(:import [com.some_long_path NewClass]))
(NewClass.)
(NewClass/getValues "some string")
invoking NewClass constructor gives an exception
CompilerException java.lang.NoClassDefFoundError: Could not initialize class com.some_long_path.NewClass
and getValues as a consequence gives
CompilerException java.lang.IllegalStateException: Attempting to call unbound fn: #'com.some_long_path.NewClass/getValues
However, if i remove the requires from NewClass namespace definition above, the code works even in another library. So the problem is caused by some missing dependencies, although i've made sure that all dependencies of testlib are also included in jartest, and that testlib.core namespace is AOT-compiled.
Also, i've tried decompiling generated com.some_long_path.NewClass class file, and there is a static initializer block that looks like this:
static
{
Util.loadWithClass("/com/some_long_path/NewClass", NewClass.class);
}
Most probably the above-mentioned error is thrown from within loadWithClass. But how do i find out what exactly is wrong?
Thanks!
UPDATE: I was able to figure out what was wrong in the namespace i was requiring through a binary search for errors (commenting out code until things worked again). It turned out that some files were slurped from resources folder in testlib, but they were not present in jartest project. Changing the code to use clojure.java.io/resource fixed the problem. However, the question still stands - how to find out exactly what was the problem, without resorting to brute force methods?
Here is the obligatory answer- there isnt a better way, without understanding the dependency tree more deeply, which often can only be done by commenting stuff out and seeing what now works. That has been my experience with java classloading from clojure and using gen-class.
Heres hoping this isnt the highest voted answer.
I'm having trouble changing the namespace in Clojure. When I'm in the REPL, or even when I do lein run, I can use
(ns ppm.core)
(in-ns ppm.core)
However, when I convert it into an uberjar, I get "Can't change/establish root binding of: ns with set" as an error. This is really frustrating me cause I'm using jars to hand in my homework, and I can't find anything to fix it. Is there a way to either set the namespace to my file, or simply import the functions into the user namespace?
Thanks in advance
I'm a bit of a Clojure newbie and something in the REPL is really confusing me.
I have a project called "misc" and a namespace at "misc/src/counter_window.clj". When I do enter the REPL from the project root folder I want to import counter_window's functions, but I seem to have to go through the following weird tango every time:
user=> (use 'counter-window)
FileNotFoundException Could not locate counter_window__init.class or counter_window.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. clojure.lang.RT.load (RT.java:449)
user=> (use 'misc.counter-window)
CompilerException java.lang.Exception: namespace 'misc.counter-window' not found after loading '/misc/counter_window', compiling:(/tmp/form-init2530455467319465680.clj:1:1)
user=> (use 'counter-window)
nil ;; the import succeeds this third time.
The warning in the FileNotFound exception doesn't seem to apply because the namespace is called counter-window in the counter_window.clj file already.
So why does this happen? Why does the import not work the first time, but then succeed the third time?
I think there is a direct relation between file path and the namespace. A file src/counter_window.clj ought to have the namespace declaration (ns counter-window).
A namespace misc.counter-window should be defined in the file src/misc/counter_window.clj. ie it will have the form (ns misc.counter-window). Note that misc is a folder inside src. Your project could be named anything, I don't think it would affect the namespaces.
Assuming what you wanted was the namespace misc.counter-window and your file is correspondingly at src/misc/counter_window.clj, the following works in the repl
(use '[misc.counter-window])
I have a problem with the Enclojure REPL and using clojure modules from it. The Load/Change REPL to file/ns works fine with an isolated clojure file, but breaks with a file which has references to another clojure file which I try to use from my project.
Here are the exact steps:
Create a new project.
Create a clojure module foobar.clj (namespace com.acme.foobar)
Define a function which returns a value in foobar.clj:
(ns com.acme.foobar
(:use com.acme.othermodule))
(defn myfunc1 []
"a")
Open a Netbeans IDE REPL
From foobar.clj's context menu select:
Change REPL to file/ns
Load
From REPL call the (myfunc1) function. This works just fine:
com.acme.foobar=> (myfunc1)
"a"
The problems start when when I try to refer to other files from foobar. Here's what I do:
Create a new clojure module othermodule.clj
(ns com.acme.othermodule)
(defn fromothermodule []
"b")
Now try to call this from foobar.clj:
(defn myfunc2 []
(fromothermodule))
From othermodule.clj's context menu I select:
Change REPL to file/ns
Load
To make the REPL realize that there is new module it should be able to run.
I do same things things to foobar.clj which now refers to othermodule.clj, but I get:
CompilerException java.io.FileNotFoundException: Could not locate com/acme/othermodule__init.class or com/acme/othermodule.clj on classpath: (NO_SOURCE_FILE:50)
com.acme.foobar=>
This error message comes from both "Change REPL to file/ns" and "Load"
What am I missing? Should I do some other tricks to make this happen? Even the desperate measure of Run->Clean and Build the main project doesn't help (that would of course make the REPL business pretty painful anyway).
I am using NetBeans 6.7.1 and enclojure-plugin-2009-11-3.nbm.
Got the right solution from Eric Thorsen in the google group:
There are three ways to create the REPL from window-menu. Don't use any of those, instead right
click on the Project and "Start Project REPL". Now the paths are set up accordingly.
My first recommendation is to move from NetBeans/Enclojure to IDEA/La Clojure. JetBrains recently created an open source version of their IDE, and the Clojure plugin works fine in it. Since discovering this, I ditched NetBeans and Enclojure. I find La Clojure a pleasure to work in, but of course your mileage may vary.
Back from when I did this in NetBeans, I seem to remember Enclojure source code resides in a subdirectory called "lib". I think I solved a similar problem by fiddling with directory prefixes on the name of the file to load. Probably something like "../lib/YourName". I managed this by trial and error, so I can't relate the exact rules and syntax.
Two things that might help:
You can run something like (println (System/getProperty "java.user.dir")) to find out where Clojure thinks it's executing from.
You could start, as I did, with using an absolute path until you find your way to the correct directory name. Something like "/home/carl/NetbeansProjects/MyProject/lib/myfile.clj" .