requiring namespaces in clojure leinengen project - clojure

I'm new with clojure and the jvm and am having trouble creating a leinengen project where I can separate my code into namespaces. My project is named cloj_test and in my cloj_test/src/cloj_test directory I have a file named db_connect.clj. In the db_connect.clj file I have code at the top to define the namespace
(ns db-connect
(:require [clojure.java.jdbc :as jdbc]
[clojure.java.jdbc.sql :as sql]))
and then a few functions to define some database functionality. cloj_test/src is on the lein classpath. When I launch the repl using "lein repl" and then type
(require 'cloj-test.db-connect)
It works. However, if I type
(require '[cloj-test.db-connect :as db])
I get this error:
Exception namespace 'cloj-test.db-connect' not found clojure.core/load-lib (core.clj:5380)
The same thing happens when I use "use". Does anybody know how I can resolve this?

The package name is missing form the ns declaration
(ns cloj-test.db-connect
(:require [clojure.java.jdbc :as jdbc]
[clojure.java.jdbc.sql :as sql]))
The namespace declaration needs to match the directory that the file is in
(except that -s are changed to _s) in the file and directory names.

Related

Leiningen keeps old defns

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.

Dependencies downloaded but still cannot require, clojure

This kills me... I cannot require anything other than built-in native deps. No hiccup, no http-kit etc... Even if I can find them on my hard drive in .m2/repository
lein new myapp,
add [markdown-clj 0.9.91] to project.clj,
add (ns metapp.core
(:require [markdown-clj :as mark]) )
lein run
Retrieving markdown-clj/markdown-clj/0.9.91/markdown-clj-0.9.91.pom from clojars
Retrieving markdown-clj/markdown-clj/0.9.91/markdown-clj-0.9.91.jar from clojars
Exception in thread "main" java.io.FileNotFoundException: Could not locate quote/markdown_clj__init.class or quote/markdown_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.,
lein deps is not returning anything
Somebody knows what's wrong please? This stacktrace isn't very helpful, so Lein can fetch deps, but doesn't know how to require them?
EDIT: Running Linux Mint 18.0, clojure is in /home/denis/clojure-1.8.0 and is called by alias java -cp /home/denis/clojure-1.8.0/clojure-1.8.0.jar clojure.main. Directory tree in myapp is /home/denis/prg/cljr/myapp
SOLUTION:
Thank you guyz, but now feel like an idiot.
So to summarize for future-comers, in project.clj, to ask for a dependency "X" doesn't mean you should "require" it as "X". You must require it the way the author specified in documentation, for example [http-kit "2.2.0"] in project.clj is required as follows
(ns metapp.core (:require [org.httpkit.client :as http] ).
Second, the way you require inside your code is not the same as the way you require in REPL, for example, this works in yourapp.core (require [stuff.core as stuff]). You could also write it like this, it works too (ns yourns (:require [stuff.core :as stuff]). But this synthaxe doesnt work: (:require [stuff.core :as stuff]).
In REPL however, it's different story! I must use (:require '[stuff.core]) if it is an added dependency, or (:require 'clojure.string) if it is a built-in library! Note that something like (require '[http.async.core]) doesn't work because it is not built-in. So if you checked the documentation https://clojuredocs.org/clojure.core/require which only shows built-in examples, like me, you are doomed.
Also for built-in library like clojure.string you can use simply (require 'clojure.string), yup, the one which didn't worked with dependencies. Have fun guys! LOOOOONNG journey ahead, clojure is only language so far I needed to spend 4 days figuring out how to IMPORT modules (poke Python, it only took 30 seconds), hope it worth it!
You should require markdown.core. From the documentation for that project:
(ns foo
(:use markdown.core))
In your case:
(ns metapp.core
(:require [markdown.core :as mark]))
should work.
Not realising that the name of the library and the namespaces that make up the library are different things is something that is easy to be tripped up by.
markdown-clj is just a name of a package. But when you require something, you need to specify a module, not a package. Most of the packages have core module so the proper usage would be:
(:require [markdown-clj.core :as mark])

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.

What is the proper way to use a dependency?

Maybe I'm missing something or just reading outdated information. Basically, I'm trying to use the CSV lib here.
I've included it in my project.clj...
:dependencies [[org.clojure/clojure "1.3.0"]
[org.clojure/data.csv "0.1.2"]]
...and retrieved the libs successfully using Leiningen. Now, what would be the proper way to include this lib for use in my program? I've tried the example posted on the lib's Github page only to get an error stating:
FileNotFoundException Could not locate clojure/data/csv__init.class or clojure/data/csv.clj on classpath: clojure.lang.RT.load (RT.java:430)
EDIT: Further clarification on what I've tried: I have the code pasted under my namespace declaration, like so:
(ns testprogram.core(:gen-class))
(require '[clojure.data.csv :as csv]
'[clojure.java.io :as io])
Trying it in the REPL yields the same result. I'm pretty sure I'm trying to 'include' them wrong.
This test worked for me:
(ns test.csv-test
(:gen-class)
(:require [clojure.data.csv :as csv]
[clojure.java.io :as io]))
(defn main- [args]
(csv/read-csv "test"))
I also encountered the "FileNotFound: could not locate" issue while testing this out. It was a simple typo in my project.clj file. I recommend double-checking that.
Note: this also worked:
(require '[clojure.data.csv :as csv]
'[clojure.java.io :as io])
(defn main- [args]
(csv/read-csv "test"))
While using the :require directive in the ns macro is certainly a best practice, is is not the source of the issue here.
In both versions, REPL output:
user=> (in-ns 'test.csv-test)
#<Namespace test.csv-test>
test.csv-test=> (main- [])
(["test"])
Also tested with lein run and java -cp <uberjar> test.csv_test
You could try the following: note the :require is nested within the ns declaration. This is the preferred way of doing it.
(ns testprogram.core(:gen-class)
(:require [clojure.data.csv :as csv]
[clojure.java.io :as io]))
I think in your case you can get it to work with the following (not tested)
(ns testprogram.core(:gen-class))
(require '(clojure.data [csv :as csv])
'(clojure.java [io :as io]))
See the following desc
http://clojure.github.com/clojure/clojure.coreapi.html#clojure.core/require

Clojure namespacing converting - to _

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."