[Git][clojure-team/prismatic-plumbing-clojure][upstream] New upstream version 0.6.0

Jérôme Charaoui (@lavamind) gitlab at salsa.debian.org
Fri Jul 15 01:46:00 BST 2022



Jérôme Charaoui pushed to branch upstream at Debian Clojure Maintainers / prismatic-plumbing-clojure


Commits:
ded0d134 by Jérôme Charaoui at 2022-07-14T20:06:13-04:00
New upstream version 0.6.0
- - - - -


22 changed files:

- + .github/workflows/test.yml
- .gitignore
- CHANGELOG.md
- README.md
- + deps.edn
- project.clj
- src/plumbing/core.cljx → src/plumbing/core.cljc
- src/plumbing/fnk/pfnk.cljx → src/plumbing/fnk/pfnk.cljc
- src/plumbing/fnk/schema.cljx → src/plumbing/fnk/schema.cljc
- src/plumbing/graph.cljx → src/plumbing/graph.cljc
- src/plumbing/graph/positional.clj
- src/plumbing/graph_async.cljx → src/plumbing/graph_async.cljc
- src/plumbing/map.cljx → src/plumbing/map.cljc
- test/plumbing/core_test.cljx → test/plumbing/core_test.cljc
- test/plumbing/fnk/fnk_examples_test.cljx → test/plumbing/fnk/fnk_examples_test.cljc
- test/plumbing/fnk/pfnk_test.cljx → test/plumbing/fnk/pfnk_test.cljc
- test/plumbing/fnk/schema_test.cljx → test/plumbing/fnk/schema_test.cljc
- test/plumbing/graph_async_test.cljx → test/plumbing/graph_async_test.cljc
- test/plumbing/graph_examples_test.cljx → test/plumbing/graph_examples_test.cljc
- test/plumbing/graph_test.cljx → test/plumbing/graph_test.cljc
- test/plumbing/map_test.cljx → test/plumbing/map_test.cljc
- + test/plumbing/test_runner.cljs


Changes:

=====================================
.github/workflows/test.yml
=====================================
@@ -0,0 +1,44 @@
+name: Test
+
+on:
+  push:
+    branches:
+    - master
+  pull_request:
+  schedule:
+    # monthly
+    - cron: "0 0 1 * *"
+
+env:
+  #bump to clear caches
+  ACTION_CACHE_VERSION: 'v1'
+
+jobs:
+  test:
+    strategy:
+      matrix:
+        java: ['8', '11', '17']
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout at v2
+      - uses: actions/cache at v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj') }}-${{ matrix.java }}
+          restore-keys: |
+            ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj') }}-
+      - name: Prepare java
+        uses: actions/setup-java at v2
+        with:
+          distribution: 'temurin'
+          java-version: ${{ matrix.java }}
+      - uses: actions/setup-node at v2
+        with:
+          node-version: '10.13.0'
+      - name: Install clojure tools
+        uses: DeLaGuardo/setup-clojure at 3.5
+        with:
+          lein: 2.9.7
+      - name: Run tests
+        run: lein all test


