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
Related
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
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 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'm trying to create a text based Clojure game (inspired by Land of Lisp).
(def *nodes* {:living-room "you are in the living-room. a wizard is snoring loudly on the couch."
:garden "you are in a beautiful garden. there is a well in front of you."
:attic "you are in the attic. there is a giant welding torch in the corner."})
(defn describe-location [location nodes]
(nodes location))
The code is running in the REPL but if I saved the code to a file and trying to run:
(describe-location :attic *nodes*)
I got:
Exception in thread "main" java.lang.IllegalArgumentException: Wrong
number of args (1) passed to: user$describe-location (wizard-game.clj:
0)
What I'm doing wrong?
Here is the file: http://dl.dropbox.com/u/3630641/wizard-game.clj
You have too many parentheses. Instead of (describe-location(:garden *nodes*)), you want (describe-location :garden *nodes*).
Remember that the name of the function goes after the open paren, not before: you were calling (:garden *nodes*) and then calling describe-location on the result, which failed because describe-location wants two arguments, not one.
one potential problem is that the version of the function that is loaded into the repl in the 'user' name space may not be the one you expect, so you may want to (load "wizard-game.clj") into a fresh REPL. though many people are using leiningen for this these days, except for the good number of people using maven directly.
first give your're game a namespace
(ns com.me.myGame
....)
then you can load it into the repl by running
(use 'com.me.myGame)
and call the functions by either their name-space-qualified names
(com.me.myGame/describe-location :attic)
or from the repl switch into that namespace:
(in-ns 'com.me.myGame)
(describe-location :attic)
or you can use leiningen to create your project and name-space automatically.
leiningen is worth it in this case because it just took me longer to write this sentence than to make a project with lein. There are a lot of good tutorials for leiningen.
lein new wizard-game
and then edit src/wizard-game/core.clj. this will let you add dependencies later with out fuss if when the project grows to world-famous-success
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" .