.. of Clojure's yin
.. not to carry often useful functions from project to project
some of these have a faint "missing from Clojure" feeling
some just very useful but have no such feeling
one thing they all have in common: no external dependencies
ok. here are a few examples, there are many more inside:
=> (require '[yang.lang :as l])
fn on every key in a map:
=> (l/fmk {"a" 42 "b" 34} keyword)
{:a 42, :b 34}
fn on every value in a map:
=> (l/fmv {"a" 42 "b" 34} inc)
{"a" 43, "b" 35}
dissoc-in.. oh, yea
=> (l/dissoc-in {:foo {:bar {:a 42 :b "don't need this"}}}
[:foo :bar :b])
{:foo {:bar {:a 42}}}
tasty sequential UUIDs:
=> (repeatedly 4 #(l/squuid))
(#uuid "5f62baed-553c-49a1-ad85-2b387634e773"
#uuid "5f62baed-93d2-4e9a-bcd1-beedcaa7e1ee"
#uuid "5f62baed-b730-44f6-946f-d55b56893121"
#uuid "5f62baed-d45d-49be-9034-c661fe8069f1")
templating:
=> (l/rebrace "{{child}}, I am your {{parent}}"
{:child "Luke" :parent "father"})
"Luke, I am your father"
make it Clojure:
=> (l/dash-keys {:a_foo 42 :b_bar 34})
{:a-foo 42, :b-bar 34}
thread and
on functions:
=> (l/and-> 5 number? pos?)
true
=> (l/and-> nil number? pos?)
false
tame those namespaced keys:
=> (l/group-by-ns {:a/one :a-one :b/one :b-one :a/two :a-two :b/two :b-two})
{:a {:one :a-one, :two :a-two},
:b {:one :b-one, :two :b-two}}
be a database, do da joins:
=> (l/join [{:a 20, :b 34} {:a 31, :b 27} {:a 28, :b 42}]
[{:a 31, :b 27} {:a 12, :b 4} {:a 28, :b 42}]
:a)
[{:a 31, :b 27} {:a 28, :b 42}]
merge maps, but merge it deep:
=> (l/merge-maps {:a {:b {:c 12}} :d 21 :z 34}
{:a {:b {:c 42}} :d 25})
{:a {:b {:c 42}}, :d 25, :z 34}
gzip / gunzip edn:
=> (l/gzip-edn {:a 42 :b 28 :c [{:z #{:a :b 42}}]})
#object["[B" 0x2aafa84f "[B@2aafa84f"]
=> (l/gunzip-edn *1)
{:a 42, :b 28, :c [{:z #{:b 42 :a}}]}
validation:
=> (defn purrs? [cat]
(or (= (:purrs cat) true)
{:error "cat doesn't purr"}))
=> (defn says-meow? [cat]
(or (= (:says cat) "meow")
{:error "cat doesn't say meow"}))
=> (defn one-tail? [cat]
(or (= (:tail cat) 1)
{:error "cat doesn't have 1 tail"}))
=> (defn four-legs? [cat]
(or (= (:legs cat) 4)
{:error "cat doesn't have 4 legs"}))
=> (y/validate [purrs?
says-meow?
one-tail?
four-legs?]
{:legs 3 :tail 3 :says "bow" :purrs true})
;; => [{:error "cat doesn't say meow"}
;; {:error "cat doesn't have 1 tail"}
;; {:error "cat doesn't have 4 legs"}]
=> (y/validate [purrs?
says-meow?
one-tail?
four-legs?]
{:legs 3 :tail 3 :says "bow" :purrs true}
{:check-all? false})
;; => [{:error "cat doesn't say meow"}]
=> (y/validate [purrs?
says-meow?
one-tail?
four-legs?]
{:legs 4 :tail 1 :says "meow" :purrs true})
;; => :valid
=> (require '[yang.time :as t])
sorting (java.time) instants:
=> (def dates [{:date (t/now-utc)} {:date (t/now-utc)} {:date (t/now-utc)}])
#'user/dates
;; DESC in time
=> (sort-by :date t/time> dates)
({:date #object[java.time.Instant 0x2f75a9b1 "2020-07-13T19:56:11.794186Z"]}
{:date #object[java.time.Instant 0x9cc0505 "2020-07-13T19:56:11.794174Z"]}
{:date #object[java.time.Instant 0x26cdd4af "2020-07-13T19:56:11.794141Z"]})
measure things:
=> (t/measure "42 sum" println (reduce + (range 42)))
"42 sum" took: 79,319 nanos
861
=> (require '[yang.codec :as c])
base64 is just too common:
=> (c/base64-encode (-> "distance from you to mars is 69,561,042" .getBytes))
"ZGlzdGFuY2UgZnJvbSB5b3UgdG8gbWFycyBpcyA2OSw1NjEsMDQy"
=> (-> "ZGlzdGFuY2UgZnJvbSB5b3UgdG8gbWFycyBpcyA2OSw1NjEsMDQy"
c/base64-decode
String.)
"distance from you to mars is 69,561,042"
=> (require '[yang.network :as n])
name of da host:
=> n/hostname
"tweedledee/10.143.34.42"
destructure URIs:
=> (n/uri->map "postgresql://192.168.10.42:4242/planets")
{:path "/planets",
:user-info nil,
:fragment nil,
:authority "192.168.10.42:4242",
:port 4242,
:host "192.168.10.42",
:scheme-specific-part "//192.168.10.42:4242/planets",
:query nil,
:scheme "postgresql"}
even if URIs are JDBC:
=> (n/jdbc-uri->map "jdbc:postgresql://192.168.10.42:4242/planets")
{:path "/planets",
:user-info nil,
:fragment nil,
:authority "192.168.10.42:4242",
:port 4242,
:dbname "planets",
:host "192.168.10.42",
:scheme-specific-part "//192.168.10.42:4242/planets",
:query nil,
:scheme "postgresql"}
=> (require '[yang.scheduler :as s])
schedule functions to run on intervals:
=> (def hh (s/every 1000 #(println "hey humans!")))
#'user/hh
hey humans!
hey humans!
hey humans!
hey humans!
hey humans!
hey humans!
hey humans!
hey humans!
hey humans!
user=> (s/stop hh)
true
start/stop a farm of threads running a function:
=> (defn f []
(println (s/thread-name))
(Thread/sleep 5000))
#'user/f
;; schedule a function "f" to run with 42 threads:
=> (def farm (s/run-fun f 42))
yang-runner-0
yang-runner-1
yang-runner-2
...
yang-runner-39
yang-runner-40
yang-runner-41
;; stop the farm of threads from calling "f":
=> (-> farm :running? (reset! false))
false
=> farm
{:pool ThreadPoolExecutor [Running, pool size = 42, active threads = 0, queued tasks = 0, completed tasks = 42]"],
:running? #atom[false 0x340b4f07]}
schedule to run a function n
times (on a different thread):
=> (sc/ftimes 5 #(println "lotery numbers are:" (repeatedly 5 (fn [] (rand-int 42)))))
lotery numbers are: (31 2 27 29 28)
lotery numbers are: (3 28 40 15 1)
lotery numbers are: (13 26 18 19 21)
lotery numbers are: (37 18 18 23 17)
lotery numbers are: (7 16 20 35 8)
=> (require '[yang.exception :as ex])
make sure no exception is left behind:
=> (ex/set-default-exception-handler)
=> (require '[yang.io :as io])
read files for what they are.. bytes:
=> (io/file->bytes "src/yang/io.clj")
#object["[B" 0x6339e604 "[B@6339e604"]
jshell> import tolitius.Yang;
jshell> var m = Map.of("foo", 42, "nested", Map.of("bar", 34), "zoo", 28)
m ==> {foo=42, nested={bar=34}, zoo=28}
jshell> var edn = Yang.mapToEdn(m)
edn ==> {:foo 42, :nested {:bar 34}, :zoo 28}
// so now it can be injected in any Clojure lib that is called from Java and expects EDN
jshell> import tolitius.Yang;
import com.google.common.base.CaseFormat;
import clojure.java.api.Clojure;
var require = Clojure.var("clojure.core", "require");
var kw = Clojure.var("clojure.core", "keyword");
var comp = Clojure.var("clojure.core", "comp");
require.invoke(Clojure.read("yang.lang"));
var fmk = Clojure.var("yang.lang", "fmk");
require ==> #'clojure.core/require
kw ==> #'clojure.core/keyword
comp ==> #'clojure.core/comp
fmk ==> #'yang.lang/fmk
jshell> var m = Map.of("answerToLife", 42, "meaningOfLifeQuestion", "what is the...")
m ==> {answerToLife=42, meaningOfLifeQuestion=what is the...}
jshell> Function<String, String> jdash = x -> CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, x);
jdash ==> $Lambda$34/0x0000000800e60040@213c3543
convert java.util.function.Function
/ Consumer
/ BiFunction
/ BiConsumer
to a Clojure function
so it later be composed together with other Clojure functions:
jshell> var dashKeys = Yang.toFun(jdash);
dashKeys ==> yang.java$jfun__GT_fun$fn__158@9d7ccfe
compose it:
jshell> fmk.invoke(m, comp.invoke(kw, dashKeys))
$14 ==> {:answer-to-life 42, :meaning-of-life-question "what is the..."}
=> (require '[yang.java :as j])
=> (def m (java.util.HashMap. {"crux.id/foo" {"crux.db/bar" "baz"} "crux.answer/life" 42}))
=> (j/map->edn m)
{:crux.id/foo #:crux.db{:bar "baz"}, :crux.answer/life 42}
Copyright © 2020 tolitius
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.
Can you improve this documentation? These fine people already did:
Anatoly & anatolyEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close