=====================================
.gitignore
=====================================
@@ -8,4 +8,5 @@ target/**
 .repl
 out
 .lein-repl-history
-/doc/
\ No newline at end of file
+/doc/
+.cpcache/


=====================================
CHANGELOG.md
=====================================
@@ -1,3 +1,8 @@
+## 0.6.0
+ * **BREAKING** Minimum supported Clojure version is now 1.8
+ * migrate cljx => cljc
+ * Fix #138: Compile graphs bigger than 100 nodes with interpreted mode in Clojure
+
 ## 0.5.5 
  * Bump schema dependency to avoid issues with Clojure 1.9 out of the box.
 


=====================================
README.md
=====================================
@@ -127,7 +127,7 @@ We can also have higher-order functions on Graphs to wrap the behavior on each s
    @(::profile-data (profiled-stats {:xs (range 10000)})))
 ```
 
-… and so on.  For more examples and details about Graph, check out the [graph examples test](https://github.com/plumatic/plumbing/blob/master/test/plumbing/graph_examples_test.cljx).
+… and so on.  For more examples and details about Graph, check out the [graph examples test](https://github.com/plumatic/plumbing/blob/master/test/plumbing/graph_examples_test.cljc).
 
 <a name="fnk"/>
 
@@ -226,7 +226,7 @@ Ever wanted to conditionally do steps in a `->>` or `->`? Now you can with our
 	[1 3 5 7 9])
 ```
 
-Check out [`plumbing.core`](https://github.com/plumatic/plumbing/blob/master/src/plumbing/core.cljx) for many other useful functions.
+Check out [`plumbing.core`](https://github.com/plumatic/plumbing/blob/master/src/plumbing/core.cljc) for many other useful functions.
 
 ## ClojureScript
 
@@ -262,7 +262,7 @@ Plumbing now has a [mailing list](https://groups.google.com/forum/#!forum/prisma
 
 ## Supported Clojure versions
 
-Plumbing is currently supported on Clojure 1.5.x and 1.6.x.
+Plumbing is currently supported on Clojure 1.8 or later, and the latest ClojureScript version.
 
 ## License
 


=====================================
deps.edn
=====================================
@@ -0,0 +1,3 @@
+{:paths ["src"]
+ :deps {prismatic/schema {:mvn/version "1.2.0"}
+        de.kotka/lazymap {:mvn/version "3.1.0"}}}


=====================================
project.clj
=====================================
@@ -1,74 +1,46 @@
-(defproject prismatic/plumbing "0.5.5"
+(defproject prismatic/plumbing "0.6.0"
   :description "Prismatic's Clojure utility belt."
   :url "https://github.com/plumatic/plumbing"
   :license {:name "Eclipse Public License - v 1.0"
             :url "http://www.eclipse.org/legal/epl-v10.html"
             :distribution :repo}
 
-  :dependencies [[prismatic/schema "1.1.7"]
+  :dependencies [[prismatic/schema "1.2.0"]
                  [de.kotka/lazymap "3.1.0" :exclusions [org.clojure/clojure]]]
 
-  :profiles {:dev {:dependencies [[org.clojure/clojure "1.6.0"]
-                                  [org.clojure/clojurescript "0.0-2665"]
-                                  [org.clojure/core.async "0.1.346.0-17112a-alpha"]]
-                   :plugins [[com.keminglabs/cljx "0.6.0" :exclusions [org.clojure/clojure]]
-                             [codox "0.8.8"]
-                             [lein-cljsbuild "1.0.5"]
-                             [com.cemerick/clojurescript.test "0.3.1"]]
-                   :cljx {:builds [{:source-paths ["src"]
-                                    :output-path "target/generated/src/clj"
-                                    :rules :clj}
-                                   {:source-paths ["src"]
-                                    :output-path "target/generated/src/cljs"
-                                    :rules :cljs}
-                                   {:source-paths ["test"]
-                                    :output-path "target/generated/test/clj"
-                                    :rules :clj}
-                                   {:source-paths ["test"]
-                                    :output-path "target/generated/test/cljs"
-                                    :rules :cljs}]}}
-             :1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]}
-             :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
-             :1.8 {:dependencies [[org.clojure/clojure "1.8.0-RC1"]]}}
-
-  :jar-exclusions [#"\.cljx"]
-  :aliases {"all" ["with-profile" "dev:dev,1.5:dev,1.7;dev,1.8"]
-            "deploy" ["do" "clean," "cljx" "once," "deploy" "clojars"]
-            "test" ["do" "clean," "cljx" "once," "test," "with-profile" "dev" "cljsbuild" "test"]}
+  :profiles {:dev {:dependencies [[org.clojure/clojure "1.10.3"]
+                                  [org.clojure/clojurescript "1.10.891"]
+                                  [org.clojure/core.async "1.4.627"]]
+                   :plugins [[codox "0.10.8"]
+                             [lein-cljsbuild "1.1.8"]
+                             [lein-doo "0.1.10"]]}
+             :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}
+             :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}
+             :1.11 {:dependencies [[org.clojure/clojure "1.11.0-master-SNAPSHOT"]]
+                    :repositories [["sonatype-oss-public" {:url "https://oss.sonatype.org/content/groups/public"}]]}}
+
+  :aliases {"all" ["with-profile" "+1.8:+1.9:+dev:+1.11"]
+            "deploy" ["do" "deploy" "clojars"]
+            "test" ["do" "test," "doo" "node" "test" "once"]}
 
   :lein-release {:deploy-via :shell
                  :shell ["lein" "deploy"]}
 
-  :auto-clean false
-
-  :source-paths ["target/generated/src/clj" "src"]
-
-  :resource-paths ["target/generated/src/cljs"]
+  :source-paths ["src"]
+  :test-paths ["test"]
 
-  :test-paths ["target/generated/test/clj" "test"]
-
-  :cljsbuild {:test-commands {"unit" ["phantomjs" :runner
-                                      "this.literal_js_was_evaluated=true"
-                                      "target/unit-test.js"]}
-              :builds
-              {:dev {:source-paths ["src"
-                                    "target/generated/src/clj"
-                                    "target/generated/src/cljs"]
+  :cljsbuild {:builds
+              {:dev {:source-paths ["src"]
                      :compiler {:output-to "target/main.js"
                                 :optimizations :whitespace
                                 :pretty-print true}}
-               :test {:source-paths ["src"
-                                     "target/generated/src/clj"
-                                     "target/generated/src/cljs"
-                                     "target/generated/test/clj"
-                                     "target/generated/test/cljs"]
+               :test {:source-paths ["src" "test"]
                       :compiler {:output-to "target/unit-test.js"
-                                 :optimizations :whitespace
-
+                                 :main plumbing.test-runner
+                                 :target :nodejs
                                  :pretty-print true}}}}
 
-  :codox {:src-uri-mapping {#"target/generated/src/clj" #(str "src/" % "x")}
-          :src-dir-uri "http://github.com/plumatic/plumbing/blob/master/"
+  :codox {:src-dir-uri "http://github.com/plumatic/plumbing/blob/master/"
           :src-linenum-anchor-prefix "L"}
 
   :jvm-opts ^:replace [])


=====================================
src/plumbing/core.cljx → src/plumbing/core.cljc
=====================================
@@ -1,17 +1,17 @@
 (ns plumbing.core
   "Utility belt for Clojure in the wild"
   (:refer-clojure :exclude [update])
-  #+cljs
+  #?(:cljs
   (:require-macros
-   [plumbing.core :refer [for-map lazy-get -unless-update]]
-   [schema.macros :as schema-macros])
+   [plumbing.core :refer [for-map lazy-get]]
+   [schema.macros :as schema-macros]))
   (:require
    [schema.utils :as schema-utils]
-   #+clj [schema.macros :as schema-macros]
-   [plumbing.fnk.schema :as schema :include-macros true]
-   #+clj [plumbing.fnk.impl :as fnk-impl]))
+   #?(:clj [schema.macros :as schema-macros])
+   [plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]
+   #?(:clj [plumbing.fnk.impl :as fnk-impl])))
 
-#+clj (set! *warn-on-reflection* true)
+#?(:clj (set! *warn-on-reflection* true))
 
 (def ^:private +none+
   "A sentinel value representing missing portions of the input data."
@@ -20,6 +20,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Maps
 
+#?(:clj
 (defmacro for-map
   "Like 'for' for building maps. Same bindings except the body should have a
   key-expression and value-expression. If a key is repeated, the last
@@ -37,33 +38,7 @@
         (doseq ~seq-exprs
           (let [~m-sym @m-atom#]
             (reset! m-atom# (assoc! ~m-sym ~key-expr ~val-expr))))
-        (persistent! @m-atom#))))
-
-(defmacro -unless-update
-  "Execute and yield body only if Clojure version preceeds introduction
-  of 'update' into core namespace."
-  [body]
-  `(schema-macros/if-cljs
-    ~body
-    ~(when (pos? (compare
-                  [1 7 0]
-                  (mapv #(get *clojure-version* %)
-                        [:major :minor :incremental])))
-       body)))
-
-(-unless-update
- (defn update
-   "Updates the value in map m at k with the function f.
-
-    Like update-in, but for updating a single top-level key.
-    Any additional args will be passed to f after the value.
-
-    WARNING As of Clojure 1.7 this function exists in clojure.core and
-    will not be exported by this namespace."
-   ([m k f] (assoc m k (f (get m k))))
-   ([m k f x1] (assoc m k (f (get m k) x1)))
-   ([m k f x1 x2] (assoc m k (f (get m k) x1 x2)))
-   ([m k f x1 x2 & xs] (assoc m k (apply f (get m k) x1 x2 xs)))))
+        (persistent! @m-atom#)))))
 
 (defn map-vals
   "Build map k -> (f v) for [k v] in map, preserving the initial type"
@@ -121,12 +96,13 @@
    :else
    x))
 
+#?(:clj
 (defmacro lazy-get
   "Like get but lazy about default"
   [m k d]
   `(if-let [pair# (find ~m ~k)]
      (val pair#)
-     ~d))
+     ~d)))
 
 (defn safe-get
   "Like get but throw an exception if not found"
@@ -220,7 +196,7 @@
   [f s]
   (keep-indexed (fn [i x] (when (f x) i)) s))
 
-#+clj
+#?(:clj
 (defn frequencies-fast
   "Like clojure.core/frequencies, but faster.
    Uses Java's equal/hash, so may produce incorrect results if
@@ -229,16 +205,16 @@
   (let [res (java.util.HashMap.)]
     (doseq [x xs]
       (.put res x (unchecked-inc (int (or (.get res x) 0)))))
-    (into {} res)))
+    (into {} res))))
 
-#+clj
+#?(:clj
 (defn distinct-fast
   "Like clojure.core/distinct, but faster.
    Uses Java's equal/hash, so may produce incorrect results if
    given values that are = but not .equal"
   [xs]
   (let [s (java.util.HashSet.)]
-    (filter #(when-not (.contains s %) (.add s %) true) xs)))
+    (filter #(when-not (.contains s %) (.add s %) true) xs))))
 
 (defn distinct-by
   "Returns elements of xs which return unique
@@ -252,14 +228,14 @@
       (do (swap! s conj id)
           x))))
 
-#+clj
+#?(:clj
 (defn distinct-id
   "Like distinct but uses reference rather than value identity, very clojurey"
   [xs]
   (let [s (java.util.IdentityHashMap.)]
     (doseq [x xs]
       (.put s x true))
-    (iterator-seq (.iterator (.keySet s)))))
+    (iterator-seq (.iterator (.keySet s))))))
 
 (defn interleave-all
   "Analogy: partition:partition-all :: interleave:interleave-all"
@@ -298,30 +274,35 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Control flow
 
+#?(:clj
 (defmacro ?>>
   "Conditional double-arrow operation (->> nums (?>> inc-all? (map inc)))"
   [do-it? & args]
   `(if ~do-it?
      (->> ~(last args) ~@(butlast args))
-     ~(last args)))
+     ~(last args))))
 
+#?(:clj
 (defmacro ?>
   "Conditional single-arrow operation (-> m (?> add-kv? (assoc :k :v)))"
   [arg do-it? & rest]
   `(if ~do-it?
      (-> ~arg ~@rest)
-     ~arg))
+     ~arg)))
 
+#?(:clj
 (defmacro fn->
   "Equivalent to `(fn [x] (-> x ~@body))"
   [& body]
-  `(fn [x#] (-> x# ~@body)))
+  `(fn [x#] (-> x# ~@body))))
 
+#?(:clj
 (defmacro fn->>
   "Equivalent to `(fn [x] (->> x ~@body))"
   [& body]
-  `(fn [x#] (->> x# ~@body)))
+  `(fn [x#] (->> x# ~@body))))
 
+#?(:clj
 (defmacro <-
   "Converts a ->> to a ->
 
@@ -330,13 +311,15 @@
    Jason W01fe is happy to give a talk anywhere any time on
    the calculus of arrow macros"
   [& body]
-  `(-> ~(last body) ~@(butlast body)))
+  `(-> ~(last body) ~@(butlast body))))
 
+#?(:clj
 (defmacro as->>
   "Like as->, but can be used in double arrow."
   [name & forms-and-expr]
-  `(as-> ~(last forms-and-expr) ~name ~@(butlast forms-and-expr)))
+  `(as-> ~(last forms-and-expr) ~name ~@(butlast forms-and-expr))))
 
+#?(:clj
 (defmacro memoized-fn
   "Like fn, but memoized (including recursive calls).
 
@@ -352,7 +335,7 @@
            v#
            (let [v# (do ~@body)]
              (swap! a# assoc args# v#)
-             v#))))))
+             v#)))))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Miscellaneous
@@ -375,8 +358,8 @@
   (first (swap-pair! a (constantly new-val))))
 
 (defn millis ^long []
-  #+clj  (System/currentTimeMillis)
-  #+cljs (.getTime (js/Date.)))
+  #?(:clj  (System/currentTimeMillis)
+     :cljs (.getTime (js/Date.))))
 
 (defn mapply
   "Like apply, but applies a map to a function with positional map
@@ -387,6 +370,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; fnk
 
+#?(:clj
 (defmacro letk
   "Keyword let.  Accepts an interleaved sequence of binding forms and map forms like:
    (letk [[a {b 2} [:f g h] c d {e 4} :as m & more] a-map ...] & body)
@@ -423,8 +407,9 @@
                                           cur-body-form)]
          `(let [~map-sym ~value-form] ~body-form))))
    `(do ~@body)
-   (reverse (partition 2 bindings))))
+   (reverse (partition 2 bindings)))))
 
+#?(:clj
 (defmacro if-letk
   "bindings => binding-form test
 
@@ -440,15 +425,17 @@
           (if temp#
             (letk [~form temp#]
               ~then)
-            ~else)))))
+            ~else))))))
 
+#?(:clj
 (defmacro when-letk
   "bindings => binding-form test
 
   When test is true, evaluates body with binding-form bound to the value of test"
   [bindings & body]
-  `(if-letk ~bindings (do ~@body)))
+  `(if-letk ~bindings (do ~@body))))
 
+#?(:clj
 (defmacro fnk
   "Keyword fn, using letk.  Generates a prismatic/schema schematized fn that
    accepts a single explicit map i.e., (f {:foo :bar}).
@@ -469,8 +456,9 @@
                             (schema-macros/extract-arrow-schematized-element &env args)
                             [nil args])
         [bind body] (schema-macros/extract-arrow-schematized-element &env more-args)]
-    (fnk-impl/fnk-form &env name? bind body &form)))
+    (fnk-impl/fnk-form &env name? bind body &form))))
 
+#?(:clj
 (defmacro defnk
   "Analogy: fn:fnk :: defn::defnk"
   [& defnk-args]
@@ -482,6 +470,6 @@
     (schema/assert-iae (symbol? name) "Name for defnk is not a symbol: %s" name)
     (let [f (fnk-impl/fnk-form &env name bind body &form)]
       `(def ~(with-meta name (merge (meta name) (assoc-when (or attr-map? {}) :doc docstring?)))
-         ~f))))
+         ~f)))))
 
-#+clj (set! *warn-on-reflection* false)
+#?(:clj (set! *warn-on-reflection* false))


=====================================
src/plumbing/fnk/pfnk.cljx → src/plumbing/fnk/pfnk.cljc
=====================================
@@ -5,10 +5,10 @@
    using fn->fnk, or using custom binding syntax (of which 'fnk' et al
    are one possible example)."
   (:require
-   [schema.core :as s :include-macros true]
-   [plumbing.fnk.schema :as schema :include-macros true]))
+   [schema.core :as s #?@(:cljs [:include-macros true])]
+   [plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]))
 
-#+clj (set! *warn-on-reflection* true)
+#?(:clj (set! *warn-on-reflection* true))
 
 (defprotocol PFnk
   "Protocol for keyword functions and their specifications, e.g., fnks and graphs."
@@ -27,7 +27,8 @@
 (defn output [^schema.core.FnSchema s]
   (.-output-schema s))
 
-(extend-type #+clj clojure.lang.Fn #+cljs object
+(extend-type #?(:clj clojure.lang.Fn
+                :cljs object)
              PFnk
              (io-schemata [this]
                (assert (fn? this))
@@ -53,4 +54,4 @@
   [f]
   (:name (meta f)))
 
-#+clj (set! *warn-on-reflection* false)
+#?(:clj (set! *warn-on-reflection* false))


=====================================
src/plumbing/fnk/schema.cljx → src/plumbing/fnk/schema.cljc
=====================================
@@ -11,13 +11,13 @@
    required, or provided via `instance`, and will thus deliberately drop extra key
    schemas on inputs as appropriate.  Output schemas may not have optional keys."
   (:require
-   [schema.core :as s :include-macros true]
+   [schema.core :as s #?@(:cljs [:include-macros true])]
    [schema.utils :as schema-utils]
-   #+clj [schema.macros :as schema-macros])
-  #+cljs
+   #?(:clj [schema.macros :as schema-macros]))
+  #?(:cljs
   (:require-macros
-   #+cljs [schema.macros :as schema-macros]
-   [plumbing.fnk.schema :refer [assert-iae]]))
+   [schema.macros :as schema-macros]
+   [plumbing.fnk.schema :refer [assert-iae]])))
 
 (def Schema (s/protocol s/Schema))
 (def InputSchema {(s/cond-pre (s/eq s/Keyword) schema.core.OptionalKey s/Keyword) Schema})
@@ -30,11 +30,12 @@
 
 ;;; Helpers
 
+#?(:clj
 (defmacro assert-iae
   "Like assert, but throws a RuntimeException in Clojure (not an AssertionError),
    and also takes args to format."
   [form & format-args]
-  `(schema-macros/assert! ~form ~@format-args))
+  `(schema-macros/assert! ~form ~@format-args)))
 
 (defn assert-distinct
   "Like (assert (distinct? things)) but with a more helpful error message."
@@ -70,9 +71,9 @@
   nil)
 
 (defn map-schema? [m]
-  #+clj  (instance? clojure.lang.APersistentMap m)
-  #+cljs (or (instance? cljs.core.PersistentArrayMap m)
-             (instance? cljs.core.PersistentHashMap m)))
+  #?(:clj  (instance? clojure.lang.APersistentMap m)
+     :cljs (or (instance? cljs.core.PersistentArrayMap m)
+               (instance? cljs.core.PersistentHashMap m))))
 
 ;;; Input schemata
 


=====================================
src/plumbing/graph.cljx → src/plumbing/graph.cljc
=====================================
@@ -22,16 +22,16 @@
    For more details and examples of Graphs, see test/plumbing/graph_examples_test.cljx."
   (:refer-clojure :exclude [compile])
   (:require
-   #+clj [lazymap.core :as lazymap]
+   #?(:clj [lazymap.core :as lazymap])
    [schema.core :as s]
-   #+clj [schema.macros :as schema-macros]
-   [plumbing.fnk.schema :as schema :include-macros true]
+   #?(:clj [schema.macros :as schema-macros])
+   [plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]
    [plumbing.fnk.pfnk :as pfnk]
-   #+clj [plumbing.fnk.impl :as fnk-impl]
-   #+clj [plumbing.graph.positional :as graph-positional]
-   [plumbing.core :as plumbing :include-macros true]
+   #?(:clj [plumbing.fnk.impl :as fnk-impl])
+   #?(:clj [plumbing.graph.positional :as graph-positional])
+   [plumbing.core :as plumbing #?@(:cljs [:include-macros true])]
    [plumbing.map :as map])
-  #+cljs (:require-macros [schema.macros :as schema-macros]))
+  #?(:cljs (:require-macros [schema.macros :as schema-macros])))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -68,11 +68,11 @@
                      (apply working-array-map))]
       (assert (every? keyword? (keys graph)))
       (with-meta graph
-        {::io-schemata (update-in (reduce schema/sequence-schemata
-                                          [{} {}]
-                                          (for [[k node] graph]
-                                            [k (pfnk/io-schemata node)]))
-                                  [0] assoc s/Keyword s/Any)
+        {::io-schemata (update (reduce schema/sequence-schemata
+                                       [{} {}]
+                                       (for [[k node] graph]
+                                         [k (pfnk/io-schemata node)]))
+                               0 assoc s/Keyword s/Any)
          ::self graph}))))
 
 ;; Any Clojure map can be treated as a graph directly, without calling ->graph
@@ -81,10 +81,10 @@
   (plumbing/safe-get (meta (->graph g)) ::io-schemata))
 
 (extend-protocol pfnk/PFnk
-  #+clj clojure.lang.IPersistentMap
-  #+cljs cljs.core.PersistentArrayMap
+  #?(:clj clojure.lang.IPersistentMap
+     :cljs cljs.core.PersistentArrayMap)
   (io-schemata [g] (io-schemata* g))
-  #+cljs cljs.core.PersistentHashMap
+  #?(:cljs cljs.core.PersistentHashMap)
   (io-schemata [g] (io-schemata* g)))
 
 (defn- split-nodes [s]
@@ -125,28 +125,55 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Compiling and running graphs
 
-#+clj
+#?(:clj (declare interpreted-eager-compile))
+#?(:clj
 (defn eager-compile
   "Compile graph specification g to a corresponding fnk that is optimized for
    speed. Wherever possible, fnks are called positionally, to reduce the
    overhead of creating and destructuring maps, and the return value is a
    record, which is much faster to create and access than a map.  Compilation
-   is relatively slow, however, due to internal calls to 'eval'."
-  [g]
-  (if (fn? g)
-    g
-    (let [g (for [[k sub-g] (->graph g)]
-              [k (eager-compile sub-g)])]
-      (graph-positional/positional-flat-compile (->graph g)))))
-
-#+clj
+   is relatively slow, however, due to internal calls to 'eval'.
+  
+   Options:
+   :positional-limit is used to decide when to switch to interpreted mode,
+   which does not compile positionally. If positional compilation is required,
+   use option {:positional-limit ##Inf} (at the risk of method-too-large errors)."
+  ([g] (eager-compile g {}))
+  ([g {:keys [positional-limit]
+       :or {positional-limit graph-positional/max-graph-size}
+       :as _opts}]
+   (let [eager-compile (fn eager-compile [g]
+                         (if (fn? g)
+                           g
+                           (let [g* (for [[k sub-g] (->graph g)]
+                                      [k (eager-compile sub-g)])]
+                             (when (every? second g*)
+                               (let [g (->graph g*)]
+                                 (when (<= (-> g pfnk/output-schema count)
+                                           positional-limit)
+                                   (graph-positional/positional-flat-compile g)))))))]
+     (or (eager-compile g)
+         (interpreted-eager-compile g))))))
+
+#?(:clj
 (defn positional-eager-compile
   "Like eager-compile, but produce a non-keyword function that can be called
    with args in the order provided by arg-ks, avoiding the overhead of creating
    and destructuring a top-level map.  This can yield a substantially faster
-   fn for Graphs with very computationally inexpensive node fnks."
+   fn for Graphs with very computationally inexpensive node fnks.
+  
+   Warning: if any level of g exceeds `graph-positional/max-graph-size`, compilation
+   may fail. Do not use for arbitrarily large graphs."
   [g arg-ks]
-  (fnk-impl/positional-fn (eager-compile g) arg-ks))
+  (fnk-impl/positional-fn
+    (eager-compile g
+                   ;; there is no interpreted mode (yet) for positional compilation,
+                   ;; but it is required by `positional-fn`. this forces eager-compile to 
+                   ;; always return a positional graph, even though compilation may fail
+                   ;; due to code size. when available, should be replaced with a scalable
+                   ;; positional compilation.
+                   {:positional-limit Double/POSITIVE_INFINITY})
+    arg-ks)))
 
 (defn simple-flat-compile
   "Helper method for simple (non-nested) graph compilations that convert a graph
@@ -202,7 +229,7 @@
    (fn [m] m)
    (fn [m k f] (assoc m k (restricted-call f m)))))
 
-#+clj
+#?(:clj
 (defn lazy-compile
   "Compile graph specification g to a corresponding fnk that returns a
    lazymap of the node result fns on a given input.  This fnk returns
@@ -216,9 +243,9 @@
    g
    false
    (fn [m] (reduce-kv assoc (lazymap/lazy-hash-map) m)) ;; into is extremely slow on lazymaps.
-   (fn [m k f] (lazymap/delay-assoc m k (delay (restricted-call f m))))))
+   (fn [m k f] (lazymap/delay-assoc m k (delay (restricted-call f m)))))))
 
-#+clj ;; TODO: move out.
+#?(:clj ;; TODO: move out.
 (defn par-compile
   "Experimental.  Launches one future per node at startup; we probably woudln't
    use this in production, and will release more sophisticated parallel
@@ -235,7 +262,7 @@
    g
    true
    (fn [m] (into (lazymap/lazy-hash-map) m))
-   (fn [m k f] (lazymap/delay-assoc m k (future (restricted-call f m))))))
+   (fn [m k f] (lazymap/delay-assoc m k (future (restricted-call f m)))))))
 
 (defn compile
   "Compile graph specification g to a corresponding fnk using the a default
@@ -243,8 +270,8 @@
    Clojure: eager-compile
    ClojureScript: interpreted-eager-compile"
   [g]
-  #+clj  (eager-compile g)
-  #+cljs (interpreted-eager-compile g))
+  #?(:clj  (eager-compile g)
+     :cljs (interpreted-eager-compile g)))
 
 (defn run
   "Eagerly run a graph on an input by compiling and then executing on this input."
@@ -300,6 +327,7 @@
             node-fn))
         g)))))
 
+#?(:clj
 (defmacro instance
   "Experimental.
 
@@ -312,7 +340,7 @@
            {:z 10}))"
   ([g m] `(instance ~g [] ~m))
   ([g bind m]
-     `(comp-partial ~g (plumbing/fnk ~bind ~m))))
+     `(comp-partial ~g (plumbing/fnk ~bind ~m)))))
 
 (defn profiled
   "Modify graph spec g, producing a new graph spec with a new top-level key
@@ -326,11 +354,12 @@
              (pfnk/fn->fnk
               (fn [m]
                 (let [pm (plumbing/safe-get m profile-key)
-                      start #+clj (System/nanoTime) #+cljs (plumbing/millis)
+                      start #?(:clj (System/nanoTime)
+                               :cljs (plumbing/millis))
                       res (f (dissoc m profile-key))]
                   (swap! pm assoc-in ks
-                         #+clj  (/ (- (System/nanoTime) start) 1000000.0)
-                         #+cljs (- (plumbing/millis) start))
+                         #?(:clj  (/ (- (System/nanoTime) start) 1000000.0)
+                            :cljs (- (plumbing/millis) start)))
                   res))
               [(assoc (pfnk/input-schema f)
                  profile-key s/Any)


=====================================
src/plumbing/graph/positional.clj
=====================================
@@ -1,5 +1,6 @@
 (ns plumbing.graph.positional
-  "A compilation method for graphs that avoids maps for speed."
+  "A compilation method for graphs that avoids maps for speed.
+  Prone to failure for graphs with more nodes than `max-graph-size`."
   (:use plumbing.core)
   (:require
    [schema.core :as s]
@@ -9,6 +10,15 @@
   (:import
    clojure.lang.IFn))
 
+(def max-graph-size
+  "The positional compilation algorithm provided by this namespace
+  reliably succeeds only with graphs with `max-graph-size` or less nodes..
+ 
+  The basic strategy is to generate a defrecord field for each node
+  (of which there is a limit of around 120) and then generate a constructor
+  function (whose code size grows linearly in the number of nodes)."
+  100)
+
 (defn def-graph-record
   "Define a record for the output of a graph. It is usable as a function to be
   as close to a map as possible. Return the typename."


=====================================
src/plumbing/graph_async.cljx → src/plumbing/graph_async.cljc
=====================================
@@ -1,16 +1,16 @@
 (ns plumbing.graph-async
-  #+cljs
+  #?(:cljs
   (:require-macros
-   [cljs.core.async.macros :refer [go]])
+   [cljs.core.async.macros :refer [go]]))
   (:require
-   #+clj [clojure.core.async :as async :refer [go <! >!]]
-   #+cljs [cljs.core.async :as async :refer [<! >!]]
-   #+clj [clojure.core.async.impl.protocols :as async-protocols]
-   #+cljs [cljs.core.async.impl.protocols :as async-protocols]
+   #?(:clj [clojure.core.async :as async :refer [go <! >!]]
+      :cljs [cljs.core.async :as async :refer [<! >!]])
+   #?(:clj [clojure.core.async.impl.protocols :as async-protocols]
+      :cljs [cljs.core.async.impl.protocols :as async-protocols])
    [plumbing.fnk.pfnk :as pfnk]
-   [plumbing.fnk.schema :as schema :include-macros true]
-   [plumbing.core :as plumbing :include-macros true]
-   [plumbing.graph :as graph :include-macros true]))
+   [plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]
+   [plumbing.core :as plumbing #?@(:cljs [:include-macros true])]
+   [plumbing.graph :as graph #?@(:cljs [:include-macros true])]))
 
 (defn asyncify
   "Take a fnk f and return an async version by wrapping non-channel
@@ -73,7 +73,7 @@
                                (swap! results assoc k r)
                                (doseq [c (child-map k)]
                                  (when (empty? (c (swap! remaining-parents
-                                                         update-in [c]
+                                                         update c
                                                          disj k)))
                                    (run-node c)))))))]
            (doseq [k (keys g)]


=====================================
src/plumbing/map.cljx → src/plumbing/map.cljc
=====================================
@@ -2,9 +2,8 @@
   "Common operations on maps (both Clojure immutable and mutable Java stuff)"
   (:refer-clojure :exclude [flatten])
   (:require
-   [plumbing.core :as plumbing :include-macros true]
-   [plumbing.fnk.schema :as schema :include-macros true]
-   #+cljs [clojure.set :as set]))
+   [plumbing.core :as plumbing #?@(:cljs [:include-macros true])]
+   [plumbing.fnk.schema :as schema #?@(:cljs [:include-macros true])]))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -117,7 +116,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Java mutable Maps
 
-#+clj
+#?(:clj
 (do
   (defn update-key!
     "Transform value in java.util.Map m under key k with fn f."
@@ -169,12 +168,12 @@
     (let [m (java.util.HashMap.)]
       (doseq [[ks v] nested-counts]
         (inc-key-in! m ks v))
-      m)))
+      m))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Ops on graphs represented as maps.
 
-#+clj
+#?(:clj
 (defn topological-sort
   "Take an adjacency list representation of a graph (a map from node names to
    sequences of child node names), and return a topological ordering of the node
@@ -202,9 +201,9 @@
               r (.remove re c)]
         (when (.containsKey re r)
           (throw (IllegalArgumentException. (format "Graph contains a cycle containing %s and %s" c r)))))
-      candidate)))
+      candidate))))
 
-#+cljs
+#?(:cljs
 (defn topological-sort
   [child-map & [include-leaves?]]
   (let [e (atom child-map)
@@ -228,4 +227,4 @@
               r rs]
         (when (find @re r)
           (throw (ex-info (str "Graph contains a cycle containing " c " and " r) {:nodes [c r]}))))
-      candidate)))
+      candidate))))


=====================================
test/plumbing/core_test.cljx → test/plumbing/core_test.cljc
=====================================
@@ -4,15 +4,15 @@
    [schema.test :as schema-test]
    [plumbing.core :as p :include-macros true]
    [plumbing.fnk.pfnk :as pfnk]
-   #+clj [plumbing.fnk.impl :as fnk-impl]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is are deftest testing use-fixtures]]))
+   #?(:clj [plumbing.fnk.impl :as fnk-impl])
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is are deftest testing use-fixtures]])))
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
   (def AssertionError js/Error)
-  (def Throwable js/Error))
+  (def Throwable js/Error)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Maps
@@ -33,21 +33,6 @@
     (is (= (count m) 1000))
     (is (= (m 999) 499500))))
 
-(p/-unless-update
- (deftest update-test
-   (testing "0 extra args"
-     (is (= {:a 5, :b 0}
-            (p/update {:a 4, :b 0} :a inc)))
-     (is (= {:a 1}
-            (p/update {} :a (fnil inc 0)))))
-   (testing "1 extra arg"
-     (is (= {:a 42, :b 0}
-            (p/update {:a 6, :b 0} :a * 7)))
-     (is (= {:a #{42}}
-            (p/update {} :a (fnil conj #{}) 42))))
-   (testing "100 extra args"
-     (is (= {:a 4951} (apply p/update {:a 1} :a + (range 100)))))))
-
 (deftest map-vals-test
   (is (= (p/map-vals inc {:a 0 :b 0})
          {:a 1 :b 1}))
@@ -164,7 +149,7 @@
   (is (= [0 1 2] (p/positions odd? [1 3 5 2 4 6])))
   (is (= [1 3 5] (take 3 (p/positions odd? (range))))))
 
-#+clj
+#?(:clj
 (deftest frequencies-fast-test
   (is (= {\p 2, \s 4, \i 4, \m 1}
          (p/frequencies-fast "mississippi")))
@@ -173,23 +158,23 @@
   ;; We don't return the right thing on = but not .equals things,
   ;; because of the difference between Java Maps and Clojure maps.
   (is (= {1 1}
-         (p/frequencies-fast [1 (BigInteger. "1")]))))
-#+clj
+         (p/frequencies-fast [1 (BigInteger. "1")])))))
+#?(:clj
 (deftest distinct-fast-test
   (is (= [1 2 3]
          (p/distinct-fast [1 2 3])))
   (is (= [1 2 3]
          (p/distinct-fast [1 2 3 2 1 2 3 2 2])))
   (is (= []
-         (p/distinct-fast []))))
+         (p/distinct-fast [])))))
 
-#+clj
+#?(:clj
 (defn are-fast-things-faster []
   (let [s (apply concat (repeat 100 (range 10000)))]
     (doseq [f [frequencies p/frequencies-fast distinct p/distinct-fast]]
       (println f)
       (dotimes [_ 5]
-        (time (doall (f s)))))))
+        (time (doall (f s))))))))
 
 (deftest distinct-by-test
   (is (= [{:id 1 :data "a"}]
@@ -210,13 +195,13 @@
                 [1 3]
                 [3 1]])))))
 
-#+clj
+#?(:clj
 (deftest distinct-id-test
   (let [x (p/distinct-id [:a :b :c :a :b (Long. 1) (Long. 1)])]
     (is (= 5 (count x)))
     (is (= #{:a :b :c 1} (set x)))
     (is (= #{:a :b :c 1} (set x)))
-    (is (empty? (p/distinct-id nil)))))
+    (is (empty? (p/distinct-id nil))))))
 
 (deftest interleave-all-test
   (is (= [:a 0 :b 1 :c :d] (p/interleave-all [:a :b :c :d] [0 1]))))
@@ -364,12 +349,12 @@
 (deftest letk-dont-require-map-for-nested-only-as
   (is (= 1 (p/letk [[[:a :as a]] {:a 1}] a))))
 
-#+clj
+#?(:clj
 (deftest letk-no-multiple-binding-test
   (is (thrown? Exception (eval '(p/letk [[a a] {:a 1}] a))))
   (is (thrown? Exception (eval '(p/letk [[a/a b/a] {:a/a 1 :b/a 2}] a))))
   (is (= 1 (p/letk [[a] {:a 1} [a] {:a a}] a)))
-  (is (= 1 (p/letk [[a/b] {:a/b 1} [a/b] {:a/b b}] b))))
+  (is (= 1 (p/letk [[a/b] {:a/b 1} [a/b] {:a/b b}] b)))))
 
 (deftest letk-multi-shadow-test
   (let [a 1 b 2 c 3 e 4 e 5
@@ -424,7 +409,7 @@
       (is (= [1 2 3]
              ((p/fnk [a {b (* a 2)} {c (inc b)}] [a b c]) {:a 1}))))
 
-    #+clj
+    #?(:clj
     (testing "positional-fn"
       (let [f (p/fnk [a {b 2} [:c :as c0] [:d d1 {d2 2} [:d3 :as d30] [:d4 d41 :as d4]]]
                 (is (= [a b c0 d1 d2 d30 d41 d4]
@@ -434,7 +419,7 @@
         ((fnk-impl/positional-fn f [:d :a :c])
          {:d1 4 :d3 17 :d4 {:d41 18 :d42 :foo}} 4 3)
         (is (= @call-count 4))
-        (is (thrown? Throwable ((p/fnk [a] a) {:b 3}))))))
+        (is (thrown? Throwable ((p/fnk [a] a) {:b 3})))))))
 
   (testing "fnk output-schema"
     (doseq [f [(p/fnk [] {:a 1 :b {:b1 2}})
@@ -559,11 +544,11 @@
   (is (thrown? Throwable (keyfn-test-docstring :wheres :mycar))))
 
 ;; Test that type hints are properly propagated for fnk and defnk.
-#+clj
+#?(:clj
 (p/defnk ^Byte a-typehinted-defnk [^Long l]
-  (.byteValue l))
+  (.byteValue l)))
 
-#+clj
+#?(:clj
 (deftest type-hints-test
   (is (= Byte (:tag (meta #'a-typehinted-defnk))))
   (doseq [f [a-typehinted-defnk
@@ -571,9 +556,9 @@
              (p/fnk [{^Long l 1}] (.byteValue l))
              (p/fnk [^Long l & m] (.byteValue l))]]
     (is (= (Byte. (byte 1)) (f {:l (Long. 1)})))
-    (is (thrown? Exception (f {:l (Integer. 1)})))))
+    (is (thrown? Exception (f {:l (Integer. 1)}))))))
 
-#+clj
+#?(:clj
 (deftest ^:slow repeated-bindings-test
   (is (thrown? Exception (eval '(p/fnk [x [:x y]] (+ x y)))))
   (is (thrown? Exception (eval '(p/fnk [{x {:y 1}} [:x y]] (+ x y)))))
@@ -582,7 +567,7 @@
   (is (thrown? Exception (eval '(p/fnk [{x {:y 1}} x] (+ x y)))))
   (is (thrown? Exception (eval '(p/fnk [x [:x y] :as m] (+ x y)))))
   (is (thrown? Exception (eval '(p/fnk [{x {:y 1}} [:x y] :as m] (+ x y)))))
-  (is (thrown? Exception (eval '(p/fnk [{x {:y 1}} x :as m] (+ x y))))))
+  (is (thrown? Exception (eval '(p/fnk [{x {:y 1}} x :as m] (+ x y)))))))
 
 (deftest optional-self-shadow-test
   (is (= 1 (let [b 1] ((p/fnk [{a b}] a) {}))))
@@ -608,7 +593,8 @@
     (is (= 3 ((p/fnk [[:m x]] (+ x (:x m))) {:m {:x 2}})))))
 
 (deftest miliis-test
-  (let [now #+clj (System/currentTimeMillis) #+cljs (.getTime (js/Date.))
+  (let [now #?(:clj (System/currentTimeMillis)
+               :cljs (.getTime (js/Date.)))
         threshold 5]
     (is (> threshold
            (- (p/millis) now)))))


=====================================
test/plumbing/fnk/fnk_examples_test.cljx → test/plumbing/fnk/fnk_examples_test.cljc
=====================================
@@ -1,22 +1,22 @@
 (ns plumbing.fnk.fnk-examples-test
   "Explaining input and output schemata, fnk syntax, and their relationships
    by example."
-  #+cljs
+  #?(:cljs
   (:require-macros
-   [cemerick.cljs.test :refer [is deftest testing]])
+   [cljs.test :refer [is deftest testing]]))
   (:require
    [schema.core :as s]
-   [plumbing.core :as p :include-macros true]
+   [plumbing.core :as p #?@(:cljs [:include-macros true])]
    [plumbing.fnk.schema :as schema]
    [plumbing.fnk.pfnk :as pfnk]
-   #+clj [clojure.test :refer :all]
-   #+cljs cemerick.cljs.test))
+   #?(:clj [clojure.test :refer :all]
+      :cljs cljs.test)))
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
   (def AssertionError js/Error)
-  (def Throwable js/Error))
+  (def Throwable js/Error)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Input and output schemata
@@ -153,12 +153,12 @@
 ;; You can also provide schema information on the inputs, with
 ;; validation like schema.core/defn.  See (doc fnk) for details.
 
-#+clj ;; This example uses clj-only annotations, but should otherwise work in cljs
+#?(:clj ;; This example uses clj-only annotations, but should otherwise work in cljs
 (p/defnk a-schematized-fnk :- (s/pred odd?)
   [a :- long b :- int]
-  (+ a b))
+  (+ a b)))
 
-#+clj
+#?(:clj
 (deftest a-schematized-fnk-test
   (is (= [{:a long :b int s/Keyword s/Any} (s/pred odd?)]
          (pfnk/io-schemata a-schematized-fnk)))
@@ -167,7 +167,7 @@
   (s/with-fn-validation
     (is (= 3 (a-schematized-fnk {:a 1 :b (int 2)})))
     (is (thrown? Exception (a-schematized-fnk {:a 1 :b 2})))
-    (is (thrown? Exception (a-schematized-fnk {:a 1 :b (int 1)})))))
+    (is (thrown? Exception (a-schematized-fnk {:a 1 :b (int 1)}))))))
 
 
 ;; fnks also have support for nested bindings, and nested maps


=====================================
test/plumbing/fnk/pfnk_test.cljx → test/plumbing/fnk/pfnk_test.cljc
=====================================
@@ -1,13 +1,13 @@
 (ns plumbing.fnk.pfnk-test
-  #+cljs
+  #?(:cljs
   (:require-macros
-   [cemerick.cljs.test :refer [is deftest testing]])
+   [cljs.test :refer [is deftest testing]]))
   (:require
    [schema.core :as s]
-   [plumbing.core :as p :include-macros true]
+   [plumbing.core :as p #?@(:cljs [:include-macros true])]
    [plumbing.fnk.pfnk :as pfnk]
-   #+clj [clojure.test :refer :all]
-   #+cljs cemerick.cljs.test))
+   #?(:clj [clojure.test :refer :all]
+      :cljs cljs.test)))
 
 (deftest meta-round-trip-test
   (let [i-schema {:x s/Any}


=====================================
test/plumbing/fnk/schema_test.cljx → test/plumbing/fnk/schema_test.cljc
=====================================
@@ -2,23 +2,23 @@
   (:require
    [schema.core :as s]
    [schema.test :as schema-test]
-   [plumbing.core :as p :include-macros true]
+   [plumbing.core :as p #?@(:cljs [:include-macros true])]
    [plumbing.fnk.pfnk :as pfnk]
    [plumbing.fnk.schema :as fnk-schema]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is are deftest testing use-fixtures]]))
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is are deftest testing use-fixtures]])))
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
-  (def RuntimeException js/Error))
+  (def RuntimeException js/Error)))
 
-#+clj ;; the expression-munging doesn't play well with cljs.
+#?(:clj ;; the expression-munging doesn't play well with cljs.
 (deftest explicit-schema-key-map-test
   (is (= {:foo true :bar false :baz false}
          (fnk-schema/explicit-schema-key-map
           {:foo s/Any (s/optional-key :bar) s/Any s/Keyword s/Keyword
-           `(s/optional-key :baz) s/Any}))))
+           `(s/optional-key :baz) s/Any})))))
 
 (deftest split-schema-keys-test
   (is (= [[:foo :bar] [:baz :bat]]
@@ -27,8 +27,8 @@
 
 (deftest merge-on-with-test
   (is (= {0 5 4 9 9 12}
-         (#+clj #'fnk-schema/merge-on-with #+cljs fnk-schema/merge-on-with
-                #(quot % 2) min + {1 2 4 9 9 4} {9 8 0 3}))))
+         (#'fnk-schema/merge-on-with
+           #(quot % 2) min + {1 2 4 9 9 4} {9 8 0 3}))))
 
 (deftest union-input-schemata-test
   (is (= {:a s/Any}
@@ -130,13 +130,13 @@
         :o3 {:x s/Any (s/optional-key :y) s/Any :z s/Any :q {:r s/Any s/Keyword s/Any} s/Keyword s/Any}
         s/Keyword s/Any}
        (p/fnk [{o1 1} o2 [:o3 x {y 2} z [:q r]]]))
-  #+clj
+  #?(:clj
   (do
     (is (= [1 2] ((eval `(p/fnk [[:x ~'x] [:y ~'y]] [~'x ~'y])) {:x {:x 1} :y {:y 2}})))
     (is (thrown? Throwable (eval `(p/fnk [{:y ~'x} {:y ~'y}] [~'x ~'y]))))
     (is (thrown? Throwable (eval `(p/fnk [{:x ~'x} {:y ~'x}] [~'x]))))
     (is (thrown? Throwable (eval `(p/fnk [[:x ~'x] ~'x] [~'x]))))
-    (is (thrown? Throwable (eval `(p/fnk [{~'x 1} ~'x] [~'x]))))))
+    (is (thrown? Throwable (eval `(p/fnk [{~'x 1} ~'x] [~'x])))))))
 
 
 (deftest fnk-out-schemata-test


=====================================
test/plumbing/graph_async_test.cljx → test/plumbing/graph_async_test.cljc
=====================================
@@ -1,14 +1,14 @@
 (ns plumbing.graph-async-test
-  #+cljs
+  #?(:cljs
   (:require-macros
-   [cljs.core.async.macros :refer [go]])
+   [cljs.core.async.macros :refer [go]]))
   (:require
-   [plumbing.core :as plumbing :include-macros true]
+   [plumbing.core :as plumbing #?@(:cljs [:include-macros true])]
    [plumbing.graph-async :as graph-async]
-   #+clj [clojure.core.async :as async :refer [go <!]]
-   #+cljs [cljs.core.async :as async :refer [<!]]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is deftest testing done]]))
+   #?(:clj [clojure.core.async :as async :refer [go <!]]
+      :cljs [cljs.core.async :as async :refer [<!]])
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is deftest testing]])))
 
 (deftest async-compile-test
   (let [c ((graph-async/async-compile
@@ -20,8 +20,9 @@
              :e (plumbing/fnk [{d 9}] (+ d 90))})
            {:x 1 :y 7})
         expected-result {:a {:a1 2 :a2 -9} :b 4 :c -18 :d 49 :e 139}]
-    #+clj (is (= expected-result
-                 (async/<!! c)))
-    #+cljs (go
-            (is (= expected-result (<! c)))
-            (done))))
+    #?(:clj (is (= expected-result
+                   (async/<!! c)))
+       :cljs (go
+               (is (= expected-result (<! c)))
+               ;;FIXME what's the equivalent to `cemerick.cljs.test/done`?
+               #_(done)))))


=====================================
test/plumbing/graph_examples_test.cljx → test/plumbing/graph_examples_test.cljc
=====================================
@@ -1,29 +1,29 @@
 (ns plumbing.graph-examples-test
   (:require
    [schema.core :as s]
-   [plumbing.core :as p :include-macros true]
-   [plumbing.fnk.pfnk :as pfnk :include-macros true]
-   [plumbing.graph :as graph :include-macros true]
+   [plumbing.core :as p #?@(:cljs [:include-macros true])]
+   [plumbing.fnk.pfnk :as pfnk #?@(:cljs [:include-macros true])]
+   [plumbing.graph :as graph #?@(:cljs [:include-macros true])]
    [plumbing.map :as map]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is deftest testing]]))
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is deftest testing]])))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Helpers
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
   (def AssertionError js/Error)
-  (def Throwable js/Error))
+  (def Throwable js/Error)))
 
 (defn hash-or-array-map?
   "Returns true if x is a PersistentHashMap or PersistentArrayMap, otherwise false"
   [x]
-  #+clj  (or (instance? clojure.lang.PersistentHashMap x)
-             (instance? clojure.lang.PersistentArrayMap x))
-  #+cljs (or (instance? cljs.core.PersistentHashMap x)
-             (instance? cljs.core.PersistentArrayMap x)))
+  #?(:clj (or (instance? clojure.lang.PersistentHashMap x)
+              (instance? clojure.lang.PersistentArrayMap x))
+     :cljs (or (instance? cljs.core.PersistentHashMap x)
+               (instance? cljs.core.PersistentArrayMap x))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Motivation
@@ -137,16 +137,16 @@
 ;;     or parallel-compile it so functions that don't depend on one-another
 ;;     are done in separate threads.
 
-#+clj
-(def lazy-stats (graph/lazy-compile stats-graph))
+#?(:clj
+(def lazy-stats (graph/lazy-compile stats-graph)))
 
-#+clj
+#?(:clj
 (deftest lazy-stats-test
   (let [output (lazy-stats {:xs [1 2 3 6]})]
     ;; Nothing has actually been computed yet
     (is (= (/ 25 2) (:m2 output)))
     ;; Now :n, :m, and :m2 have been computed, but :v is still behind a delay
-    ))
+    )))
 
 ;; In cases where only some results from a set of related calculations are
 ;; needed, this lazy compilation can be very convenient and powerful.
@@ -155,14 +155,14 @@
 ;; problem, and lets the compiler do the work of figuring out what can be
 ;; done in parallel.
 
-#+clj
-(def par-stats (graph/par-compile stats-graph))
+#?(:clj
+(def par-stats (graph/par-compile stats-graph)))
 
-#+clj
+#?(:clj
 (deftest par-stats-test
   (let [output (par-stats {:xs [1 2 3 6]})]
     ;; Nodes are being computed in futures, with :m and :m2 going in parallel
-    (is (= (/ 7 2) (:v output)))))
+    (is (= (/ 7 2) (:v output))))))
 
 ;; There are also some compilation modes for performance tuning. If you're
 ;; interested in the details, see below under "Compiling Graphs".
@@ -322,7 +322,7 @@
 ;; can take the value from the parent as input.
 ;; when using a positional graph, you need to order your nodes such that
 ;; the local version is created before it is used.
-#+clj
+#?(:clj
 (deftest local-scoping-rules-test
   (let [x (p/fnk [a x] (inc (+ a x)))
         y (p/fnk [x] (* 2 x))
@@ -341,7 +341,7 @@
                                       5 21)
                                      normalize-output)]
     (is (= expected-result graph-result positional-graph-result))
-    (is (thrown? RuntimeException (graph/graph :y y :x x :z z)))))
+    (is (thrown? RuntimeException (graph/graph :y y :x x :z z))))))
 
 ;; If you're defining a graph explicitly in code, it's rather bad form
 ;; to put the nodes out of topological order (like the first example
@@ -447,7 +447,7 @@
 ;; For example, here's a graph with the same shape as 'stats' but
 ;; where the nodes are slow to compute:
 
-#+clj
+#?(:clj
 (do
   (def slow-graph
     (graph/graph
@@ -490,7 +490,7 @@
       ;; lazy computes stuff as needed
       (let [par (graph/par-compile slow-graph)
             par-out (timed-is 0 keys (par in))]
-        (timed-is 450 true? (= out (into {} par-out))))))) ;; :b1 and :b2 are done in parallel
+        (timed-is 450 true? (= out (into {} par-out)))))))) ;; :b1 and :b2 are done in parallel
 
 ;; There are also some compilation modes for performance tuning. If you're
 ;; going to call your graph in an inner loop, where creating and destructuring
@@ -505,14 +505,14 @@
    :b2 (p/fnk [a] (- a 3))
    :c (p/fnk [b1 b2] (+ b1 b2))))
 
-#+clj
+#?(:clj
 (deftest positional-graph-test
   (let [out {:a 4 :b1 8 :b2 1 :c 9}
         positional-fast (graph/positional-eager-compile fast-graph [:x])
         output (positional-fast 3)]
     (testing "output is a record, not a map"
       (is (not (hash-or-array-map? output))))
-    (is (= out (into {} output)))))
+    (is (= out (into {} output))))))
 
 ;; You won't get all the speedup if you have fnks that expect graph parameters,
 ;; though, such as
@@ -523,7 +523,7 @@
 ;; It's also worth noting that eager-compile does many of the same
 ;; optimizations on the inside, so it also returns a record, not a map.
 
-#+clj
+#?(:clj
 (deftest eager-graph-test
   (let [out {:a 4 :b1 8 :b2 1 :c 9}
         eager-fast (graph/eager-compile fast-graph)
@@ -531,7 +531,7 @@
     ;; The output is a record, not a map.
     (testing "output is a record, not a map"
       (is (not (hash-or-array-map? output))))
-    (is (= out (into {} output)))))
+    (is (= out (into {} output))))))
 
 ;; On the other hand, if you're worried about the computational expense of
 ;; compiling, you can reduce it from a few tens of milliseconds (usually not a
@@ -612,7 +612,7 @@
 ;; Under this simple scheme, we can define functions to start up and
 ;; shutdown a service in just 20 lines of code.
 
-#+clj
+#?(:clj
 (do
   (defn resource-transform [g]
     (assoc (map/map-leaves
@@ -702,7 +702,7 @@
       (shutdown-service svc-map)))
 
   (deftest ^:slow pointless-service-test
-    (test-pointless-service pointless-service {:max-age 1})))
+    (test-pointless-service pointless-service {:max-age 1}))))
 
 ;; To make this sort of composition useful on a large scale, we also
 ;; need a way to provide contextual arguments to subgraphs,


=====================================
test/plumbing/graph_test.cljx → test/plumbing/graph_test.cljc
=====================================
@@ -6,15 +6,16 @@
    [schema.core :as s]
    [schema.test :as schema-test]
    [plumbing.fnk.pfnk :as pfnk]
-   #+clj [plumbing.fnk.impl :as fnk-impl]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is deftest testing use-fixtures]]))
+   #?@(:clj [[plumbing.fnk.impl :as fnk-impl]
+             [plumbing.graph.positional :as positional]])
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is deftest testing use-fixtures]])))
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
   (def AssertionError js/Error)
-  (def Throwable js/Error))
+  (def Throwable js/Error)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -171,7 +172,7 @@
 (deftest interpreted-eager-compile-test
   (test-eager-compile graph/interpreted-eager-compile identity))
 
-#+clj
+#?(:clj
 (deftest eager-compile-test
   ;; eager-compile outputs records rather than ordinary maps as outputs.
   (test-eager-compile graph/eager-compile (partial walk/prewalk #(if (map? %) (into {} %) %)))
@@ -180,9 +181,44 @@
     (is (= [2] (vals o)))
     (is (= 2 (o :x) (get o :x) (:x o)))
     (is (= {:x 2} (into {} o)))
-    (is (not= {:x 2} o))))
-
-#+clj
+    (is (not= {:x 2} o)))))
+
+#?(:clj
+(deftest large-eager-compile-test
+  ;; graphs equal or smaller than positional/max-graph-size, eager-compile returns records
+  (let [size positional/max-graph-size
+        o ((graph/eager-compile 
+             (apply
+               graph/graph
+               (mapcat (fn [i]
+                         (let [k (keyword (str "x" i))]
+                           [k (plumbing/fnk [b a] [k a b])]))
+                       (range size))))
+           {:a 1, :b 2})
+        expected-map (into {}
+                           (map #(let [k (keyword (str "x" %))]
+                                   [k [k 1 2]])
+                                (range size)))]
+    (is (= [:x0 1 2] (o :x0) (get o :x0) (:x0 o)))
+    (is (= expected-map (into {} o)))
+    (is (not= expected-map o)))
+  ;; above positional/max-graph-size, eager-compile returns ordinary maps
+  (let [size (inc positional/max-graph-size)
+        o ((graph/eager-compile
+             (apply
+               graph/graph
+               (mapcat (fn [i]
+                         (let [k (keyword (str "x" i))]
+                           [k (plumbing/fnk [b a] [k a b])]))
+                       (range size))))
+           {:a 1, :b 2})]
+    (is (= (into {}
+                 (map #(let [k (keyword (str "x" %))]
+                         [k [k 1 2]])
+                      (range size)))
+           o)))))
+
+#?(:clj
 (do ;; test defschema with eager-compile -- there were some issues previously
   (ns test (:require [schema.core :as s]))
   (s/defschema Foo {s/Keyword s/Num})
@@ -194,9 +230,9 @@
       (is (= [{:bar test/Foo s/Keyword s/Any}
               {:foo s/Any}]
              (pfnk/io-schemata f)
-             (pfnk/io-schemata g))))))
+             (pfnk/io-schemata g)))))))
 
-#+clj
+#?(:clj
 (deftest positional-eager-compile-test
   (let [f (graph/positional-eager-compile
            (graph/graph
@@ -206,9 +242,24 @@
     (is (= 19 (:x (f 5 3))))
     (is (= 11 (:x (f fnk-impl/+none+ 3))))
     (is (thrown? Exception (f 1)))
-    (is (thrown? Exception (f 3 fnk-impl/+none+)))))
-
-#+clj
+    (is (thrown? Exception (f 3 fnk-impl/+none+))))))
+
+#?(:clj
+(deftest large-positional-eager-compile-test
+  (let [size (inc positional/max-graph-size) ;; make sure :positional-limit is respected
+        fields (vec (repeatedly size gensym))
+        f (graph/positional-eager-compile
+            (apply
+              graph/graph
+              (mapcat (fn [i]
+                        (let [k (keyword (str "x" i))]
+                          [k (plumbing/fnk [b a] [k a b])]))
+                      (range size)))
+            [:b :a])]
+    (is (= [:x0 :asdf 42]
+           (:x0 (f 42 :asdf)))))))
+
+#?(:clj
 (deftest lazy-compile-test
   (let [a (atom [])
         g (graph/graph
@@ -231,7 +282,7 @@
                                 :x (plumbing/fnk [a])
                                 :y (plumbing/fnk [b] (inc b))
                                 :z (plumbing/fnk [y] (inc y))))
-                              {:b 3})))))
+                              {:b 3}))))))
 
 (deftest bind-non-map-with-as-test
   (is (= (:y (graph/run (graph/graph :x (plumbing/fnk [] {:a "1"})
@@ -239,17 +290,17 @@
                         {}))
          "1")))
 
-#+clj
+#?(:clj
 (defn chain-graph [n]
   (plumbing/for-map [i (range n)]
     (keyword (str "x" (inc i)))
     (let [p (keyword (str "x" i))]
-      (pfnk/fn->fnk (fn [m] (inc (p m))) [{p s/Any} s/Any]))))
+      (pfnk/fn->fnk (fn [m] (inc (p m))) [{p s/Any} s/Any])))))
 
-#+clj
+#?(:clj
 (deftest chain-graph-test
   (is (= 100 (:x100 ((graph/eager-compile (chain-graph 100)) {:x0 0}))))
-  (is (= 100 (:x100 ((graph/lazy-compile (chain-graph 100)) {:x0 0})))))
+  (is (= 100 (:x100 ((graph/lazy-compile (chain-graph 100)) {:x0 0}))))))
 
 
 (deftest comp-partial-fn-test
@@ -315,7 +366,7 @@
         (is (= {:x 16 :y 26} (select-keys (graph/run inst-o {:z 3}) [:x :y])))))
     (is (thrown? Exception (graph/instance raw-g [z] {:a z})))))
 
-#+clj
+#?(:clj
 (deftest ^:slow profiled-test
   (let [approx-= (fn [x y] (< (Math/abs (- x y)) 10))
         times {:a 100 :b 200 :c 400}
@@ -328,9 +379,9 @@
     (is (= (select-keys execed [:a :b :c])
            {:a 11 :b -10 :c -110}))
     (doseq [[k t] times]
-      (is (approx-= t (get @(:profile-stats execed) k))))))
+      (is (approx-= t (get @(:profile-stats execed) k)))))))
 
-#+cljs
+#?(:cljs
 (deftest profiled-test
   (let [stats-graph {:n  (plumbing/fnk [xs]   (count xs))
                      :m  (plumbing/fnk [xs n] (/ (plumbing/sum identity xs) n))
@@ -341,9 +392,9 @@
         profile-stats @(::profile-stats output)]
     (is (map? profile-stats))
     (is (= #{:n :m :m2 :v}
-           (set (keys profile-stats))))))
+           (set (keys profile-stats)))))))
 
-#+clj
+#?(:clj
 (defn time-graphs "How slow are big chain graphs?" []
   (let [n 1000
         g (chain-graph n)
@@ -354,6 +405,6 @@
              :lazy   (time (graph/lazy-compile g))}]
       (println k)
       (dotimes [_ 5]
-        (println (time (plumbing/sum tk (repeatedly 10 #(f {:x0 1})))))))))
+        (println (time (plumbing/sum tk (repeatedly 10 #(f {:x0 1}))))))))))
 
 (use-fixtures :once schema-test/validate-schemas)


=====================================
test/plumbing/map_test.cljx → test/plumbing/map_test.cljc
=====================================
@@ -4,16 +4,16 @@
    [plumbing.core :as plumbing]
    [plumbing.map :as map]
    [clojure.string :as str]
-   #+clj [clojure.test :refer :all]
-   #+cljs [cemerick.cljs.test :refer-macros [is deftest testing use-fixtures]])
-  #+cljs
-  (:require-macros [plumbing.map :as map]))
+   #?(:clj [clojure.test :refer :all]
+      :cljs [cljs.test :refer-macros [is deftest testing use-fixtures]]))
+  #?(:cljs
+     (:require-macros [plumbing.map :as map])))
 
-#+cljs
+#?(:cljs
 (do
   (def Exception js/Error)
   (def AssertionError js/Error)
-  (def Throwable js/Error))
+  (def Throwable js/Error)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Clojure immutable maps
@@ -106,7 +106,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Java mutable Maps
 
-#+clj
+#?(:clj
 (do
   (deftest update-key!-test
     (let [m (java.util.HashMap. {:a 1 :b 2})]
@@ -154,7 +154,7 @@
 
   (deftest deep-collate-test
     (is (= {:a {:b 3.0 :c -1.0} :b 4.0}
-           (clojureize (map/deep-collate [[[:a :b] 1.0] [[:a :c] -1.0] [[:a :b] 2.0] [[:b] 4.0]]))))))
+           (clojureize (map/deep-collate [[[:a :b] 1.0] [[:a :c] -1.0] [[:a :b] 2.0] [[:b] 4.0]])))))))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


=====================================
test/plumbing/test_runner.cljs
=====================================
@@ -0,0 +1,20 @@
+(ns plumbing.test-runner
+  (:require [doo.runner :refer-macros [doo-tests]]
+            plumbing.core-test
+            plumbing.fnk.fnk-examples-test
+            plumbing.fnk.pfnk-test
+            plumbing.fnk.schema-test
+            plumbing.graph-async-test
+            plumbing.graph-examples-test
+            plumbing.graph-test
+            plumbing.map-test))
+
+(doo-tests
+  'plumbing.core-test
+  'plumbing.fnk.fnk-examples-test
+  'plumbing.fnk.pfnk-test
+  'plumbing.fnk.schema-test
+  'plumbing.graph-async-test
+  'plumbing.graph-examples-test
+  'plumbing.graph-test
+  'plumbing.map-test)



View it on GitLab: https://salsa.debian.org/clojure-team/prismatic-plumbing-clojure/-/commit/ded0d134d8377befc07f0dfe72c610fdd2c3f6e0

-- 
View it on GitLab: https://salsa.debian.org/clojure-team/prismatic-plumbing-clojure/-/commit/ded0d134d8377befc07f0dfe72c610fdd2c3f6e0
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20220715/d9e84a04/attachment.htm>


More information about the pkg-java-commits mailing list