diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..85efa96 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: [push, pull_request] + +jobs: + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch_depth: 0 + + - name: Setup Babashka + uses: turtlequeue/setup-babashka@v1.3.0 + with: + babashka-version: 0.7.8 + + - name: Prepare java + uses: actions/setup-java@v2 + with: + distribution: 'zulu' + java-version: '8' + + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@4.0 + with: + lein: 2.9.1 + + - name: Run clj tests + run: bb test:clj + + - name: Run cljs tests + run: bb test:cljs + + - name: Run babashka tests + run: bb test:bb diff --git a/.gitignore b/.gitignore index 8588983..cb62692 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ pom.xml.asc .lein-failures .cljs_node_repl out/ +.cpcache +.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4eb8d9f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: clojure -lein: 2.9.1 -cache: - directories: - - $HOME/.m2 -script: - - lein test - - lein doo node test-build once diff --git a/README.md b/README.md index 20e3dec..91741f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Specter [![Build Status](https://secure.travis-ci.org/redplanetlabs/specter.png?branch=master)](http://travis-ci.org/redplanetlabs/specter) +# Specter Specter rejects Clojure's restrictive approach to immutable data structure manipulation, instead exposing an elegant API to allow any sort of manipulation imaginable. Specter especially excels at querying and transforming nested and recursive data, important use cases that are very complex to handle with vanilla Clojure. @@ -334,6 +334,10 @@ When using Specter in a project with [clj-kondo](https://github.com/clj-kondo/cl com.rpl.specter/defrichnav clojure.core/defn}} ``` +# Babashka + +This library is compatible with [babashka](https://babashka.org/) as of specter 1.1.4 and babashka 0.7.8. + # License Copyright 2015-2020 Red Planet Labs, Inc. Specter is licensed under Apache License v2.0. diff --git a/bb.edn b/bb.edn new file mode 100644 index 0000000..0d3f3c8 --- /dev/null +++ b/bb.edn @@ -0,0 +1,19 @@ +{:paths ["src/clj"] + :tasks + {test:clj {:doc "Run clj tests with leiningen" + :task (shell "lein test")} + + test:cljs {:doc "Run cljs tests with leiningen" + :task (shell "lein doo node test-build once")} + + test:bb {:doc "Run bb tests" + :extra-paths ["test"] + :extra-deps {org.clojure/test.check {:mvn/version "0.9.0"} + io.github.cognitect-labs/test-runner + {:git/tag "v0.5.0" :git/sha "b3fd0d2"} + org.clojure/tools.namespace {:git/url "https://github.com/babashka/tools.namespace" + :git/sha "3625153ee66dfcec2ba600851b5b2cbdab8fae6c"}} + :requires ([cognitect.test-runner :as tr]) + :task (apply tr/-main + "-d" "test" + *command-line-args*)}}} diff --git a/src/clj/com/rpl/specter/impl.cljc b/src/clj/com/rpl/specter/impl.cljc index 2493271..9a92b2c 100644 --- a/src/clj/com/rpl/specter/impl.cljc +++ b/src/clj/com/rpl/specter/impl.cljc @@ -15,10 +15,11 @@ #?(:clj [clojure.pprint :as pp]) [clojure.string :as s] [clojure.walk :as walk] - #?(:clj [riddley.walk :as riddley])) - - #?(:clj (:import [com.rpl.specter Util MutableCell]))) + #?(:bb [clojure.walk :as riddley] + :clj [riddley.walk :as riddley])) + #?@(:bb [] + :clj [(:import [com.rpl.specter Util MutableCell])])) (def NONE ::NONE) @@ -82,7 +83,9 @@ (defn intern* [ns name val] (throw (ex-info "intern not supported in ClojureScript" {})))) -#?( +#?(:bb + (defmacro fast-object-array [i] + `(object-array ~i)) :clj (defmacro fast-object-array [i] `(com.rpl.specter.Util/makeObjectArray ~i))) @@ -101,7 +104,8 @@ (if (= platform :cljs) `(p/select* ~this ~@args) `(let [~hinted ~this] - (.select* ~hinted ~@args))))) + (#?(:bb p/select* + :clj .select*) ~hinted ~@args))))) :cljs (defn exec-select* [this vals structure next-fn] (p/select* ^not-native this vals structure next-fn))) @@ -115,7 +119,8 @@ (if (= platform :cljs) `(p/transform* ~this ~@args) `(let [~hinted ~this] - (.transform* ~hinted ~@args))))) + (#?(:bb p/transform* + :clj .transform*) ~hinted ~@args))))) :cljs (defn exec-transform* [this vals structure next-fn] @@ -214,13 +219,19 @@ (set_cell [cell x]))) -#?(:cljs +#?(:bb + (defrecord MutableCell [x]) + :cljs (deftype MutableCell [^:volatile-mutable q] PMutableCell (set_cell [this x] (set! q x)))) -#?( +#?(:bb + (defn mutable-cell + ([] (mutable-cell nil)) + ([v] (MutableCell. (volatile! v)))) + :clj (defn mutable-cell ([] (mutable-cell nil)) @@ -232,7 +243,10 @@ ([init] (MutableCell. init)))) -#?( +#?(:bb + (defn set-cell! [^MutableCell c v] + (vreset! (:x c) v)) + :clj (defn set-cell! [^MutableCell c v] (.set c v)) @@ -242,7 +256,10 @@ (set_cell cell val))) -#?( +#?(:bb + (defn get-cell [^MutableCell c] + @(:x c)) + :clj (defn get-cell [^MutableCell c] (.get c)) @@ -290,8 +307,10 @@ (defn do-compiled-traverse* [apath structure] (reify #?(:clj clojure.lang.IReduce :cljs cljs.core/IReduce) (#?(:clj reduce :cljs -reduce) - [this afn] - (#?(:clj .reduce :cljs -reduce) this afn (afn))) + [this afn] + #?(:bb (reduce afn (afn) this) + :default + (#?(:clj .reduce :cljs -reduce) this afn (afn)))) (#?(:clj reduce :cljs -reduce) [this afn start] (let [cell (mutable-cell start)] @@ -308,6 +327,9 @@ )))) #?( +:bb +(defn- call-reduce-interface [^clojure.lang.IReduce traverser afn start] + (reduce afn start traverser)) :clj (defn- call-reduce-interface [^clojure.lang.IReduce traverser afn start] (.reduce traverser afn start) @@ -322,8 +344,10 @@ (let [traverser (do-compiled-traverse* apath structure)] (reify #?(:clj clojure.lang.IReduce :cljs cljs.core/IReduce) (#?(:clj reduce :cljs -reduce) - [this afn] - (#?(:clj .reduce :cljs -reduce) this afn (afn))) + [this afn] + #?(:bb (reduce afn (afn) this) + :default + (#?(:clj .reduce :cljs -reduce) this afn (afn)))) (#?(:clj reduce :cljs -reduce) [this afn start] (let [res (call-reduce-interface traverser afn start)] diff --git a/src/clj/com/rpl/specter/navs.cljc b/src/clj/com/rpl/specter/navs.cljc index 6465432..a587402 100644 --- a/src/clj/com/rpl/specter/navs.cljc +++ b/src/clj/com/rpl/specter/navs.cljc @@ -8,7 +8,8 @@ #?(:clj (:use [com.rpl.specter.macros :only [defnav defrichnav]] [com.rpl.specter.util-macros :only [doseqres]])) (:require [com.rpl.specter.impl :as i] - #?(:clj [clojure.core.reducers :as r]))) + #?@(:bb [] + :clj [[clojure.core.reducers :as r]]))) (defn not-selected?* @@ -103,7 +104,10 @@ structure)) #?(:clj clojure.lang.PersistentArrayMap) - #?(:clj + #?(:bb + (all-transform [structure next-fn] + (non-transient-map-all-transform structure next-fn {})) + :clj (all-transform [structure next-fn] (let [k-it (.keyIterator structure) v-it (.valIterator structure) @@ -185,10 +189,13 @@ :else - (->> structure - (r/map next-fn) - (r/filter not-NONE?) - (into empty-structure)))))) + #?(:bb (into empty-structure + (comp (map next-fn) (filter not-NONE?)) + structure) + :clj (->> structure + (r/map next-fn) + (r/filter not-NONE?) + (into empty-structure))))))) #?(:cljs default) @@ -255,7 +262,10 @@ #?(:clj clojure.lang.PersistentArrayMap) - #?(:clj + #?(:bb + (map-vals-transform [structure next-fn] + (map-vals-non-transient-transform structure {} next-fn)) + :clj (map-vals-transform [structure next-fn] (let [k-it (.keyIterator structure) v-it (.valIterator structure) @@ -282,7 +292,10 @@ array )] (clojure.lang.PersistentArrayMap. array))))) - #?(:clj + #?(:bb + (map-keys-transform [structure next-fn] + (map-keys-non-transient-transform structure {} next-fn)) + :clj (map-keys-transform [structure next-fn] (let [k-it (.keyIterator structure) v-it (.valIterator structure) @@ -505,7 +518,10 @@ structure (updater structure next-fn)))) -#?( +#?(:bb + (defn vec-count [v] + (count v)) + :clj (defn vec-count [^clojure.lang.IPersistentVector v] (.length v)) @@ -557,7 +573,10 @@ (assoc v i newe)))))) -#?( +#?(:bb + (defn transient-vec-count [v] + (count v)) + :clj (defn transient-vec-count [^clojure.lang.ITransientVector v] (.count v))