pax_global_header00006660000000000000000000000064151630000260014503gustar00rootroot0000000000000052 comment=7bf261913c880e38fde6c27c48fbb4be25e2b2df weavejester-medley-50201e1/000077500000000000000000000000001516300002600155435ustar00rootroot00000000000000weavejester-medley-50201e1/.github/000077500000000000000000000000001516300002600171035ustar00rootroot00000000000000weavejester-medley-50201e1/.github/workflows/000077500000000000000000000000001516300002600211405ustar00rootroot00000000000000weavejester-medley-50201e1/.github/workflows/test.yml000066400000000000000000000017471516300002600226530ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - name: Prepare java uses: actions/setup-java@v5 with: 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.2 dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha11 - name: Install clojure tools uses: DeLaGuardo/setup-clojure@13.6.0 with: lein: 2.12.0 - name: Cache clojure dependencies uses: actions/cache@v5 with: path: ~/.m2/repository key: cljdeps-${{ hashFiles('project.clj') }} restore-keys: cljdeps- - name: Run clj and cljs tests run: lein test-all - name: Run cljr tests run: cljr -X:test weavejester-medley-50201e1/.gitignore000066400000000000000000000001611516300002600175310ustar00rootroot00000000000000/target /classes /checkouts /codox pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port /.cpcache /.clj-kondo weavejester-medley-50201e1/.travis.yml000066400000000000000000000000501516300002600176470ustar00rootroot00000000000000language: clojure script: lein test-all weavejester-medley-50201e1/CONTRIBUTING.md000066400000000000000000000021131516300002600177710ustar00rootroot00000000000000# Contributing Guidelines **Do** follow [the seven rules of a great Git commit message][1]. **Do** follow [the Clojure Style Guide][2]. **Do** include tests for your change when appropriate. **Do** ensure that the CI checks pass. **Do** squash the commits in your PR to remove corrections irrelevant to the code history, once the PR has been reviewed. **Do** feel free to pester the project maintainers about the PR if it hasn't been responded to. Sometimes notifications can be missed. **Don't** include more than one feature or fix in a single PR. **Don't** include changes unrelated to the purpose of the PR. This includes changing the project version number, adding lines to the `.gitignore` file, or changing the indentation or formatting. **Don't** open a new PR if changes are requested. Just push to the same branch and the PR will be updated. **Don't** overuse vertical whitespace; avoid multiple sequential blank lines. **Don't** docstring private vars or functions. [1]: https://chris.beams.io/posts/git-commit/#seven-rules [2]: https://github.com/bbatsov/clojure-style-guide weavejester-medley-50201e1/LICENSE.txt000066400000000000000000000265011516300002600173720ustar00rootroot00000000000000Eclipse Public License - v 1.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program. "Contributor" means any person or entity that distributes the Program. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement, including all Contributors. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. 3. REQUIREMENTS A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: a) it complies with the terms and conditions of this Agreement; and b) its license agreement: i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange. When the Program is made available in source code form: a) it must be made available under this Agreement; and b) a copy of this Agreement must be included with each copy of the Program. Contributors may not remove or alter any copyright notices contained within the Program. Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. weavejester-medley-50201e1/README.md000066400000000000000000000031051516300002600170210ustar00rootroot00000000000000# Medley [![Build Status](https://github.com/weavejester/medley/actions/workflows/test.yml/badge.svg)](https://github.com/weavejester/medley/actions/workflows/test.yml) Medley is a lightweight Clojure/ClojureScript library of useful, *mostly* pure functions that are "missing" from clojure.core. Medley has a tighter focus than [flatland/useful][] or [Plumbing][], and limits itself to a small set of general-purpose functions. [flatland/useful]: https://github.com/flatland/useful [plumbing]: https://github.com/plumatic/plumbing ## Installation Add the following dependency to your deps.edn file: dev.weavejester/medley {:mvn/version "1.10.0"} Or to your Leiningen project file: [dev.weavejester/medley "1.10.0"] Or to your deps-clr.edn file: io.github.weavejester/medley {:git/tag "1.10.0" :git/sha "FIXME"} ## Documentation * [API Docs](http://weavejester.github.io/medley/medley.core.html) ## Pre-1.0 Breaking Changes In 0.7.0 the minimum Clojure version was changed from 1.5.1 to 1.7.0 to take advantage of [reader conditionals][]. The `update` function has also been removed, as it is now present in `clojure.core`. In 0.6.0 the type signature of `greatest` and `least` was changed to be more like `max` and `min` in Clojure core. If you're upgrading from a version prior to 0.6.0, please update your usage of `greatest` and `least`. [reader conditionals]: http://dev.clojure.org/display/design/Reader+Conditionals ## License Copyright © 2026 James Reeves Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version. weavejester-medley-50201e1/deps-clr.edn000066400000000000000000000003701516300002600177440ustar00rootroot00000000000000{: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"]}}}} weavejester-medley-50201e1/deps.edn000066400000000000000000000000651516300002600171670ustar00rootroot00000000000000{:deps {org.clojure/clojure {:mvn/version "1.9.0"}}} weavejester-medley-50201e1/project.clj000066400000000000000000000026571516300002600177150ustar00rootroot00000000000000(defproject dev.weavejester/medley "1.10.0" :description "A lightweight library of useful, mostly pure functions" :url "https://github.com/weavejester/medley" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.9.0"]] :plugins [[lein-codox "0.10.8"] [lein-cljsbuild "1.1.8"] [lein-doo "0.1.11"]] :codox {:output-path "codox" :metadata {:doc/format :markdown} :source-uri "http://github.com/weavejester/medley/blob/{version}/{filepath}#L{line}"} :cljsbuild {:builds {:test {:source-paths ["src" "test"] :compiler {:output-to "target/main.js" :output-dir "target" :main medley.test-runner :optimizations :simple}}}} :doo {:paths {:rhino "lein run -m org.mozilla.javascript.tools.shell.Main"}} :aliases {"test-cljs" ["doo" "rhino" "test" "once"] "test-clj" ["with-profile" "default:+1.10:+1.11:+1.12" "test"] "test-all" ["do" ["test-clj"] ["test-cljs"]]} :profiles {:provided {:dependencies [[org.clojure/clojurescript "1.10.439"]]} :test {:dependencies [[org.mozilla/rhino "1.9.1"]]} :dev {:dependencies [[criterium "0.4.6"]] :jvm-opts ^:replace {}} :1.10 {:dependencies [[org.clojure/clojure "1.10.0"]]} :1.11 {:dependencies [[org.clojure/clojure "1.11.2"]]} :1.12 {:dependencies [[org.clojure/clojure "1.12.4"]]}}) weavejester-medley-50201e1/src/000077500000000000000000000000001516300002600163325ustar00rootroot00000000000000weavejester-medley-50201e1/src/medley/000077500000000000000000000000001516300002600176115ustar00rootroot00000000000000weavejester-medley-50201e1/src/medley/core.cljc000066400000000000000000000642021516300002600214020ustar00rootroot00000000000000(ns medley.core "A small collection of useful, mostly pure functions that might not look out of place in the clojure.core namespace." (:refer-clojure :exclude [abs boolean? ex-cause ex-message random-uuid regexp? uuid uuid?])) (defn find-first "Finds the first item in a collection that matches a predicate. Returns a transducer when no collection is provided." ([pred] (fn [rf] (fn ([] (rf)) ([result] (rf result)) ([result x] (if (pred x) (ensure-reduced (rf result x)) result))))) ([pred coll] (reduce (fn [_ x] (when (pred x) (reduced x))) nil coll))) (defn dissoc-in "Dissociate a value in a nested associative structure, identified by a sequence of keys. Any collections left empty by the operation will be dissociated from their containing structures." ([m ks] (if-let [[k & ks] (seq ks)] (if (seq ks) (let [v (dissoc-in (get m k) ks)] (if (empty? v) (dissoc m k) (assoc m k v))) (dissoc m k)) m)) ([m ks & kss] (if-let [[ks' & kss] (seq kss)] (recur (dissoc-in m ks) ks' kss) (dissoc-in m ks)))) (defn- editable? [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))) (defn assoc-some "Associates a key k, with a value v in a map m, if and only if v is not nil." ([m k v] (if (nil? v) m (assoc m k v))) ([m k v & kvs] (if (editable? m) (loop [acc (assoc-some-transient! (transient (or m {})) k v) kvs kvs] (if (next kvs) (recur (assoc-some-transient! acc (first kvs) (second kvs)) (nnext kvs)) (if (zero? (count acc)) m (with-meta (persistent! acc) (meta m))))) (loop [acc (assoc-some m k v) kvs kvs] (if (next kvs) (recur (assoc-some acc (first kvs) (second kvs)) (nnext kvs)) acc))))) (defn update-existing "Updates a value in a map given a key and a function, if and only if the key exists in the map. See: `clojure.core/update`." {:arglists '([m k f & args]) :added "1.1.0"} ([m k f] (if-let [kv (find m k)] (assoc m k (f (val kv))) m)) ([m k f x] (if-let [kv (find m k)] (assoc m k (f (val kv) x)) m)) ([m k f x y] (if-let [kv (find m k)] (assoc m k (f (val kv) x y)) m)) ([m k f x y z] (if-let [kv (find m k)] (assoc m k (f (val kv) x y z)) m)) ([m k f x y z & more] (if-let [kv (find m k)] (assoc m k (apply f (val kv) x y z more)) m))) (defn update-existing-in "Updates a value in a nested associative structure, if and only if the key path exists. See: `clojure.core/update-in`." {:added "1.3.0"} [m ks f & args] (let [up (fn up [m ks f args] (let [[k & ks] ks] (if-let [kv (find m k)] (if ks (assoc m k (up (val kv) ks f args)) (assoc m k (apply f (val kv) args))) m)))] (up m ks f args))) (defn- reduce-map [f coll] (let [coll' (if (record? coll) (into {} coll) coll)] (if (editable? coll') (persistent! (reduce-kv (f assoc!) (transient (empty coll')) coll')) (reduce-kv (f assoc) (empty coll') coll')))) (defn map-entry "Create a map entry for a key and value pair." [k v] #?(: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 a function that takes two arguments, the key and value, and returns the new key and value as a collection of two elements." [f coll] (reduce-map (fn [xf] (fn [m k v] (let [[k v] (f k v)] (xf m k v)))) coll)) (defn map-keys "Maps a function over the keys of an associative collection." [f coll] (reduce-map (fn [xf] (fn [m k v] (xf m (f k) v))) coll)) (defn map-vals "Maps a function over the values of one or more associative collections. The function should accept number-of-colls arguments. Any keys which are not shared among all collections are ignored." ([f coll] (reduce-map (fn [xf] (fn [m k v] (xf m k (f v)))) coll)) ([f c1 & colls] (reduce-map (fn [xf] (fn [m k v] (if (every? #(contains? % k) colls) (xf m k (apply f v (map #(get % k) colls))) m))) c1))) (defn map-kv-keys "Maps a function over the key/value pairs of an associative collection, using the return of the function as the new key." {:added "1.2.0"} [f coll] (reduce-map (fn [xf] (fn [m k v] (xf m (f k v) v))) coll)) (defn map-kv-vals "Maps a function over the key/value pairs of an associative collection, using the return of the function as the new value." {:added "1.2.0"} [f coll] (reduce-map (fn [xf] (fn [m k v] (xf m k (f k v)))) coll)) (defn filter-kv "Returns a new associative collection of the items in coll for which `(pred (key item) (val item))` returns true." [pred coll] (reduce-map (fn [xf] (fn [m k v] (if (pred k v) (xf m k v) m))) coll)) (defn filter-keys "Returns a new associative collection of the items in coll for which `(pred (key item))` returns true." [pred coll] (reduce-map (fn [xf] (fn [m k v] (if (pred k) (xf m k v) m))) coll)) (defn filter-vals "Returns a new associative collection of the items in coll for which `(pred (val item))` returns true." [pred coll] (reduce-map (fn [xf] (fn [m k v] (if (pred v) (xf m k v) m))) coll)) (defn remove-kv "Returns a new associative collection of the items in coll for which `(pred (key item) (val item))` returns false." [pred coll] (filter-kv (complement pred) coll)) (defn remove-keys "Returns a new associative collection of the items in coll for which `(pred (key item))` returns false." [pred coll] (filter-keys (complement pred) coll)) (defn remove-vals "Returns a new associative collection of the items in coll for which `(pred (val item))` returns false." [pred coll] (filter-vals (complement pred) coll)) (defn queue "Creates an empty persistent queue, or one populated with a collection." ([] #?(: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? #?(:cljs cljs.core/PersistentQueue :default clojure.lang.PersistentQueue) x)) (defn boolean? "Returns true if x is a boolean." [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." {:arglists '([& xs])} ([] nil) ([a] a) ([a b] (if (neg? (compare a b)) a b)) ([a b & more] (reduce least (least a b) more))) (defn least-by "Return the argument for which (keyfn x) is least. Determined by the compare function in O(n) time. Prefer `clojure.core/min-key` if keyfn returns numbers." {:arglists '([keyfn & xs]) :added "1.6.0"} ([_] nil) ([_ x] x) ([keyfn x y] (if (neg? (compare (keyfn x) (keyfn y))) x y)) ([keyfn x y & more] (let [kx (keyfn x) ky (keyfn y) [v kv] (if (neg? (compare kx ky)) [x kx] [y ky])] (loop [v v kv kv more more] (if more (let [w (first more) kw (keyfn w)] (if (pos? (compare kw kv)) (recur v kv (next more)) (recur w kw (next more)))) v))))) (defn greatest "Find the greatest argument (as defined by the compare function) in O(n) time." {:arglists '([& xs])} ([] nil) ([a] a) ([a b] (if (pos? (compare a b)) a b)) ([a b & more] (reduce greatest (greatest a b) more))) (defn greatest-by "Return the argument for which (keyfn x) is greatest. Determined by the compare function in O(n) time. Prefer `clojure.core/max-key` if keyfn returns numbers." {:arglists '([keyfn & xs]) :added "1.6.0"} ([_] nil) ([_ x] x) ([keyfn x y] (if (pos? (compare (keyfn x) (keyfn y))) x y)) ([keyfn x y & more] (let [kx (keyfn x) ky (keyfn y) [v kv] (if (pos? (compare kx ky)) [x kx] [y ky])] (loop [v v kv kv more more] (if more (let [w (first more) kw (keyfn w)] (if (neg? (compare kw kv)) (recur v kv (next more)) (recur w kw (next more)))) v))))) (defn join "Lazily concatenates a collection of collections into a flat sequence." {:added "1.1.0"} [colls] (lazy-seq (when-let [s (seq colls)] (concat (first s) (join (rest s)))))) (defn deep-merge "Recursively merges maps together. If all the maps supplied have nested maps under the same keys, these nested maps are merged. Otherwise the value is overwritten, as in `clojure.core/merge`." {:arglists '([& maps]) :added "1.1.0"} ([]) ([a] a) ([a b] (when (or a b) (letfn [(merge-entry [m e] (let [k (key e) v' (val e)] (if (contains? m k) (assoc m k (let [v (get m k)] (if (and (map? v) (map? v')) (deep-merge v v') v'))) (assoc m k v'))))] (reduce merge-entry (or a {}) (seq b))))) ([a b & more] (reduce deep-merge (or a {}) (cons b more)))) (defn mapply "Applies a function f to the argument list formed by concatenating everything but the last element of args with the last element of args. This is useful for applying a function that accepts keyword arguments to a map." {:arglists '([f & args])} ([f m] (apply f (apply concat m))) ([f a & args] (apply f a (apply concat (butlast args) (last args))))) (defn collate-by "Similar to `clojure.core/group-by`, this groups values in a collection, coll, based on the return value of a function, keyf applied to each element. Unlike `group-by`, the values of the map are constructed via an initf and collatef function. The initf function is applied to the first element matched by keyf, and defaults to the identity function. The collatef function takes the result of initf and the next keyed element, and produces a new value. To put this in context, the `group-by` function can be defined as: (defn group-by [f coll] (collate-by f conj vector coll)) While the `medley.core/index-by` function can be (and is) defined as: (defn index-by [f coll] (collate-by f (fn [_ x] x) coll))" {:added "1.8.0"} ([keyf collatef coll] (collate-by keyf collatef identity coll)) ([keyf collatef initf coll] (persistent! (reduce (fn [m v] (let [k (keyf 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)))) (defn index-by "Returns a map of the elements of coll keyed by the result of f on each element. The value at each key will be the last element in coll associated with that key. This function is similar to `clojure.core/group-by`, except that elements with the same key are overwritten, rather than added to a vector of values." {:added "1.2.0"} [f coll] #_(persistent! (reduce #(assoc! %1 (f %2) %2) (transient {}) coll)) (collate-by f (fn [_ x] x) coll)) (defn interleave-all "Returns a lazy seq of the first item in each coll, then the second, etc. Unlike `clojure.core/interleave`, the returned seq contains all items in the supplied collections, even if the collections are different sizes." {:arglists '([& colls])} ([] ()) ([c1] (lazy-seq c1)) ([c1 c2] (lazy-seq (let [s1 (seq c1), s2 (seq c2)] (if (and s1 s2) (cons (first s1) (cons (first s2) (interleave-all (rest s1) (rest s2)))) (or s1 s2))))) ([c1 c2 & colls] (lazy-seq (let [ss (keep seq (conj colls c2 c1))] (when (seq ss) (concat (map first ss) (apply interleave-all (map rest ss)))))))) (defn distinct-by "Returns a lazy sequence of the elements of coll, removing any elements that return duplicate values when passed to a function f. Returns a stateful transducer when no collection is provided." ([f] (fn [rf] (let [seen (volatile! #{})] (fn ([] (rf)) ([result] (rf result)) ([result x] (let [fx (f x)] (if (contains? @seen fx) result (do (vswap! seen conj fx) (rf result x))))))))) ([f coll] (let [step (fn step [xs seen] (lazy-seq ((fn [[x :as xs] seen] (when-let [s (seq xs)] (let [fx (f x)] (if (contains? seen fx) (recur (rest s) seen) (cons x (step (rest s) (conj seen fx))))))) xs seen)))] (step coll #{})))) (defn dedupe-by "Returns a lazy sequence of the elements of coll, removing any **consecutive** elements that return duplicate values when passed to a function f. Returns a stateful transducer when no collection is provided." ([f] (fn [rf] (let [pv (volatile! ::none)] (fn ([] (rf)) ([result] (rf result)) ([result x] (let [prior @pv fx (f x)] (vreset! pv fx) (if (= prior fx) result (rf result x)))))))) ([f coll] (sequence (dedupe-by f) coll))) (defn take-upto "Returns a lazy sequence of successive items from coll up to and including the first item for which `(pred item)` returns true. Returns a transducer when no collection is provided." ([pred] (fn [rf] (fn ([] (rf)) ([result] (rf result)) ([result x] (let [result (rf result x)] (if (pred x) (ensure-reduced result) result)))))) ([pred coll] (lazy-seq (when-let [s (seq coll)] (let [x (first s)] (cons x (when-not (pred x) (take-upto pred (rest s))))))))) (defn drop-upto "Returns a lazy sequence of the items in coll starting *after* the first item for which `(pred item)` returns true. Returns a stateful transducer when no collection is provided." ([pred] (fn [rf] (let [dv (volatile! true)] (fn ([] (rf)) ([result] (rf result)) ([result x] (if @dv (do (when (pred x) (vreset! dv false)) result) (rf result x))))))) ([pred coll] (rest (drop-while (complement pred) coll)))) (defn partition-between "Applies pred to successive values in coll, splitting it each time `(pred prev-item item)` returns logical true. Returns a lazy seq of partitions. Returns a stateful transducer when no collection is provided." {:added "1.7.0"} ([pred] (fn [rf] (let [part #?(:clj (java.util.ArrayList.) :cljr (System.Collections.ArrayList.) :cljs (array-list)) prev (volatile! ::none)] (fn ([] (rf)) ([result] (rf (if #?(:cljr (zero? (.-Count part)) :default (.isEmpty part)) result (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 (#?(:cljs keyword-identical? :default identical?) p ::none) (not (pred p input))) (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) (#?(:cljr .Add :default .add) part input)) ret))))))))) ([pred coll] (lazy-seq (letfn [(take-part [prev coll] (lazy-seq (when-let [[x & xs] (seq coll)] (when-not (pred prev x) (cons x (take-part x xs))))))] (when-let [[x & xs] (seq coll)] (let [run (take-part x xs)] (cons (cons x run) (partition-between pred (lazy-seq (drop (count run) xs)))))))))) (defn partition-after "Returns a lazy sequence of partitions, splitting after `(pred item)` returns true. Returns a stateful transducer when no collection is provided." {:added "1.5.0"} ([pred] (partition-between (fn [x _] (pred x)))) ([pred coll] (partition-between (fn [x _] (pred x)) coll))) (defn partition-before "Returns a lazy sequence of partitions, splitting before `(pred item)` returns true. Returns a stateful transducer when no collection is provided." {:added "1.5.0"} ([pred] (partition-between (fn [_ x] (pred x)))) ([pred coll] (partition-between (fn [_ x] (pred x)) coll))) (defn window "A sliding window, returning a lazy sequence of partitions, containing each element and n-1 preceeding elements, when present. Therefore partitions at the start may contain fewer items than the rest. Returns a stateful transducer when no collection is provided. For a sliding window containing each element and n-1 _following_ elements, use `clojure.core/partition` with a `step` size of 1." {:added "1.9.0"} ([n] (fn [rf] (let [part #?(:clj (java.util.ArrayList. n) :cljr (System.Collections.ArrayList.) :cljs (array))] (fn ([] (rf)) ([result] (rf result)) ([result x] #?(:clj (.add part x) :cljr (.Add part x) :cljs (.push part x)) (when (< n #?(:clj (.size part) :cljr (.Count part) :cljs (.-length part))) #?(:clj (.remove part 0) :cljr (.RemoveAt part 0) :cljs (.shift part))) (rf result (vec #?(:clj (.toArray part) :cljr (.ToArray part) :cljs (.slice part))))))))) ([n coll] (letfn [(part [part-n coll] (let [run (doall (take part-n coll))] (lazy-seq (when (== part-n (count run)) (cons run (part (min n (inc part-n)) (if (== n part-n) (rest coll) coll)))))))] (part (min 1 n) coll)))) (defn indexed "Returns an ordered, lazy sequence of vectors `[index item]`, where item is a value in coll, and index its position starting from zero. Returns a stateful transducer when no collection is provided." ([] (fn [rf] (let [i (volatile! -1)] (fn ([] (rf)) ([result] (rf result)) ([result x] (rf result [(vswap! i inc) x])))))) ([coll] (map-indexed vector coll))) (defn insert-nth "Returns a lazy sequence of the items in coll, with a new item inserted at the supplied index, followed by all subsequent items of the collection. Runs in O(n) time. Returns a stateful transducer when no collection is provided." {:added "1.2.0"} ([index item] (fn [rf] (let [idx (volatile! (inc index))] (fn ([] (rf)) ([result] (if (= @idx 1) (rf (rf result item)) (rf result))) ([result x] (if (zero? (vswap! idx dec)) (rf (rf result item) x) (rf result x))))))) ([index item coll] (lazy-seq (if (zero? index) (cons item coll) (when (seq coll) (cons (first coll) (insert-nth (dec index) item (rest coll)))))))) (defn remove-nth "Returns a lazy sequence of the items in coll, except for the item at the supplied index. Runs in O(n) time. Returns a stateful transducer when no collection is provided." {:added "1.2.0"} ([index] (fn [rf] (let [idx (volatile! (inc index))] (fn ([] (rf)) ([result] (rf result)) ([result x] (if (zero? (vswap! idx dec)) result (rf result x))))))) ([index coll] (lazy-seq (if (zero? index) (rest coll) (when (seq coll) (cons (first coll) (remove-nth (dec index) (rest coll)))))))) (defn replace-nth "Returns a lazy sequence of the items in coll, with a new item replacing the item at the supplied index. Runs in O(n) time. Returns a stateful transducer when no collection is provided." {:added "1.2.0"} ([index item] (fn [rf] (let [idx (volatile! (inc index))] (fn ([] (rf)) ([result] (rf result)) ([result x] (if (zero? (vswap! idx dec)) (rf result item) (rf result x))))))) ([index item coll] (lazy-seq (if (zero? index) (cons item (rest coll)) (when (seq coll) (cons (first coll) (replace-nth (dec index) item (rest coll)))))))) (defn abs "Returns the absolute value of a number." [x] (if (neg? x) (- x) x)) (defn deref-swap! "Atomically swaps the value of the atom to be `(apply f x args)`, where x is the current value of the atom, then returns the original value of the atom. This function therefore acts like an atomic `deref` then `swap!`." {:arglists '([atom f & args])} ([atom f] #?(: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)))) (defn deref-reset! "Sets the value of the atom without regard for the current value, then returns the original value of the atom. See also: [[deref-swap!]]." [atom newval] (deref-swap! atom (constantly newval))) (defn ex-message "Returns the message attached to the given Error/Throwable object. For all other types returns nil. Same as `cljs.core/ex-message` except it works for 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 "Returns the cause attached to the given ExceptionInfo/Throwable object. For all other types returns nil. Same as `cljs.core/ex-cause` except it works for 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 :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 "Generates a new random UUID. Same as `cljs.core/random-uuid` except it works 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 :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"} #?(:clj [^java.util.List coll item] :cljr [^System.Collections.IEnumerable coll item] :default [coll item]) (when (some? coll) (let [index (#?(:cljr .IndexOf :default .indexOf) coll item)] (when-not (neg? index) index)))) (defn find-in "Similar to `clojure.core/find`, except that it finds a key/value pair in an nested associate structure `m`, given a sequence of keys `ks`. See also: `clojure.core/get-in`." {:added "1.9.0"} [m ks] (if (next ks) (-> (get-in m (butlast ks)) (find (last ks))) (find m (first ks)))) (letfn [(first* [s v] (if s (first s) v))] (defn map-padded "Similar to `clojure.core/map`, except that it runs until all colls are exhausted, using `val` as the missing value for each exhausted coll." {:added "1.10.0"} #_{:clj-kondo/ignore [:unused-binding]} ([f val c1] (map f c1)) ([f val c1 c2] (lazy-seq (let [s1 (seq c1) s2 (seq c2)] (when (or s1 s2) (cons (f (first* s1 val) (first* s2 val)) (map-padded f val (rest s1) (rest s2))))))) ([f val c1 c2 c3] (lazy-seq (let [s1 (seq c1) s2 (seq c2) s3 (seq c3)] (when (or s1 s2 s3) (cons (f (first* s1 val) (first* s2 val) (first* s3 val)) (map-padded f val (rest s1) (rest s2) (rest s3))))))) ([f val c1 c2 c3 & colls] (let [step (fn step [cs] (lazy-seq (let [ss (mapv seq cs)] (when (some identity ss) (cons (apply f (mapv #(first* % val) ss)) (step (mapv rest ss)))))))] (step (conj colls c3 c2 c1)))))) (defn sequence-padded "Similar to `clojure.core/sequence`, except that it runs until all colls are exhausted, using `val` as the missing value for each exhausted coll." {:added "1.10.0"} #_{:clj-kondo/ignore [:unused-binding]} ([xform val c1] (sequence xform c1)) ([xform val c1 & colls] (let [f (xform conj) step (fn step [cs] (lazy-seq (let [ss (mapv seq cs)] (if (some identity ss) (let [res (apply f nil (mapv #(if % (first %) val) ss))] (cond (reduced? res) (f (deref res)) (nil? res) (step (mapv rest ss)) :else (concat res (lazy-seq (step (mapv rest ss)))))) (f nil)))))] (step (conj colls c1))))) weavejester-medley-50201e1/test/000077500000000000000000000000001516300002600165225ustar00rootroot00000000000000weavejester-medley-50201e1/test/medley/000077500000000000000000000000001516300002600200015ustar00rootroot00000000000000weavejester-medley-50201e1/test/medley/core_test.cljc000066400000000000000000000570771516300002600226450ustar00rootroot00000000000000(ns medley.core-test #?@(: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 (testing "sequences" (is (= (m/find-first even? [7 3 3 2 8]) 2)) (is (nil? (m/find-first even? [7 3 3 7 3])))) (testing "transducers" (is (= (transduce (m/find-first even?) + 0 [7 3 3 2 8]) 2)) (is (= (transduce (m/find-first even?) + 0 [7 3 3 7 3]) 0)))) (deftest test-dissoc-in (is (= (m/dissoc-in {:a {:b {:c 1 :d 2}}} [:a :b :c]) {:a {:b {:d 2}}})) (is (= (m/dissoc-in {:a {:b {:c 1}}} [:a :b :c]) {})) (is (= (m/dissoc-in {:a {:b {:c 1} :d 2}} [:a :b :c]) {:a {:d 2}})) (is (= (m/dissoc-in {:a {:b {:c 1} :d 2} :b {:c {:d 2 :e 3}}} [:a :b :c] [:b :c :d]) {:a {:d 2} :b {:c {:e 3}}})) (is (= (m/dissoc-in {:a 1} []) {:a 1}))) (deftest test-assoc-some (is (= (m/assoc-some {:a 1} :b 2) {:a 1 :b 2})) (is (= (m/assoc-some {:a 1} :b nil) {:a 1})) (is (= (m/assoc-some {:a 1} :b 2 :c nil :d 3) {:a 1 :b 2 :d 3})) (is (= (m/assoc-some nil :a 1) {:a 1})) (is (= (m/assoc-some nil :a 1 :b 2) {:a 1 :b 2})) (is (nil? (m/assoc-some nil :a nil))) (is (nil? (m/assoc-some nil :a nil :b nil))) (let [input (with-meta {:a 1} {:m 42})] (is (= {:m 42} (meta (m/assoc-some input :b 2 :c nil :d 3)))))) (deftest test-update-existing (is (= (m/update-existing {:a 1} :a inc) {:a 2})) (is (= (m/update-existing {:a 1 :b 2} :a inc) {:a 2 :b 2})) (is (= (m/update-existing {:b 2} :a inc) {:b 2})) (is (= (m/update-existing {:a nil} :a str) {:a ""})) (is (= (m/update-existing {} :a str) {}))) (deftest test-update-existing-in (is (= (m/update-existing-in {:a 1} [:a] inc) {:a 2})) (is (= (m/update-existing-in {:a 1 :b 2} [:a] inc) {:a 2 :b 2})) (is (= (m/update-existing-in {:b 2} [:a] inc) {:b 2})) (is (= (m/update-existing-in {:a nil} [:a] str) {:a ""})) (is (= (m/update-existing-in {} [:a] str) {})) (is (= (m/update-existing-in {:a [:b {:c 42} :d]} [:a 1 :c] inc) {:a [:b {:c 43} :d]})) (is (= (m/update-existing-in {:a [:b {:c 42} :d]} [:a 1 :c] + 7) {:a [:b {:c 49} :d]})) (is (= (m/update-existing-in {:a [:b {:c 42} :d]} [:a 1 :c] + 3 4) {:a [:b {:c 49} :d]})) (is (= (m/update-existing-in {:a [:b {:c 42} :d]} [:a 1 :c] + 3 3 1) {:a [:b {:c 49} :d]})) (is (= (m/update-existing-in {:a [:b {:c 42} :d]} [:a 1 :c] vector 9 10 11 12 13 14) {:a [:b {:c [42 9 10 11 12 13 14]} :d]}))) (deftest test-map-entry (is (= (key (m/map-entry :a 1)) :a)) (is (= (val (m/map-entry :a 1)) 1)) (is (= (first (m/map-entry :a 1)) :a)) (is (= (second (m/map-entry :a 1)) 1)) (is (= (type (m/map-entry :a 1)) (type (first {:a 1}))))) (defrecord MyRecord [x]) (deftest test-map-kv (is (= (m/map-kv (fn [k v] [(name k) (inc v)]) {:a 1 :b 2}) {"a" 2 "b" 3})) (is (= (m/map-kv (fn [k v] [(name k) (inc v)]) (sorted-map :a 1 :b 2)) {"a" 2 "b" 3})) (is (= (m/map-kv (fn [k v] (m/map-entry (name k) (inc v))) {:a 1 :b 2}) {"a" 2 "b" 3})) (testing "map-kv with record" (is (= (m/map-kv (fn [k v] (m/map-entry (name k) (inc v))) (->MyRecord 1)) {"x" 2})))) (deftest test-map-keys (is (= (m/map-keys name {:a 1 :b 2}) {"a" 1 "b" 2})) (is (= (m/map-keys name (sorted-map :a 1 :b 2)) (sorted-map "a" 1 "b" 2))) (testing "map-keys with record" (is (= (m/map-keys name (->MyRecord 1)) {"x" 1})))) (deftest test-map-vals (is (= (m/map-vals inc {:a 1 :b 2}) {:a 2 :b 3})) (is (= (m/map-vals inc (sorted-map :a 1 :b 2)) (sorted-map :a 2 :b 3))) (testing "map-vals with record" (is (= (m/map-vals inc (->MyRecord 1)) {:x 2}))) (testing "multiple collections" (is (= (m/map-vals + {:a 1 :b 2 :c 3} {:a 4 :c 5 :d 6}) {:a 5, :c 8})) (is (= (m/map-vals min (sorted-map :z 10 :y 8 :x 4) {:x 7, :y 14, :z 13} {:x 11, :y 6, :z 9} {:x 19, :y 3, :z 2} {:x 4, :y 0, :z 16} {:x 17, :y 14, :z 13}) (sorted-map :x 4 :y 0 :z 2))) (is (= (m/map-vals #(%1 %2) {:a nil? :b some?} {:b nil}) {:b false})))) (deftest test-map-kv-keys (is (= (m/map-kv-keys + {1 2, 2 4}) {3 2, 6 4})) (is (= (m/map-kv-keys + (sorted-map 1 2, 2 4)) (sorted-map 3 2, 6 4))) (is (= (m/map-kv-keys str (->MyRecord 1)) {":x1" 1}))) (deftest test-map-kv-vals (is (= (m/map-kv-vals + {1 2, 2 4}) {1 3, 2 6})) (is (= (m/map-kv-vals + (sorted-map 1 2, 2 4)) (sorted-map 1 3, 2 6))) (is (= (m/map-kv-vals str (->MyRecord 1)) {:x ":x1"}))) (deftest test-filter-kv (is (= (m/filter-kv (fn [k v] (and (keyword? k) (number? v))) {"a" 1 :b 2 :c "d"}) {:b 2})) (is (= (m/filter-kv (fn [k v] (= v 2)) (sorted-map "a" 1 "b" 2)) (sorted-map "b" 2)))) (deftest test-filter-keys (is (= (m/filter-keys keyword? {"a" 1 :b 2}) {:b 2})) (is (= (m/filter-keys #(re-find #"^b" %) (sorted-map "a" 1 "b" 2)) (sorted-map "b" 2)))) (deftest test-filter-vals (is (= (m/filter-vals even? {:a 1 :b 2}) {:b 2})) (is (= (m/filter-vals even? (sorted-map :a 1 :b 2)) (sorted-map :b 2)))) (deftest test-remove-kv (is (= (m/remove-kv (fn [k v] (and (keyword? k) (number? v))) {"a" 1 :b 2 :c "d"}) {"a" 1 :c "d"})) (is (= (m/remove-kv (fn [k v] (= v 2)) (sorted-map "a" 1 "b" 2)) (sorted-map "a" 1)))) (deftest test-remove-keys (is (= (m/remove-keys keyword? {"a" 1 :b 2}) {"a" 1})) (is (= (m/remove-keys #(re-find #"^b" %) (sorted-map "a" 1 "b" 2)) {"a" 1}))) (deftest test-remove-vals (is (= (m/remove-vals even? {:a 1 :b 2}) {:a 1})) (is (= (m/remove-keys #(re-find #"^b" %) (sorted-map "a" 1 "b" 2)) {"a" 1}))) (deftest test-queue (testing "empty" #?(:cljs (is (instance? cljs.core.PersistentQueue (m/queue))) :default (is (instance? clojure.lang.PersistentQueue (m/queue)))) (is (empty? (m/queue)))) (testing "not empty" #?(: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? #?(:cljs (is (m/queue? cljs.core.PersistentQueue.EMPTY)) :default (is (m/queue? clojure.lang.PersistentQueue/EMPTY))) (is (not (m/queue? [])))) (deftest test-boolean? (is (m/boolean? true)) (is (m/boolean? false)) (is (not (m/boolean? nil))) (is (not (m/boolean? "foo"))) (is (not (m/boolean? 1)))) (deftest test-least (is (= (m/least) nil)) (is (= (m/least "a") "a")) (is (= (m/least "a" "b") "a")) (is (= (m/least 3 2 5 -1 0 2) -1))) (deftest test-least-by (is (= (m/least-by :a) nil)) (is (= (m/least-by :a {:a 42}) {:a 42})) (is (= (m/least-by :a {:a 3} {:a 1} {:a 2}) {:a 1})) (is (= (m/least-by :a {:a 3 :b 1} {:a 2 :b 2} {:a 2 :b 3}) {:a 2 :b 3})) (is (= (m/least-by last "foo" "baa" "baz" "qux") "baa"))) (deftest test-greatest (is (= (m/greatest) nil)) (is (= (m/greatest "a") "a")) (is (= (m/greatest "a" "b") "b")) (is (= (m/greatest 3 2 5 -1 0 2) 5))) (deftest test-greatest-by (is (= (m/greatest-by :a) nil)) (is (= (m/greatest-by :a {:a 42}) {:a 42})) (is (= (m/greatest-by :a {:a 3} {:a 1} {:a 2}) {:a 3})) (is (= (m/greatest-by :a {:a 2 :b 1} {:a 3 :b 2} {:a 3 :b 3}) {:a 3 :b 3})) (is (= (m/greatest-by last "foo" "baa" "baz" "qux") "baz"))) (deftest test-join (is (= (m/join [[1 2] [] [3] [4 5 6]]) [1 2 3 4 5 6])) (is (= (m/join (sorted-map :x 1, :y 2, :z 3)) [:x 1 :y 2 :z 3])) (let [a (atom 0) s (m/join (iterate #(do (swap! a inc) (range (inc (count %)))) ()))] (is (= (first s) 0)) (is (= @a 1)) (is (= (second s) 0)) (is (= @a 2)))) (deftest test-deep-merge (is (= (m/deep-merge) nil)) (is (= (m/deep-merge {:a 1}) {:a 1})) (is (= (m/deep-merge {:a 1} nil) {:a 1})) (is (= (m/deep-merge {:a 1} {:a 2 :b 3}) {:a 2 :b 3})) (is (= (m/deep-merge {:a {:b 1 :c 2}} {:a {:b 2 :d 3}}) {:a {:b 2 :c 2 :d 3}})) (is (= (m/deep-merge {:a {:b 1}} {:a 1}) {:a 1})) (is (= (m/deep-merge {:a 1} {:b 2} {:b 3 :c 4}) {:a 1 :b 3 :c 4})) (is (= (m/deep-merge {:a {:b {:c {:d 1}}}} {:a {:b {:c {:e 2}}}}) {:a {:b {:c {:d 1 :e 2}}}})) (is (= (m/deep-merge {:a {:b [1 2]}} {:a {:b [3 4]}}) {:a {:b [3 4]}})) (is (= (m/deep-merge (->MyRecord 1) {:x 2}) (->MyRecord 2))) (is (= (m/deep-merge {:a (->MyRecord 1)} {:a {:x 2 :y 3}}) {:a (map->MyRecord {:x 2 :y 3})}))) (deftest test-mapply (letfn [(foo [& {:keys [bar]}] bar)] (is (= (m/mapply foo {}) nil)) (is (= (m/mapply foo {:baz 1}) nil)) (is (= (m/mapply foo {:bar 1}) 1))) (letfn [(foo [bar & {:keys [baz]}] [bar baz])] (is (= (m/mapply foo 0 {}) [0 nil])) (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])) (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]) {1 [1], 2 [2 2], 3 [3 3]})) (is (= (m/collate-by identity conj hash-set [1 2 2 3 3]) {1 #{1}, 2 #{2}, 3 #{3}})) (is (= (m/collate-by first conj list ["foo" "bar" "baz"]) {\f '("foo"), \b '("baz" "bar")})) (is (= (m/collate-by first (fn [_ x] x) ["foo" "bar" "baz"]) {\f "foo", \b "baz"})) (is (= (m/collate-by even? + [1 2 3 4 5 6]) {true 12, false 9})) (is (= (m/collate-by first (fn [_ x] x) []) {})) (is (= (m/collate-by first conj vector []) {}))) (deftest test-index-by (is (= (m/index-by identity [1 2 3]) {1 1, 2 2, 3 3})) (is (= (m/index-by inc [1 2 3]) {2 1, 3 2, 4 3})) (is (= (m/index-by first ["foo" "bar" "baz"]) {\f "foo", \b "baz"})) (is (= (m/index-by first []) {}))) (deftest test-interleave-all (is (= (m/interleave-all []) [])) (is (= (m/interleave-all [1 2 3]) [1 2 3])) (is (= (m/interleave-all [1 2 3] [4 5 6]) [1 4 2 5 3 6])) (is (= (m/interleave-all [1 2 3] [4 5 6] [7 8 9]) [1 4 7 2 5 8 3 6 9])) (is (= (m/interleave-all [1 2] [3]) [1 3 2])) (is (= (m/interleave-all [1 2 3] [4 5]) [1 4 2 5 3])) (is (= (m/interleave-all [1] [2 3] [4 5 6]) [1 2 4 3 5 6]))) (deftest test-distinct-by (testing "sequences" (is (= (m/distinct-by count ["a" "ab" "c" "cd" "def"]) ["a" "ab" "def"])) (is (= (m/distinct-by count []) [])) (is (= (m/distinct-by first ["foo" "faa" "boom" "bar"]) ["foo" "boom"]))) (testing "transucers" (is (= (into [] (m/distinct-by count) ["a" "ab" "c" "cd" "def"]) ["a" "ab" "def"])) (is (= (into [] (m/distinct-by count) []) [])) (is (= (into [] (m/distinct-by first) ["foo" "faa" "boom" "bar"]) ["foo" "boom"])))) (deftest test-dedupe-by (testing "sequences" (is (= (m/dedupe-by count ["a" "b" "bc" "bcd" "cd"]) ["a" "bc" "bcd" "cd"])) (is (= (m/dedupe-by count []) [])) (is (= (m/dedupe-by first ["foo" "faa" "boom" "bar"]) ["foo" "boom"]))) (testing "transucers" (is (= (into [] (m/dedupe-by count) ["a" "b" "bc" "bcd" "cd"]) ["a" "bc" "bcd" "cd"])) (is (= (into [] (m/dedupe-by count) []) [])) (is (= (into [] (m/dedupe-by first) ["foo" "faa" "boom" "bar"]) ["foo" "boom"])))) (deftest test-take-upto (testing "sequences" (is (= (m/take-upto zero? [1 2 3 0 4 5 6]) [1 2 3 0])) (is (= (m/take-upto zero? [0 1 2 3 4 5 6]) [0])) (is (= (m/take-upto zero? [1 2 3 4 5 6 7]) [1 2 3 4 5 6 7]))) (testing "tranducers" (is (= (into [] (m/take-upto zero?) [1 2 3 0 4 5 6]) [1 2 3 0])) (is (= (into [] (m/take-upto zero?) [0 1 2 3 4 5 6]) [0])) (is (= (into [] (m/take-upto zero?) [1 2 3 4 5 6 7]) [1 2 3 4 5 6 7])) (is (= (transduce (m/take-upto zero?) (completing (fn [_ x] (reduced x))) nil [0 1 2]) 0)))) (deftest test-drop-upto (testing "sequences" (is (= (m/drop-upto zero? [1 2 3 0 4 5 6]) [4 5 6])) (is (= (m/drop-upto zero? [0 1 2 3 4 5 6]) [1 2 3 4 5 6])) (is (= (m/drop-upto zero? [1 2 3 4 5 6 7]) []))) (testing "transducers" (is (= (into [] (m/drop-upto zero?) [1 2 3 0 4 5 6]) [4 5 6])) (is (= (into [] (m/drop-upto zero?) [0 1 2 3 4 5 6]) [1 2 3 4 5 6])) (is (= (into [] (m/drop-upto zero?) [1 2 3 4 5 6 7]) [])))) (deftest test-partition-after (testing "sequences" (is (= (m/partition-after identity nil) '())) (is (= (m/partition-after even? [1 3 5 6 8 9 10 11]) '((1 3 5 6) (8) (9 10) (11)))) (is (= (m/partition-after even? [2 4 6 8 10]) '((2) (4) (6) (8) (10)))) (is (= (m/partition-after even? [1 3 5 7 9]) '((1 3 5 7 9))))) (testing "transducers" (is (= (transduce (m/partition-after identity) conj nil) [])) (is (= (transduce (m/partition-after even?) conj [1 3 5 6 8 9 10 11]) [[1 3 5 6] [8] [9 10] [11]])) (is (= (sequence (m/partition-after even?) [2 4 6 8 10]) '([2] [4] [6] [8] [10]))) (is (= (into [] (m/partition-after even?) [1 3 5 7 9]) [[1 3 5 7 9]])) (is (= (transduce (m/partition-after even?) (completing (fn [coll x] (cond-> (conj coll x) (= [8] x) reduced))) [] [1 3 5 6 8 9]) [[1 3 5 6] [8]])))) (deftest test-partition-before (testing "sequences" (is (= (m/partition-before identity nil) '())) (is (= (m/partition-before even? [1 3 5 6 8 9 10 11]) '((1 3 5) (6) (8 9) (10 11)))) (is (= (m/partition-before even? [2 4 6 8 10]) '((2) (4) (6) (8) (10)))) (is (= (m/partition-before even? [1 3 5 7 9]) '((1 3 5 7 9))))) (testing "transducers" (is (= (transduce (m/partition-before identity) conj nil) [])) (is (= (transduce (m/partition-before even?) conj [1 3 5 6 8 9 10 11]) [[1 3 5] [6] [8 9] [10 11]])) (is (= (sequence (m/partition-before even?) [2 4 6 8 10]) '([2] [4] [6] [8] [10]))) (is (= (into [] (m/partition-before even?) [1 3 5 7 9]) [[1 3 5 7 9]])) (is (= (transduce (m/partition-before even?) (completing (fn [coll x] (cond-> (conj coll x) (= [6] x) reduced))) [] [1 3 5 6 8 9]) [[1 3 5] [6]])))) (deftest test-partition-between (testing "sequences" (is (= (m/partition-between = nil) '())) (is (= (m/partition-between < [1]) '((1)))) (is (= (m/partition-between < [1 1 2 2 1 1 3 3 3]) '((1 1) (2 2 1 1) (3 3 3)))) (is (= (m/partition-between < [1 2 3 4]) '((1) (2) (3) (4)))) (is (= (m/partition-between < [4 3 2 1]) '((4 3 2 1))))) (testing "transducers" (is (= (transduce (m/partition-between <) conj nil) [])) (is (= (transduce (m/partition-between <) conj [1]) [[1]])) (is (= (transduce (m/partition-between <) conj [1 1 2 2 1 1 3 3 3]) [[1 1] [2 2 1 1] [3 3 3]])) (is (= (sequence (m/partition-between <) [1 2 3 4]) '([1] [2] [3] [4]))) (is (= (into [] (m/partition-between <) [4 3 2 1]) [[4 3 2 1]])) (is (= (transduce (m/partition-between <) (completing (fn [coll x] (cond-> (conj coll x) (= [8] x) reduced))) [] [1 2 3 2 8 9]) [[1] [2] [3 2] [8]])))) (deftest test-window (testing "sequences" (is (= (m/window 2 nil) '())) (is (= (m/window 2 [:a]) '((:a)))) (is (= (m/window 2 [:a :b]) '((:a) (:a :b)))) (is (= (m/window 2 [:a :b :c]) '((:a) (:a :b) (:b :c)))) (is (= (take 3 (m/window 0 [:a :b :c])) '(() () ()))) (is (= (m/window 10 [:a :b :c]) '((:a) (:a :b) (:a :b :c))))) (testing "transducers" (is (= (transduce (m/window 2) conj nil) [])) (is (= (transduce (m/window 2) conj [:a]) [[:a]])) (is (= (transduce (m/window 2) conj [:a :b]) [[:a] [:a :b]])) (is (= (transduce (m/window 2) conj [:a :b :c]) [[:a] [:a :b] [:b :c]])) (is (= (transduce (m/window 0) conj [:a :b :c]) [[] [] []])) (is (= (transduce (m/window 10) conj [:a :b :c]) [[:a] [:a :b] [:a :b :c]])) (is (= (transduce (m/window 2) (completing (fn [coll x] (cond-> (conj coll x) (= [:a :b] x) reduced))) [] [:a :b :c :d]) [[:a] [:a :b]])))) (deftest test-indexed (testing "sequences" (is (= (m/indexed [:a :b :c :d]) [[0 :a] [1 :b] [2 :c] [3 :d]])) (is (= (m/indexed []) []))) (testing "transducers" (is (= (into [] (m/indexed) [:a :b :c :d]) [[0 :a] [1 :b] [2 :c] [3 :d]])) (is (= (into [] (m/indexed) []) [])))) (deftest test-insert-nth (testing "sequences" (is (= (m/insert-nth 0 :a [1 2 3 4]) [:a 1 2 3 4])) (is (= (m/insert-nth 1 :a [1 2 3 4]) [1 :a 2 3 4])) (is (= (m/insert-nth 3 :a [1 2 3 4]) [1 2 3 :a 4])) (is (= (m/insert-nth 4 :a [1 2 3 4]) [1 2 3 4 :a]))) (testing "transducers" (is (= (into [] (m/insert-nth 0 :a) [1 2 3 4]) [:a 1 2 3 4])) (is (= (into [] (m/insert-nth 1 :a) [1 2 3 4]) [1 :a 2 3 4])) (is (= (into [] (m/insert-nth 3 :a) [1 2 3 4]) [1 2 3 :a 4])) (is (= (into [] (m/insert-nth 4 :a) [1 2 3 4]) [1 2 3 4 :a])))) (deftest test-remove-nth (testing "sequences" (is (= (m/remove-nth 0 [1 2 3 4]) [2 3 4])) (is (= (m/remove-nth 1 [1 2 3 4]) [1 3 4])) (is (= (m/remove-nth 3 [1 2 3 4]) [1 2 3]))) (testing "transducers" (is (= (into [] (m/remove-nth 0) [1 2 3 4]) [2 3 4])) (is (= (into [] (m/remove-nth 1) [1 2 3 4]) [1 3 4])) (is (= (into [] (m/remove-nth 3) [1 2 3 4]) [1 2 3])))) (deftest test-replace-nth (testing "sequences" (is (= (m/replace-nth 0 :a [1 2 3 4]) [:a 2 3 4])) (is (= (m/replace-nth 1 :a [1 2 3 4]) [1 :a 3 4])) (is (= (m/replace-nth 3 :a [1 2 3 4]) [1 2 3 :a]))) (testing "transducers" (is (= (into [] (m/replace-nth 0 :a) [1 2 3 4]) [:a 2 3 4])) (is (= (into [] (m/replace-nth 1 :a) [1 2 3 4]) [1 :a 3 4])) (is (= (into [] (m/replace-nth 3 :a) [1 2 3 4]) [1 2 3 :a])))) (deftest test-abs (is (= (m/abs -3) 3)) (is (= (m/abs 2) 2)) (is (= (m/abs -2.1) 2.1)) (is (= (m/abs 1.8) 1.8)) #?@(: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)] (is (= (m/deref-swap! a inc) 0)) (is (= @a 1)) (is (= (m/deref-swap! a inc) 1)) (is (= @a 2)))) (deftest test-deref-reset! (let [a (atom 0)] (is (= (m/deref-reset! a 3) 0)) (is (= @a 3)) (is (= (m/deref-reset! a 1) 3)) (is (= @a 1)))) (deftest test-ex-message (is (= (m/ex-message (ex-info "foo" {})) "foo")) (let [ex (new #?(:cljs js/Error :default Exception) "bar")] (is (= (m/ex-message ex) "bar")))) (deftest test-ex-cause (let [cause (new #?(:cljs js/Error :default Exception) "foo")] (is (= (m/ex-cause (ex-info "foo" {} cause)) cause)) #?@(:cljs [] :default [(is (= (m/ex-cause (Exception. "foo" cause)) cause))]))) (deftest test-uuid? (let [x #uuid "d1a4adfa-d9cf-4aa5-9f05-a15365d1bfa6"] (is (m/uuid? x)) (is (not (m/uuid? 2))) (is (not (m/uuid? (str x)))) (is (not (m/uuid? nil))))) (deftest test-uuid (let [x (m/uuid "d1a4adfa-d9cf-4aa5-9f05-a15365d1bfa6")] (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 :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? (is (m/regexp? #"x")) (is (not (m/regexp? "x"))) (is (not (m/regexp? nil)))) (deftest test-index-of (is (nil? (m/index-of nil :a))) (is (nil? (m/index-of [] :a))) (is (nil? (m/index-of '() :a))) (is (nil? (m/index-of [:a] :b))) (is (nil? (m/index-of '(:a) :b))) (is (= 1 (m/index-of [:a :b :c :d] :b))) (is (= 2 (m/index-of '(:a :b :c :d) :c))) (is (= 1 (m/index-of (range 0 10) 1))) (is (= 1 (m/index-of (map str [:a :b]) ":b")))) (deftest test-find-in (is (nil? (m/find-in {} [:a]))) (is (nil? (m/find-in {} [:a :b]))) (is (nil? (m/find-in {:a {}} [:a :b]))) (is (= [:a 1] (m/find-in {:a 1} [:a]))) (is (= [:b 2] (m/find-in {:a {:b 2}} [:a :b]))) (is (= [:b {:c 3}] (m/find-in {:a {:b {:c 3}}} [:a :b]))) (is (= [:c 3] (m/find-in {:a {:b {:c 3}}} [:a :b :c])))) (deftest test-map-padded (is (= (map + (range 3) (range 4) (range 5) (range 10)) [0 4 8] (take 3 (m/map-padded + 0 (range 3) (range 4) (range 5) (range 10))))) (is (= [0 4 8 19 28 35 36 37 38 39] (m/map-padded + 10 (range 3) (range 4) (range 5) (range 10)))) (is (= () (m/map-padded + 10 () () ()))) (testing "laziness" (let [state (volatile! [])] (is (= [0 4 8 19 28] (take 5 (m/map-padded (fn [a b c d] (vswap! state conj [a b c d]) (+ a b c d)) 10 (range 3) (range 4) (range 5) (range 10))))) (is (= [[0 0 0 0] [1 1 1 1] [2 2 2 2] [10 3 3 3] [10 10 4 4]] @state)))) (testing "handles sequences with nils" (is (= [[nil 0 0 0] [nil 1 1 1] [nil 2 2 2] [:missing 3 3 3] [:missing :missing 4 4] [:missing :missing :missing 5]] (take 6 (m/map-padded vector :missing [nil nil nil] (range 4) (range 5) (range 10))))))) (deftest test-sequence-padded (is (= (map + (range 3) (range 4) (range 5) (range 10)) [0 4 8] (take 3 (m/sequence-padded (map +) 0 (range 3) (range 4) (range 5) (range 10))))) (is (= [0 4 8 19 28 35 36 37 38 39] (m/sequence-padded (map +) 10 (range 3) (range 4) (range 5) (range 10)))) (is (= () (m/sequence-padded (map +) 10 () () ()))) (testing "laziness" (let [state (volatile! [])] (is (= [0 4 8 19 28] (take 5 (m/sequence-padded (map (fn [a b c d] (vswap! state conj [a b c d]) (+ a b c d))) 10 (range 3) (range 4) (range 5) (range 10))))) (is (= [[0 0 0 0] [1 1 1 1] [2 2 2 2] [10 3 3 3] [10 10 4 4]] @state)))) (testing "handles sequences with nils" (is (= [[nil 0 0 0] [nil 1 1 1] [nil 2 2 2] [:missing 3 3 3] [:missing :missing 4 4] [:missing :missing :missing 5]] (take 6 (m/sequence-padded (map vector) :missing [nil nil nil] (range 4) (range 5) (range 10)))))) (testing "slightly more complex xform" (let [xf (comp (map vector) (drop 5) (filter (comp even? second)) (map #(mapv inc %)) (take 5))] (is (= [[101 19 507] [101 25 509] [101 31 511] [101 37 513] [101 43 515]] (m/sequence-padded xf 100 (range 5) (range 0 50 3) (range 500 1000))))))) weavejester-medley-50201e1/test/medley/test_runner.cljs000066400000000000000000000002121516300002600232210ustar00rootroot00000000000000(ns medley.test-runner (:require [doo.runner :refer-macros [doo-tests]] [medley.core-test])) (doo-tests 'medley.core-test)