diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b0e098c..d36e19e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,6 +13,14 @@ jobs: distribution: 'zulu' java-version: '8' + - name: Prepare dotnet + uses: xt0rted/setup-dotnet@v1.5.0 + + - name: Prepare Clojure CLR + run: | + dotnet tool install --global Clojure.Main --version 1.12.0-alpha10 + dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha4 + - name: Install clojure tools uses: DeLaGuardo/setup-clojure@10.1 with: @@ -25,5 +33,8 @@ jobs: key: cljdeps-${{ hashFiles('project.clj') }} restore-keys: cljdeps- - - name: Run tests + - name: Run clj and cljs tests run: lein test-all + + - name: Run cljr tests + run: cljr -X:test diff --git a/README.md b/README.md index b42d6b7..de7d41e 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ Or to your Leiningen project file: [dev.weavejester/medley "1.8.1"] +Or to your deps-clr.edn file: + + io.github.weavejester/medley {:git/tag "FIXME" :git/sha "FIXME"} + ## Documentation * [API Docs](http://weavejester.github.io/medley/medley.core.html) diff --git a/deps-clr.edn b/deps-clr.edn new file mode 100644 index 0000000..6e4856e --- /dev/null +++ b/deps-clr.edn @@ -0,0 +1,6 @@ +{:paths ["src"] + :aliases + {:test {:extra-paths ["test"] + :extra-deps {io.github.dmiller/test-runner {:git/tag "v0.5.1clr" :git/sha "814e06f"}} + :exec-fn cognitect.test-runner.api/test + :exec-args {:dirs ["test"]}}}} diff --git a/src/medley/core.cljc b/src/medley/core.cljc index ef1bcb3..96ba1c9 100644 --- a/src/medley/core.cljc +++ b/src/medley/core.cljc @@ -38,8 +38,8 @@ (dissoc-in m ks)))) (defn- editable? [coll] - #?(:clj (instance? clojure.lang.IEditableCollection coll) - :cljs (satisfies? cljs.core/IEditableCollection coll))) + #?(:cljs (satisfies? cljs.core/IEditableCollection coll) + :default (instance? clojure.lang.IEditableCollection coll))) (defn- assoc-some-transient! [m k v] (if (nil? v) m (assoc! m k v))) @@ -102,8 +102,8 @@ (defn map-entry "Create a map entry for a key and value pair." [k v] - #?(:clj (clojure.lang.MapEntry. k v) - :cljs (cljs.core/MapEntry. k v nil))) + #?(:cljs (cljs.core/MapEntry. k v nil) + :default (clojure.lang.MapEntry. k v))) (defn map-kv "Maps a function over the key/value pairs of an associative collection. Expects @@ -184,21 +184,21 @@ (defn queue "Creates an empty persistent queue, or one populated with a collection." - ([] #?(:clj clojure.lang.PersistentQueue/EMPTY - :cljs cljs.core/PersistentQueue.EMPTY)) + ([] #?(:cljs cljs.core/PersistentQueue.EMPTY + :default clojure.lang.PersistentQueue/EMPTY)) ([coll] (into (queue) coll))) (defn queue? "Returns true if x implements clojure.lang.PersistentQueue." [x] - (instance? #?(:clj clojure.lang.PersistentQueue - :cljs cljs.core/PersistentQueue) x)) + (instance? #?(:cljs cljs.core/PersistentQueue + :default clojure.lang.PersistentQueue) x)) (defn boolean? "Returns true if x is a boolean." [x] - #?(:clj (instance? Boolean x) - :cljs (or (true? x) (false? x)))) + #?(:cljs (or (true? x) (false? x)) + :default (instance? Boolean x))) (defn least "Return the least argument (as defined by the compare function) in O(n) time." @@ -322,12 +322,14 @@ (persistent! (reduce (fn [m v] (let [k (keyf v)] - (assoc! m k #?(:clj (if-let [kv (find m k)] - (collatef (val kv) v) - (initf v)) - :cljs (if (contains? m k) - (collatef (get m k) v) - (initf v)))))) + (assoc! m k #?(:cljs + (if (contains? m k) + (collatef (get m k) v) + (initf v)) + :default + (if-let [kv (find m k)] + (collatef (val kv) v) + (initf v)))))) (transient {}) coll)))) @@ -453,27 +455,31 @@ {:added "1.7.0"} ([pred] (fn [rf] - (let [part #?(:clj (java.util.ArrayList.) :cljs (array-list)) + (let [part #?(:clj (java.util.ArrayList.) + :cljr (System.Collections.ArrayList.) + :cljs (array-list)) prev (volatile! ::none)] (fn ([] (rf)) ([result] - (rf (if (.isEmpty part) + (rf (if #?(:cljr (zero? (.-Count part)) + :default (.isEmpty part)) result - (let [v (vec (.toArray part))] - (.clear part) + (let [v (vec (#?(:cljr .ToArray :default .toArray) part))] + (#?(:cljr .Clear :default .clear) part) (unreduced (rf result v)))))) ([result input] (let [p @prev] (vreset! prev input) - (if (or (#?(:clj identical? :cljs keyword-identical?) p ::none) + (if (or (#?(:cljs keyword-identical? :default identical?) p ::none) (not (pred p input))) - (do (.add part input) result) - (let [v (vec (.toArray part))] - (.clear part) + (do (#?(:cljr .Add :default .add) part input) + result) + (let [v (vec (#?(:cljr .ToArray :default .toArray) part))] + (#?(:cljr .Clear :default .clear) part) (let [ret (rf result v)] (when-not (reduced? ret) - (.add part input)) + (#?(:cljr .Add :default .add) part input)) ret))))))))) ([pred coll] (lazy-seq @@ -601,14 +607,16 @@ This function therefore acts like an atomic `deref` then `swap!`." {:arglists '([atom f & args])} ([atom f] - #?(:clj (loop [] - (let [value @atom] - (if (compare-and-set! atom value (f value)) - value - (recur)))) - :cljs (let [value @atom] - (reset! atom (f value)) - value))) + #?(:cljs + (let [value @atom] + (reset! atom (f value)) + value) + :default + (loop [] + (let [value @atom] + (if (compare-and-set! atom value (f value)) + value + (recur)))))) ([atom f & args] (deref-swap! atom #(apply f % args)))) @@ -624,6 +632,7 @@ Clojure as well as ClojureScript." [ex] #?(:clj (when (instance? Throwable ex) (.getMessage ^Throwable ex)) + :cljr (when (instance? Exception ex) (.-Message ^Exception ex)) :cljs (cljs.core/ex-message ex))) (defn ex-cause @@ -632,18 +641,22 @@ Clojure as well as ClojureScript." [ex] #?(:clj (when (instance? Throwable ex) (.getCause ^Throwable ex)) + :cljr (when (instance? Exception ex) (.-InnerException ^Exception ex)) :cljs (cljs.core/ex-cause ex))) (defn uuid? "Returns true if the value is a UUID." [x] - (instance? #?(:clj java.util.UUID :cljs cljs.core/UUID) x)) + (instance? #?(:clj java.util.UUID + :cljr System.Guid + :cljs cljs.core/UUID) x)) (defn uuid "Returns a UUID generated from the supplied string. Same as `cljs.core/uuid` in ClojureScript, while in Clojure it returns a `java.util.UUID` object." [s] #?(:clj (java.util.UUID/fromString s) + :cljr (System.Guid. s) :cljs (cljs.core/uuid s))) (defn random-uuid @@ -651,21 +664,26 @@ for Clojure as well as ClojureScript." [] #?(:clj (java.util.UUID/randomUUID) + :cljr (System.Guid/NewGuid) :cljs (cljs.core/random-uuid))) (defn regexp? "Returns true if the value is a regular expression." {:added "1.4.0"} [x] - (instance? #?(:clj java.util.regex.Pattern :cljs js/RegExp) x)) + (instance? #?(:clj java.util.regex.Pattern + :cljr System.Text.RegularExpressions.Regex + :cljs js/RegExp) x)) (defn index-of "Returns the index of the first occurrence of the item in the sequential collection coll, or nil if not found." {:added "1.9.0"} - [^java.util.List coll item] + #?(:clj [^java.util.List coll item] + :cljr [^System.Collections.IEnumerable coll item] + :default [coll item]) (when (some? coll) - (let [index (.indexOf coll item)] + (let [index (#?(:cljr .IndexOf :default .indexOf) coll item)] (when-not (neg? index) index)))) (defn find-in diff --git a/test/medley/core_test.cljc b/test/medley/core_test.cljc index 13ff474..7c143fd 100644 --- a/test/medley/core_test.cljc +++ b/test/medley/core_test.cljc @@ -1,7 +1,8 @@ (ns medley.core-test - #?(:clj (:import [clojure.lang ArityException])) - (:require #?(:clj [clojure.test :refer :all] - :cljs [cljs.test :refer-macros [deftest is testing]]) + #?@(:cljs [] + :default [(:import [clojure.lang ArityException])]) + (:require #?(:cljs [cljs.test :refer-macros [deftest is testing]] + :default [clojure.test :refer :all]) [medley.core :as m])) (deftest test-find-first @@ -162,17 +163,17 @@ (deftest test-queue (testing "empty" - #?(:clj (is (instance? clojure.lang.PersistentQueue (m/queue))) - :cljs (is (instance? cljs.core.PersistentQueue (m/queue)))) + #?(:cljs (is (instance? cljs.core.PersistentQueue (m/queue))) + :default (is (instance? clojure.lang.PersistentQueue (m/queue)))) (is (empty? (m/queue)))) (testing "not empty" - #?(:clj (is (instance? clojure.lang.PersistentQueue (m/queue [1 2 3]))) - :cljs (is (instance? cljs.core.PersistentQueue (m/queue [1 2 3])))) + #?(:cljs (is (instance? cljs.core.PersistentQueue (m/queue [1 2 3]))) + :default (is (instance? clojure.lang.PersistentQueue (m/queue [1 2 3])))) (is (= (first (m/queue [1 2 3])) 1)))) (deftest test-queue? - #?(:clj (is (m/queue? clojure.lang.PersistentQueue/EMPTY)) - :cljs (is (m/queue? cljs.core.PersistentQueue.EMPTY))) + #?(:cljs (is (m/queue? cljs.core.PersistentQueue.EMPTY)) + :default (is (m/queue? clojure.lang.PersistentQueue/EMPTY))) (is (not (m/queue? [])))) (deftest test-boolean? @@ -241,9 +242,11 @@ (is (= (m/mapply foo 0 {:baz 1}) [0 1])) (is (= (m/mapply foo 0 {:spam 1}) [0 nil])) (is (= (m/mapply foo 0 nil) [0 nil])) - #?@(:clj [(is (thrown? ArityException (m/mapply foo {}))) - (is (thrown? IllegalArgumentException (m/mapply foo 0)))] - :cljs [(is (thrown? js/Error (m/mapply foo 0)))]))) + (is (thrown? #?(:clj IllegalArgumentException + :cljr ArgumentException + :cljs js/Error) (m/mapply foo 0))) + #?(:cljs (is (= (m/mapply foo {}) [nil nil])) + :default (is (thrown? ArityException (m/mapply foo {})))))) (deftest test-collate-by (is (= (m/collate-by identity conj vector [1 2 2 3 3]) @@ -451,10 +454,11 @@ (is (= (m/abs 2) 2)) (is (= (m/abs -2.1) 2.1)) (is (= (m/abs 1.8) 1.8)) - #?@(:clj [(is (= (m/abs -1/3) 1/3)) - (is (= (m/abs 1/2) 1/2)) - (is (= (m/abs 3N) 3N)) - (is (= (m/abs -4N) 4N))])) + #?@(:cljs [] + :default [(is (= (m/abs -1/3) 1/3)) + (is (= (m/abs 1/2) 1/2)) + (is (= (m/abs 3N) 3N)) + (is (= (m/abs -4N) 4N))])) (deftest test-deref-swap! (let [a (atom 0)] @@ -472,12 +476,14 @@ (deftest test-ex-message (is (= (m/ex-message (ex-info "foo" {})) "foo")) - (is (= (m/ex-message (new #?(:clj Exception :cljs js/Error) "bar")) "bar"))) + (let [ex (new #?(:cljs js/Error :default Exception) "bar")] + (is (= (m/ex-message ex) "bar")))) (deftest test-ex-cause - (let [cause (new #?(:clj Exception :cljs js/Error) "foo")] + (let [cause (new #?(:cljs js/Error :default Exception) "foo")] (is (= (m/ex-cause (ex-info "foo" {} cause)) cause)) - #?(:clj (is (= (m/ex-cause (Exception. "foo" cause)) cause))))) + #?@(:cljs [] + :default [(is (= (m/ex-cause (Exception. "foo" cause)) cause))]))) (deftest test-uuid? (let [x #uuid "d1a4adfa-d9cf-4aa5-9f05-a15365d1bfa6"] @@ -488,14 +494,20 @@ (deftest test-uuid (let [x (m/uuid "d1a4adfa-d9cf-4aa5-9f05-a15365d1bfa6")] - (is (instance? #?(:clj java.util.UUID :cljs cljs.core.UUID) x)) + (is (instance? #?(:clj java.util.UUID + :cljr System.Guid + :cljs cljs.core.UUID) x)) (is (= x #uuid "d1a4adfa-d9cf-4aa5-9f05-a15365d1bfa6")))) (deftest test-random-uuid (let [x (m/random-uuid) y (m/random-uuid)] - (is (instance? #?(:clj java.util.UUID :cljs cljs.core.UUID) x)) - (is (instance? #?(:clj java.util.UUID :cljs cljs.core.UUID) y)) + (is (instance? #?(:clj java.util.UUID + :cljr System.Guid + :cljs cljs.core.UUID) x)) + (is (instance? #?(:clj java.util.UUID + :cljr System.Guid + :cljs cljs.core.UUID) y)) (is (not= x y)))) (deftest test-regexp?