tupelo.core

Tupelo - Making Clojure even sweeter

*lazy-gen-buffer-size*

dynamic

Default output buffer size for `lazy-gen`.

*spy-enabled*

dynamic

*spy-enabled-map*

dynamic

->false

(->false & args)
A function that accepts any number of args, does nothing, and returns `false`.

->kw

(->kw arg)
Inputs: [arg :- (s/cond-pre s/Keyword s/Str s/Symbol s/Num)]
Returns: s/Keyword

Coerce arg to a keyword

->list

(->list arg)
Inputs: [arg :- [s/Any]]
Returns: [s/Any]

Coerce any sequential argument into a List.

->map-entry

(->map-entry arg)
Inputs: [arg]
Returns: tsk/MapEntry

Coerce arg into a clojure.lang.MapEntry

->nil

(->nil & args)
A function that accepts any number of args, does nothing, and returns `nil`.

->one

(->one & args)
A function that accepts any number of args, does nothing, and returns the number one.

->set

(->set arg)
Inputs: [arg]
Returns: tsk/Set

Converts arg to a set.

->sorted-map

(->sorted-map map-in)
Inputs: [map-in :- tsk/Map]
Returns: tsk/Map

Coerces a map into a sorted-map

->sorted-map-generic

(->sorted-map-generic map-in)
Inputs: [map-in :- tsk/Map]
Returns: tsk/Map

Coerces a map into a sorted-map

->sorted-set

(->sorted-set set-in)
Inputs: [set-in :- tsk/Set]
Returns: tsk/Set

Coerces a set into a sorted-set

->sorted-set-generic

(->sorted-set-generic set-in)
Inputs: [set-in :- tsk/Set]
Returns: tsk/Set

Coerces a set into a sorted-set-generic

->str

(->str arg)
Inputs: [arg :- (s/cond-pre s/Keyword s/Str s/Symbol s/Num)]
Returns: s/Str

Coerce arg to a string

->sym

(->sym arg)
Inputs: [arg :- (s/cond-pre s/Keyword s/Str s/Symbol)]
Returns: s/Symbol

Coerce arg to a symbol

->true

(->true & args)
A function that accepts any number of args, does nothing, and returns `true`.

->vector

(->vector & args)
Inputs: [& args :- [s/Any]]
Returns: [s/Any]

Wraps all args in a vector, as with `clojure.core/vector`. Will (recursively) recognize
any embedded calls to (unwrap <vec-or-list>) and insert their elements as with the
unquote-spicing operator (~@). Examples:

    (->vector 1 2 3 4 5 6 7 8 9)              =>  [1 2 3 4 5 6 7 8 9]
    (->vector 1 2 3 (unwrap [4 5 6]) 7 8 9)   =>  [1 2 3 4 5 6 7 8 9] 

->zero

(->zero & args)
A function that accepts any number of args, does nothing, and returns the number zero.

all-rel=

(all-rel= x-vals y-vals & opts)
Applies

append

(append listy & elems)
Inputs: [listy :- tsk/List & elems :- [s/Any]]
Returns: tsk/List

Given a sequential object (vector or list), add one or more elements to the end.

bigdecimal?

(bigdecimal? x)
Returns true if x is a java.math.BigDecimal (synonym for `clojure.core/decimal?`)

bigint?

(bigint? x)
Returns true if x is a clojure.lang.BigInt

biginteger?

(biginteger? x)
Returns true if x is a java.math.BigInteger

chan->lazy-seq

(chan->lazy-seq chan)
Accepts a core.async channel and returns the contents as a lazy list.

char->codepoint

(char->codepoint arg)
Inputs: [arg :- s/Any]
Returns: s/Int

Convert a char to an unicode int

char->sym

(char->sym ch)

chars-thru

(chars-thru start-char stop-char)
Given two characters (or numerical equivalents), returns a seq of characters
(inclusive) from the first to the second.  Characters must be in ascending order.

check-spy-enabled

macro

(check-spy-enabled tag & forms)

clip-str

(clip-str nchars & args)
Converts all args to single string and clips any characters beyond nchars.

cljs-env?

(cljs-env? env)
Take the &env from a macro, and tell whether we are expanding into cljs.

codepoint->char

(codepoint->char arg)
Inputs: [arg :- s/Int]
Returns: s/Any

Convert a unicode int to a char

cond-it->

macro

(cond-it-> & forms)
A threading macro like cond-> that always uses the symbol 'it' as the placeholder for the next threaded value.
Works in both the conditional form and the value form:

  (let [params {:a 1 :b 1 :c nil :d nil}]
    (cond-it-> params
      (:a it)        (update it :b inc)
      (= (:b it) 2)  (assoc it :c "here")
      (:c it)        (assoc it :d "again")))

  ;=> {:a 1, :b 2, :c "here", :d "again"}

const-fn

(const-fn val)
Returns a function that always returns the specified value, and accepts any number of args
(synonym for `clojure.core/constantly`).

contains-elem?

(contains-elem? coll elem)
Inputs: [coll :- s/Any elem :- s/Any]
Returns: s/Bool

For any collection coll & element tgt, returns true if coll contains at least one
instance of tgt; otherwise returns false. Note that, for maps, each element is a
vector (i.e MapEntry) of the form [key value].

contains-key?

