define project specific tasks in leiningen - clojure

Is there a way to define rake like tasks within a project for leiningen.
I want to define a custom task in leiningen project.clj which will invoke a function in my project namespace

You can define project-specific aliases, e.g.:
:aliases {"launch" ["run" "-m" "myproject.main"]
;; Values from the project map can be spliced into the arguments
;; using :project/key keywords.
"launch-version" ["run" "-m" "myproject.main" :project/version]
"dumbrepl" ["trampoline" "run" "-m" "clojure.main/main"]
;; :pass-through-help ensures `lein my-alias help` is not converted
;; into `lein help my-alias`.
"go" ^:pass-through-help ["run" "-m"]
;; For complex aliases, a docstring may be attached. The docstring
;; will be printed instead of the expansion when running `lein help`.
"deploy!" ^{:doc "Recompile sources, then deploy if tests succeed."}
;; Nested vectors are supported for the "do" task
["do" "clean" ["test" ":integration"] ["deploy" "clojars"]]}
You should be able to combine this feature with lein-exec plugin to define an alias to run arbitrary clojure code within your project:
:aliases {"dosmth" ["exec" "-ep" "(use 'myproject.main) (foo 42)"]}
Now you can use dosmth task with lein:
lein dosmth
which is just an alias to
lein exec -ep "(use 'myproject.main) (foo 42)"

Related

access library functions in leiningen REPL

