What to import for -?> in Clojure? - clojure

I'm trying to use -?> in Clojure but get the error:
Caused by: java.lang.RuntimeException: Unable to resolve symbol: -?> in this context
What do I need to import in order to use it?

First of all, you need to add a dependency on core.incubator to your project.clj (if you aren't using leiningen, that should be your first step):
:dependencies [...
[org.clojure/core.incubator "0.1.1"]]
Next, you can use it in your code like this:
(ns myapp.core
(:use [clojure.core.incubator :only [-?>]]))
If you're using Clojure 1.4, this will also work:
(ns myapp.core
(:require [clojure.core.incubator :refer [-?>]]))
And is preferable if you don't plan to support Clojure pre-1.4 versions of Clojure.

Related

Why do I get IllegalAccessError when trying to import a protocol or record from another namespace

I have a file in my project where I define a few protocols and records (defprotocol and defrecord).
I'm trying to use them in a different file/namespace like this:
(ns myapp.core
(:require [myapp.protocols :refer [SomeProtocol]]))
This causes an Execution error (IllegalAccessError) at .... Does anyone know why?
btw, doing :refer :all does work but I don't want to bring in several unneeded symbols into the namespace.
thanks

Fastest way to try out a new library in a REPL using Leinengen with Clojure

New clojure developer trying to experiment with the HTTP kit clojure library in a REPL.
I created a new project in leinengen, lein new app kit-expt.
Then I modified the :dependencies block in project.clj to include [http-kit "2.2.0"].
Then I run lein deps, then lein repl.
In the REPL I try to run (:require [org.httpkit.client :as http]).
However, when I run this I get the error
CompilerException java.lang.ClassNotFoundException: org.httpkit.client, compiling:(/private/var/folders/cs/b0kcg6fx0335crbvn6xtgq7xl5c29j/T/form-init7575648818353088270.clj:1:1)
What am I doing wrong?
The :require form you're using is invalid, a keyword only for use in an ns (namespace) form. Try removing the : and just use (require ..., which is commonly used in a REPL. See more require examples here.
The HTTP Client docs you refer to assume you're in a source file using ns.
There appears to be something wrong in your environment. If I run it (Ubuntu 16.04) it works great:
(require '[org.httpkit.client :as http])
(pr-str (clojure.core/deref (http/get "http://google.com"))))
=> "{:opts {:method :get, :url \"http://www.google.com/\", :query-params nil, :form-params nil, :trace-re".....
Update
As Micah pointed out, in the repl you need the above form of require. Notice that it doesn't have the leading colon, and it does have a single-quote before the left square bracket. It must also be inside parentheses instead of square brackets.
In the ns form (which I prefer), everything has the opposite convention:
(ns tst.clj.core
(:use clj.core clojure.test tupelo.test)
(:require
[tupelo.core :as t]
[org.httpkit.client :as http] ))

Why can't Leiningen always use my :gen-class properly?

Let's say I create a new Leiningen project (lein new app example) and add some code in example/src/example/core.clj that makes use of :gen-class:
(ns example.core
(:gen-class :extends javafx.application.Application))
(defn -start [this stage]
(.show stage))
(defn -main [& args]
(javafx.application.Application/launch example.core args))
If I then create a JAR (lein uberjar) and run it, everything works fine. However, if I instead try to run my app directly (lein run), I get a ClassNotFoundException. In addition, if I open a REPL (lein repl), I first get the same error as before, but after running this code:
(compile 'example.core)
the error no longer appears in lein run or lein repl.
Could someone please explain to me what exactly is going on here, and how I can run my app directly without needing to manually compile my code from a REPL?
Edit: After fooling around a bit more, I found that the solution to this problem is to add
:aot [example.core]
to project.clj. (Thanks #Mars!) I'm still confused, though, because I had previously tried simply removing ^:skip-aot, which (according to the docs) should work:
This will be AOT compiled by default; to disable this, attach
^:skip-aot metadata to the namespace symbol.
But it doesn't. Why?
Another edit (if I should split any of this into a separate question, let me know and I'll do so): I've been playing with hyphens (lein new app my-example), and weird stuff has been happening. This doesn't work:
(ns my-example.core
(:gen-class :extends javafx.application.Application))
;; ...
(defn -main [& args]
(javafx.application.Application/launch my-example.core args))
But this does:
(ns my-example.core
(:gen-class
:name my-example.Core
:extends javafx.application.Application))
;; ...
(defn -main [& args]
(javafx.application.Application/launch my-example.Core args))
So my class name can either start with a lowercase letter (example.core) or contain a hyphen (my-example.Core), but not both? I really don't get it.
And finally, lein uberjar fails on that final example (with the explicit :name), because
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.
As far as I can tell, the only way to fix that is to split the Application subclass into a separate namespace. Is there another way?
Agreed with #Mars, the problem is that lein run does not AOT the example.core namespace. The default Leiningen template made the example.core non AOT:
(defproject example "0.1.0-SNAPSHOT"
...
:main ^:skip-aot example.core
...)
My best guess is that you could define your app using defrecord and use that as a class instead of the namespace.

How can I use clj-http in riemann.config

I use riemann and now I write my riemann.config.
I want to use clj-http post all events from riemann stream to my web server. But I don't know how to import clj-http from riemann.jar.
I code (:use clj-http.client) or (:require [clj-http.client :as client]) in riemann.config but got error:
java.lang.ClassNotFoundException: clj-http.client
Could anyone help me ?
I did something similar few months ago and this was working for me. I was using http-kit :
(require '[org.httpkit.client :as http])
Since both http-kit and cli-http are available in riemann ( see https://github.com/aphyr/riemann/blob/master/project.clj ) You should be able to require cli-http the same way :
(require '[clj-http.client :as client])
Problem in your configuration is that you are using (:use ... an (:require .... which is supposed to be used within the namespace declaration. Since riemann.config doesn't contain namespace declaration you can't use these forms. When calling
(:use clj-http.client)
you get ClassNotFoundException because clojure is trying to invoke function :use on clj-http.client , which can't be found. Outside the namespace declaration :use is just a standard keyword with no special meaning.

ClassNotFoundException on use of another ns

As simple as this question is, I can't seem to find the right way for different namespaces in the same directory to validly refer to one another. I have two files:
project_root/src/babbler/core.clj:
(ns babbler.core
(:gen-class)
(use '[clojure.string :only (join split)]))
(defn foo [] "Foo")
and then project_root/src/babbler/bar.clj:
(ns babbler.bar)
(use [babbler.core :as babble])
This file also contains a main method, which is specified in my project.clj via :main babbler.bar
My entire structure is that generated by counterclockwise, with with default leiningen template.
The result of running lein repl is this:
Exception in thread "main" java.lang.ClassNotFoundException: babbler.core, compiling:(babbler/bar.clj:3:1)
at clojure.lang.Compiler.analyze(Compiler.java:6380)
at clojure.lang.Compiler.analyze(Compiler.java:6322)
at clojure.lang.Compiler$VectorExpr.parse(Compiler.java:3024)
at clojure.lang.Compiler.analyze(Compiler.java:6363)
at clojure.lang.Compiler.analyze(Compiler.java:6322)
(...)
Your use should be inside the definition of the namespace:
(ns babbler.bar
(use [babbler.core :as babble]))
In fact use is discouraged, you may want to write it as:
(ns babbler.bar
(:require [babbler.core :as babble :refer [foo]]))
That way you can call any function f from the babbler.core namespace as babble/f, and you can call foo directly. In addition, your file has information about where foo comes from so you or someone else won't need to go searching for it.