From 0763d45f1a78a5f6741984c12318d4140bef6fbb Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 26 May 2018 04:46:43 +0200 Subject: [PATCH 1/4] Fix indentation of `cond` --- src/better_cond/core.clj | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/better_cond/core.clj b/src/better_cond/core.clj index 7725006..2d7809e 100644 --- a/src/better_cond/core.clj +++ b/src/better_cond/core.clj @@ -41,17 +41,17 @@ :let, :when-let and :do do not need to be written as keywords." [& clauses] (when-let [[test expr & more-clauses] (seq clauses)] - (if (next clauses) - (if (or (= :do test) (= 'do test)) - `(do ~expr (cond ~@more-clauses)) - (if (or (= :let test) (= 'let test)) - `(let ~expr (cond ~@more-clauses)) - (if (or (= :when test) (= 'when test)) - `(when ~expr (cond ~@more-clauses)) - (if (or (= :when-let test) (= 'when-let test)) - `(when-let ~expr (cond ~@more-clauses)) - `(if ~test ~expr (cond ~@more-clauses)))))) - test))) + (if (next clauses) + (if (or (= :do test) (= 'do test)) + `(do ~expr (cond ~@more-clauses)) + (if (or (= :let test) (= 'let test)) + `(let ~expr (cond ~@more-clauses)) + (if (or (= :when test) (= 'when test)) + `(when ~expr (cond ~@more-clauses)) + (if (or (= :when-let test) (= 'when-let test)) + `(when-let ~expr (cond ~@more-clauses)) + `(if ~test ~expr (cond ~@more-clauses)))))) + test))) (defmacro defnc "defn with implicit cond" [& defn-args] (cond From a191b48820a213e49e7448d2fe56acab01418eb7 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 26 May 2018 04:49:11 +0200 Subject: [PATCH 2/4] `cond`: make keyword/symbol equivalence code more concise --- src/better_cond/core.clj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/better_cond/core.clj b/src/better_cond/core.clj index 2d7809e..3cdb9c4 100644 --- a/src/better_cond/core.clj +++ b/src/better_cond/core.clj @@ -42,13 +42,13 @@ [& clauses] (when-let [[test expr & more-clauses] (seq clauses)] (if (next clauses) - (if (or (= :do test) (= 'do test)) + (if (#{:do 'do} test) `(do ~expr (cond ~@more-clauses)) - (if (or (= :let test) (= 'let test)) + (if (#{:let 'let} test) `(let ~expr (cond ~@more-clauses)) - (if (or (= :when test) (= 'when test)) + (if (#{:when 'when} test) `(when ~expr (cond ~@more-clauses)) - (if (or (= :when-let test) (= 'when-let test)) + (if (#{:when-let 'when-let} test) `(when-let ~expr (cond ~@more-clauses)) `(if ~test ~expr (cond ~@more-clauses)))))) test))) From 0b5d870bef963f9df7ff565747976e7fa6b348c8 Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 26 May 2018 05:38:31 +0200 Subject: [PATCH 3/4] Implement support for a :while clause --- README.md | 4 +- src/better_cond/core.clj | 23 ++++++----- test/better_cond/core_test.clj | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 124d668..a70f3b9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A variation on cond which sports let bindings, when-let bindings, when and impli *New in version 2.0.1:* - Cond supports `do` for a single-line side effect. -- Cond allows symbols as an alternative to keywords for let, when-let, when, and do. +- Cond allows symbols as an alternative to keywords for let, when-let, when, while and do. - Two new macros: `defnc` and `defnc-` are like `defn` and `defn-` with an implicit cond wrapped around the body. `better-cond 2.0.1` requires Clojure 1.9 alpha 16 or higher. If you are still on Clojure 1.8, use `better-cond 1.0.1` @@ -78,7 +78,7 @@ In Clojurescript, it is best to use `:require-macros`: (:require-macros [better-cond.core :refer [cond]])) ``` -As of version 2.0.0, writing let, when-let, when, and do as keywords is optional. So you can also write it like this, if you prefer: +As of version 2.0.0, writing let, when-let, when, while and do as keywords is optional. So you can also write it like this, if you prefer: ```clojure (cond diff --git a/src/better_cond/core.clj b/src/better_cond/core.clj index 3cdb9c4..9c40498 100644 --- a/src/better_cond/core.clj +++ b/src/better_cond/core.clj @@ -37,20 +37,21 @@ :let [a (quot a 2)] (odd? a) 2 3). - Also supports :when-let. - :let, :when-let and :do do not need to be written as keywords." + Also supports :let, :when, :when-let, :do and :while, which do not need to be written as keywords." [& clauses] (when-let [[test expr & more-clauses] (seq clauses)] (if (next clauses) - (if (#{:do 'do} test) - `(do ~expr (cond ~@more-clauses)) - (if (#{:let 'let} test) - `(let ~expr (cond ~@more-clauses)) - (if (#{:when 'when} test) - `(when ~expr (cond ~@more-clauses)) - (if (#{:when-let 'when-let} test) - `(when-let ~expr (cond ~@more-clauses)) - `(if ~test ~expr (cond ~@more-clauses)))))) + (if (#{:while 'while} test) + `(while ~expr (cond ~@more-clauses)) + (if (#{:do 'do} test) + `(do ~expr (cond ~@more-clauses)) + (if (#{:let 'let} test) + `(let ~expr (cond ~@more-clauses)) + (if (#{:when 'when} test) + `(when ~expr (cond ~@more-clauses)) + (if (#{:when-let 'when-let} test) + `(when-let ~expr (cond ~@more-clauses)) + `(if ~test ~expr (cond ~@more-clauses))))))) test))) (defmacro defnc "defn with implicit cond" [& defn-args] diff --git a/test/better_cond/core_test.clj b/test/better_cond/core_test.clj index 9783e3c..eafbedd 100644 --- a/test/better_cond/core_test.clj +++ b/test/better_cond/core_test.clj @@ -3,3 +3,76 @@ (:require [clojure.test :refer :all] [better-cond.core :refer :all])) +(deftest cond-test + + (testing "Base cases" + (is (= (cond) nil) + (= (cond :any-value) :any-value))) + + (testing "Can behave like the regular clojure.core/cond" + (testing "Falsey clauses are never invoked" + (let [proof (atom [])] + (is (= [:proven] + (do (cond false (swap! proof conj :never-invoked) + true (swap! proof conj :proven)) + @proof))))) + + (testing ":else clause works" + (is (= :proven (cond false nil :else :proven))))) + + (testing "Supports :let, :when :when-let, :do and :while directives" + (testing "Basic :let and :when support" + (testing "Passing :when clause" + (is (= [4 4] + (cond :let [a 2] + :when (pos? a) + :let [b (* a 2)] + [b b])))) + (testing "Failing :when clause" + (is (nil? + (cond :let [a -1] + :when (pos? a) + :let [b (* a 2)] + [b b]))))) + + (testing ":when-let" + (testing "Passing :when-let clause" + (is (= [4 4] + (cond :let [a 2] + :when-let [b (some-> a (* 2))] + [b b])))) + (testing "Failing :when-let clause" + (is (nil? + (cond :let [a nil] + :when-let [b (some-> a (* 2))] + [b b]))))) + + (testing ":do" + (let [proof (atom nil) + result (cond :let [a 2] + :when (pos? a) + :do (reset! proof :proven) + :let [b (* a 2)] + [b b])] + (is (= result [4 4])) + (is (= :proven @proof)))) + + (testing ":while" + (testing "Top-level :while" + (let [counter (atom 0) + condition (atom true) + proof (atom [])] + (cond :while @condition + :let [n (inc @counter)] + :do (reset! counter n) + :do (reset! condition (< @counter 10)) + (swap! proof conj n)) + (is (= @proof [1 2 3 4 5 6 7 8 9 10])))) + (testing "Nested :while" + (let [proof (atom [])] + (cond :let [a (atom 1)] + :while (< @a 10) + :let [b (* @a @a)] + :do (swap! proof conj b) + (swap! a inc)) + (is (= @proof [1 4 9 16 25 36 49 64 81]))))))) From 717623675c720e458c92554630f1d5dee2e40cfa Mon Sep 17 00:00:00 2001 From: vemv Date: Sat, 26 May 2018 05:46:09 +0200 Subject: [PATCH 4/4] Implement support for a :when-some clause Fixes #9 --- README.md | 4 ++-- src/better_cond/core.clj | 26 ++++++++++++++------------ test/better_cond/core_test.clj | 14 +++++++++++++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a70f3b9..9e48456 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A variation on cond which sports let bindings, when-let bindings, when and impli *New in version 2.0.1:* - Cond supports `do` for a single-line side effect. -- Cond allows symbols as an alternative to keywords for let, when-let, when, while and do. +- Cond allows symbols as an alternative to keywords for let, when-let, when, while, when-some and do. - Two new macros: `defnc` and `defnc-` are like `defn` and `defn-` with an implicit cond wrapped around the body. `better-cond 2.0.1` requires Clojure 1.9 alpha 16 or higher. If you are still on Clojure 1.8, use `better-cond 1.0.1` @@ -78,7 +78,7 @@ In Clojurescript, it is best to use `:require-macros`: (:require-macros [better-cond.core :refer [cond]])) ``` -As of version 2.0.0, writing let, when-let, when, while and do as keywords is optional. So you can also write it like this, if you prefer: +As of version 2.0.0, writing let, when-let, when, when-some, while and do as keywords is optional. So you can also write it like this, if you prefer: ```clojure (cond diff --git a/src/better_cond/core.clj b/src/better_cond/core.clj index 9c40498..850bb9b 100644 --- a/src/better_cond/core.clj +++ b/src/better_cond/core.clj @@ -37,21 +37,23 @@ :let [a (quot a 2)] (odd? a) 2 3). - Also supports :let, :when, :when-let, :do and :while, which do not need to be written as keywords." + Also supports :let, :when, :when-let, :when-some, :do and :while, which do not need to be written as keywords." [& clauses] (when-let [[test expr & more-clauses] (seq clauses)] (if (next clauses) - (if (#{:while 'while} test) - `(while ~expr (cond ~@more-clauses)) - (if (#{:do 'do} test) - `(do ~expr (cond ~@more-clauses)) - (if (#{:let 'let} test) - `(let ~expr (cond ~@more-clauses)) - (if (#{:when 'when} test) - `(when ~expr (cond ~@more-clauses)) - (if (#{:when-let 'when-let} test) - `(when-let ~expr (cond ~@more-clauses)) - `(if ~test ~expr (cond ~@more-clauses))))))) + (if (#{:when-some 'when-some} test) + `(when-some ~expr (cond ~@more-clauses)) + (if (#{:while 'while} test) + `(while ~expr (cond ~@more-clauses)) + (if (#{:do 'do} test) + `(do ~expr (cond ~@more-clauses)) + (if (#{:let 'let} test) + `(let ~expr (cond ~@more-clauses)) + (if (#{:when 'when} test) + `(when ~expr (cond ~@more-clauses)) + (if (#{:when-let 'when-let} test) + `(when-let ~expr (cond ~@more-clauses)) + `(if ~test ~expr (cond ~@more-clauses)))))))) test))) (defmacro defnc "defn with implicit cond" [& defn-args] diff --git a/test/better_cond/core_test.clj b/test/better_cond/core_test.clj index eafbedd..d890466 100644 --- a/test/better_cond/core_test.clj +++ b/test/better_cond/core_test.clj @@ -75,4 +75,16 @@ :let [b (* @a @a)] :do (swap! proof conj b) (swap! a inc)) - (is (= @proof [1 4 9 16 25 36 49 64 81]))))))) + (is (= @proof [1 4 9 16 25 36 49 64 81]))))) + + (testing ":when-some" + (testing "Passing :when-some clause" + (is (= [false false] + (cond :let [a [false]] + :when-some [b (some-> a first)] + [b b])))) + (testing "Failing :when-some clause" + (is (nil? + (cond :let [a [nil]] + :when-some [b (some-> a first)] + [b b])))))))