Using Incanter and Clojure Soup together - clojure

I am learning Clojure - it's a lot of fun! I am trying to use Incanter and Clojure Soup in the same file:
(require '[jsoup.soup :as soup])
(use '(incanter core stats io charts datasets))
And I get the following error:
CompilerException java.lang.IllegalStateException: $ already refers to: #'jsoup.soup/$ in namespace: user, compiling
I think I understand why, but how can I solve this problem? Appreciate this website and all the gurus on it!
Thanks.

If you only actually use one of the $ functions then you can exclude the other one
(ns myproject.example
(:require [jsoup.soup :as soup]
[incanter [core :refer :all :exclude [$]]
[stats :refer :all]
[io :refer :all]
[charts :refer :all]
[datasets :refer :all]]))
or you can take the approach of explicitly naming the vars you want to refer to in your namespace and explicitly calling the others by namespace-alias/function, which would look more like this:
(ns myproject.example
(:require [jsoup.soup :as soup]
[incanter [core :refer [$ ... and others here ...]
:as incanter]
[stats :as stats]
[io :as io]
[charts :as charts]
[datasets :as dataset]]))
The use method of using other namespaces is discouraged in modern clojure code and has been subsumed by the refer form, so I use that form in these examples. It's also strongly encouraged to put the refer forms in the namespace declaration.

Related

What is the difference between core.clj and inope.clj in a clojure project?

What is the difference between core & inope?
I have a very brief idea that core is like the main equivalent in Java. And inope is like an interface between java and clojure, although I dont understand the purpose of inope entirely.
I found this in a project and this is my understanding:
inope.clj is used for writing java clojure interoperable functions.
The namespace contents imply that it functions like core.clj here.
in this inope.clj file, they have imported dependencies and defined java-clojure interoperable functions in gen-class as such :
(ns prject-avon.inope
(:require [prject-avon.ioutil :as utl]
[aero.core :as aero-core :refer (read-config)]
[clojure.java.data :as clj-data]
[malli.core :as m]
[malli.util :as mu]
[malli.instrument :as mi]
[malli.error :as me]
[malli.json-schema :as json-schema]
(:gen-class
:methods [ ^{:static true} [validateData [Object String] Boolean]
]))
<Functions are defined here>
Those are just names, there's no significance to them. In particular, I've never heard of inope myself. The only way you can reliably judge is by the namespace's contents and their usage. It's also very possible that a single namespace contains all sorts of unrelated stuff.

Clojure namespace not accessible

I'm trying to load two namespaces from the library "spurious-aws-sdk-helper" (which by the way I've installed locally - this is me testing it before deploying to Clojars). And I'm loading the namespaces from inside an if statement.
Once the namespaces are loaded I call a function which is provided by one of the loaded namespaces.
The problem is that when executing the code via lein ring server I get a Java exception informing me that the namespace I'm trying to access isn't available.
But if I run lein repl and then (use 'spurious-clojure-example.routes.home) the relevant top level namespace; then (require '[spurious-aws-sdk-helper.core :as core]) the namespace - much like in the code I'll linked to in a moment demonstrates - then the namespace WILL be available and subsequently the call to the function won't error?
I'm not sure if it's one of those errors which are misleading and in fact it's not the namespace I'm trying to require that's the problem, but something inside of it that's the issue? But if that was true then why would it work when called manually by myself within lein repl?
The code I'm referring to is: https://github.com/Integralist/spurious-clojure-example/blob/baseline/src/spurious_clojure_example/routes/home.clj#L9-L10
(ns spurious-clojure-example.routes.home
(:use [amazonica.aws.s3])
(:require [compojure.core :refer :all]
[environ.core :refer [env]]
[spurious-clojure-example.views.layout :as layout]))
(if (env :debug)
(do
(require '[spurious-aws-sdk-helper.core :as core])
(require '[spurious-aws-sdk-helper.utils :refer [endpoint cred]])
(core/configure {:s3 "test-bucket4"
:sqs "test-queue4"
:ddb (slurp "./resources/config/schema.yaml")})))
(def bucket-path "news-archive/dev/election2014-council_title")
(def content
(apply str (line-seq
(clojure.java.io/reader
(:object-content
(get-object (cred (endpoint :spurious-s3)) :bucket-name "shared" :key bucket-path))))))
(defn home []
(layout/common [:h1 content]))
(defroutes home-routes
(GET "/" [] (home)))
It's the (core/configure ...) call that triggers a Java exception saying "core" namespace isn't available. But running the following code from lein repl works fine...
(use 'spurious-clojure-example.routes.home)
(require '[spurious-aws-sdk-helper.core :as core])
(core/configure ...rest of code...)
UPDATE 1:
Just to clarify I've updated the code as follows...
(when (env :debug)
(require '[spurious-aws-sdk-helper.core :as core])
(require '[spurious-aws-sdk-helper.utils :refer [endpoint cred]])
(core/configure
{:s3 "test-bucket7"
:sqs "test-queue9"
:ddb (slurp "./resources/config/schema.yaml")}))
...and when running it within the REPL it works fine.
The problem is when running it via lein ring server.
I've started reading about (ns-resolve) here: http://technomancy.us/143
But the solution it suggests: (ns-resolve 'core 'configure) didn't work; it just threw an Unable to resolve symbol: core in this context error.
I created a app with lein new compojure-app and when :debug value is truthy, require clojure.string :as str and then also printing something to shell.
The code below works via lein ring server. I tested it with :debug values true and false. I see in your example, you use environ so, I put {:debug true} or {:debug false} in .lein-env.
(ns integralist.handler
(:require [compojure.core :refer [defroutes routes]]
[ring.middleware.resource :refer [wrap-resource]]
[ring.middleware.file-info :refer [wrap-file-info]]
[hiccup.middleware :refer [wrap-base-url]]
[compojure.handler :as handler]
[compojure.route :as route]
[integralist.routes.home :refer [home-routes]]
[environ.core :refer [env]]))
(when (env :debug)
(require '[clojure.string :as str]))
(when (env :debug)
(defn it-works! []
(println "It works!:" (str/split "Clojure is Awesome" #" "))))
(defn init []
(println "integralist is starting")
(when (env :debug)
(it-works!)))
(defn destroy []
(println "integralist is shutting down"))
(defroutes app-routes
(route/resources "/")
(route/not-found "Not Found"))
(def app
(-> (routes home-routes app-routes)
(handler/site)
(wrap-base-url)))
Tried it with:
(when true ; also tried with false
(require '[clojure.string :as str])
(str/split "Clojure is awesome!" #" "))
=> No such namespace: str
I'm a tiny bit surprised as well since if and when should only evaluate the body of their expressions for the appropriate branch and not touch the other expressions. I did not expect a namespace error on false.
More surprising is I did not expect a namespace error on true as well. I'd guess it's some java compilation thing trying to resolve the namespace even before code evaluation. I don't know the specifics of why.
As for what you should do, this code is funky and I've never thought of or seen anyone doing anything similar. Unless there is some specific reason for doing this, the solution is simple: shove your requires to the very top in ns. There's no need to change anything else.

Provide multiple implementations for a Clojure protocol

I have a namespace that exposes common data-related functions (get-images, insert-user). I then have two database backends that have those same functions and implement them differently. They implement the interface as it were. Each backend is contained within a namespace.
I can't seem to be able to find a good solution on how to accomplish this.
I tried dynamically loading the ns but no luck. Once you do (:require [abc :as x]), the x isn't a real value.
I tried using defprotocol and deftype but that's all kinds of weird because the functions in the deftype need to be imported, too and that messes everything up for me.
Is there some idiomatic solution to this?
I don't see why protocols are not sufficient?
In ns data.api:
(ns data.api)
(defprotocol DB
(get-images [this])
(insert-user [this]))
In ns data.impl1:
(ns data.impl1
(:require [data.api :refer :all]))
(defrecord Database1 [connection-params]
DB
(get-images [_] ...)
(insert-user [_] ...))
Same thing in ns data.impl2.
Then when you go to use a particular db, just create the correct record:
(ns data.user
(:require [data.api :refer :all])
[data.impl1 :refer (->Database1)])
(defn use-db []
(let [db1 (->Database1 {})]
(get-images db1)))

In Clojure 1.4 what is the use of refer within require?

What advantage does using :refer in :require have over using :only in :use? Are the following synonymous?
(ns so.example (:use [my.lib :only [function]]))
and
(ns so.example (:require [my.lib :refer [function]]))
Main idea of adding :refer to :require is to get rid completely of :use, leaving only one operator to load other packages. You can emulate existing :use with (:require [my.lib :refer :all])...
yes, they are equivalent,
:refer and :require are the basic operations required to build namespaces. :use is more convienient
:require causes classes to be loaded
:refer adds things to the name space which is really just a map (actually a couple of maps)
:use is :refer + :require
as much is it may look like it, there really is no magic to namespaces
if you make a namespace like this
(ns so.example (:use my.lib))
the equivalent with :require would be:
(ns so.example (:require [my.lib :refer [function1 function2 function3
list every function in example
here and remember to keep it
up to date ]]))
As of the 1.4.0 release, there's no longer a good reason to use use. Use require :refer instead. From the Clojure 1.4.0 changelog: "require can now take a :refer option. :refer takes a list of symbols to refer from the namespace or :all to bring in all public vars."
(from https://8thlight.com/blog/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html)

Getting IllegalStateException when reloading a namespace in the REPL

My namespace declaration looks like this:
(ns test.foo
(:use
[clj-http.client :only (get) :as client]
[net.cgrand.enlive-html :only (select) :as html]))
It works fine in the REPL, the first time I use it. Then, when I modify the code and try the following in the REPL:
(use :reload 'test.foo)
I get:
java.lang.IllegalStateException: get already refers to: #'clj-http.client/get in namespace: test.foo (foo.clj:1)
I'm on windows with counterclockwise and also tried with leiningen (lein repl).
You should not shadow core fns by accident. You have to be explicit about your intent:
(ns test.foo
(:refer-clojure :exclude [get]) ; suppress the shadowing warning
(:require [clojure.core :as core]) ; allow to still reach clojure.core/get through core/get
(:use
[clj-http.client :only (get) :as client]
[net.cgrand.enlive-html :only (select) :as html]))