Skip to content

Commit c38c5bd

Browse files
alexander-yakushevbbatsov
authored andcommitted
[apropos] Make comparator robust
1 parent 7425bee commit c38c5bd

File tree

2 files changed

+30
-26
lines changed

2 files changed

+30
-26
lines changed

src/orchard/apropos.clj

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[orchard.misc :as misc]
77
[orchard.query :as query])
88
(:import
9-
[clojure.lang MultiFn]))
9+
(clojure.lang MultiFn Var)))
1010

1111
;;; ## Overview
1212
;;
@@ -17,20 +17,31 @@
1717

1818
;;; ## Symbol Search
1919

20-
(defn- safe-comparator [x y]
21-
(compare (pr-str x) (pr-str y)))
20+
(defn- priority-ns? [ns]
21+
(some-> ns ns-name name (.startsWith "clojure.")))
2222

23-
(defn- default-comparator [ns clojure-ns?]
24-
(fn [x y]
23+
(defn- default-comparator [this-ns]
24+
(fn [^Var x, ^Var y]
2525
(cond
2626
(= x y) 0
2727
(nil? x) 1
2828
(nil? y) -1
29-
(= x ns) -1
30-
(= y ns) 1
31-
(and (clojure-ns? x) (not (clojure-ns? y))) -1
32-
(and (clojure-ns? y) (not (clojure-ns? x))) 1
33-
:else (safe-comparator x y))))
29+
:else
30+
(let [ns1 (when (instance? Var x) (.ns ^Var x))
31+
ns2 (when (instance? Var y) (.ns ^Var y))
32+
;; First, vars from the namespace `this-ns`.
33+
;; Then, vars from "priority" namespaces (everything from clojure.*)
34+
;; Finally, all the rest.
35+
prio-ns1 (cond (and this-ns (= ns1 this-ns)) 0
36+
(priority-ns? ns1) 1
37+
:else 2)
38+
prio-ns2 (cond (and this-ns (= ns2 this-ns)) 0
39+
(priority-ns? ns2) 1
40+
:else 2)
41+
c (compare prio-ns1 prio-ns2)]
42+
(if (zero? c)
43+
(compare (str x) (str y))
44+
c)))))
3445

3546
(defn apropos-sort
3647
"Return a list of vars, ordered with `ns` first,
@@ -39,18 +50,8 @@
3950
[ns vars]
4051
(assert (every? (some-fn class? var? symbol?) vars)
4152
(pr-str vars))
42-
(let [clojure-ns? #(.startsWith (str (ns-name %)) "clojure.")
43-
key-fn (comp :ns meta)]
44-
;; https://clojure.org/guides/comparators
45-
(try
46-
(sort-by key-fn (default-comparator ns clojure-ns?) vars)
47-
;; Handle https://github.com/clojure-emacs/orchard/issues/128
48-
(catch IllegalArgumentException e
49-
(when (System/getProperty "orchard.internal.test-suite-running")
50-
;; Don't accept this exception in our CI - we should fix this if it's reproducible.
51-
(throw e))
52-
;; Fallback to a simpler comparator:
53-
(sort-by key-fn safe-comparator vars)))))
53+
;; https://clojure.org/guides/comparators
54+
(sort (default-comparator ns) vars))
5455

5556
(defn find-symbols
5657
"Takes a map and returns a list of maps containing name, doc and type.

test/orchard/apropos_test.clj

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111
(defn some-random-function [])
1212

1313
(deftest apropos-sort-test
14-
(doseq [namespace (all-ns)]
15-
(let [vars (->> namespace ns-interns vals)]
16-
(is (sut/apropos-sort namespace vars)
17-
"Doesn't throw errors"))))
14+
(testing "sorts first by the given ns, then clojure namespaces, then the rest, all alphabetically"
15+
(is (= [#'some-random-function #'+ #'str #'find-symbols]
16+
(sut/apropos-sort (find-ns 'orchard.apropos-test)
17+
[#'str #'find-symbols #'some-random-function #'+]))))
18+
19+
(testing "doesn't throw errors"
20+
(is (sut/apropos-sort *ns* (mapcat (comp vals ns-interns) (all-ns))))))
1821

1922
(deftest var-name-test
2023
(testing "Returns Var's namespace-qualified name"

0 commit comments

Comments
 (0)