I type the following at the Clojurescript namespace.
cljs.user> (use '[clojure.zip :only [insert-child]])
WARNING: Use of undeclared Var cljs.user/use at line 1
"Error evaluating:" (use (quote [clojure.zip :only [insert-child]])) :as "cljs.user.use.call(null,cljs.core.vec([\"\\uFDD1'clojure.zip\",\"\\uFDD0'only\",cljs.core.vec([\"\\uFDD1'insert-child\"])]));\n"
#<TypeError: Cannot call method 'call' of undefined>
TypeError: Cannot call method 'call' of undefined
at eval (eval at <anonymous> (http://localhost:3000/main.js:32728:147), <anonymous>:1:85)
at eval (eval at <anonymous> (http://localhost:3000/main.js:32728:147), <anonymous>:6:3)
at http://localhost:3000/main.js:32728:142
at evaluate_javascript (http://localhost:3000/main.js:32741:4)
at Object.callback (http://localhost:3000/main.js:32806:138)
at goog.messaging.AbstractChannel.deliver (http://localhost:3000/main.js:31059:13)
at goog.net.xpc.CrossPageChannel.deliver_ (http://localhost:3000/main.js:32164:14)
at Function.goog.net.xpc.NativeMessagingTransport.messageReceived_ (http://localhost:3000/main.js:31732:13)
at goog.events.Listener.handleEvent (http://localhost:3000/main.js:22590:26)
at Object.goog.events.fireListener (http://localhost:3000/main.js:22924:21)
nil
It seems to be stating that the 'use' method does not exist in the cljs.user namespace. This kind of makes sense to me, as Clojurescript itself cannot evaluate Clojure expressions. However, I know that Clojurescript has a clojure.zip namespace, I have used clojure.zip in the namespace declaration as (:use [clojure.zip :only [insert-child]]).
How do I use the Clojurescript version of clojure.zip in the Clojurescript repl?
Because ClojureScript namespaces are implemented completely differently than Clojure, ClojureScript does not support the use or require forms directly.
Instead, you must use the ns macro. To use clojure.zip in the cljs.user namespace, then, just do the following:
(ns cljs.user (:use [clojure.zip :only [insert-child]]))
Note that the forms supported in the ClojureScript version of ns are a subset of those supported in Clojure; specifically, :use clauses must specify an :only form, and the :require clause must specify an :as form.
Related
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.
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.
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.
When using clojure.string, I receive the following warnings
WARNING: replace already refers to: #'clojure.core/replace in namespace: tutorial.regexp, being replaced by: #'clojure.string/replace
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: tutorial.regexp, being replaced by: #'clojure.string/reverse
my clojure script is:
(ns play-with-it
(:use [clojure.string]))
Is there any way to fix those warnings?
Yes, switch to
(ns play-with-it
(:require [clojure.string :as string]))
and then say e.g.
(string/replace ...)
to call clojure.string's replace function.
With :use, you bring in all Vars from clojure.string directly into your namespace, and since some of those have names clashing with Vars in clojure.core, you get the warning. Then you'd have to say clojure.core/replace to get at what's usually simply called replace.
The clash of names is by design; clojure.string is meant to be required with an alias like this. str and string are the most frequently chosen aliases.
In addition to Michał's answer, you can exclude vars from clojure.core:
user=> (ns foo)
nil
foo=> (defn map [])
WARNING: map already refers to: #'clojure.core/map in namespace: foo, being replaced by: #'foo/map
#'foo/map
foo=> (ns bar
(:refer-clojure :exclude [map]))
nil
bar=> (defn map [])
#'bar/map
In addition to Alex's answer you can also refer only the vars you want from a given namespace.
(ns foo.core
(:use [clojure.string :only (replace-first)]))
This would not throw a warning since replace-first is not in clojure.core. However, you would still receive a warning if you did the following:
(ns foo.core
(:use [clojure.string :only (replace)]))
In general it seems people are tending toward (ns foo.bar (:require [foo.bar :as baz])).
Since Clojure 1.4 you can refer the individual functions you need from a namespace using :require with a :refer:
(ns play-with-it
(:require [clojure.string :refer [replace-first]]))
This is now recommended over :use.
Assuming you don't need the clojure.string/replace or clojure.string/reverse, that would also remove the warnings.
See this SO question and this JIRA issue for more details.
I've seen several different ways for :use in clojure--what's the idiomatic/preferred method?
#1
(ns namespace.core
(:use [[something.core]
[another.core]]))
or #2 EDIT: Use this with conjunction with :only.
(ns namespace.core
(:use [something.core]
[another.core]))
or #3
(ns namespace.core
(:use [something.core
another.core]))
or #4
(ns namespace.core
(:use (something.core
another.core)))
or #5 EDIT: This is idiomatic, but one should be using :use as in #2
(ns namespace.core
(:use something.core
another.core))
Choice #5 is idiomatic, unless you are passing additional options such as :only, :exclude, etc. Colin's blog post covers the options in great detail.
The API for dealing with namespaces is unnecessarily difficult to learn. However, it is certainly capable enough for a wide variety of uses, so the pressure for a rewrite has yet to reach the boiling point for anyone.
Actually none of them are idiomatic. You should always have an :only clause in your :uses. Your best bet is adding :only to #2. If you don't want to enumerate all the vars you're taking from another namespace, consider (:require [foo.bar :as bar]).
One point of note that we should mention is that the
(:use (clojure set xml)) statement is considered a promiscuous operation
and therefore discouraged. [...] When organizing your
code along namespaces, it’s good practice to export and import only those
elements needed.
-from the Joy of Clojure, page 183.
The one exception is that a test namespace should bare-use the namespace it tests.
The cases 1, 3 and 4 are not valid and throw some Exception. I haven't seen 2 - only in combination with :only or the like.
(ns namespace.core
(:use
[something.core :only (x)]
another.core))
I usually use 5.
In Clojure 1.4+ I wouldn't use use at all. require can do all that use can do now, so forget about use. One less thing to worry about.
If you want use-like behaviour (still bad form, imo) you can do:
(ns namespace.core
(:require
[something.core :refer :all]
[another.core :refer :all]))
If you want :use .. :only behaviour, use:
(ns namespace.core
(:require
[something.core :refer [foo bar]]
[another.core :refer [quux]]))
More detail: In Clojure 1.4 what is the use of refer within require?