Get Clojure namespaces in current .jar file - clojure

I'm looking for a way to get a list of all the current namespaces in the current project, i.e. excluding namespaces in imported jars, libraries etc.
Currently I have found bultitude which seems pretty close to what I need and can do:
(bultitude.core/namespaces-on-classpath)
However this returns all the namespaces on the classpath, including "clojure.core" etc. rather than just the ones in the current project.
Is there an easy and reliable way to solve this?

what about the tools.namespace lib? there are the api:
find-namespaces-in-dir
find-namespaces-in-jarfile
find-namespaces-on-classpath

Well, it depends.
The idea behind bultitude is to provide a list of namespaces on the classpath. Any .clj files on that classpath will be accounted for.
You can, however, look up only namespaces beginning with a certain prefix. Usually projects also begin with a certain prefix in their namespaces. Would that work? Example from the readme:
user=> (b/namespaces-on-classpath :prefix "bultitude")
(bultitude.core-test bultitude.core)
If that isn't good enough, you can try to give it a classpath that only your files are on, but that may not work so well.
user=> (b/namespaces-on-classpath :prefix "bultitude" :classpath "src:test")
(bultitude.core bultitude.core-test)

Related

require all namespaces with a prefix

Hello fellow Clojurians,
I would like to make my Clojure project extensible by auto-loading its plugin namespaces from the classpath. I would like to solve it by require-ing every namespace that has a given prefix.
(require-all-ns 'module.custom)
;; this should require module.custom.video, module.custom.audio, module.custom.xxx, ...
Obviously all-ns does not work here as it only lists already loaded namespaces.
I can easily find all namespaces by walking the file system. But I want it to work when additional namespaces are inside a jar file on in an other directory on the classpath. I also need it to work when my program is packaged.
My question is: how to require every namespaces from the file system?
Thank you

Is there any way to force Clojure to map a parent namespace path to a certain directory?

I like that boot lets me put all my source files in the current directory. However, I would still like to develop code that refers to a parent namespace, to make it easier to import into other projects. For example, I'd like to make all my namespaces start with the same prefix, but still have their source files reside in the current directory, like this:
(ns polysyndeton.conjunctions ...) ; in ./conjunctions.clj
(ns polysyndeton.disjunctions ...) ; in ./disjunctions.clj
(ns polysyndeton.util ...) ; in ./util.clj
How can I tell boot or Clojure that any namespace starting with polysyndeton. should be found in the current directory?
I don't think it possible (without workarounds that are not recommended). Clojure uses the directory structure corresponding to the namespace segments to find source files on the classpath. So you must adhere to this structure.
Also see: What are common conventions for using namespaces in Clojure?
You can achieve this easily with a symlink. Note that this will map ANY strings like polysyndeton.polysyndeton.polysyndeton.{...}.util to the file util.clj:
ln -s . polysyndeton

Dealing with resources (copying) when building a ClojurScript project using leiningen

I have just begun playing with ClojureScript and I'd like to collect all CSS files into a single folder (out/css). I found leiningen-less and with the following config I get the compiled CSS files into the correct location:
:less {:source-paths ["src/less"]
:target-path "out/css"}
I can't find any documentation on how I can handle the ordinary CSS files (e.g. the file for resetting defaults, css/reset.css). Basically I want the equivalent of cp css/*css out/css.
I did find lein-resource but it does a bit more than I require (pass things through stencil) and more importantly it through an UnsupportedOperationException on my with what I thought would a be a valid configuration:
:resource {:resource-paths ["css" {:target-path "out/css"}]}
Please englighten me!
For your particular use case just rename reset.css to reset.less. less should be able to read CSS without problems.
For more advanced frontend tooling maybe consider adding something like make/grunt/etc. More complexity but more power & flexibility.
I think better and easy solution would be that you write a function that uses clojure.java.io library functions and integrate them with lein-less "compiler" fork, so this is my internal function proposal:
(defn your-fn[]
(remove-folder "./out") ;; => you have to do how to make that fn following io lib doc
(copy-folder "./css ./out") ;; ;; => you have to do how to make that fn following io lib doc
(run-compiler :javascript
{:project-root "your-project-root/"
:source-paths ["less"]
:target-path "out"})))
PS: note that you need to call this fn from your clojurescript compilation process, BTW I didn't know if there is a way for that :)