(contains-key? map-or-set elem)
Inputs: [map-or-set :- (s/pred (fn* [p1__16486#] (or (map? p1__16486#) (set? p1__16486#)))) elem :- s/Any]
Returns: s/Bool

For any map or set, returns true if elem is a map key or set element, respectively

contains-val?

(contains-val? map elem)
Inputs: [map :- tsk/Map elem :- s/Any]
Returns: s/Bool

For any map, returns true if elem is present in the map for at least one key.

destruct

macro

(destruct bindings & forms)
Natural destructuring:
  (let [data {:a 1
              :b {:c 3
                  :d 4}}]
    ...
    (destruct [data {:a ?
                     :b {:c ?}}]
    ...
then can use local values  a=1, c=3.  With vector data:
  (let [data [1 2 3 4 5]]
    ...
    (destruct [data [a b c]]
     ...
  then can use local values a=1 b=2 c=3.  Can use `(restruct)`, `(restruct data)`, or `(restruct-all)`
  to re-structure & return original data shape using current values.

dissoc-in

(dissoc-in the-map keys-vec)
Inputs: [the-map :- tsk/KeyMap keys-vec :- [s/Keyword]]
Returns: s/Any

A sane version of dissoc-in that will not delete intermediate keys.
 When invoked as (dissoc-in the-map [:k1 :k2 :k3... :kZ]), acts like
 (clojure.core/update-in the-map [:k1 :k2 :k3...] dissoc :kZ). That is, only
 the map entry containing the last key :kZ is removed, and all map entries
 higher than kZ in the hierarchy are unaffected.

drop-at

(drop-at coll index)
Inputs: [coll :- tsk/List index :- s/Int]
Returns: tsk/List

Removes an element from a collection at the specified index.

drop-if

(drop-if pred coll)
Returns a vector of items in coll for which (pred item) is false (alias for clojure.core/remove)

edn->json

(edn->json arg)
Inputs: [arg]
Returns: s/Str

Shortcut to cheshire.core/generate-string

exception-message

(exception-message exception)
Returns the message from an exception => (.getMessage exception)

exception-stacktrace

(exception-stacktrace exception)
Returns the stacktrace from an exception 

falsey?

(falsey? arg)
Returns true if arg is logical false (either nil or false); otherwise returns false. Equivalent
to (not (truthy? arg)).

fetch

(fetch the-map the-key)
Inputs: [the-map :- tsk/Map the-key :- s/Any]
Returns: s/Any

A fail-fast version of keyword/map lookup.  When invoked as (fetch the-map :the-key),
 returns the value associated with :the-key as for (clojure.core/get the-map :the-key).
 Throws an Exception if :the-key is not present in the-map.

fetch-in

(fetch-in the-map keys-vec)
Inputs: [the-map :- tsk/Map keys-vec :- tsk/Vec]
Returns: s/Any

A fail-fast version of clojure.core/get-in. When invoked as (fetch-in the-map keys-vec),
 returns the value associated with keys-vec as for (clojure.core/get-in the-map keys-vec).
 Throws an Exception if the path keys-vec is not present in the-map.

fibo-nth

(fibo-nth N)
Returns the N'th Fibonacci number (zero-based). Note that
N=91 corresponds to approx 2^62

fibo-thru

(fibo-thru limit)
Returns a vector of Fibonacci numbers up to limit (inclusive). Note that a
2^62  corresponds to 91'st Fibonacci number.

fibonacci-seq

(fibonacci-seq)
A lazy seq of Fibonacci numbers (memoized).

first-or-nil

(first-or-nil seq-arg)
Returns the first item in a sequence, or nil

for-list

macro

(for-list & forms)
Like clojure.core/for but returns results in an eager list.
Wraps the loop body in a `do` as with `doseq`. Not lazy.

forv

macro

(forv & forms)
Like clojure.core/for but returns results in a vector.
Wraps the loop body in a `do` as with `doseq`. Not lazy.

fourth-or-nil

(fourth-or-nil seq-arg)
Returns the fourth item in a sequence, or nil

get-in-strict

(get-in-strict data path)

glue

(glue & colls)
Glues together like collections:

   (glue [1 2] [3 4] [5 6])                -> [1 2 3 4 5 6]
   (glue {:a 1} {:b 2} {:c 3})             -> {:a 1 :c 3 :b 2}
   (glue #{1 2} #{3 4} #{6 5})             -> #{1 2 6 5 3 4}
   (glue "I" " like " \a " nap!" )  -> "I like a nap!"

If you want to convert to a sorted set or map, just put an empty one first:

   (glue (sorted-map) {:a 1} {:b 2} {:c 3})      -> {:a 1 :b 2 :c 3}
   (glue (sorted-set) #{1 2} #{3 4} #{6 5})      -> #{1 2 3 4 5 6}

 If there are duplicate keys when using glue for maps or sets, then "the last one wins":

   (glue {:band :VanHalen :singer :Dave}  {:singer :Sammy}) 

glue-rows

(glue-rows coll-2d)
 Convert a vector of vectors (2-dimensional) into a single vector (1-dimensional).
Equivalent to `(apply glue ...)`

grab

(grab the-key the-map)
Inputs: [the-key :- s/Any the-map :- tsk/Map]
Returns: s/Any

A fail-fast version of keyword/map lookup.  When invoked as (grab :the-key the-map),
 returns the value associated with :the-key as for (clojure.core/get the-map :the-key).
 Throws an Exception if :the-key is not present in the-map.

has-length?

(has-length? coll n)
Returns true if the collection has the indicated length. Does not hang for infinite sequences.

has-none?

(has-none? pred coll)
Inputs: [pred :- s/Any coll :- [s/Any]]
Returns: s/Bool

For any predicate pred & collection coll, returns false if (pred x) is logical true for at least one x in
 coll; otherwise returns true.  Equivalent to clojure.core/not-any?, but inverse of has-some?.

has-some?

(has-some? pred coll)
Inputs: [pred :- s/Any coll :- [s/Any]]
Returns: s/Bool

For any predicate pred & collection coll, returns true if (pred x) is logical true for at least one x in
 coll; otherwise returns false.  Like clojure.core/some, but returns only true or false.

idx

(idx coll index-val)
Inputs: [coll :- tsk/List index-val :- s/Int]

Indexes into a vector, allowing negative index values

if-cljs

macro

(if-cljs then else)
Return then if we are generating cljs code and else for Clojure code.
https://groups.google.com/d/msg/clojurescript/iBY5HaQda4A/w1lAQi9_AwsJ

if-java-1-7-plus

macro

(if-java-1-7-plus if-form else-form)
If JVM is Java 1.7 or higher, evaluates if-form into code. Otherwise, evaluates else-form.

if-java-1-8-plus

macro

(if-java-1-8-plus if-form else-form)
If JVM is Java 1.8 or higher, evaluates if-form into code. Otherwise, evaluates else-form.

increasing-or-equal?

(increasing-or-equal? a b)
Inputs: [a :- tsk/List b :- tsk/List]
Returns: s/Bool

Returns true iff the vectors are in (strictly) lexicographically increasing-or-equal order
  [1 2]  [1]        -> false
  [1 2]  [1 1]      -> false
  [1 2]  [1 2]      -> true
  [1 2]  [1 2 nil]  -> true
  [1 2]  [1 2 3]    -> true
  [1 2]  [1 3]      -> true
  [1 2]  [2 1]      -> true
  [1 2]  [2]        -> true 

increasing?

(increasing? a b)
Inputs: [a :- tsk/List b :- tsk/List]
Returns: s/Bool

Returns true iff the vectors are in (strictly) lexicographically increasing order
  [1 2]  [1]        -> false
  [1 2]  [1 1]      -> false
  [1 2]  [1 2]      -> false
  [1 2]  [1 2 nil]  -> true
  [1 2]  [1 2 3]    -> true
  [1 2]  [1 3]      -> true
  [1 2]  [2 1]      -> true
  [1 2]  [2]        -> true 

indent-lines-with

(indent-lines-with indent-str txt)
Inputs: [indent-str :- s/Str txt :- s/Str]
  Returns: s/Str

  Splits out each line of txt using clojure.string/split-lines, then
  indents each line by prepending it with the supplied string. Joins lines together into
  a single string result, with each line terminated by a single 
ewline.

index-using

(index-using pred coll)
Finds the first index N where (< N (count coll)) such that (pred (drop N coll)) is truthy.
Returns `nil` if no match found.

indexed

(indexed & colls)
Given one or more collections, returns a sequence of indexed tuples from the collections:
(indexed xs ys zs) -> [ [0 x0 y0 z0]
                        [1 x1 y1 z1]
                        [2 x2 y2 z2]
                        ... ] 

insert-at

(insert-at coll index elem)
Inputs: [coll :- tsk/List index :- s/Int elem :- s/Any]
Returns: tsk/List

Inserts an element into a collection at the specified index.

int->kw

(int->kw arg)

int-neg?

(int-neg? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is an integer and is negative

int-nonneg?

(int-nonneg? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is an integer and is not negative

int-nonpos?

(int-nonpos? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is an integer and is not positive

int-pos?

(int-pos? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is an integer and is positive

int-val?

(int-val? x)
Returns true iff arg is an integer value of any Clojure/Java type
(all int types, float/double, BigInt/BigInteger, BigDecimal, clojure.lang.Ratio).

is-clojure-1-10-plus?

(is-clojure-1-10-plus?)

is-clojure-1-7-plus?

(is-clojure-1-7-plus?)

is-clojure-1-8-plus?

(is-clojure-1-8-plus?)

is-clojure-1-9-plus?

(is-clojure-1-9-plus?)

is-java-1-7-plus?

(is-java-1-7-plus?)

is-java-1-7?

(is-java-1-7?)

is-java-1-8-plus?

(is-java-1-8-plus?)

is-java-1-8?

(is-java-1-8?)

is-pre-clojure-1-10?

(is-pre-clojure-1-10?)

is-pre-clojure-1-8?

(is-pre-clojure-1-8?)

is-pre-clojure-1-9?

(is-pre-clojure-1-9?)

it->

macro

(it-> expr & forms)
A threading macro like as-> that always uses the symbol 'it' as the placeholder for the next threaded value:
(it-> 1
      (inc it)
      (+ it 3)
      (/ 10 it))
;=> 2 

java-version

(java-version)
Inputs: []
Returns: s/Str

java-version-matches?

(java-version-matches? version-str)
Inputs: [version-str :- s/Str]
Returns: s/Bool

Returns true if Java version exactly matches supplied string.

java-version-min?

(java-version-min? version-str)
Inputs: [version-str :- s/Str]
Returns: s/Bool

Returns true if Java version is at least as great as supplied string.
     Sort is by lexicographic (alphabetic) order.

json->edn

(json->edn json-str)
Inputs: [json-str :- s/Str]

Shortcut to cheshire.core/parse-string

keep-if

(keep-if pred coll)
Returns a vector of items in coll for which (pred item) is true (alias for clojure.core/filter)

keyvals

(keyvals m)
Inputs: [m :- tsk/Map]
Returns: [s/Any]

For any map m, returns the (alternating) keys & values of m as a vector, suitable for reconstructing m via
 (apply hash-map (keyvals m)). (keyvals {:a 1 :b 2} => [:a 1 :b 2] 

keyvals-seq

(keyvals-seq ctx)(keyvals-seq the-map the-keys)
Inputs: ([ctx :- tsk/KeyMap] [the-map :- tsk/KeyMap the-keys :- [s/Any]])
Returns: [s/Any]

For any map m, returns the (alternating) keys & values of m as a vector, suitable for reconstructing m via
 (apply hash-map (keyvals m)). (keyvals {:a 1 :b 2} => [:a 1 :b 2]

   Usage:  (keyvals-seq ctx) ctx-default: {:missing-ok false}
           (keyvals-seq the-map the-keys) 

kw->int

(kw->int arg)

kw->str

(kw->str arg)
Inputs: [arg :- s/Keyword]
Returns: s/Str

Converts a keyword to a string

kw->sym

(kw->sym arg)
Inputs: [arg :- s/Keyword]
Returns: s/Symbol

Converts a keyword to a symbol

last-or-nil

(last-or-nil seq-arg)
Returns the last item in a sequence, or nil

lazy-cons

macro

(lazy-cons curr-val recursive-call-form)
The simple way to create a lazy sequence:
(defn lazy-next-int [n]
  (t/lazy-cons n (lazy-next-int (inc n))))
(def all-ints (lazy-next-int 0)) 

lazy-gen

macro

(lazy-gen & forms)
Creates a 'generator function' that returns a lazy seq of results
via `yield` (a la Python).

let-some

macro

(let-some bindings & forms)
Threads forms as with `when-some`, but allow more than 1 pair of binding forms.

let-spy

macro

(let-spy & exprs)
An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
expressions, printing both the expression and its value to stdout. Returns the value of the
last expression.

let-spy-pretty

macro

(let-spy-pretty & exprs)
An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
expressions, printing both the expression and its value to stdout. Returns the value of the
last expression.

list->entries

(list->entries data)
Inputs: [data :- tsk/Vec]
Returns: [tsk/Map]

Returns a vector of list-entry maps given a vector/list

list-entries->vec

(list-entries->vec list-entries)
Inputs: [list-entries :- tsk/Vec]
Returns: tsk/Vec

list-entry

(list-entry idx val)
Constructs a list-entry map given an index and value

list-entry?

(list-entry? arg)
Returns true iff the arg is a list-entry

listy?

(listy? arg)
Returns true if arg is a list or a seq, else false.

macro?

(macro? s)
Returns true if a quoted symbol resolves to a macro. Usage:

(println (macro? 'and))  ;=> true 

map-entry

(map-entry key val)
Inputs: [key val]
Returns: tsk/MapEntry

Returns a clojure.lang.MapEntry constructed from the given key and val

map-keys

(map-keys map-in tx-fn & tx-args)
Inputs: [map-in :- tsk/Map tx-fn :- tsk/Fn & tx-args]
Returns: tsk/Map

Transforms each key in a map using the supplied `tx-fn`:

  (t/map-keys {1 :a 2 :b 3 :c} inc)                  =>  {  2 :a   3 :b 4   :c}
  (t/map-keys {1 :a 2 :b 3 :c} {1 101 2 202 3 303})  =>  {101 :a 202 :b 303 :c}

map-let

macro

(map-let bindings & forms)
Usage:
  (map-let bindings & forms)

Given bindings and forms like `(map-let [x xs, y ys, ...] (+ x y))`, will iterate over the
collections [xs ys ...] assigning successive values of each collection to [x y ...], respectively.
The local symbols [x y ...] can then be used in `forms` to generate the output mapping.
Will throw if collections are not all of the same length. Not lazy.

map-let*

macro

(map-let* context bindings & forms)
Usage:  (map-let* ctx bindings & forms)

where ctx is a map with default values:
  {:strict true
   :lazy   false}

map-list

macro

(map-list & forms)
Like clojure.core/map but returns results in an eager list. Not lazy.

map-vals

(map-vals map-in tx-fn & tx-args)
Inputs: [map-in :- tsk/Map tx-fn :- tsk/Fn & tx-args]
Returns: tsk/Map

Transforms each value in a map using the supplied `tx-fn`:

    (t/map-vals {:a 1 :b 2 :c 3} inc)                  =>  {:a 2,   :b 3,   :c 4}
    (t/map-vals {:a 1 :b 2 :c 3} {1 101 2 202 3 303})  =>  {:a 101, :b 202, :c 303} 

MapKeySpec

matches?

macro

(matches? pattern & values)
A shortcut to clojure.core.match/match to aid in testing.  Returns true if the data value
matches the pattern value.  Underscores serve as wildcard values. Usage:

  (matches? pattern & values)

sample:

  (matches?  [1 _ 3] [1 2 3] )         ;=> true
  (matches?  {:a _ :b _       :c 3}
             {:a 1 :b [1 2 3] :c 3}
             {:a 2 :b 99      :c 3}
             {:a 3 :b nil     :c 3} )  ;=> true

Note that a wildcald can match either a primitive or a composite value.

nl

(nl)
Abbreviated name for `newline` 

nonneg?

(nonneg? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is not negative

nonpos?

(nonpos? arg)
Inputs: [arg]
Returns: s/Bool

Returns true iff x is not positive

noop

A function that accepts any number of args, does nothing, and returns `nil`.

not-empty?

(not-empty? coll)
Inputs: [coll]
Returns: s/Bool

For any collection coll, returns true if coll contains any items; otherwise returns false.
 Equivalent to (not (empty? coll)).

not-nil?

(not-nil? arg)
Inputs: [arg :- s/Any]
Returns: s/Bool

Returns true if arg is not nil; false otherwise. Equivalent to (not (nil? arg)),
 or the poorly-named clojure.core/some? 

onlies

(onlies coll)
Given an outer collection of length-1 collections, returns a sequence of the unwrapped values.
(onlies  [ [1] [2] [3] ])  =>  [1 2 3]
(onlies #{ [1] [2] [3] })  => #{1 2 3} 

only

(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent.

only2

(only2 coll)
Given a collection like `[[5]]`, returns `5`.  Equivalent to `(only (only coll))`.

pair?

(pair? coll)
Returns true if the collection contains exactly 2 items.

partition-using

(partition-using pred coll)
Inputs: [pred :- s/Any coll :- tsk/List]

Partitions a collection into vector of segments based on a predicate with a collection argument.
The first segment is initialized by removing the first element from `coll`, with subsequent
elements similarly transferred as long as `(pred remaining-coll)` is falsey. When
`(pred remaining-coll)` becomes truthy, the algorithm begins building the next segment.
Thus, the first partition finds the smallest N (< 0 N) such that (pred (drop N coll))
is true, and constructs the segment as (take N coll). If pred is never satisified,
[coll] is returned.

prepend

(prepend & args)
Inputs: [& args]
Returns: tsk/List

Given a sequential object (vector or list), add one or more elements to the beginning

prettify

(prettify coll)
Recursively walks a data structure and returns a prettified version.
Converts all lists to vectors. Converts all maps & sets to sorted collections.

pretty

(pretty arg)(pretty arg writer)
Shortcut to clojure.pprint/pprint. Returns it (1st) argument.

pretty-str

(pretty-str arg)
Returns a string that is the result of clojure.pprint/pprint

print-versions

(print-versions)

quad?

(quad? coll)
Returns true if the collection contains exactly 4 items.

rand-elem

(rand-elem coll)
Returns a random element from a collection

range-vec

(range-vec & args)
An eager version clojure.core/range that always returns its result in a vector.

rel=

(rel= val1 val2 & {:as opts})
Returns true if 2 double-precision numbers are relatively equal, else false.  Relative equality
is specified as either (1) the N most significant digits are equal, or (2) the absolute
difference is less than a tolerance value.  Input values are coerced to double before comparison.
Example:

  (rel= 123450000 123456789   :digits 4   )  ; true
  (rel= 1         1.001       :tol    0.01)  ; true

replace-at

(replace-at coll index elem)
Inputs: [coll :- tsk/List index :- s/Int elem :- s/Any]
Returns: tsk/List

Replaces an element in a collection at the specified index.

rest-or-empty

(rest-or-empty seq-arg)
Returns a sequence with the first item removed, or a zero-length seq if there are no more items

rest-or-nil

(rest-or-nil seq-arg)
Returns a sequence with the first item removed, or nil if there are no more items

restruct

(restruct & args)
within a `(destruct [<data> <shape>] ...) form, `(restruct)` or `(restruct <data>)` causes re-structuring
& return of original data shape using current values.

restruct-all

(restruct-all & args)
within a `(destruct [data-1 <shape-1>
                      data-2 <shape-2] ...) form, causes re-structuring & return of original data shapes using
current values as with (vals->map data-1 data-2 ...)

second-or-nil

(second-or-nil seq-arg)
Returns the second item in a sequence, or nil

seq->str

(seq->str seq-in)
Convert a seq into a string (using pr) with a space preceding each value

sequential->idx-map

(sequential->idx-map data)
Inputs: [data :- [s/Any]]
Returns: #:s{Any s/Any}

set-match-ctx?

(set-match-ctx? ctx-in pattern & values)

set-match?

(set-match? pattern & values)

set=

(set= & colls)
Inputs: [& colls]
Returns: s/Bool

Returns true if the collections are equal when converted to sets.

single?

(single? coll)
Returns true if the collection contains a single item.`

some-it->

macro

(some-it-> expr & forms)
Threads forms as with `it->`, terminates & returns `nil` if any expression is nil.

sorted-map-generic

(sorted-map-generic)
Returns a generic sorted map, able to accept keys of different classes

sorted-map-via-path

(sorted-map-via-path src-map path-vec)(sorted-map-via-path src-map path-vec ascending?)
Inputs: ([src-map :- tsk/Map path-vec :- tsk/Vec] [src-map :- tsk/Map path-vec :- tsk/Vec ascending? :- s/Bool])
Returns: tsk/Map


*************************************************************************
***** WARNING:  due to a bug in clojure.core/sorted-map-by,         *****
*****           this crashes if namespaced keys are used.           *****
*************************************************************************

Given a source map, returns a sorted version of the same map. The value to sort
by is specified via a path vector as with `clojure.core/get-in`, where the first
element is always specified as `:*`, since the path must work for every top-level key
in <src-map>. The sorting value must be acceptable to clojure.core/compare.
Defaults to ascending sort order.  Returns an instance of `clojure.data.avl.AVLMap`.
NOTE:  because of peculiarities of clojure.core/sorted-map-by, one cannot add new entries
to the sorted map.  Instead, a new map must be created from a plain map.
Usage:
  (sorted-map-via <src-map> <path-vec>)
  (sorted-map-via <src-map> <path-vec> <ascending?>)

Example:
  (let [unsorted {:c {:val 3}
                  :a {:val 1}
                  :b {:val 2}}
        sorted   (sorted-map-via unsorted [:* :val])]
    (assert (= unsorted sorted))) 

sorted-set-generic

(sorted-set-generic)
Returns a generic sorted set, able to accept keys of different classes

split-match

(split-match coll tgt)
Splits a collection src by matching with a sub-sequence tgt of length L.
Finds the first index N such that (= tgt (->> coll (drop N) (take L))) is true.
Returns a length-2 vector of [ (take N coll) (drop N coll) ].
If no match is found, [ coll [] ] is returned.

split-using

(split-using pred coll)
Splits a collection based on a predicate with a collection argument.
Finds the first index N such that (pred (drop N coll)) is true. Returns a length-2 vector
of [ (take N coll) (drop N coll) ]. If pred is never satisified, [ coll [] ] is returned.

spy

(spy arg1 arg2)(spy value)
A form of (println ...) to ease debugging display of either intermediate values in threading
forms or function return values. There are three variants.  Usage:

 (spy :msg <msg-string>)
     This variant is intended for use in either thread-first (->) or thread-last (->>)
     forms.  The keyword :msg is used to identify the message string and works equally
     well for both the -> and ->> operators. Spy prints both <msg-string>  and the
     threading value to stdout, then returns the value for further propogation in the
     threading form. For example, both of the following:
         (->   2
               (+ 3)
               (spy :msg "sum" )
               (* 4))
         (->>  2
               (+ 3)
               (spy :msg "sum" )
               (* 4))
     will print 'sum => 5' to stdout.

 (spy <msg-string> <value>)
     This variant is intended for simpler use cases such as function return values.
     Function return value expressions often invoke other functions and cannot be
     easily displayed since (println ...) swallows the return value and returns nil
     itself.  Spy will output both <msg-string> and the value, then return the value
     for use by further processing.  For example, the following:
         (println (* 2
                    (spy "sum" (+ 3 4))))
   will print:
         sum => 7
         14
   to stdout.

 (spy <value>)
     This variant is intended for use in very simple situations and is the same as the
     2-argument arity where <msg-string> defaults to 'spy'.  For example (spy (+ 2 3))
     prints 'spy => 5' to stdout.  

spy-indent-reset

(spy-indent-reset)
Reset the spy indent level to zero.

spy-pretty

macro

(spy-pretty & exprs)
Like `spyx-pretty` but without printing the original form

spyx

macro

(spyx & exprs)
An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
expressions, printing both the expression and its value to stdout. Returns the value of the
last expression.

spyx-pretty

macro

(spyx-pretty & exprs)
Like `spyx` but with pretty printing (clojure.pprint/pprint)

spyxx

macro

(spyxx expr)
An expression (println ...) for use in threading forms (& elsewhere). Evaluates the supplied
expression, printing both the expression, its type, and its value to stdout, then returns the value.

starts-with?

(starts-with? coll tgt-in)
Inputs: [coll tgt-in]
Returns: s/Bool

Returns true when the initial elements of coll match those of tgt

str->chars

(str->chars arg)
Inputs: [arg :- s/Str]
Returns: [s/Any]

Converts a string to a vector of chars

str->kw

(str->kw arg)
Inputs: [arg :- s/Str]
Returns: s/Keyword

Converts a string to a keyword

str->sym

(str->sym arg)
Inputs: [arg :- s/Str]
Returns: s/Symbol

Converts a string to a symbol

strcat

(strcat & args)
Recursively concatenate all arguments into a single string result.

sublist

(sublist listy idx-low)(sublist listy idx-low idx-bound)
Inputs: ([listy :- tsk/List idx-low :- s/Int] [listy :- tsk/List idx-low :- s/Int idx-bound :- s/Int])
Returns: tsk/List

Like clojure.core/subvec, but works for any sequence (remniscent of java.util.List/subList)

submap-by-keys

(submap-by-keys map-arg keep-keys & opts)
Inputs: [map-arg :- tsk/Map keep-keys :- (s/if set? tsk/Set tsk/List) & opts]
Returns: tsk/Map

Returns a new map containing entries with the specified keys. Throws for missing keys,
unless `:missing-ok` is specified. Usage:

    (submap-by-keys {:a 1 :b 2} #{:a   }             )  =>  {:a 1}
    (submap-by-keys {:a 1 :b 2} #{:a :z} :missing-ok )  =>  {:a 1}

submap-by-vals

(submap-by-vals map-arg keep-vals & opts)
Inputs: [map-arg :- tsk/Map keep-vals :- (s/if set? tsk/Set tsk/List) & opts]
Returns: tsk/Map

Returns a new map containing entries with the specified vals. Throws for missing vals,
unless `:missing-ok` is specified. Usage:

    (submap-by-vals {:a 1 :b 2 :A 1} #{1  }             )  =>  {:a 1 :A 1}
    (submap-by-vals {:a 1 :b 2 :A 1} #{1 9} :missing-ok )  =>  {:a 1 :A 1} 

submap?

(submap? inner-map outer-map)
Inputs: [inner-map :- #:s{Any s/Any} outer-map :- #:s{Any s/Any}]
Returns: s/Bool

Returns true if the map entries (key-value pairs) of one map are a subset of the entries of
 another map.  Similar to clojure.set/subset?

submatch?

(submatch? smaller larger)
Returns true if the first arg is (recursively) a subset/submap/subvec of the 2nd arg

swap-out!

(swap-out! tgt-atom swap-fn & args)
Just like clojure.core/swap!, but returns the old value

sym->kw

(sym->kw arg)
Inputs: [arg :- s/Symbol]
Returns: s/Keyword

Converts a symbol to a keyword

sym->str

(sym->str arg)
Inputs: [arg :- s/Symbol]
Returns: s/Str

Converts a symbol to a string

take-while-result

(take-while-result pred coll)
Inputs: [pred coll]
Returns: tsk/List

Takes from a collection based on a predicate with a collection argument.
Continues taking from the source collection until `(pred <taken-items>)` is falsey.
If pred is never falsey, `coll` is returned.

third-or-nil

(third-or-nil seq-arg)
Returns the third item in a sequence, or nil

thru

(thru end)(thru start end)(thru start end step)
Returns a sequence of integers. Like clojure.core/rng, but is inclusive of the right boundary value. Not lazy. 

triple?

(triple? coll)
Returns true if the collection contains exactly 3 items.

truthy?

(truthy? arg)
Returns true if arg is logical true (neither nil nor false); otherwise returns false.

try-catchall

macro

(try-catchall & body)
A cross-platform variant of try-catch that catches all exceptions.
Does not (yet) support finally, and does not need or want an exception class.

unlazy

(unlazy coll)
Converts a lazy collection to a concrete (eager) collection of the same type.

unnest

(unnest & values)
Inputs: [& values]
Returns: [s/Any]

Given any set of arguments including vectors, maps, sets, & scalars, performs a depth-first
recursive walk returning scalar args (int, string, keyword, etc) in a single 1-D vector.

unwrap

(unwrap data)
Inputs: [data :- [s/Any]]
Returns: Unwrapped

Works with the `->vector` function to unwrap vectors/lists to insert
their elements as with the unquote-spicing operator (~@). Examples:

    (->vector 1 2 3 4 5 6 7 8 9)              =>  [1 2 3 4 5 6 7 8 9]
    (->vector 1 2 3 (unwrap [4 5 6]) 7 8 9)   =>  [1 2 3 4 5 6 7 8 9] 

val=

(val= & vals)
Inputs: [& vals]
Returns: s/Bool

Compares values for equality using clojure.core/=, treating records as plain map values:

    (defrecord SampleRec [a b])
    (assert (val= (->SampleRec 1 2) {:a 1 :b 2}))   ; fails for clojure.core/= 

validate

(validate tst-fn tst-val)
(validate tst-fn tst-val)
Used to validate intermediate results. Returns tst-val if the result of
(tst-fn tst-val) is truthy.  Otherwise, throws ex-info with ex-data
{:sample-val sample-val :tst-result tst-result}.

validate-map-keys

(validate-map-keys tst-map valid-keys)
Inputs: [tst-map :- tsk/Map valid-keys :- MapKeySpec]
Returns: s/Any

validate-or-default

(validate-or-default is-valid? sample-val default-val)
Returns `sample-val` if `(is-valid? sample-val)` is truthy; else returns `default-val`

vals->map

macro

(vals->map & symbols)
Called with a list of symbols like `(vals->map a b c)` returns a map
like {:a a :b b :c c}.

    (let [a 1
          b 2
          c 3]
      (vals->map a b c))  ;=>  {:a 1 :b 2 :c 3} }

See `with-map-vals` for simple destructuring of such maps.

verify

macro

(verify form)
(verify <some-expr>)
Used to verify intermediate results. Returns value of <some-expr> if the result
is truthy.  Otherwise, throws an Exception.

walk-maps->sorted

(walk-maps->sorted form)
Recursively walks form, converting all maps to sorted-maps. 

walk-with-parents

(walk-with-parents data interceptor)
Inputs: [data :- s/Any interceptor :- tsk/KeyMap]
Returns: s/Any

Performs a depth-first traversal of a data structure, using an interceptor with signature:

    {:enter (fn [parents data] ...)
     :leave (fn [parents data] ...) }

 For each data node in the tree, the `:enter` function is called prior to walking
 the subtree rooted at that element, and the `:leave` function is called after
 walking the subtree. The result of each function replaces the data value.

 The `parents` arg to each interceptor function is a vector of elements from the
 root data value passed in.  Using dummy (i.e. noop) interceptors which simply
 print their args as a map, we have this example:

 Clojure maps & vectors/lists have special processing.  They are broken up into a sequence of
 MapEntry/ListEntry elements, which are included in the :parents vector before walking the child
 data values. In this way, a map val can easily determine its correspond key or vice versa, and a
 vector/list/seq element can easily determine its index.

(walk-with-parents  {:a 1 :b {:c 3}}}  <noop-intc>) =>

     :enter => {:parents [],                                                       :data {:a 1, :b {:c 3}}}
     :enter => {:parents [{:a 1, :b {:c 3}} [:a 1]],                               :data :a}
     :leave => {:parents [{:a 1, :b {:c 3}} [:a 1]],                               :data :a}
     :enter => {:parents [{:a 1, :b {:c 3}} [:a 1]],                               :data 1}
     :leave => {:parents [{:a 1, :b {:c 3}} [:a 1]],                               :data 1}
     :enter => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}]],                          :data :b}
     :leave => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}]],                          :data :b}
     :enter => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}]],                          :data {:c 3}}
     :enter => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}] {:c 3} [:c 3]],            :data :c}
     :leave => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}] {:c 3} [:c 3]],            :data :c}
     :enter => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}] {:c 3} [:c 3]],            :data 3}
     :leave => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}] {:c 3} [:c 3]],            :data 3}
     :leave => {:parents [{:a 1, :b {:c 3}} [:b {:c 3}]],                          :data {:c 3}}
     :leave => {:parents [],                                                       :data {:a 1, :b {:c 3}}}

     NOTE: in above, items in the :parents like `[:a 1]` are #clojure.lang.MapEntry values.

(walk-with-parents  [10 [20 21]]  <noop-intc>) =>

     :enter => {:parents [],
                :data [10 [20 21]]}
     :enter => {:parents [[10 [20 21]] #t.c.ListEntry{:index 0, :value 10}],
                :data 10}
     :enter => {:parents [[10 [20 21]] #t.c.ListEntry{:index 1, :value [20 21]}],
                :data [20 21]}
     :enter => {:parents [[10 [20 21]] #t.c.ListEntry{:index 1, :value [20 21]} [20 21] #t.c.ListEntry{:index 0, :value 20}],
                :data 20}
     :enter => {:parents [[10 [20 21]] #t.c.ListEntry{:index 1, :value [20 21]} [20 21] #t.c.ListEntry{:index 1, :value 21}],
                :data 21}

     NOTE: in above, `#t.c.ListEntry` stands for `#tupelo.core.ListEntry`, an analog of #clojure.lang.MapEntry

walk-with-parents-readonly

(walk-with-parents-readonly data intc)
Inputs: [data :- s/Any intc :- tsk/KeyMap]
Returns: s/Any

Walks a data structure as with `walk-with-parents`, but in a read-only mode
(interceptor function return values are ignored). Use for side-effects
such as printing or validation (throw Exception to indicate validation failure).
Returns input value (can be used for chaining). 

when-clojure-1-10-plus

macro

(when-clojure-1-10-plus & forms)
Wraps code that should only be included for Clojure 1.10 or higher.  Otherwise, code is supressed.

when-clojure-1-8-plus

macro

(when-clojure-1-8-plus & forms)
Wraps code that should only be included for Clojure 1.8 or higher.  Otherwise, code is supressed.

when-clojure-1-9-plus

macro

(when-clojure-1-9-plus & forms)
Wraps code that should only be included for Clojure 1.9 or higher.  Otherwise, code is supressed.

when-not-clojure-1-9-plus

macro

(when-not-clojure-1-9-plus & forms)
Wraps code that should only be included for Clojure versions prior to 1.9.  Otherwise, code is supressed.

wild-item?

(wild-item? item)
Inputs: [item :- s/Any]
Returns: s/Bool

Returns true if any element in a nested collection is the wildcard :*

wild-match-root?

(wild-match-root? ctx-in)

wild-match?

multimethod

Returns true if a pattern is matched by one or more values.  The special keyword :* (colon-star)
in the pattern serves as a wildcard value.  Note that a wildcald can match either a primitive or a
composite value: Classic usage:

  (wild-match? pattern & values)

examples:

  (wild-match? {:a :* :b 2}
               {:a 1  :b 2})         ;=> true

  (wild-match? [1 :* 3]
               [1 2  3]
               [1 9  3] ))           ;=> true

  (wild-match? {:a :*       :b 2}
               {:a [1 2 3]  :b 2})   ;=> true

wild-match? also accepts a context map; usage:

  (wild-match? ctx)

example (default values shown):

  (wild-match?  { :submap-ok   false
                  :subset-ok   false
                  :subvec-ok   false
                  :wildcard-ok true
                  :pattern     <required param>
                  :values    [ <patttern-spec>+ ]   ; vector of 1 or more required
                } )

wild-submatch?

(wild-submatch? pattern & values)
Simple wrapper for wild-match? where all types of sub-matching are enabled.

with-debug-tag

macro

(with-debug-tag debug-tag & forms)

with-err-str

macro

(with-err-str & body)
Evaluates exprs in a context in which *err* is bound to a fresh
StringWriter.  Returns the string created by any nested printing
calls.

with-exception-default

macro

(with-exception-default default-val & forms)
Evaluates body & returns its result.  In the event of an exception, default-val is returned
instead of the exception.

with-map-vals

macro

(with-map-vals the-map items-vec & forms)
Given a map like {:a 1 :b 2 :c 3} (such as generated by `(vals->map a b c)`),
performs safe `let` destructuring using `grab` like:

   (let [some-map  {:a 1 :b 2 :c 3} } ]
     (with-map-vals some-map [a b c]
        (+ a b c)))  ;=>  6

`with-map-vals` is safe for typos since `grab` will throw is the requrested map key is not present.
See `vals->map` for simple creation of labelled data maps.

with-nil-default

(with-nil-default default-val sample-val)
Returns `sample-val` if not nil; else returns `default-val`

with-result

macro

(with-result result & forms)
Evaluates `result` and returns it; also evaluates `forms` for their side-effects.

with-spy-enabled

macro

(with-spy-enabled tag & forms)

with-spy-indent

macro

(with-spy-indent & forms)
Increments indentation level of all spy, spyx, or spyxx expressions within the body.

with-system-err-str

macro

(with-system-err-str & body)
Evaluates exprs in a context in which JVM System/err is bound to a fresh
PrintStream.  Returns the string created by any nested printing calls.

with-system-out-str

macro

(with-system-out-str & body)
Evaluates exprs in a context in which JVM System/out is bound to a fresh
PrintStream.  Returns the string created by any nested printing calls.

with-timer

macro

(with-timer id & forms)
Prints `id` and the elapsed (elapsed) execution time for a set of forms.

with-timer-x

macro

(with-timer-x form)
Prints the form and its (elapsed) execution time.

xbutlast

(xbutlast coll)
Inputs: [coll :- [s/Any]]
Returns: s/Any

Returns a vector of all but the last value in a list or vector. Throws if empty.

xfirst

(xfirst coll)
Returns the first value in a list or vector. Throws if empty.

xfourth

(xfourth coll)
Returns the fourth value in a list or vector. Throws if (< len 4).

xlast

(xlast coll)
Inputs: [coll :- [s/Any]]
Returns: s/Any

Returns the last value in a list or vector. Throws if empty.

xrest

(xrest coll)
Returns the last value in a list or vector. Throws if empty.

xreverse

(xreverse coll)
Returns a vector containing a sequence in reversed order. Throws if nil.

xsecond

(xsecond coll)
Returns the second value in a list or vector. Throws if (< len 2).

xtake

(xtake n coll)
Returns the first n values from a collection.  Returns map for map colls.
Throws if empty.

xthird

(xthird coll)
Returns the third value in a list or vector. Throws if (< len 3).

xvec

(xvec coll)
Inputs: [coll :- [s/Any]]
Returns: [s/Any]

Converts a collection into a vector. Throws if given nil.

yield

macro

(yield value)
Within a 'generator function' created by `lazy-gen`, populates the
result lazy seq with the supplied value (a la Python). Returns the value.

yield-all

macro

(yield-all values)
Within a 'generator function' created by `lazy-gen`, populates the
result lazy seq with each item from the supplied collection. Returns the collection.

zip

(zip & args)
Zips together vectors producing a vector of tuples (like Python zip). Not lazy.
Example:

   (zip [:a :b :c] [1 2 3]) ->  [ [:a 1] [:b 2] [:c 3] ]

 ***** WARNING - will hang for infinite length inputs ***** 

zip*

(zip* context & colls)
Usage:  (zip* context & colls)
where context is a map with default values:  {:strict true}
Not lazy. 

zip-1*

(zip-1* context & colls)
Usage:  (zip* context & colls)
where context is a map with default values:  {:strict true}
Not lazy. 

zip-lazy

(zip-lazy & colls)
Usage:  (zip-lazy coll1 coll2 ...)
    (zip-lazy xs ys zs) -> [ [x0 y0 z0]
                             [x1 y1 z1]
                             [x2 y2 z2]
                             ... ]

Returns a lazy result. Will truncate to the length of the shortest collection.
A convenience wrapper for `(map vector coll1 coll2 ...)`.