Can I lookup things within a Lein Project in the REPL? - clojure

Say I have a vanilla project.clj like
(defproject myservice "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:mailing-list {:name "myservice#example.com" :post "myservice#climate.com"}
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[ring/ring-core "1.4.0"]
[ring/ring-jetty-adapter "1.4.0"]
[compojure "1.4.0"]
[ring/ring-defaults "0.1.5"]
[org.clojure/tools.logging "0.3.1"]
[clj-http "2.0.0"]]
:plugins [[lein-ring "0.9.7"]]
:ring {:handler myservice.core/standalone-app
:port 3000}
:profiles {
:uberjar {:ring {:handler myservice.core/app}}}
)
In a lein repl, can I lookup values from the project.clj? How? Of course my blind hack didn't work?
user=> (:mailing-list project)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: project in this context, compiling:(/private/var/folders/1g/fnytl2x93sx6hp2f1rsf4h1r5xtqv_/T/form-init6671981825845237047.clj:1:1)
The follow on question is can I use stuff from the project map further on in the project.clj? Like if I wanted to pull that mailing list :name out and substitute it in as a :deb :maintainer?
:deb
{:toDir "target"
:package "mysevice"
:maintainer {:name "Meeples", :email "myservice#example.com"}
...
}
I'm sure you can tell, I'm kind-of new to this, but the project.clj is just executable Clojure, no? If I knew the name of the project's map, I should be able to query it, right?

You can def data as you usually would and include them using ~
(def mailing-list {:name "myservice#example.com" :post "myservice#climate.com"})
(defproject myservice "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:mailing-list ~mailing-list
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]
[ring/ring-core "1.4.0"]
[ring/ring-jetty-adapter "1.4.0"]
[compojure "1.4.0"]
[ring/ring-defaults "0.1.5"]
[org.clojure/tools.logging "0.3.1"]
[clj-http "2.0.0"]]
:plugins [[lein-ring "0.9.7"]]
:ring {:handler myservice.core/standalone-app
:port 3000}
:profiles {
:uberjar {:ring {:handler myservice.core/app}}}
:deb {
:toDir "target"
:package "mysevice"
:maintainer {:name "Meeples", :email (:name ~mailing-list)}})

This is the relevant line in leiningen : https://github.com/technomancy/leiningen/blob/b29b2ea41b6d177a8a57493b979164eab0931e4d/leiningen-core/src/leiningen/core/project.clj#L405
Given the namespace is leiningen.core.project, the map should be under it.

Related

FileNotFoundException with Leiningen and Ring

I'm currently using Leiningen and Ring through the command line on a project I'm making called reagent_test, and I ran into a problem:
C:/...reagent_test>lein ring server
... huge chunk of errors
Caused by: java.io.FileNotFoundException: Could not locate reagent_test/core__init.class or reagent_test/core.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.
... more errors
If anyone wants a gist for the issue, I'll make one if needed.
The problem is, the files are all in the right place. Here's my project.clj:
(defproject reagent-test "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:plugins [[lein-cljsbuild "1.1.5"]
[lein-ring "0.10.0"]]
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.456"]
[ring "1.4.0"]
[leiningen "2.7.1"]
[reagent "0.6.0"]
[garden "1.3.2"]]
:cljsbuild {:builds {:app {:source-paths ["src/cljs"]}
:compiler {:output-to "resources/public/main.js"
:pretty-print true}}}
:ring {:handler reagent-test.core/-main})
And my project structure is like this (at least, for the relevant files):
src:
clj:
reagent_test:
core.clj
cljs:
reagent_test:
core.cljs
project.clj
In both core.clj and core.cljs I have this as my namespace:
(ns reagent-test.core)
NOTE: Folders have a colon and files don't.
In the namespace declaration at the top of the file you should use a dash:
(ns reagent-test.core)
Whereas the file (and all the directories above the file) should use underscores. So the filename should be whatever/reagent_test/core.clj or whatever/reagent_test/core.cljs.
As Chris Murphy has pointed out in the comments of his answer. Since you have changed your project directory structure a little, you will need to modify your project.clj file:
(defproject reagent-test "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:plugins [[lein-cljsbuild "1.1.5"]
[lein-ring "0.10.0"]]
:source-paths ["src/clj"]
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.456"]
[ring "1.4.0"]
[leiningen "2.7.1"]
[reagent "0.6.0"]
[garden "1.3.2"]]
:cljsbuild {:builds {:app {:source-paths ["src/cljs"]}
:compiler {:output-to "resources/public/main.js"
:pretty-print true}}}
:ring {:handler reagent-test.core/-main})
The addition is the :source-paths key which should specify the directory for the Clojure code. By default lein uses the src directory as the root for the Clojure source files.

Compiling ClojureScript from cljc files with lein

