diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5140c90..b4040ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,17 +19,18 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v1.4.3 + uses: actions/setup-java@v4 with: - java-version: 15 + distribution: temurin + java-version: 21 - name: Setup Clojure - uses: DeLaGuardo/setup-clojure@3.2 + uses: DeLaGuardo/setup-clojure@13.2 with: cli: latest - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: cache-clj with: @@ -42,21 +43,22 @@ jobs: build-cljs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v1.4.3 + uses: actions/setup-java@v4 with: - java-version: 15 + distribution: temurin + java-version: 21 - name: Setup Clojure - uses: DeLaGuardo/setup-clojure@3.2 + uses: DeLaGuardo/setup-clojure@13.2 with: cli: latest - name: Setup Node.js - uses: actions/setup-node@v2.1.2 + uses: actions/setup-node@v4 with: - node-version: 14 + node-version: latest - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: cache-cljs with: diff --git a/src/wing/core.cljc b/src/wing/core.cljc index 886c606..3e6e5d7 100644 --- a/src/wing/core.cljc +++ b/src/wing/core.cljc @@ -115,6 +115,21 @@ (when (seq args) (/ (apply sum args) (count args)))) +(defn median + "Variadic function which finds the median of `args`. Returns nil on empty collections." + [& args] + (let [n (count args)] + (if (even? n) + (->> args + sort + (drop (dec (quot n 2))) + (take 2) + (apply avg)) + (->> args + sort + (drop (quot n 2)) + first)))) + (defn standard-deviation "Varidic function wheich will return the standard deviation of the provided `args`. Returns `nil` on empty collections" @@ -522,6 +537,26 @@ disj conj) s val)) +(defn induct + "Apply `f` to `x` and associate it under key `k`. + + Optionally takes functions `gs` which if provided will be mapped over as inputs to `f`. + + Examples: + + (induct {:name \"Bob\"} :letter-count (comp count :name)) + ;; => {:name \"Bob\" :letter-count 3} + + (induct {:name \"Bob\"} :letter-count count :name) + ;; => {:name \"Bob\" :letter-count 3} + + (induct {:cat-count 3 :dog-count 4} :cat+dog-count + :cat-count :dog-count) + ;; => {:cat-count 3 :dog-count 4 :cat+dog-count 7}" + [x k f & gs] + (if-not (seq gs) + (assoc x k (f x)) + (assoc x k (apply f (for [g gs] (g x)))))) + #?(:clj (defn fn-arities "Return a set of all arities defined for `f`. diff --git a/test/wing/core_test.cljc b/test/wing/core_test.cljc index 35a9820..e507546 100644 --- a/test/wing/core_test.cljc +++ b/test/wing/core_test.cljc @@ -166,6 +166,17 @@ (is (= 3.94 (sut/round (sut/standard-deviation 4 9 11 12 17 5 8 12 14) 2))))) +(deftest median-test + (testing "returns the median of the numbers" + (is 2 (sut/median 1 2 3))) + + (testing "returns the avg of two numbers if the median is between" + (is 2.5 (sut/median 1 2 3 3))) + + (testing "returns nil when called with empty args" + (is (nil? (sut/median))))) + + (deftest round-test (testing "obeys precision" (are [expected n precision] (= expected (sut/round n precision)) @@ -579,6 +590,15 @@ (is (= 1 (sut/fn-arity (constantly nil)))) (is (= 0 (sut/fn-arity (fn [] 1)))))) +(deftest induct-test + (testing "with no mapping fns" + (is (= {:name "Bob" :letter-count 3} + (sut/induct {:name "Bob"} :letter-count (comp count :name))))) + + (testing "with mapping fns" + (is (= {:cat-count 3 :dog-count 4 :cat+dog-count 7} + (sut/induct {:cat-count 3 :dog-count 4} :cat+dog-count + :cat-count :dog-count))))) + (defspec sliding-behaves-like-partition 5 (prop/for-all [[step size] (gen/such-that