Injecting namespaces in functions in clojure - clojure

Is it possible to inject namespaces in a function in Clojure?
I want my i/o to be outside from the program and only inject it. The problem i faced, that i tried to give a namespace and invoke it i get the error message:
No name namespace: my
(ns mymain
(:require [myio]))
...
(defn my-test [my]
(my/showworld))
;(play_game)
(my-test myio)

The usual way to pass logic is through functions and not by namespace aliases:
(defn my-test [show-world]
(show-world))
(require 'myio)
(my-test myio/show-world)

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

Using required namespace in the repl

When I require a namespace inside a clojure-script source file, I can use it afterwards in the code.
E.g:
(ns my.core
(:require [mylib.core :as lib]))
(lib/my-f)
(def something 99)
However, when I try to call (lib/my-f) inside the repl - after changing the namespace via (ns my.core) - I cannot access it. In contrast, all other definitions inside the ns are acessible: like something from the example above.
Is there a way to access the requirements in the repl? Or do I have to require them manually in the repl every time? This would be very tedious of course.
If you use ns to change namespace in a ClojureScript REPL, this sets the namespace aliases to match those used in the ns form.
Here is an example illustrating the concept:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))
foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)
bar.core=> (ns foo.core)
foo.core=> (string/starts-with? "abc" "a")
WARNING: No such namespace: string, could not locate string.cljs, string.cljc, or Closure namespace "" at line 1 <cljs repl>
WARNING: Use of undeclared Var string/starts-with? at line 1 <cljs repl>
ReferenceError: "string" is not defined
If instead you use the in-ns REPL special to change to an existing namespace, this will preserve aliases:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))
foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)
bar.core=> (in-ns 'foo.core)
nil
foo.core=> (string/starts-with? "abc" "a")
true
An interesting related aspect: If you use require, it will, under the hoods, employ an ns form with special meta baked into the form that preserves existing aliases:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (require '[clojure.string :as string])
nil
cljs.user=> (require '[clojure.string :as str])
nil
cljs.user=> (string/starts-with? "abc" "a")
true
cljs.user=> (str/starts-with? "abc" "a")
true
If you are curious, this is the :merge true meta here: https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/repl.cljc#L679
and it is honored by the analyzer here: https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/analyzer.cljc#L1953
By seeing how this works, it should provide some insight into why an ns form evaluated directly in the REPL (without merge meta) can lead to aliases being cleared.
In short, avoid directly using the ns special to change to a namespace in the REPL. Instead use it to create a new namespace in the REPL while specifying any required namespaces.
Use the in-ns REPL special to switch to an existing namespace. It can also be used to create a new namespace.
Use require to load namespaces into the REPL, and then use in-ns to switch to them.
As long as you require the namespace before switching to it with ns or in-ns, this all should work fine. The puzzling thing to me is that something is accessible, meaning your code was loaded: that should mean that its namespace form was evaluated too, and thus you should have its aliases available. Are you sure you did this from a fresh state, and didn't, say, define something independently as well? Double-check by:
Close the repl
Start a new repl
(require 'my.core)
(in-ns 'my.core)
Check that the stuff in your question is still true. Can you still access something? Can you still not access lib/my-f? I predict that one of those two things will change: you should be able to access neither, or both.

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.

Error in #'namespace/name_of_function

I am doing a project in Clojure. When I run the program I get an error:
#'targil4_2_new.core/writeAndNext
Where targil4_2_new is the name of my namespace and writeAndNext is the name of a function in this namespace.
How do I know what the problem is?
How are you calling your function?
Could you show me your trace error?
In your example you should call your function in this way:
1 - require function namespace:
In REPL:
(require '[targil4_2_new.core :as xpto])
Or in your application:
(ns my-app.old-core
(:require [targil4_2_new.core :as xpto]))
2 - call your function:
(xpto/writeAndNext ) //you can add your arguments