reload middleware that handles explicitly loaded source files

Ring comes with the middleware 'reload' (https://github.com/ring-clojure/ring/blob/master/ring-devel/src/ring/middleware/reload.clj). It's based on ns-tracker (https://github.com/weavejester/ns-tracker). ns-tracker looks through source directories for likely source files that begin with an ns form. It builds a dependency graph from the information contained in those ns forms. This of course works perfectly, but only for dependencies explicitly included in the ns form.
There's an idiom in Clojure where a namespace is broken into several files. There is a single source file that defines a namespace (with an ns form). This file can contain any number of top-level forms, but notably will include loads, normally at the top level but not necessarily I suppose. The files loaded begin with in-ns forms. This is not as obscure a technique as you might think... clojure.core uses it.
The contents of these loaded files do not in themselves constitute modules, nor can they necessarily be coerced into being modules (circular dependencies etc).
ns-tracker does not scan source files looking for load expressions nor does it look for in-ns forms. And the reasons are clear enough. But it really messes up my workflow since changes to the loaded files, obviously, will not reload the namespace.
Does anyone know if there's a library that deals with explicitly loaded source files? If there isn't something I'll hack something together (probably by writing some ugly macro around load) and make it available publicly.
Okay, answering my question... I have extended ns-tracker and submitted a pull request. It's less hacky that I expected, actually reasonably reasonable.
My fork is at: https://github.com/hutch/ns-tracker
There are a number of changes to ns-tracker included. Specifically to my question, it supports the usage of load/in-ns in the way used by clojure/core.
You can use this fork in your projects by using the leiningen 'checkouts' mechanism.

FileNotFoundException when making a jar file from the clojure file

I am trying to go through the process of creating a jar file from a simple clojure file. Below is my clojure code:
(ns app.first (:gen-class))
(refer 'clojure.core)
(defn -main [& args] (println "this program worked!"))
I am using these instructions to create the jar file: http://en.wikibooks.org/wiki/Clojure_Programming/Tutorials_and_Tips
I see the error "java.io.FileNotFoundException: Could not locate app/hello__init.class or app/hello.clj on classpath: (NO_SOURCE_FILE:0)" when I try to complete the (compile 'app.first) step.
The only difference between my attempt and the link is the name of my file (first.clj instead of hello.clj).
Can anyone see where I am going wrong? Or for that matter, all I want to do is learn how to create a jar from a clojure file, so if anyone knows of a better/easier way to do that, let me know.
It's better to use Leiningen for such tasks - it allows to maintain dependencies, and packs all necessary components into jar file
I'm rusty on this, but I heard about other people with similar problems.
I think it's helpful to remember that the classpath you indicate points to the root of your class tree, and package names end up creating subdirectories within that tree. Awkwardly stated, but I hope you get the idea. Thus, I think you need to do some kind of gymnastics with creating directories to match the "app.first" -> "/app/first" hierarchy.
Sorry, that's as close as I come to a sensible and useful answer. Hope this helps you.
EDIT:
The Prime Directive of Computer Science: It only works if you do everything right! I spent almost 10 minutes fiddling with this but was finally successful.
Here's what I needed to do to get your program to compile:
created a directory app, and within that, first.clj with your code.
checked for the *compile-path* by doing (pr *compile-path) within Clojure. It said "classes".
created a second directory classes parallel to app.
in the shell, did export CLASSPATH=.:./classes
in Clojure, did (compile 'app.first)
... and I found a bunch of class files in classes. JARring those should be a snap.
I found it very helpful to run (doc compile) because that reminded me of the requirement to have a directory to satisfy the requirement for a *compile-path*.