├── .travis.yml ├── .gitignore ├── project.clj ├── test └── kezban │ └── core │ ├── _>>>_test.clj │ ├── lazy_test.clj │ ├── nnth_test.clj │ ├── nth_safe_test.clj │ ├── if_let_test.clj │ ├── when_let_test.clj │ ├── array?_test.clj │ ├── xor_test.clj │ └── quoted_test.clj ├── LICENSE ├── README.md └── src └── kezban └── core.cljc /.travis.yml: -------------------------------------------------------------------------------- 1 | language: clojure 2 | lein: lein 3 | branches: 4 | only: 5 | - master 6 | jdk: 7 | - openjdk11 8 | notifications: 9 | email: 10 | - ertu.ctn@gmail.com 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | pom.xml 5 | pom.xml.asc 6 | *.jar 7 | *.class 8 | /.lein-* 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | .idea/ 13 | *.iml 14 | resources/ 15 | test/kezban/test_framework.clj 16 | .DS_Store -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject kezban "0.1.94" 2 | :description "Utility library for Clojure(Script)" 3 | :license {:name "Apache License" 4 | :url "http://www.apache.org/licenses/LICENSE-2.0"} 5 | :url "https://github.com/ertugrulcetin/kezban" 6 | :profiles {:dev {:dependencies [[org.clojure/clojure "1.11.0"] 7 | [org.clojure/clojurescript "1.11.4"]]}}) 8 | -------------------------------------------------------------------------------- /test/kezban/core/_>>>_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.->>>-test 2 | (:require [kezban.core :refer :all] 3 | [clojure.test :refer :all])) 4 | 5 | (deftest test-nil 6 | (is (= (->>>) nil))) 7 | 8 | (deftest test-with-one-arg 9 | (is (= (->>> 1) 1)) 10 | (is (= (->>> true) true)) 11 | (is (= (->>> []) []))) 12 | 13 | (deftest test-with-funtions-and-args 14 | (is (= (->>> 1 inc inc) 3)) 15 | (is (= (->>> 5 #(+ % 1) #(inc %)) 7)) 16 | (is (= (->>> 5 #(+ % 1) #(* 2 %)) 12))) 17 | -------------------------------------------------------------------------------- /test/kezban/core/lazy_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.lazy-test 2 | (:require [clojure.test :refer :all] 3 | [kezban.core :refer :all])) 4 | 5 | (deftest test-false 6 | (is (= (lazy? nil) false)) 7 | (is (= (lazy? []) false)) 8 | (is (= (lazy? [1 2 3]) false))) 9 | 10 | (deftest test-true 11 | (is (= (lazy? (lazy-seq 1)) true)) 12 | (is (= (lazy? (lazy-cat [1 2 3] [4 5 6])) true)) 13 | (is (= (lazy? (for [i (range 10)] i)) true)) 14 | (is (= (lazy? (interleave [1 2] [3 4] [5 6])) true))) 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2020 Ertuğrul Çetin 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /test/kezban/core/nnth_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.nnth-test 2 | (:require [clojure.test :refer :all] 3 | [kezban.core :refer :all])) 4 | 5 | (deftest test-nil 6 | (is (= (nnth nil 0) nil)) 7 | (is (= (nnth [] 0) nil)) 8 | (is (= (nnth '() 0) nil))) 9 | 10 | (deftest test-like-nth 11 | (is (= (nnth [0 1 2 3] 0) 0)) 12 | (is (= (nnth [0 1 2 3] 1) 1)) 13 | (is (= (nnth [0 1 2 3] 2) 2)) 14 | (is (= (nnth [0 1 2 3] 3) 3)) 15 | (is (= (nnth [0 1 2 3] 4) nil))) 16 | 17 | (deftest test-like-ffirst 18 | (is (= (nnth [[0 1 2 3]] 0 0) 0))) 19 | 20 | (deftest test-nested-level-2 21 | (is (= (nnth [[0 1 2] [3 4 5] [6 7 8]] 1 2) 5)) 22 | (is (= (nnth [[0 1 2] [3 4 5] [6 7 8]] 2 2) 8))) 23 | 24 | (deftest test-nested-level-3 25 | (is (= (nnth [[[0 1 2]] [[3 4 5]] [[6 7 8]]] 1 0 0) 3)) 26 | (is (= (nnth [[[0 1 2]] [[3 4 5]] [[6 7 8]]] 1 0 1) 4)) 27 | (is (= (nnth [[[0 1 2]] [[3 4 5]] [[6 7 8]]] 1 0 9) nil))) 28 | -------------------------------------------------------------------------------- /test/kezban/core/nth_safe_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.nth-safe-test 2 | (:require [kezban.core :refer :all] 3 | [clojure.test :refer :all])) 4 | 5 | (def coll [1 2 3 4 5]) 6 | 7 | (deftest test-nth-safe-truthy 8 | (is (= (nth-safe coll 0) 1)) 9 | (is (= (nth-safe coll 1) 2)) 10 | (is (= (nth-safe coll 2) 3)) 11 | (is (= (nth-safe coll 3) 4)) 12 | (is (= (nth-safe coll 4) 5))) 13 | 14 | (deftest test-nth-safe-falsy 15 | (is (= (nth-safe coll -1) nil)) 16 | (is (= (nth-safe coll 6) nil)) 17 | (is (= (nth-safe coll 7) nil)) 18 | (is (= (nth-safe coll 8) nil)) 19 | (is (= (nth-safe coll 9) nil)) 20 | (is (= (nth-safe coll 10) nil))) 21 | 22 | (deftest test-nth-safe-falsy-with-default-val 23 | (is (= (nth-safe coll -1 "ertu") "ertu")) 24 | (is (= (nth-safe coll 6 "sexy") "sexy")) 25 | (is (= (nth-safe coll 7 "angara") "angara"))) 26 | 27 | (deftest test-not-found 28 | (is (= (nth-safe [false "ertu" 1] 0 "!!!") false)) 29 | (is (= (nth-safe [false nil 1] 1 "!!!") nil))) 30 | -------------------------------------------------------------------------------- /test/kezban/core/if_let_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.if-let-test 2 | (:require [kezban.core :refer :all] 3 | [clojure.test :refer :all])) 4 | 5 | 6 | (deftest test-if-let*-truthy 7 | (is (= (if-let* [a 1] a 2) 1)) 8 | (is (= (if-let* [a 1] a 2) 1)) 9 | (is (= (if-let* [a 1 b 2] a) 1)) 10 | (is (= (if-let* [a 1 b 2 c true] b) 2)) 11 | (is (= (if-let* [a 1 b 2 c true] c) true))) 12 | 13 | (deftest test-if-let*-truthy-with-body 14 | (is (= (if-let* [a 1 b 2] 15 | (do 16 | (println "Hey Handsome!") 17 | (* a b))) 2)) 18 | 19 | (is (= (if-let* [a 1 b 3 c true] 20 | "Good girl!") "Good girl!"))) 21 | 22 | (deftest test-if-let*-falsy 23 | (is (= (if-let* [a 1 b nil] a) nil)) 24 | (is (= (if-let* [a 1 b 2 c false] b) nil)) 25 | (is (= (if-let* [a 1 b false c 3] a) nil))) 26 | 27 | (deftest test-if-let*-falsy-then 28 | (is (= (if-let* [a 1 b nil] a "Hmm :)") "Hmm :)")) 29 | (is (= (if-let* [a 1 b 2 c false] b "Let me try that") "Let me try that")) 30 | (is (= (if-let* [a 1 b false c 3] a "I don't bite") "I don't bite"))) 31 | -------------------------------------------------------------------------------- /test/kezban/core/when_let_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.when-let-test 2 | (:require [kezban.core :refer :all] 3 | [clojure.test :refer :all])) 4 | 5 | (deftest test-when-let*-truthy 6 | (is (= (when-let* [a 1] a) 1)) 7 | (is (= (when-let* [a 1 b 2] a) 1)) 8 | (is (= (when-let* [a 1 b 2 c true] b) 2)) 9 | (is (= (when-let* [a 1 b 2 c true] c) true))) 10 | 11 | (deftest test-when-let*-truthy-with-body 12 | (is (= (when-let* [a 1 b 2] 13 | (println "Hi there sexy!") 14 | (dotimes [_ 3] 15 | (println "Yeah..")) 16 | a) 1)) 17 | 18 | (is (= (when-let* [a 1 b 2 c true] 19 | (println "Let's try again!") 20 | "Me Gusto!") "Me Gusto!"))) 21 | 22 | (deftest test-when-let*-falsy 23 | (is (= (when-let* [a 1 b nil] a) nil)) 24 | (is (= (when-let* [a 1 b 2 c false] b) nil)) 25 | (is (= (when-let* [a 1 b false c 3] a) nil))) 26 | 27 | (deftest test-when-let*-falsy-with-body 28 | (is (= (when-let* [a 1 b 2 c false] 29 | (println "Come on run this shit!") 30 | (println "Damn!") 31 | a) nil)) 32 | 33 | (is (= (when-let* [a 1 b false c 3] 34 | (println "Please?") 35 | a) nil))) 36 | -------------------------------------------------------------------------------- /test/kezban/core/array?_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.array?-test 2 | (:require [clojure.test :refer :all] 3 | [kezban.core :refer :all]) 4 | (:import (java.util List))) 5 | 6 | (deftest test-false 7 | (is (= (array? nil) false)) 8 | (is (= (array? false) false)) 9 | (is (= (array? true) false)) 10 | (is (= (array? 1) false)) 11 | (is (= (array? [1 2 3]) false)) 12 | (is (= (array? "ertu") false)) 13 | (is (= (array? :nope (char-array 1)) false)) 14 | (is (= (array? :nope nil) false)) 15 | (is (= (array? :nope) false))) 16 | 17 | (deftest test-true 18 | (is (= (array? (char-array 1)) true)) 19 | (is (= (array? (byte-array 1)) true)) 20 | (is (= (array? (short-array 1)) true)) 21 | (is (= (array? (int-array 1)) true)) 22 | (is (= (array? (long-array 1)) true)) 23 | (is (= (array? (float-array 1)) true)) 24 | (is (= (array? (double-array 1)) true)) 25 | (is (= (array? (boolean-array 1)) true)) 26 | (is (= (array? (make-array String 1)) true)) 27 | (is (= (array? (make-array List 1)) true))) 28 | 29 | (deftest test-type-true 30 | (is (= (array? :char (char-array 1)) true)) 31 | (is (= (array? :byte (byte-array 1)) true)) 32 | (is (= (array? :short (short-array 1)) true)) 33 | (is (= (array? :int (int-array 1)) true)) 34 | (is (= (array? :long (long-array 1)) true)) 35 | (is (= (array? :float (float-array 1)) true)) 36 | (is (= (array? :double (double-array 1)) true)) 37 | (is (= (array? :boolean (boolean-array 1)) true))) 38 | -------------------------------------------------------------------------------- /test/kezban/core/xor_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.xor-test 2 | (:require [kezban.core :refer :all] 3 | [clojure.test :refer :all])) 4 | 5 | (deftest test-with-no-arg 6 | (is (= (xor) true))) 7 | 8 | (deftest test-with-one-arg 9 | (is (= (xor 1) 1))) 10 | 11 | (deftest test-with-truthy-truthy 12 | (is (= (xor true true) false)) 13 | (is (= (xor 1 true) false)) 14 | (is (= (xor true 1) false)) 15 | (is (= (xor some reduce) false))) 16 | 17 | (deftest test-with-falsy-falsy 18 | (is (= (xor false false) false)) 19 | (is (= (xor nil false) false)) 20 | (is (= (xor nil nil) nil)) 21 | (is (= (xor nil nil false) false)) 22 | (is (= (xor nil nil false nil) nil)) 23 | (is (= (xor nil nil false nil (zero? 1)) false)) 24 | (is (= (xor nil nil false nil (zero? 1) nil) nil)) 25 | (is (= (xor (zero? 1) nil false nil (zero? 1) nil) nil)) 26 | (is (= (xor (= (zero? 0) (zero? 1)) nil false) false)) 27 | (is (= (xor (= (zero? 0) (zero? 1)) nil false nil) nil))) 28 | 29 | (deftest test-with-result-truthy 30 | (is (= (xor true false) true)) 31 | (is (= (xor false true) true)) 32 | (is (= (xor false true false) true)) 33 | (is (= (xor false true false false) true)) 34 | (is (= (xor false nil false nil nil true) true)) 35 | (is (= (xor some reduce false true) true)) 36 | (is (= (xor some reduce true) true)) 37 | (is (= (xor some reduce true some some) some)) 38 | (is (= (xor true nil true reduce) reduce)) 39 | (is (= (xor (zero? 1) (zero? 0)) true)) 40 | (is (= (xor (zero? 1) (zero? 0) nil false) true)) 41 | (is (= (xor (println "Ass") false true) true))) 42 | -------------------------------------------------------------------------------- /test/kezban/core/quoted_test.clj: -------------------------------------------------------------------------------- 1 | (ns kezban.core.quoted-test 2 | (:require [clojure.test :refer :all] 3 | [kezban.core :refer :all])) 4 | 5 | (deftest test-false 6 | (is (= (quoted? nil) false)) 7 | (is (= (quoted? true) false)) 8 | (is (= (quoted? false) false)) 9 | (is (= (quoted? 1) false)) 10 | (is (= (quoted? 1.1) false)) 11 | (is (= (quoted? :a) false)) 12 | (is (= (quoted? "ertu") false)) 13 | (is (= (quoted? \a) false))) 14 | 15 | (deftest test-true 16 | (is (= (quoted? 'ertu) true)) 17 | (is (= (quoted? '()) true))) 18 | 19 | (deftest test-1st-level-true 20 | (is (= (quoted? '(println "canısı")) true)) 21 | (is (= (quoted? '(reduce + [1 2])) true))) 22 | 23 | (deftest test-1st-level-false 24 | (is (= (quoted? (println "canısı")) false))) 25 | 26 | (deftest test-2nd-level-true 27 | (is (= (quoted? '((list "canısı"))) true)) 28 | (is (= (quoted? '(("deneme" "canısı"))) true)) 29 | (is (= (quoted? '(("deneme" "canısı"))) true))) 30 | 31 | (deftest test-2nd-level-falsy 32 | (is (= (quoted? ('(list "canısı"))) false)) 33 | (is (= (quoted? ('("deneme" "canısı"))) false)) 34 | (is (= (quoted? ('("deneme" "canısı"))) false))) 35 | 36 | (deftest test-3th-level-true 37 | (is (= (quoted? '('('(println "aga" 1)))) true)) 38 | (is (= (quoted? '('('(println "aga" 1.2)))) true))) 39 | 40 | (deftest test-3th-level-true 41 | (is (= (quoted? (('(println "aga" 1)))) false)) 42 | (is (= (quoted? (('(println "aga" 1.2)))) false))) 43 | 44 | (deftest test-with-list 45 | (is (= (quoted? (println nil false)) false))) 46 | 47 | (deftest test-with-vector-true 48 | (is (= (quoted? '[(println "Deneme") me reduce]) true)) 49 | (is (= (quoted? '[]) true))) 50 | 51 | (deftest test-with-vector-false 52 | (is (= (quoted? [(println "Deneme") me reduce]) false)) 53 | (is (= (quoted? []) false))) 54 | 55 | (deftest test-with-map-true 56 | (is (= (quoted? '{:a 1 :b 2}) true)) 57 | (is (= (quoted? '{}) true))) 58 | 59 | (deftest test-with-map-false 60 | (is (= (quoted? {:a 1 :b 2}) false)) 61 | (is (= (quoted? {}) false))) 62 | 63 | (deftest test-with-set-true 64 | (is (= (quoted? '#{:a :b :c}) true)) 65 | (is (= (quoted? '#{}) true))) 66 | 67 | (deftest test-with-set-false 68 | (is (= (quoted? #{:a :b :c}) false)) 69 | (is (= (quoted? #{}) false))) 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kezban [![Build Status](https://travis-ci.org/ertugrulcetin/kezban.svg?branch=master)](https://travis-ci.org/ertugrulcetin/kezban) [![GitHub License](https://img.shields.io/badge/license-Apache-blue.svg)](https://github.com/ertugrulcetin/kezban/blob/master/LICENSE) 2 | 3 | Utility library for **Clojure and ClojureScript**. 4 | 5 | The library targets **Clojure 1.8** and above. 6 | 7 | ## Leiningen 8 | 9 | [![Clojars Project](https://clojars.org/kezban/kezban/latest-version.svg)](https://clojars.org/kezban) 10 | 11 | ## Usage 12 | 13 | ### kezban.core 14 | 15 | ```clojure 16 | ;;use kezban.core 17 | (use 'kezban.core) 18 | ``` 19 | 20 | **when-let*** 21 | 22 | ```clojure 23 | 24 | user=> (when-let* [a 1 b 2 c 3] 25 | (println "I <3 Clojure") 26 | a) 27 | => "I <3 Clojure" 28 | => 1 29 | 30 | ;;returns nil when one binding is nil or false 31 | user=> (when-let* [a 1 b nil c 3] 32 | (println "Please print me!") 33 | a) 34 | => nil 35 | ``` 36 | 37 | **if-let*** 38 | 39 | ```clojure 40 | 41 | user=> (if-let* [a 1 b 2 c (+ a b)] 42 | c) 43 | => 3 44 | 45 | ;;returns then part when one binding is nil or false 46 | user=> (if-let* [a 1 b nil c 3] 47 | "Nope not here" 48 | "Here I Am!") 49 | => "Here I Am!" 50 | ``` 51 | 52 | **cond-as->** 53 | 54 | ```clojure 55 | (cond-as-> 1 n 56 | true (+ n 1) 57 | false (+ n 2) 58 | true (+ 5 n)) 59 | => 7 60 | ``` 61 | 62 | **->>>** 63 | 64 | ```clojure 65 | ;; Alternative to ->, ->> and (comp) with one arg 66 | ;; Applying Left-To-Right 67 | ;; First Argument has to be a value(input)! 68 | 69 | ;; comp equivalent: ((comp #(+ 1 %) #(+ % 1) inc) 5) 70 | ;; standard equivalent (+ 1 (+ (inc 5) 1)) 71 | 72 | user=> (->>> 5 inc #(+ % 1) #(+ 1 %)) ;;5 is the input 73 | => 8 74 | 75 | 76 | ;; comp equivalent: ((comp inc second reverse) '("a" 2 8 "b")) 77 | ;; standard equivalent (inc (second (reverse '("a" 2 8 "b")))) 78 | 79 | user=> (->>> '("a" 2 8 "b") reverse second inc) ;;'("a" 2 8 "b") is the input 80 | => 9 81 | ``` 82 | 83 | 84 | **nth-safe** 85 | 86 | ```clojure 87 | 88 | (def coll [1 2 3 4 5]) 89 | 90 | user=> (nth-safe coll 0) 91 | => 1 92 | 93 | user=> (nth-safe coll 12) 94 | => nil 95 | 96 | user=> (nth-safe coll 12 "not-found-value") 97 | => "not-found-value" 98 | ``` 99 | 100 | **nnth** 101 | 102 | ```clojure 103 | 104 | (nnth [1 [2 3 [4 5]]] 1 2 1) 105 | => 5 106 | ``` 107 | 108 | **def-** 109 | ```clojure 110 | 111 | (def- my-coll [1 2 3]) 112 | => #'kezban.core/my-coll 113 | 114 | (:private (meta #'kezban.core/my-coll)) 115 | => true 116 | ``` 117 | 118 | **xor** 119 | ```clojure 120 | 121 | (xor false true nil) 122 | => true 123 | 124 | (xor false nil) 125 | => nil 126 | ``` 127 | 128 | **pprint-macro** 129 | ```clojure 130 | 131 | (pprint-macro (when-let [a 1] 132 | (println a))) 133 | (let* 134 | [temp__4657__auto__ 1] 135 | (if temp__4657__auto__ (do (let* [a temp__4657__auto__] (println a))))) 136 | => nil 137 | ``` 138 | 139 | **quoted?** 140 | ```clojure 141 | 142 | (quoted? '(+ 1 2)) 143 | => true 144 | 145 | (quoted? (+ 1 2)) 146 | => false 147 | ``` 148 | 149 | **array?** 150 | ```clojure 151 | 152 | (array? (int-array 1)) 153 | => true 154 | 155 | (array? :int (int-array 1)) 156 | => true 157 | ``` 158 | 159 | **lazy?** 160 | ```clojure 161 | 162 | (lazy? (map inc [1 2 3])) 163 | => true 164 | ``` 165 | 166 | **any-pred** 167 | ```clojure 168 | 169 | (filter (any-pred even? odd?) [2 4 5 7]) 170 | => (2 4 5 7) 171 | ``` 172 | 173 | **try-> and try->>** 174 | ```clojure 175 | 176 | (try-> 5 inc dec str inc) ;;also thread last version: try->> 177 | => nil 178 | ``` 179 | 180 | **multi-comp** 181 | ```clojure 182 | 183 | (def data [{:v 12, :a 10} {:v 21, :a 113} {:v 1, :a 2} {:v 12, :a 223} {:v 100, :a 23} {:v 1, :a 113}]) 184 | 185 | (sort #(multi-comp [:a :v] > %1 %2) data) 186 | ;or 187 | (sort #(multi-comp [:a :v] %2 %1) data) 188 | => ({:v 12, :a 223} {:v 21, :a 113} {:v 1, :a 113} {:v 100, :a 23} {:v 12, :a 10} {:v 1, :a 2}) 189 | ``` 190 | 191 | **with-out** 192 | ```clojure 193 | 194 | (with-out 195 | (println "Normal out") 196 | (.println (System/err) "Error occurred!")) 197 | => {:err "Error occurred!\n", :out "Normal out\n"} 198 | 199 | ``` 200 | 201 | **letm** 202 | ```clojure 203 | 204 | (letm [a 1 205 | b (+ a 1)]) 206 | => {:a 1, :b 2} 207 | ``` 208 | 209 | **in?** 210 | ```clojure 211 | 212 | (in? 3 [1 2 3 4]) 213 | => true 214 | ``` 215 | 216 | **take-while-and-n-more** 217 | ```clojure 218 | 219 | (take-while-and-n-more even? 2 [2 4 6 7 9 13 15]) 220 | => (2 4 6 7 9) 221 | ``` 222 | 223 | **dissoc-in** 224 | ```clojure 225 | 226 | (dissoc-in {:a {:b {:c 1 :d 2}}} [:a :b :d]) 227 | => {:a {:b {:c 1}}} 228 | ``` 229 | 230 | **with-timeout** 231 | ```clojure 232 | 233 | (with-timeout 100 234 | (Thread/sleep 1500)) 235 | => CompilerException java.util.concurrent.TimeoutException 236 | 237 | (with-timeout 1000 238 | (Thread/sleep 500) 239 | 5) 240 | => 5 241 | ``` 242 | 243 | **url->file** 244 | ```clojure 245 | 246 | (url->file "http://file.url" (io/file "your file path to get content")) 247 | => returns your file instance 248 | ``` 249 | 250 | **cond-let** 251 | ```clojure 252 | 253 | (cond-let [a 5 254 | b (+ a 1)] 255 | 256 | (even? a) 257 | (println "a is odd") 258 | 259 | (even? b) 260 | (println "b is even")) 261 | b is even 262 | => nil 263 | ``` 264 | 265 | **keywordize** 266 | ```clojure 267 | 268 | (keywordize "hey Whats Up?") 269 | => :hey-whats-up? 270 | ``` 271 | 272 | **source-clj-file** 273 | ```clojure 274 | 275 | (source-clj-file 'clojure.string) 276 | => returns clojure.string's namespace source code in string 277 | ``` 278 | 279 | **time*** 280 | ```clojure 281 | 282 | ;;unlike time, time* allows you to provide more than one form 283 | (time* 284 | (Thread/sleep 2500) 285 | 12) 286 | 287 | => {:duration 2505.328818, :result 12} 288 | ``` 289 | 290 | **process-lazy-seq** 291 | ```clojure 292 | 293 | (process-lazy-seq (fn [i] 294 | (println (inc i))) 10000 (range)) 295 | 296 | ;; we can process 10000 data at time and not getting OutOfMemory Exception 297 | ``` 298 | 299 | 300 | **when-no-aot** 301 | ```clojure 302 | 303 | ;; binding will happen when *compile-files* set to false 304 | (def db-conn (when-no-aot (create-db-connection!))) 305 | 306 | ``` 307 | 308 | **defay** 309 | ```clojure 310 | 311 | (defay current-time (println "Hi!") (System/currentTimeMillis)) 312 | ;; Hi! 313 | ;;=> 1587327846466 314 | 315 | @current-time 316 | 317 | ;;=> 1587327846466 318 | 319 | ;; Expands to this: 320 | (def current-time (delay (println "Hi!") 321 | (System/currentTimeMillis))) 322 | 323 | (when-not *compile-files* @current-time) 324 | 325 | ``` 326 | 327 | **locals** 328 | ```clojure 329 | 330 | (defn my-fn 331 | [a] 332 | (let [b 2] 333 | (locals))) 334 | 335 | (my-fn 1) 336 | ;;=> {a 1, b 2} 337 | ``` 338 | 339 | **prog1** 340 | ```clojure 341 | 342 | (prog1 (+ 1 2) 343 | (println "Result: " <>)) 344 | 345 | ;;Result: 3 346 | ;;=> 3 347 | ``` 348 | 349 | 350 | **defm** 351 | ```clojure 352 | (defm my-add [x y] 353 | (println "Result: " (+ x y)) 354 | (+ x y)) 355 | 356 | (my-add 1 2) 357 | ;;Result: 3 358 | ;;=> 3 359 | 360 | (my-add 1 2) 361 | ;;=> 3 362 | ``` 363 | ```clojure 364 | 365 | Memoized function, expands to this: 366 | 367 | (def my-add 368 | (memoize 369 | (fn [x y] 370 | (println "Result: " (+ x y)) 371 | (+ x y)))) 372 | ``` 373 | 374 | ## License 375 | ``` 376 | Copyright © 2022 Ertuğrul Çetin 377 | 378 | Licensed under the Apache License, Version 2.0 (the "License"); 379 | you may not use this file except in compliance with the License. 380 | You may obtain a copy of the License at 381 | 382 | http://www.apache.org/licenses/LICENSE-2.0 383 | 384 | Unless required by applicable law or agreed to in writing, software 385 | distributed under the License is distributed on an "AS IS" BASIS, 386 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 387 | See the License for the specific language governing permissions and 388 | limitations under the License. 389 | ``` 390 | -------------------------------------------------------------------------------- /src/kezban/core.cljc: -------------------------------------------------------------------------------- 1 | (ns kezban.core 2 | (:require [clojure.pprint :as pp] 3 | [clojure.walk :as walk] 4 | [clojure.string :as str] 5 | #?(:clj [clojure.java.io :as io])) 6 | #?(:cljs (:require-macros [cljs.core :as core] 7 | [cljs.support :refer [assert-args]])) 8 | #?(:clj (:import 9 | (java.io StringWriter ByteArrayOutputStream PrintStream) 10 | (java.util.concurrent TimeUnit TimeoutException FutureTask) 11 | (java.net URL) 12 | (clojure.lang RT)))) 13 | 14 | 15 | #?(:cljs 16 | (defmacro assert-all 17 | "Internal - do not use!" 18 | [fnname & pairs] 19 | `(do (when-not ~(first pairs) 20 | (throw (ex-info ~(str fnname " requires " (second pairs)) {:clojure.error/phase :macro-syntax-check}))) 21 | ~(let [more (nnext pairs)] 22 | (when more 23 | (list* `assert-all fnname more)))))) 24 | 25 | 26 | #?(:clj 27 | (defmacro assert-all 28 | [& pairs] 29 | `(do (when-not ~(first pairs) 30 | (throw (IllegalArgumentException. 31 | (str (first ~'&form) " requires " ~(second pairs) " in " ~'*ns* ":" (:line (meta ~'&form)))))) 32 | ~(let [more (nnext pairs)] 33 | (when more 34 | (list* `assert-all more)))))) 35 | 36 | 37 | (defmacro def- 38 | [name x] 39 | (list `def (with-meta name (assoc (meta name) :private true)) x)) 40 | 41 | 42 | (defmacro when-let* 43 | "Multiple binding version of when-let" 44 | [bindings & body] 45 | (when (seq bindings) 46 | (assert-all #?(:cljs when-let*) 47 | (vector? bindings) "a vector for its binding" 48 | (even? (count bindings)) "exactly even forms in binding vector")) 49 | (if (seq bindings) 50 | `(when-let [~(first bindings) ~(second bindings)] 51 | (when-let* ~(vec (drop 2 bindings)) ~@body)) 52 | `(do ~@body))) 53 | 54 | 55 | (defmacro if-let* 56 | "Multiple binding version of if-let" 57 | ([bindings then] 58 | `(if-let* ~bindings ~then nil)) 59 | ([bindings then else] 60 | (when (seq bindings) 61 | (assert-all #?(:cljs if-let*) 62 | (vector? bindings) "a vector for its binding" 63 | (even? (count bindings)) "exactly even forms in binding vector")) 64 | (if (seq bindings) 65 | `(if-let [~(first bindings) ~(second bindings)] 66 | (if-let* ~(vec (drop 2 bindings)) ~then ~else) 67 | ~else) 68 | then))) 69 | 70 | 71 | (defmacro cond-as-> 72 | [expr name & clauses] 73 | (assert-all #?(:cljs cond-as->) 74 | (even? (count clauses)) "exactly even forms in clauses") 75 | (let [g (gensym) 76 | steps (map (fn [[test step]] `(if ~test ~step ~name)) 77 | (partition 2 clauses))] 78 | `(let [~g ~expr 79 | ~name ~g 80 | ~@(interleave (repeat name) (butlast steps))] 81 | ~(if (empty? steps) 82 | name 83 | (last steps))))) 84 | 85 | 86 | (defmacro ->>> 87 | "Takes a set of functions and value at the end of the arguments. 88 | Returns a result that is the composition 89 | of those funtions.Applies the rightmost of fns to the args(last arg is the value/input!), 90 | the next fn (left-to-right) to the result, etc." 91 | [& form] 92 | `((comp ~@(reverse (rest form))) ~(first form))) 93 | 94 | 95 | (defn nth-safe 96 | "Returns the value at the index. get returns nil if index out of 97 | bounds,unlike nth nth-safe does not throw an exception, returns nil instead.nth-safe 98 | also works for strings, Java arrays, regex Matchers and Lists, and, 99 | in O(n) time, for sequences." 100 | ([coll n] 101 | (nth-safe coll n nil)) 102 | ([coll n not-found] 103 | (nth coll n not-found))) 104 | 105 | 106 | (defn nnth 107 | [coll index & indices] 108 | (reduce #(nth-safe %1 %2) coll (cons index indices))) 109 | 110 | 111 | (defn- xor-result 112 | [x y] 113 | (if (and x y) 114 | false 115 | (or x y))) 116 | 117 | 118 | #?(:clj 119 | (defmacro xor 120 | ([] true) 121 | ([x] x) 122 | ([x & next] 123 | (let [first x 124 | second `(first '(~@next)) 125 | ;; used this eval approach because of lack of private function usage in macro! 126 | result (xor-result (eval first) (eval second))] 127 | `(if (= (count '~next) 1) 128 | ~result 129 | (xor ~result ~@(rest next))))))) 130 | 131 | 132 | #?(:clj 133 | (defmacro pprint-macro 134 | [form] 135 | `(pp/pprint (walk/macroexpand-all '~form)))) 136 | 137 | 138 | ;;does not support syntax-quote 139 | (defmacro quoted? 140 | [form] 141 | (if (coll? form) 142 | (let [f (first form) 143 | s (str f)] 144 | `(= "quote" ~s)) 145 | false)) 146 | 147 | 148 | (defn- type->str 149 | [type] 150 | (case type 151 | :char "class [C" 152 | :byte "class [B" 153 | :short "class [S" 154 | :int "class [I" 155 | :long "class [J" 156 | :float "class [F" 157 | :double "class [D" 158 | :boolean "class [Z" 159 | nil)) 160 | 161 | 162 | (defn array? 163 | ([arr] 164 | (array? nil arr)) 165 | ([type arr] 166 | (let [c (class arr)] 167 | (if type 168 | (and (= (type->str type) (str c)) (.isArray c)) 169 | (or (some-> c .isArray) false))))) 170 | 171 | 172 | (defn lazy? 173 | [x] 174 | (= "class clojure.lang.LazySeq" (str (type x)))) 175 | 176 | 177 | (defn any-pred 178 | [& preds] 179 | (complement (apply every-pred (map complement preds)))) 180 | 181 | 182 | (defmacro try-> 183 | [x & forms] 184 | `(try 185 | (-> ~x ~@forms) 186 | (catch #?(:clj Throwable) #?(:cljs js/Error) _#))) 187 | 188 | 189 | (defmacro try->> 190 | [x & forms] 191 | `(try 192 | (->> ~x ~@forms) 193 | (catch #?(:clj Throwable) #?(:cljs js/Error) _#))) 194 | 195 | 196 | (defn multi-comp 197 | ([fns a b] 198 | (multi-comp fns < a b)) 199 | ([[f & others :as fns] order a b] 200 | (if (seq fns) 201 | (let [result (compare (f a) (f b)) 202 | f-result (if (= order >) (* -1 result) result)] 203 | (if (= 0 f-result) 204 | (recur others order a b) 205 | f-result)) 206 | 0))) 207 | 208 | 209 | #?(:clj 210 | (defmacro with-out [& body] 211 | `(let [err-buffer# (ByteArrayOutputStream.) 212 | original-err# System/err 213 | tmp-err# (PrintStream. err-buffer# true "UTF-8") 214 | out# (with-out-str (try 215 | (System/setErr tmp-err#) 216 | ~@body 217 | (finally 218 | (System/setErr original-err#))))] 219 | {:out out# 220 | :err (.toString err-buffer# "UTF-8")}))) 221 | 222 | 223 | (defmacro letm 224 | [bindings] 225 | (assert-all #?(:cljs letm) 226 | (vector? bindings) "a vector for its binding" 227 | (even? (count bindings)) "an even number of forms in binding vector") 228 | `(let* ~(destructure bindings) 229 | (merge ~@(map #(hash-map (keyword %) %) (take-nth 2 bindings))))) 230 | 231 | 232 | (defn in? 233 | [x coll] 234 | (boolean (some #(= x %) coll))) 235 | 236 | 237 | (defn take-while-and-n-more 238 | [pred n coll] 239 | (let [[head tail] (split-with pred coll)] 240 | (concat head (take n tail)))) 241 | 242 | 243 | (defn dissoc-in 244 | ([m ks] 245 | (if-let [[k & ks] (seq ks)] 246 | (if (seq ks) 247 | (let [v (dissoc-in (get m k) ks)] 248 | (if (empty? v) 249 | (dissoc m k) 250 | (assoc m k v))) 251 | (dissoc m k)) 252 | m)) 253 | ([m ks & kss] 254 | (if-let [[ks' & kss] (seq kss)] 255 | (recur (dissoc-in m ks) ks' kss) 256 | (dissoc-in m ks)))) 257 | 258 | 259 | #?(:clj 260 | (defmacro with-timeout 261 | [ms & body] 262 | `(let [task# (FutureTask. (fn [] ~@body)) 263 | thr# (Thread. task#)] 264 | (try 265 | (.start thr#) 266 | (.get task# ~ms TimeUnit/MILLISECONDS) 267 | (catch TimeoutException _# 268 | (.cancel task# true) 269 | (.stop thr#) 270 | (throw (TimeoutException. "Execution timed out."))) 271 | (catch Exception e# 272 | (.cancel task# true) 273 | (.stop thr#) 274 | (throw e#)))))) 275 | 276 | 277 | #?(:clj 278 | (defn url->file 279 | [src f] 280 | (let [source (URL. src)] 281 | (with-open [i (.openStream source) 282 | o (io/output-stream f)] 283 | (io/copy i o)) 284 | f))) 285 | 286 | 287 | (defmacro cond-let 288 | [bindings & forms] 289 | (assert-all #?(:cljs cond-let) 290 | (vector? bindings) "a vector for its binding" 291 | (even? (count bindings)) "an even number of forms in binding vector") 292 | `(let* ~(destructure bindings) 293 | (cond ~@forms))) 294 | 295 | 296 | (defn keywordize 297 | [s] 298 | (-> s 299 | str/lower-case 300 | str/trim 301 | (str/replace #"\s+" "-") 302 | keyword)) 303 | 304 | 305 | #?(:clj 306 | (defn source-clj-file 307 | [ns] 308 | (require ns) 309 | (some->> ns 310 | ns-publics 311 | vals 312 | first 313 | meta 314 | :file 315 | (.getResourceAsStream (RT/baseLoader)) 316 | slurp))) 317 | 318 | 319 | #?(:clj 320 | (defmacro time* 321 | [& forms] 322 | `(let [start# (. System (nanoTime)) 323 | ret# (do ~@forms)] 324 | {:duration (/ (double (- (. System (nanoTime)) start#)) 1000000.0) 325 | :result ret#}))) 326 | 327 | 328 | (defn process-lazy-seq 329 | [f threshold lazy-s] 330 | (when-let [data (seq (take threshold lazy-s))] 331 | (doseq [d data] 332 | (f d)) 333 | (recur f threshold (drop threshold lazy-s)))) 334 | 335 | 336 | #?(:clj 337 | (defmacro when-no-aot 338 | [& body] 339 | `(when-not *compile-files* 340 | ~@body))) 341 | 342 | 343 | #?(:clj 344 | (defmacro defay 345 | [name & forms] 346 | `(do 347 | (def ~name (delay ~@forms)) 348 | (when-not *compile-files* 349 | (deref ~name))))) 350 | 351 | 352 | #?(:clj 353 | (defmacro locals 354 | [] 355 | (->> (keys &env) 356 | (map (fn [binding] [`(quote ~binding) binding])) 357 | (into {})))) 358 | 359 | 360 | (defmacro prog1 361 | [first-form & body] 362 | `(let [~'<> ~first-form] 363 | ~@body 364 | ~'<>)) 365 | 366 | (defmacro defm [name params & body] 367 | `(def ~name (memoize (fn ~params ~@body)))) 368 | --------------------------------------------------------------------------------