Does cljc / lein / clojurescript work yet?
I was previously using cljx, and was able to compile the same project with the cljx plugin for lein firing off a cljsbuild task.
Now I'm switching to cljc, I want to compile my cljc files into both compiled Java and into javascript for use in the browser.
Here's my current project.clj file
(defproject com.mysite/myproj "0.3.2-SNAPSHOT"
:description ""
:url ""
:license {:name "Gnu Lesser Public License"
:url "https://www.gnu.org/licenses/lgpl.html"}
:dependencies [[org.clojure/clojure "1.7.0"]]
:plugins [[lein-cljsbuild "1.0.3"]
[lein-localrepo "0.4.0"] ]
:source-paths ["cljc" "src" ]
:cljsbuild {:builds [{
:source-paths ["cljc" ]
:compiler {
:output-to "browser-based/js/main.js"
:optimizations :whitespace
:pretty-print true }
} ]}
:hooks [leiningen.cljsbuild]
:aot [myproj.core]
:main myproj.core)
I don't remember exactly where I copied some of this from, but I assume that the leiningen.cljsbuild hook was what automatically fired off the cljs build process. However after removing the cljx plugin, and moving to cljc, this is successfully compiling the Java version of my program but doesn't seem to be producing any javascript.
Yes, it works.
Try with:
(defproject com.mysite/myproj "0.3.2-SNAPSHOT"
:description ""
:url ""
:license {:name "Gnu Lesser Public License"
:url "https://www.gnu.org/licenses/lgpl.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.28"]
:plugins [[lein-cljsbuild "1.0.6"]
[lein-localrepo "0.4.0"]]
:source-paths ["cljc" "src"]
:cljsbuild {:builds [{
:source-paths ["cljc" "src"]
:compiler {:output-to "browser-based/js/main.js"
:optimizations :whitespace
:pretty-print true}}]}
:hooks [leiningen.cljsbuild])
Then run: lein compile or lein cljsbuild once
Please note that I changed the :source-paths under :cljsbuild to include "src": :source-paths ["cljc" "src"]. Apart from that I added an explicit dependency on clojurescript and bumped cljsbuild version to 1.0.6
By the way, why do you have a separate cljc directory? You can have your cljc, clj & cljs files sharing the same directory structure.

GUI Using Seesaw

I am trying to make a small window using Seesaw for Clojure. I have created a project "sample" using Leiningen.
lein new app sample
I have made added the dependency in the project file.
(defproject sample "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"] [seesaw "1.4.4"]]
:main ^:skip-aot sample.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
My source file is as follows:
(ns sample.core
(:gen-class)
(:require [seesaw.core :as seesaw]
[seesaw.dev :as dev]))
(def window (seesaw/frame
:title "First Example"
:content "hello world"))
(dev/show-options window)
But when I run it I keep getting an error: clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: No such namespace: dev, compiling:(C:\Users\A\sample\src\sample\core.clj:10:1)
I followed your instructions and it worked fine for me, so long as I left the -main definition in place.

Compilation error including clj-time in project

I have included [clj-time "0.8.0"] in my project.clj. I then refer to clj-time in my namespace like so:
(ns school-finder.tasks
(:require [clj-time.core :as t]))
However when I try and run the project I get the following compilation error:
Exception in thread "main" java.lang.IllegalArgumentException: No single method: second of interface: clj_time.core.DateTimeProtocol found for function: second of protocol: DateTimeProtocol, compiling:(clj_time/coerce.clj:146:64)
What am I doing wrong?
I think this is a known bug: https://github.com/clj-time/clj-time/issues/124
If you just do a lein clean (possibly followed by a lein deps) that should solve it.
It's hard to say where the problem is, so here's a working example:
project.clj:
(defproject hello "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[clj-time "0.8.0"]]
:source-paths ["dev"])
src/hello/core.clj:
(ns hello.core
(:require [clj-time.core :as t]))
(println (t/now))

Resource not found : Exception Directory does not exist: resources ring.middleware.file/ensure-dir (file.clj:12)

I am deploying a Clojure project built on luminus on Ubuntu server. When I try to start my server I get the following exception:
Exception Directory does not exist: resources ring.middleware.file/ensure-dir (file.clj:12)
This is my project.clj file
(defproject big5 "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[lib-noir "0.5.0"]
[compojure "1.1.5" :exclusions [ring/ring-core]]
[com.cemerick/friend "0.1.5"]
[ring-server "0.2.7"]
[clabango "0.5"]
[korma "0.3.0-RC6"]
[mysql/mysql-connector-java "5.1.6"]
[com.taoensso/timbre "2.7.1"]
[com.taoensso/tower "2.0.1"]
[com.postspectacular/rotor "0.1.0"]
[markdown-clj "0.9.19"]
[clj-json "0.5.3"]
[clj-time "0.6.0"]
[log4j "1.2.17"
:exclusions
[javax.mail/mail
javax.jms/jms
com.sun.jdmk/jmxtools
com.sun.jmx/jmxri]]
[org.slf4j/slf4j-log4j12 "1.7.5"]]
:plugins [[lein2-eclipse "2.0.0"]
[lein-ring "0.8.7"]
[lein-midje "3.0.0"]]
:ring {:handler big5.handler/war-handler
:init big5.handler/init
:destroy big5.handler/destroy}
:profiles
{:production {:ring {:open-browser? false
:stacktraces? false
:auto-reload? false}}
:dev {:dependencies [[ring-mock "0.1.3"]
[ring/ring-devel "1.1.8"]
[midje "1.5.1"]]}}
:min-lein-version "2.0.0")
I believe Leiningen uses the resources directory as the classpath root. Typically resources/public is where you store your static web assets like images, javascript, and stylesheets. If you create those directories you should be good.
Here are some references for you:
Resources in Clojure applications
Serving static files with ring/compojure - from a war
Finally, from the luminus documentation itself:
http://www.luminusweb.net/docs#anatomy_of_a_luminus_application