Clojure project layout and relative imports - clojure

I'm having a hard time starting out on my first clojure project. I have found a ton of tutorials and answers to questions, but none of the seems to answer my problem.
I have created a blank project using Leiningen. This example explains my problem:
project.clj:
(defproject clojurenet "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"]
[net.mikera/core.matrix "0.34.0"]
[org.clojure/math.numeric-tower "0.0.1"]]
:main ^:skip-aot clojurenet.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
src/clojurenet/core.clj:
(ns clojurenet.core)
(:require clojurenet.hello)
(:gen-class))
(defn -main
[& args]
(clojurenet.hello/helloworld)
src/clojurenet/hello.clj:
(ns clojurenet.hello)
(defn helloworld []
(println "Hello World!"))
When I run lein run I get the error message Exception in thread "main" java.lang.ClassNotFoundException: clojurenet.hello, compiling:(clojurenet/core.clj:2:3). How am I supposed to do this?
I would also rather use :refer :all syntax in the core file, but i belive this example should be the simplest.
I'm sure there is a stupid simple solution to this, but my research has not been successful.
Additionally, do you have som good tutorials for building you first project? I find that some tutorials are outdated, and most of the only describes how to use the REPL.
Thanks in advance!

You have unbalanced parantheses in clojurenet.core
(ns clojurenet.core) ;; <- remove ) to fix
(:require clojurenet.hello)
(:gen-class))
I recommend using a balancing editing mode like ParEdit. You may want to try out this implementation if you are using Sublime.

Related

Could not resolve symbol: clojure.core.logic/membero

I am trying to run the function membero as outlined by
https://clojuredocs.org/clojure.core.logic/membero
(ns clojure-noob.core
(:gen-class)
(:require [clojure.core.logic :as logic]))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
(logic/membero :a [:a :b :c]) ; => Could not resolve symbol: logic/membero
(clojure.core.logic/membero :a [:a :b :c]); => Could not resolve symbol: clojure.core.logic/membero
I am just starting out my clojure journey, please be gentle.
I see 2 possibilities,
a) membero is deprecated or shifted to some other directory
b) something about my setup that is preventing me from running it.
a) seems to be ruled out since there are still membero mentions in recent post
How do I use core.logic to search for valid nested maps in a database of maps?
Set membership in core.logic without CLP(set) - defne behaviour
Thank you to Martin Půda for pointing me to dependencies.
membero was not the point of this post. My problem is not knowing where to add dependencies when I start seeing "Could not resolve symbol:" errors.
Adding the dependency in project.clj like the following solves the issue.
(defproject clojure-noob "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [[org.clojure/clojure "1.10.3"]
[org.clojure/core.logic "1.0.1"]]
:main ^:skip-aot clojure-noob.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
My next confusion that followed was why can't we do (require [org.clojure/core.logic "1.0.1"]) in repl to just change the dependencies without restarting repl.
Turns out this is something that is not supported out of the box but commonly requested
https://clojureverse.org/t/whats-the-right-way-to-hot-reload-dependencies-without-restarting-the-repl/5357
Any way to add dependency to lein project without REPL restart?
Any way to add dependency to lein project without REPL restart?
Promegranate https://github.com/clj-commons/pomegranate
was proposed as a means to do it. Will post an update when I tried it.

Hugsql can not read my sql file

I am truely lost here. I have a very simple application. All it does is to insert a user into the user table in my Database. I using Postgres. The code is
(ns signupper.db (:require [hugsql.core :as hugsql]))
(hugsql/def-db-fns "sql/q.sql")
Inside the direvtory where db.clj is I made a directory called sql and inside of it there is a file called q.sql.
When I ran my REPL and type (require '[signupper.db :as db]) I get the following error message:
CompilerException clojure.lang.ExceptionInfo: Can not read file: sql/q.sql {}, compiling:(signupper/db.clj:4:1)
Any one has any idea?
Thanks.
Your sql directory needs to be on the path. Please check your project.clj file, under resource-paths, and verify your sql directory is accessible via one of the paths there stated.
If not, you might either move your sql directory or include the path into the resource-paths entry.
If you are using Leiningen you should add your sql folder under the :resource-paths key to your project.clj like this:
(defproject test-project "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.8.0"]]
:main ^:skip-aot test-project.core
:target-path "target/%s"
:resource-paths ["sql" "resources"] ; <-- here
:profiles {:uberjar {:aot :all}})
Hugsql expects the path relative to the directory on the classpath. (This is the same as Clojure namespaces.)
So, your code should look like this:
(ns signupper.db (:require [hugsql.core :as hugsql]))
(hugsql/def-db-fns "signupper/db/sql/q.sql")
See the example in the docs: https://www.hugsql.org/#start-sql
My experience :
If your path is like this :
"/home/user/Desktop/sql/q.sql"
project.clj must be like this -->
:resource-paths ["/home/user/Desktop/sql" "other resources"]
and core.clj -->
(hugsql/def-db-fns "q.sql")
But if you write in core.clj
(hugsql/def-db-fns "/home/user/Desktop/sql/q.sql")
Computer sees like this :
"/home/user/Desktop/sql/home/user/Desktop/sql/q.sql"
Just had the same issue.
Apparently, the function def-db-fns starts the path from the folder src and not the root of the project.
I think one way you can solve this is putting your file inside the src directory, and call the function with
(hugsql/def-db-fns "q.sql")