For the development of a library I started from a lein project, invoked like so:
lein new mylib
if I call lein install now, I can access my library in other projects. But trying to immidiately test the functions I wrote failed:
lein repl
...
(dir mylib.core)
Exception No namespace: mylib.core found clojure.core/the-ns (core.clj:4008)
Do I have to add something to the project.clj file maybe?
In order to use a library you must cause the code to be loaded - that it be on the classpath is not sufficient.
You can do this easily in an ns declaration in a file of course, but in the repl it can be easier to use (require '[my-lib.whatever :as w]) after which one can call (w/foo) (w/bar) etc. as expected. You can also use (in-ns 'my-lib.whatever) in order to switch to the namespace, but this will not give you a good result unless you have previously used require or use or load-file etc. to get the definitions first.
Let's say you created a new library named clj-foo.
% lein new clj-foo
Start your repl.
% cd clj-foo
% lein repl
In the repl, load the main entry point to your library and switch to its namespace.
(load-file "src/clj_foo/core.clj")
(ns clj-foo.core)
Now you're in the clj-foo.core namespace, make sure to add back in the repl ns to get things like doc available.
(use 'clojure.repl)
That's it. You're all set to start calling functions in your library. Note that other library files will be available from the clj-foo.core namespace if they were loaded by namespace declaration at the top of clj_foo/core.clj. If not, then you'll need to invoke load-file with their path as well.
If you make changes in core.clj. You can invoke load-file again to pick up the new code. As you progress, you can use cider to facilitate loading of individual functions and files. But that's for another question. :)
You need to add a dependency to use your library from another project. To do this add a vector (a tuple-2) to the vector that is the value of the :dependencies key in the project.clj file. Here's an example:
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.clojure/core.async "0.2.371"]
[default-db-format "0.1.0-SNAPSHOT"]
[com.andrewmcveigh/cljs-time "0.3.14"]]
My own local library is called default-db-format. Its really no different to adding a dependency for com.andrewmcveigh/cljs-time.
As you say you can already do this, but are having trouble getting a REPL connection to the project of the library itself. When you go (in-ns 'some-path), you need the single quote in front of some-path. Note that some-path is a different thing to the name of your library.
Rather than use lein repl you can use the figwheel repl - if your project is setup with figwheel. My library has only one entry point and that is lein figwheel devcards. After that I had no problem going to a namespace and trying out a function:
cljs.user=> (in-ns 'default-db-format.core)
nil
default-db-format.core=> (check 1 2)
As noisesmith mentioned having a REPL in your IDE is the best setup. No fiddly typing just bring up pre-configured REPLs (per namespace) with the click of a button (or keystroke). Figwheel/Cursive setup instructions here.
I was also facing the same issue with the following configuration:
Leiningen 2.9.0 on Java 1.8.0_201 Java HotSpot(TM) 64-Bit Server VM
My file looks like this, and from the repl I desired to invoke the foo function
(ns cljtest.test
(:gen-class))
(defn foo [input]
(assoc {} "a" 123))
Both these approaches worked fine for me on the repl.
1)Switch to the appropriate name space:
cljtest.core=> (in-ns 'cljtest.test)
#object[clojure.lang.Namespace 0x90175dd "cljtest.test"]
cljtest.test=> (foo nil)
{"a" 123}
cljtest.test=>
2)Require the appropriate name space:
cljtest.core=> (require '[cljtest.test :as test])
nil
cljtest.core=> (test/foo nil)
{"a" 123}
cljtest.core=>

How i can add github/local dependencies with Boot (clojure)

For instance i want to fork some existing clojar, extend it and use in my project.
How i can do this w/o pushing to clojars/maven?
Interested in both options: link to github and local path.
Thanks!
UPD
What i want is to include some existing Clojure project as dependency, similar like ruby gem allows.
Is this possible with Boot? Or i always need to compile to java?
Here is how I have setup my fork of castra on the castra-simple example for hoplon.
https://github.com/hoplon/demos/tree/master/castra-simple
open shell
git clone castra:repo
in castra dir
file: build.boot
; ...
(def +version+ "3.0.0-SNAPSHOT")
; ...
boot watch build-jar
open new shell
git clone castra-simple:repo
in castra-simple
file: boot.build
(set-env!
:dependencies
'[
;; ...
[hoplon/castra "3.0.0-SNAPSHOT"] ;;forked repo
;; ...
]
:source-paths #{"src"}
:resource-paths #{"assets"})
;; ...
(deftask dev
"Build castra-simple for local development."
[]
(comp
(serve
:handler 'app.handler/app
:reload true
:port 8000)
(watch) (speak) (hoplon) (reload) (cljs-repl) (cljs)
;;forked repo
(checkout :dependencies '[[hoplon/castra "3.0.0-SNAPSHOT"]])))
boot dev
As i figured out with Boot you can specify source-paths:
(set-env! :source-paths #{"src", "../clj-mailgun/src"})
This is the only way to add other projects into your. (adding source-code, not .jar)
There is no way to specify github link - you should clone it manually and add to :source-paths path.
Please correct me if i am missing something.

difference in lein repl namespace for lein apps and libraries?

I have no trouble calling functions in lein repl from my namespaces when I have created a lein new app .... But I don't seem to be able to call functions in lein repl when I just create a library project via lein new .... Details follow:
When I create a lein app with, say lein new app my-app, and then, from the project directory (the directory that contains project.clj), I do lein repl. The repl leaves me in the namespace my-app.core
my-app.core=>
I can now call functions in the repl, even functions defined in side files.
my-app.core=> (-main)
; Hello, world!
my-app.core=> (my-app.anotherfile/foo)
; Hey, there; this is foo from anotherfile
so long as I :require [my-app.anotherfile] in the ns macro of core.clj.
Ok, great; now I would like to do similarly with a lein library. So I lein new my-lib, then lein repl, and I'm in the user namespace:
user=>
huh? Ok, well, my lib contains a function that I want to call (this is just the one that leiningen creates by default)
(ns my-lib.core)
(defn foo
"I don't do a whole lot."
[x]
(println x "Hello, World!"))
I try
user=> (in-ns 'my-lib.core)
my-lib.core=> (foo 42)
; CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1:1)
nope. How about this?
user=> (my-lib.core/foo 42)
; ClassNotFoundException two-files-lib.core java.net.URLClassLoader$1.run (URLClassLoader.java:202
aha! Different error, but still no cure in sight. lein compile and lein javac don't seem to do anything either.
I have been unable to find or deduce the correct incantations in the docs or online and would be grateful for advice.
In a default lein new project you need to require the namespaces you wish to use explicitly -- (require 'my-lib.core). in-ns simply creates a new empty namespace of the given name if it doesn't already exist, it doesn't load any code from the classpath.
App projects do this automatically and switch to the main namespace in the REPL task, because they have a :main foo.core entry in their project.clj by default. It's possible to do it for a library, but you shouldn't -- as a side effect, it causes AOT compilation of the main namespace, which is generally undesirable.
Instead, in lein2 you can use :repl-options {:init-ns my-lib.core}.

How to run/debug compojure web app via counterclockwise (or la clojure)

I'm trying to write my first web app in compojure. I'm using ccw, and I File-New-Project, Clojure Project and use the "compojure" leiningen template. End up with project.clj looking like
(defproject asdf "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]]
:plugins [[lein-ring "0.8.2"]]
:ring {:handler asdf.handler/app}
:profiles
{:dev {:dependencies [[ring-mock "0.1.3"]]}})
src/asdf/handler.clj looks like
(ns asdf.handler
(:use compojure.core)
(:require [compojure.handler :as handler]
[compojure.route :as route]))
(defroutes app-routes
(GET "/" [] "Hello World")
(route/not-found "Not Found"))
(def app
(handler/site app-routes))
I found I can run this using lein ring server from the command line, but I'm not sure how to run this from eclipse. I'm of course hoping to be able not only to run it, but also to debug it and set breakpoints and such. Is there a way to do this in eclipse? Or, if not, how about IntelliJ/La-Clojure? (I'm a bit afraid of emacs, for now, but maybe if it's super-simple I'd give it a try).
Or, is this just not the typical development process for a compojure app? (If not, what is? Just run lein ring server and pray?)
If it makes a difference this is on Win7.
Here's a recipe that's work great for me while developing Ring applications:
Ensure you have leiningen support properly configured for your projet (do it once if in doubt):
in the package explorer, select the project, and invoke the contextual command Leiningen > Reset configuration
then also invoke the Leiningen > Update dependencies command
you should see a Leiningen Dependencies virtual node in your project, referencing the direct and transitive dependencies of your project
Select the asdf.handler file, right click and then Debug as > Clojure Application
Open the asdf.handler namespace in an editor
With the cursor currently still in the editor, type Ctrl+Alt+N to jump to the REPL and switch the REPL's current namespace to asdf.handler at the same time
Start the app by typing (app) + Enter (or Ctrl+Enter if your cursor is not at the end of the line)
You can now navigate between the editors and the REPL.
To send editor content to the REPL, select it, and hit Ctrl+Enter
If you hit Ctrl+Enter without a selection, the whole 'top level expression' (e.g. a defn) will be sent to the REPL
To resend the whole file to the REPL, type Ctrl+Alt+S
the whole list of keyboard shortcuts specific to CCW is here: http://code.google.com/p/counterclockwise/wiki/EditorKeyBindingsFeatures
Note that a future version of Counterclockwise will integrate a little bit more with Leiningen 2, but as it currently stands, the very nature of developing ring applications make it not so painful to bootstrap things as described above, IMHO
You can run Compojure/Ring apps on IntelliJ IDEA and La Clojure with the following steps:
Generate pom.xml from leiningen's project.clj using lein pom command.
Import maven project with IntelliJ IDEA as usual. You might want to make sure that you have Clojure jar in classpath.
Once the project is loaded, you can start Clojure REPL using Tools -> Start Clojure Console.
To load a Clojure file to REPL, select Tools -> Clojure REPL -> Load file to REPL.
After that, to start a Ring app you can just load a Clojure file that invokes ring.adapter.jetty/run-jetty.
The code to run a simple route on http://localhost:4004/ would look like this:
(require 'compojure.core)
(require 'ring.adapter.jetty)
(ring.adapter.jetty/run-jetty
(compojure.core/routes (compojure.core/ANY "/" [] "Hello world!"))
{:port 4004 :join? false})
:join? option is important, if it would be set to true (the default), the REPL would not accept more commands. Your routes will usually be more complex and compojure.core/defroutes or other means should be used.
You can put such file in test path, so it wouldn't be loaded when running the project outside of IDEA.
If Clojure facet is not added to your module, you can add it in File -> Project Structure -> Modules.
A complete sample (with jetty reloading) is available here: https://github.com/tlipski/ganelon-demo - development is done with IDEA and real site runs on Heroku: http://ganelon.herokuapp.com.
Debugging Clojure apps run with the technique above is possible as well - you just have to:
Create Remote debugging Run profile in IntelliJ IDEA
Add apropriate JVM options from a profile above (e.g. agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005) to REPL settings in File -> Project Structure -> Modules -> [your module] -> Clojure facet -> JVM Arguments field.
Start REPL with Tools -> Start Clojure Console.
Start Remote debugging profile.
After that, you can add breakpoints, inspect variables, etc.

Standalone clojure app

I'm a beginner with clojure, only starting it yesterday.
I have gathered that a simple way to create a standalone app is with leiningen lein new foo.
I tried to create a hello world test project with leiningen. I added :main and :aot directives to project.clj, added :gen-class to the core.clj file and tried lein run, but I get errors about class definition not found.
Exception in thread "main" java.lang.NoClassDefFoundError:
Caused by: java.lang.ClassNotFoundException:
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
The core.clj file
(ns test.core
(:gen-class))
(defn -main [& args] (println "Hello main"))
And the project.clj file
(defproject test "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:main test.core
:aot [test.core]
:dependencies [[org.clojure/clojure "1.2.1"]])
Edit: After further testing, it seems like copying the project to my desktop works as is, which I think points to that the environment on my laptop is somehow borked, but I don't know how.
The environment on desktop is clojure from repositories and leiningen from AUR. On laptop the clojure is from clojure.org and leining is from github.
[UPDATE April 2013]
Leiningen 2, which has been officially released for some time, includes the concept of project templates. By default, Leiningen provides an app template that provides what you need out of the box. Try:
lein new app my-project
You will see that Leiningen creates the familiar project template, but also includes:
The default namespace of my-project.core as the :main entry in your project.clj file
The :gen-class form in the namespace declaration of my-project.core
A default -main function in the my-project.core namespace
For those who cannot yet use Leiningen 2, the lein-newnew plugin provides an equivalent experience under Leiningen 1.
[/UPDATE]
To build a project that, when run, prints "Hello World!", you'd do as follows (revision of your process above):
Setup
lein new my-project
cd my-project
lein deps
You should now have a basic structure in place and the Clojure jar in your lib folder.
Write a Function
Now edit src/my_project/core.clj with your editor of choice, adding the following below the (ns ...) form:
(defn -main []
(println "Hello World!"))
This function is inside your my-project.core namespace. To ensure this gets run as your main, let's add a gen-class parameter to your namespace definition at the top, so that it now looks like this at the top of core.clj:
(ns my-project.core
(:gen-class :main true))
So all together, your core.clj file looks like this:
(ns my-project.core
(:gen-class :main true))
(defn -main []
(println "Hello World!"))
Configure it as the Main Function
Once you've got src/my_project/core.clj edited as above, you need to tell Leiningen (the build tool) where the "main" function for your project lives. Here's an example defproject form that does this:
(defproject my-project "1.0.0-SNAPSHOT"
:description "My Project"
:dependencies [[org.clojure/clojure "1.2.1"]]
:main my-project.core)
Now the -main function inside my-project.core becomes the entry-point for your program.
Run It
You can now have two options for running this project:
Use lein run at the command-line while at the root of your my-project project
Create a standalone jar file by running lein uberjar. You can then run the resultant jar file by running java -jar my-project-1.0.0-SNAPSHOT-standalone.jar
Figured it out. I had the latest leiningen from git, which was borked somehow. I checked out the 1.6.1 tag and ran self-install, and now it works.
I missed it, You named your project test, you can't do that change the name to something else it will work.
You say above
lein new foo
what you mean is
lein new test