How to run library's `main` with Leiningen? - clojure

I had used some library, let's say it is Clojure itself (which is always added to project.clj). Clojure provides clj CLI tool (which is src/cli/clojure/main.clj, but nevermind). How to use it with lein? I mean, is there any command/plugin/technique which will allow me to use library's main?

Every Var in every namespace is equal in the eyes of Clojure. From your code, just execute like:
(some.awesome.lib/-main ...)
or whatever the fully-qualified symbol pointing to the Var in question.
For further details, please see this question:
When to use a Var instead of a function?
Also
See the output of
> lein help run
Using lein, you can type
lein run -m my.awesome.proj/some-fn
or
lein run -m some.awesome.lib/-main
since to Clojure some.awesome.lib/-main is no different than any other function (the hyphen prefix on -main is just a convention and makes no difference to the Clojure compiler).
You can also set up project.clj to automatically call any function of your choosing when you type lein run by adding:
:main some.awesome.lib/-main

Related

What is the easiest way to load a clojure library all the time?

A question from an utter newcomer to clojure: What if I want to be able to start a clojure REPL from anywhere, for example because I just want to compute an exponent? How can I set up my system to do this? (I've deleted earlier links to not-quite-answers because they were cluttering up the question.) The Pomegranate documentation linked by #Jared314's answer below helped me see that I can do this:
~$ lein repl
...
user=> (use '[cemerick.pomegranate :only (add-dependencies)])
nil
user=> (add-dependencies :coordinates '[[org.clojure/math.numeric-tower "0.0.2"]])
{[org.clojure/clojure "1.3.0"] nil, [org.clojure/math.numeric-tower "0.0.2"] #{[org.clojure/clojure "1.3.0"]}}
user=> (use 'clojure.math.numeric-tower)
nil
user=> (expt 2 3)
8
Yay!
Now how can I make this happen every time I start the REPL, no matter what subdirectory I'm in?
I think I'm just ignorant of basic clojure setup. Sorry about that.
Second major edit:
I've figured out that if I use raw clojure without lein, I can execute commands on startup of the repl. For example, if the file .clojurerc contains the text (print "Yow!\n"), I can do this:
~$ java -cp /usr/local/lib/clojure-1.5.1/clojure-1.5.1.jar clojure.main -i .clojurerc -r
Clojure 1.5.1
Yow!
user=>
Can I do something like this with lein? Or maybe better yet, load clojure.math.numeric-tower automatically in clojure without using lein (since for simple command line experimentation, lein's startup is slower than starting clojure directly).
(It may seem as if I'm not trying to solve this on my own, but I that's not so. I have been doing web searches and experimenting, but I keep hitting brick walls. I'm starting to feel as if clojure is only intended for full-blown programming projects. I had assumed that it could be good for add-hoc experiments and calculations (as lisps traditionally are but Java is not). I'm not trying to incite arguments. I'm just frustrated. There ought to be a simple, well-known formula for doing what I'm trying to do.)
When you want external dependencies you will need either a new project, lein new testproject1, the lein-oneoff plugin, Pomegranate, a Leiningen profile :dependencies entry, or some specific IDE feature. (I know at least LightTable allows external dependencies in their Instarepl, so I assume you can do it in Emacs and CCW.)
It might be best to start with creating a new test project so you can see the project.clj layout. But, if you just want a one-off library in a repl, take a look at the instructions for Pomegranate's add-classpath command. Pomegranate is accessible by default in the lein repl, so their example should work without anything extra.
Edit:
From your updated question, it sounds like you want a persistent repl dependency. You can add [org.clojure/math.numeric-tower "0.0.2"] to your ~/.lein/profiles.clj profile file, under the :repl profile.
{:user {}
:repl {:dependencies [[org.clojure/math.numeric-tower "0.0.2"]]
:repl-options {:init (use 'clojure.math.numeric-tower)}}}
Then when you run lein repl:
(expt 2 3) ;=> 8
Looking at this question a few months later, I realized that I settled on a different solution, but never posted it. I now leave references to math.numeric-tower out of both .clojurerc and .lein/project.clj, since I don't need it for most Leiningen projects. And when I want to use Clojure for quick calculations, I start Clojure via a shell script without Leiningen to avoid slow startup. This is what's in the shell script:
#!/bin/sh
jars=/usr/local/lib/clojure-1.5.1/clojure-1.5.1.jar:/usr/local/lib/clojure-1.5.1/math.numeric-tower-0.0.2.jar
while [ "$1" != "${1%.jar}" ]; do # while param is a jar file
jars="$jars:$1"
shift
done
jars="$jars:."
exec rlwrap java -cp "$jars" clojure.main -e "(use 'clojure.math.numeric-tower)" "$#" -r
The middle part allows you to add jars on the command line, but in practice I don't find that useful, given that I use Leiningen for ongoing projects. Someone else might find that part of the script useful, though. rlwrap is a utility that gives you command line history, though it's not as good as what Leiningen provides, for my purposes.

How to extract Clojure REPL history

I have written some code within the plain console REPL of Clojure (lein repl). Now I would like to extract the history in order to get the code that I have written in there. Can I do this somehow?
Each Leiningen project stores its REPL usage history in the .lein-repl-history file. There's a global repl-history file as well, located at ~/.lein.

Pass argument to leiningen readable by project.clj

I have a project.clj file that I want to use differently depending on an argument passed in when called by leiningen. Here is my hypothetical sample project
(defproject simple "0.0.1"
:source-paths [(get-argument "source.path")])
(In this case get-argument would simply call System/getProperty). I would use this file like this,
lein2 compile -Dsource.path=path/to/location
The problem is two-fold,
I don't know how to pass an argument to leiningen. It doesn't accept the -Dkey=value syntax. I couldn't find anything in documentation about passing optional/extra arguments. Am I missing something obvious?
The subforms inside defproject seem to be handled a special way. I couldn't find an easy way to put code into it.
I have found some approaches
https://github.com/weavejester/environ looks promising, but it seems to work only in proper clojure code, not inside project.clj
https://groups.google.com/forum/?fromgroups=#!topic/leiningen/t8G6Et1_j8w -- this is a workaround that may solve half of the problem
What is an elegant way to set up a leiningen project that requires different dependencies based on the build platform? gives some idea how to eval code in project.clj
https://github.com/sattvik/leinjacker promises to do some dirty tricks, but I couldn't make it work in my environment
(What I actually want to use it for is that I have a clojurescript project with different artifacts. While it's possible to configure different builds for it, they all share the same crossovers.)
One approach that is convenient on unix-like platforms is to use an environment variable, combined with lein's willingness to evaluate expressions marked with a tilde in project.clj files. So for your example, you could provide a project.clj like:
(defproject simple "0.0.1"
:source-paths [~(System/getenv "MY_SRC_PATH")]
:dependencies [[org.clojure/clojure "1.5.0"]])
...then set the environment variable when launching lein like this:
MY_SRC_PATH="s2" lein compile
I don't know how well this approach would work on Windows.

Changing Cake's current directory

Is it possible to configure Cake such that, if test.clj looks like this:
(use 'java.io.File)
(println (.getAbsolutePath (File. ".")))
running cake run test.clj will print the current directory, not /home/retief/.cake/. ?
Running clojure test.clj works properly, with my custom (and very simple) clojure script, but this requires me to start a new jvm every time. Being able to use cake to avoid this and keep my current directory would be useful.
I recognize that using cake within an actual clojure project sets the current directory to the project root, but I am trying to find something that would work for more general scripting tasks.
Cake's persistent JVM doesn't see what directory the client-cake-process is in at the time of your call because the JVM is already running. It will likely be simpler to design your scripts to take the path as an argument.
ps: Cake and leiningen are merging anyway.

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