Clojure compile time

I'm testing out Clojure for the first time, and wanted to write a simple websocket client application. I've found the library https://github.com/stylefruits/gniazdo and got the code to work (using lein run). However, compiling the code into a jar (either with lein jar or lein uberjar is either stuck or takes ages (aborted after ~1h))
steps:
lein new app testing
modified src/testing/core.clj and project.clj (see below)
lein jar (or lein uberjar)
For simplicity I've have this very simple code, which already takes ages to compile into a jar:
(ns testing.core
(:gen-class))
(require '[gniazdo.core :as ws])
(def socket
(ws/connect
"wss://some.url.com/"))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(ws/close socket))
project.clj:
(defproject testing "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.8.0"]
[stylefruits/gniazdo "1.0.1"]]
:main ^:skip-aot testing.core
:aot [testing.core]
:target-path "target/%s"
:profiles {:uberjar {:aot :all}})
output of running lein jar:
$lein jar
Compiling testing.core
2017-12-11 14:15:14.813:INFO::main: Logging initialized #1352ms
and nothing aferwards. Is this normal behaviour (and it just takes ages to compile) or am I missing something here? Clojure looks very interesting, but if it takes even for such a small program hours to compile, deployment could be a problem in my circumstances.
When that namespace is compiled Ahead of Time (:aot [testing.core] in your project.clj), this code gets evaluated during compilation:
(def socket
(ws/connect "wss://some.url.com/"))
This is likely what's causing the hang. The compiler never moves on from this because it has made a blocking call.
You could remove the :aot directive if you don't need it (and you probably don't). I think this can be a somewhat confusing default when creating a new Leiningen project.
You could do something like wrap that socket/conn in a delay:
(def socket (delay (ws/connect "wss://some.url.com/")))
And then deref/# it wherever you need the value. This just delays evaluation of ws/connect until you ask.

importing java lib in clojure, how does it work?

I'm trying to build my first clojure leiningen project but I have an issue using a specific java class in my code.
While coding, I was looking for a specific functionnality and found out about DatatypeConverter (http://docs.oracle.com/javase/7/docs/api/javax/xml/bind/DatatypeConverter.html).
Then I had to figure how to import the library. I don't know anything about Maven but I ended up somewhat (educated?) guessing I should looking for the library there https://search.maven.org/.
So there is what I ended up writing for my project.clj file:
(defproject game-backend "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"}
:main game-backend.core
:dependencies [
[org.clojure/clojure "1.8.0"]
[javax.xml.bind/jaxb-api "2.2.12"]
])
and here is my ns macro call in my core.clj file:
(ns game-backend.core
(:require [clojure.java.io])
(:import
(java.security DigestInputStream)
(java.io FileInputStream)
(javax.xml.bind DataTypeConverter)
)
)
and when I tun lein run I get the following error (a package was downloaded at some point in time): Exception in thread "main" java.lang.ClassNotFoundException: javax.xml.bind.DataTypeConverter, compiling:(game_backend/core.clj:1:1)
I(m have no idea how many steps I've done wrong (all of them?). Can you please enlight me on how it should be done?
Try a lowercase 't' DatatypeConverter
(ns game-backend.core
(:require [clojure.java.io])
(:import
(java.security DigestInputStream)
(java.io FileInputStream)
(javax.xml.bind DatatypeConverter)
)
)
Take a look inside your maven repository (.m2 directory). You will be able to find the jar file there. Then look at the .class files in that jar.
DatatypeConverter.class
That's one way to find that you should be using a lowercase 't'.
Also you can add multiple classes of a package:
(:import (java.io File Bits BufferedInputStream))

How does one pre-load a clojure file in the leiningen repl?

I have some clojure functions that I would like pre-loaded when I start the clojure REPL. The functions aren't much use unless you are using them within the context of a REPL.
If it helps, I generally use leiningen to start a clojure REPL for me.
How can I tell clojure (or leiningen, if it's not available through flat clojure) to pre-load a clojure file containing these definitions for me?
There are several ways to do this described in the leiningen sample project
one of my favorite methods is so put the code you want in the default repl namespace into
/path/to/project/dev/user.clj:
(ns user)
(def foo 42)
and add a line like this into the project.clj file:
(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"]]
:source-paths ["dev"])
This makes it clear that this is for dev while still getting it loaded into the default namespace.
When you run nrepl-jack-in form emacs or "lein repl" form the shell, you should be greeted with a user> namespace with your code loaded:
; nREPL 0.1.6
user> foo
42