Say I made a change to a Clojure library (eg. added a parameter to the request-token in clj-oauth) and want to use that changed library in my project. What's the best way to do this, short of compiling the new library as a JAR and copying that to my project lib?
I want to be able to tweak the library and my project at the same time (preferably in the REPL). If I were doing this in Ruby, I would download and 'require' the gem, then reopen that class in my own project source and add or override the methods as needed.
You can hack directly at the REPL. Suppose you've got incanter on your classpath.
Start a REPL. The first thing we need to do is bring the incanter classes into it.
user> (require 'incanter.core)
nil
Now we can see the function incanter.core/matrix?
user> (incanter.core/matrix? 2)
false
We can look at the original source code:
user> (require 'clojure.repl)
nil
user> (clojure.repl/source incanter.core/matrix?)
(defn matrix?
" Test if obj is 'derived' incanter.Matrix."
([obj] (is-matrix obj)))
nil
Let's go and screw it up:
First change to the incanter.core namespace:
user> (in-ns 'incanter.core)
#<Namespace incanter.core>
Then we can redefine it, using the old source code as a crib:
incanter.core> (defn matrix? [obj] "hello")
#'incanter.core/matrix?
Unit test:
incanter.core> (matrix? 2)
"hello"
Switch back to the user namespace:
incanter.core> (in-ns 'user)
#<Namespace user>
Try it out:
user> (matrix? 2)
; Evaluation aborted.
There is no definition of user/matrix. We redefined it in the incanter.core namespace.
user> (incanter.core/matrix? 2)
"hello"
For experimenting at the repl, it's ok just to change source files and re-compile the single file (C-C C-k in emacs), or if you're in the right namespace, just re-evaluate the definition.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Now, if we want to make our valuable change permanent and available to other projects, it depends on how everything is set up.
I use maven for dependency management, so it would be a question of modifying the source file, and then re-running the build process for the library to compile the new version and install it into the local maven repository.
With a maven project, that should be as simple as
$ mvn install
A note about version numbers:
If you do make permanent modifications and use dependency management to coordinate the differences, then you should change the version number of your library, from maybe 1.2.0 to 1.2.0-johnshack-SNAPSHOT, or something that is unlikely to collide with the real thing when you want to use an unperverted version in another project. You wouldn't want a modified version finding its way into projects where it isn't welcome.
Then you modify your own project files to make sure that you use the hacked version where you want to, and the next time you start your repl, it should pull in the last hack that you installed.
You will need to reinstall again every time you want your changes to make their way into the repository, but that's actually probably a good thing.
Unfortunately, (and it was at this point that I started to wish that I had chosen a different example) Incanter turns out to be a leiningen project which is split into sub-modules in an ad-hoc scripty sort of way, so we need to figure out how it expects to be installed. The figuring out turned out to be quite hard, although the answer is easy. Leiningen sets my hair on fire.
You can get incanter's source here:
$ git clone http://github.com/liebke/incanter.git
and the relevant source file is:
~/incanter/modules/incanter-core/src/incanter/core.clj
Modify it to break the matrix? function, and then it turns out that what you have to do is:
Change the version numbers in both the top level project.clj, and also in the submodule project.clj.
Then you run lein install in the incanter-core directory, and then again in the top-level directory, and you have to do it in that order. I don't quite understand why.
At the moment all this seems needlessly complicated. I'm (fairly) sure that it will settle down as the tools mature.
If you're using (or wouldn't mind using) cake, check out the subproject dependencies section of the README. I think it might be exactly what you're looking for.
You upload it to clojars under a different name depend on that.
Related
I am using lein repl without a project so there is no project.clj.
I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js
on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.
Is this a dependency that I still need to install? If so, how do I install it without going through a project?
I don't understand the JVM as I am new to it, so add a little extra information in your answer.
I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.
I am using lein run without a project so there is no project.clj.
If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.
clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]]
You can also use the lein deps command if you only want to fetch dependencies.
You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?
You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.
If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.
For example, using Clojure CLI tooling:
$ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
Clojure 1.9.0
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:foo "bar"})
"{\"foo\":\"bar\"}"
user=> (System/getProperty "java.class.path")
"src:
/Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
/Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
/Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
/Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.
This is a great opportunity to use lein try. Once you add it to your ~/.lein/profiles.clj, you'd simply run: lein try org.clojure/data.json and you'll be greeted with a running REPL with that dependency just a require away.
I am very new to both Clojure and Leiningen. I have installed Clojure on Windows at C:\clojure-1.5.1 and leiningen-win-installer beta1 at C:\.lein\bin.
Now I am trying the example from Eric Rochester's book. I have included dependent libraries for Incanter in project.clj and also using dep.
How do I use the command (use 'incanter.core)? I am getting 'use' is not recognized as an internal or external command. In addition, how do I use lein commands at user=>?
Edit - I forgot "lein deps" until I saw Mars's answer
Before you start lein repl, you have to make the project (with "lein new getting-data" or whatever is in the book).
That makes a new directory, and in that directory you find and edit "project.clj" to include the dependencies (as shown in book).
cd into the directory that project.clj is in and run "lein deps" from the dos/powershell prompt.
THEN when you run lein repl, from within that same directory, at the user=> prompt, do
(use 'incanter.core)
and it will come back with "nil" and you'll be running. You might want to first run some examples from the leiningen page to get more of a feel for lein. You always type clojure commands at the "user=>" prompt, not at the "c:....>" prompt.
There's a bit of subtlety in Leiningen project.clj's. I haven't found an easy introduction. Levin Magruder's advice will no doubt get you started. The basic idea is that once the project file is set up correctly, lein deps will go out and find the libraries you need, and put them in a place where lein repl can find them. Then use will work for the libraries that have been downloaded. For more info, study of the detailed comments project.clj sample file may be helpful. (Not part of the answer to this question, but if you're having problems with use, you're likely to get tripped up by ns and filenames soon (I was): I recommend Colin Jones' introduction to ns and its options.)
I'm new to Clojure and Leiningen, and I've determined that some of what I'll want to use is located in clojure.contrib.generic.math-functions. I found API information for that at http://richhickey.github.com/clojure-contrib/branch-1.1.x/math-api.html, but I can't find anything that helps me figure out what I should put into my project.clj file for that dependency.
I have tried [clojure.contrib.generic.math-functions "1.1"], [clojure.contrib.generic.math-functions "1.1.x"], and [clojure.contrib.generic.math-functions "1.1.0"]. For each of those, I get something like...
...
Caused by: org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException: Missing:
----------
1) clojure.contrib.generic.math-functions:clojure.contrib.generic.math-functions:jar:1.1
All clojure-contrib namespaces are shipped within a single jar file, for which the dependency has to be listed like:
[org.clojure/clojure-contrib "1.2.0"]
Please note that there are different versions available of that artifact. The 1.2.0 is the current stable release.
In order to use functions coming from the math-functions namespace in your clojure code, you need to either require or use such namespace, usually done within the ns form at the beginning of your source file:
(ns my.namespace
(:use [clojure.contrib.generic.math-functions]))
Have a look here to see the differences between use and require.
The next version of Leiningen will have a search task for precisely this purpose. It will search Clojars, Maven Central, and any other repositories your project has listed, provided they offer up downloadable indices. It's already implemented, so if you run Leiningen from git you can use it.
Also, the Leiningen tutorial covers this. Type "lein help tutorial".
You can generally find what you need at clojars.org - it's the default repository for leiningen. The current stable release of Clojure is 1.2.0, so you'd have this in your leiningen project.clj:
[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
To use the generic math functions in your clojure, require or use it in your namespace declaration at the top of your source file:
(ns your-namespace
(:use [clojure.contrib.generic.math-functions :as mathf]))
This allows you to refer to the functions in that namespace like this:
(mathf/abs -10) ;; => 10
:use-ing namespaces with :as is the preferred way to use functions from other namespaces in your code. require is ok, but you'd have to prefix your functions with the entire namespace (e.g. clojure.contrib.generic.math-functions/abs) so that's not practical. Using a namespace without :as allows you to use these functions without any prefix at all (e.g. abs), but you're more likely to get namespace clashes and it might be difficult to see where functions come from, especially if you :use many libraries.
You can browse all libraries available from the default leiningen repository by checking out http://clojars.org/repo/. The structure of clojure-contrib will change when 1.3.0 is out, so you'll have to include the specific contrib library if you're using version 1.3.0-alpha-xx:
[org.clojure.contrib/generic "1.3.0-alpha4"]
Now that the clojure.contrib has been broken up, the math functions are in something called math.numeric-tower. The lein dependency is specified like this:
[org.clojure/math.numeric-tower "0.0.1"]
You can use or require as seems appropriate, for example
(use '[clojure.math.numeric-tower])
I'm trying to set up a simple clojure project, and I'm not sure how to load files between the project. I'm sure that the answer is in the documentation, but I can't find a simple answer any where and I'm not sure where to look.
Essentially, my directory looks like this:
Clojure/
clojure/
clojure.jar
other clojure files
clojure-contrib/
clojure-contrib.jar
other contrib files
project/
main.clj
utils.clj
And I want main.clj to be something like this:
(ns project.main
(:require project.utils))
(greet)
and utils.clj to be something like this:
(ns project.utils)
(defn greet [] (println "Hello, World!"))
But that fails with:
Exception in thread "main" java.io.FileNotFoundException: Could not locate project/utils__init.class or project/utils.clj on classpath: (main.clj:1)
When I attempt to run it. My classpath includes the top Clojure/ directory and both jars. I also tried putting the project/ directory in the classpath as well, with no luck.
How do you set up a simple clojure project?
You don't mention what your environment is (i.e. Emacs/SLIME/Swank, vim/Vimclojure), so I'm going to assume you are trying to invoke it from the command line.
You need to have your Clojure/ project directory in the classpath:
java -cp path/to/clojure.jar:path/to/clojure-contrib.jar:path/to/Clojure ...
Make sure to check that paths are correct relative to current working directory. It needs to point to the root of your namespace (i.e. if running in Clojure/, the path is .).
In fact, your project layout Works On My Machine(tm), with the exception that I have use instead of require (but you should've got a different error anyway if you got to the point when Clojure could find all your files).
This answer I posted to another question should hopefully give you an idea of how your filenames should relate to namespace names for things to work. However, since your question is "how to set up a simple Clojure project", the following is a better start:
Go to GitHub and grab Leiningen.
Follow the instructions in the README. You'll end up doing something like
$ lein new my-project
$ cd my-project
# ... edit project.clj ...
$ lein deps
Hack away! You'll need to put your files in the correct places. That will mean putting your source files in the directory tree rooted at my-project/src, with your core namespace most likely residing at my-project/src/my_project/core.clj. But really, I've explained all the details in the answer linked to above, so please read it (and do leave a comment if I missed something). :-)
Leiningen will take care of the basic project layout and setting up the classpath for a REPL / swank / nailgun for you (if you haven't yet come across the latter two, you will soon -- but that's a separate topic, the swank part of which I have covered to a certain degree e.g. in this SO answer), so hopefully you'll never need to deal with the java -cp ... nonsense by hand. (The swank-related answer I linked to in the last parenthetical remark has details on how to set up swank with the correct classpath from within Emacs.)
I'm using emacs with clojure-swank and slime and trying to set my development environment. And I ran into a problem. When I start a repl I'm stuck in an unknown directory preventing me to load my namespace. Because the clojure repl can't find the right file.
Does anyone know how to change the current directory?
PS: I've just started using emacs and slime so I'm a noob.
If you want to change slime's notion of the current directory, press ,cd<CR> (<CR> = Enter) and type in the path.
However, this is not really the proper solution to the problem. The proper solution involves setting up the classpath so that you can (use 'your.namespace). To this end, I wonder if this very long answer I provided to a question about setting up the classpath properly might be helpful... :-)
Incidentally, I somewhat object to solutions involving add-classpath, as that is currently marked as deprecated and was never meant to be relied upon in the first place... Though on the other hand, it certainly may work perfectly well and it's worth knowing about just in case it might come in handy as a quick-and-dirty classpath injection gimmick.
Now if you want a real nice SLIME-based development environment, I'd like to point you to a very nice clojure-project elisp function by Phil Hagelberg which sets up all relevant variables and launches SLIME in the main directory of a project (to be supplied interactively). It's been posted to the Clojure group, in fact here's a link to the Mail Archive's copy of that message. Note there's one thing which needs correction in there -- swank-clojure-jar-path ought to be set to the full path to clojure.jar. Otherwise it's a fantastic tool.
Actually I mentioned that function in this response to a question about managing the classpath when using Clojure and Emacs. The other answers might be interesting as well.
And if you're only just beginning to use SLIME, do watch the SLIME video, linked to from SLIME's homepage which is now available under a link posted by Michiel in the comments. It's a very good introduction. :-)
Leiningen is a new Clojure build tool that worries about classpathing for you. You set up a simple project file in the project's root directory to specify the main class of your project, and it automagically discovers all the JARs in your lib directory and loads them for you.
I now just type "lein swank" at a command line and then M-x slime-connect in Emacs, and everything just works. (This could easily be automated with a little Elisp.)
More info in this blog post.
Short answer:
(load-file "full-path-to-definition")
Long answer:
Here's what my bootstrapping process looks like:
In ~/.clojure/user.clj (this file is auto-run when you boot slime/clojure):
(add-classpath "file://path/to/foo.jar") ; Include these jars in the classpath
(add-classpath "file://path/to/foo2.jar")
(load-file "file://workspace/bootstrap.clj")
In bootstrap.clj:
(compile 'my.package)
Package file(s) is at /workspace/my/package.clj
In package.clj:
(ns my.package)
(defn foo [] (+ 2 2))
The best approach I've found when using Emacs, SLIME and swank-clojure is to use the (Emacs Lisp) function swank-clojure-project. From its documentation:
(swank-clojure-project PATH)
Setup classpath for a clojure project and starts a new SLIME session.
Kills existing SLIME session, if any.
If you do a "M-x swank-clojure-project", it will interactively prompt you for your project directory; once you've selected it, all the jars in a lib subdirectory, as well as the src and classes folder will be added to your classpath. It will also honor a Maven/lein directory structure, in other words: it will usually just work.
If you change something, e.g. add a new jar file, simply do swank-clojure-project again.