Skip to content
This repository was archived by the owner on Apr 25, 2024. It is now read-only.

Commit 8be9b2b

Browse files
CLJ-1188 via Var intern
Signed-off-by: Stuart Halloway <[email protected]>
1 parent 92f7d93 commit 8be9b2b

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed

src/jvm/clojure/api/API.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright (c) Rich Hickey and Contributors. All rights reserved.
3+
* The use and distribution terms for this software are covered by the
4+
* Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
5+
* which can be found in the file epl-v10.html at the root of this distribution.
6+
* By using this software in any fashion, you are agreeing to be bound by
7+
* the terms of this license.
8+
* You must not remove this notice, or any other, from this software.
9+
**/
10+
11+
package clojure.api;
12+
13+
import clojure.lang.IFn;
14+
import clojure.lang.Symbol;
15+
import clojure.lang.Var;
16+
17+
public class API {
18+
private API() {}
19+
20+
private static Symbol asSym(Object o) {
21+
Symbol s;
22+
if (o instanceof String) {
23+
s = Symbol.intern((String) o);
24+
} else {
25+
s = (Symbol) o;
26+
}
27+
return s;
28+
}
29+
30+
/**
31+
* Returns the var associated with qualifiedName.
32+
*
33+
* @param qualifiedName a String or clojure.lang.Symbol
34+
* @return a clojure.lang.IFn
35+
*/
36+
public static IFn var(Object qualifiedName) {
37+
Symbol s = asSym(qualifiedName);
38+
return var(s.getNamespace(), s.getName());
39+
}
40+
41+
/**
42+
* Returns an IFn associated with the namespace and name.
43+
*
44+
* @param ns a String or clojure.lang.Symbol
45+
* @param name a String or clojure.lang.Symbol
46+
* @return a clojure.lang.IFn
47+
*/
48+
public static IFn var(Object ns, Object name) {
49+
return Var.intern(asSym(ns), asSym(name));
50+
}
51+
52+
/**
53+
* Read one object from the String s. Reads data in the
54+
* <a href="http://edn-format.org">edn format</a>.
55+
* @param s
56+
* @return an Object, or nil.
57+
*/
58+
public static Object read(String s) {
59+
return EDN_READ_STRING.invoke(s);
60+
}
61+
62+
static {
63+
Symbol edn = (Symbol) var("clojure.core", "symbol").invoke("clojure.edn");
64+
var("clojure.core", "require").invoke(edn);
65+
}
66+
private static final IFn EDN_READ_STRING = var("clojure.edn", "read-string");
67+
}

src/jvm/clojure/api/package.html

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<html>
2+
3+
<!--
4+
Copyright (c) Rich Hickey and Contributors. All rights reserved.
5+
The use and distribution terms for this software are covered by the
6+
Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
7+
which can be found in the file epl-v10.html at the root of this distribution.
8+
By using this software in any fashion, you are agreeing to be bound by
9+
the terms of this license.
10+
You must not remove this notice, or any other, from this software.
11+
-->
12+
13+
<body>Clojure interop from Java.
14+
15+
<p>The clojure.api package provides a minimal interface to bootstrap
16+
Clojure access from other JVM languages. It does this by providing:
17+
</p>
18+
19+
<ol>
20+
<li>The ability to use Clojure's namespaces to locate an arbitrary
21+
<a href="http://clojure.org/vars">var</a>, returning the
22+
var's <code>clojure.lang.IFn</code> interface.</li>
23+
<li>A convenience method <code>read</code> for reading data using
24+
Clojure's edn reader</li>
25+
</ol>
26+
27+
<p><code>IFn</code>s provide complete access to
28+
Clojure's <a href="http://clojure.github.com/clojure/">API</a>s.
29+
You can also access any other library written in Clojure, after adding
30+
either its source or compiled form to the classpath.</p>
31+
32+
<p>The public Java API for Clojure consists of the following classes
33+
and interfaces:
34+
</p>
35+
36+
<ol>
37+
<li>clojure.api.API</li>
38+
<li>clojure.lang.IFn</li>
39+
</ol>
40+
41+
<p>All other Java classes should be treated as implementation details,
42+
and applications should avoid relying on them.</p>
43+
44+
<p>To lookup and call a Clojure function:
45+
<pre>
46+
IFn plus = API.var("clojure.core", "+");
47+
plus.invoke(1, 2);
48+
</pre>
49+
</p>
50+
51+
<p>Functions in <code>clojure.core</code> are automatically loaded. Other
52+
namespaces can be loaded via <code>require</code>:
53+
<pre>
54+
IFn require = API.var("clojure.core", "require");
55+
require.invoke(API.read("clojure.set"));
56+
</pre>
57+
</p>
58+
59+
<p><code>IFn</code>s can be passed to higher order functions, e.g. the
60+
example below passes <code>plus</code> to <code>read</code>:
61+
<pre>
62+
IFn map = API.var("clojure.core", "map");
63+
IFn inc = API.var("clojure.core", "inc");
64+
map.invoke(inc, API.read("[1 2 3]"));
65+
</pre>
66+
</p>
67+
68+
<p>Most IFns in Clojure refer to functions. A few, however, refer to
69+
non-function data values. To access these, use <code>deref</code>
70+
instead of <code>fn</code>:</p>
71+
72+
<pre>
73+
IFn printLength = API.var("clojure.core", "*print-length*");
74+
API.var("clojure.core", "deref").invoke(printLength);
75+
</pre>
76+
77+
</body>
78+
</html>

test/clojure/test_clojure/api.clj

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
; Copyright (c) Rich Hickey. All rights reserved.
2+
; The use and distribution terms for this software are covered by the
3+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4+
; which can be found in the file epl-v10.html at the root of this distribution.
5+
; By using this software in any fashion, you are agreeing to be bound by
6+
; the terms of this license.
7+
; You must not remove this notice, or any other, from this software.
8+
9+
(ns clojure.test-clojure.api
10+
(:require [clojure.test.generative :refer (defspec)]
11+
[clojure.test-clojure.generators :as cgen])
12+
(:import clojure.lang.IFn
13+
clojure.api.API
14+
clojure.lang.Var))
15+
16+
(set! *warn-on-reflection* true)
17+
18+
(defn roundtrip
19+
"Print an object and read it back with API/read"
20+
[o]
21+
(binding [*print-length* nil
22+
*print-dup* nil
23+
*print-level* nil]
24+
(API/read (pr-str o))))
25+
26+
(defn api-var-str
27+
[^Var v]
28+
(API/var (str (.name (.ns v)))
29+
(str (.sym v))))
30+
31+
(defn api-var
32+
[^Var v]
33+
(API/var (.name (.ns v))
34+
(.sym v)))
35+
36+
(defspec api-can-read
37+
roundtrip
38+
[^{:tag cgen/ednable} o]
39+
(when-not (= o %)
40+
(throw (ex-info "Value cannot roundtrip with API/read" {:printed o :read %}))))
41+
42+
(defspec api-can-find-var
43+
api-var
44+
[^{:tag cgen/var} v]
45+
(when-not (= v %)
46+
(throw (ex-info "Var cannot roundtrip through API/var" {:from v :to %}))))
47+
48+
(defspec api-can-find-var-str
49+
api-var-str
50+
[^{:tag cgen/var} v]
51+
(when-not (= v %)
52+
(throw (ex-info "Var cannot roundtrip strings through API/var" {:from v :to %}))))
53+
54+

0 commit comments

Comments
 (0)