pax_global_header00006660000000000000000000000064133462064770014526gustar00rootroot0000000000000052 comment=6c631261135c1f66223863e6bd469ed9b1b11277 Moses-Moses-2.1.0-1/000077500000000000000000000000001334620647700140365ustar00rootroot00000000000000Moses-Moses-2.1.0-1/.gitignore000066400000000000000000000001001334620647700160150ustar00rootroot00000000000000*.bat tsc* ldoc* LuaMinify* *.ld luacov* *.exe *.dll test* bust*Moses-Moses-2.1.0-1/.luacov000066400000000000000000000023171334620647700153330ustar00rootroot00000000000000--- Global configuration file. Copy, customize and store in your -- project folder as '.luacov' for project specific configuration -- @class module -- @name luacov.defaults return { -- default filename to load for config options if not provided -- only has effect in 'luacov.defaults.lua' ['configfile'] = '.luacov', -- filename to store stats collected ['statsfile'] = 'luacov.stats.out', -- filename to store report ['reportfile'] = 'luacov.report.out', -- Run reporter on completion? (won't work for ticks) runreport = true, -- Delete stats file after reporting? deletestats = false, -- Patterns for files to include when reporting -- all will be included if nothing is listed -- (exclude overrules include, do not include -- the .lua extension) ['include'] = { 'moses' }, -- Patterns for files to exclude when reporting -- all will be included if nothing is listed -- (exclude overrules include, do not include -- the .lua extension) ['exclude'] = { 'luacov$', 'luacov.reporter$', 'luacov.defaults$', 'luacov.runner$', 'luacov.stats$', 'luacov.tick$', 'mediator.*$', 'busted$', 'busted.*$', 'luassert.*$', 'pl.*$', 'say.*$', 'spec.*$' }, } Moses-Moses-2.1.0-1/.travis.yml000066400000000000000000000011731334620647700161510ustar00rootroot00000000000000language: python sudo: false env: - LUA="lua=5.1" - LUA="lua=5.2" - LUA="lua=5.3" - LUA="luajit=2.0" - LUA="luajit=2.1" before_install: - pip install hererocks - hererocks lua_install -r^ --$LUA - export PATH=$PATH:$PWD/lua_install/bin # Add directory with all installed binaries to PATH install: - luarocks install busted - luarocks install luacov - luarocks install luacov-coveralls script: - busted --verbose --coverage after_success: - luacov-coveralls --exclude $TRAVIS_BUILD_DIR/lua_install branches: except: - gh-pages notifications: email: on_success: change on_failure: always Moses-Moses-2.1.0-1/CHANGELOG.md000066400000000000000000000261161334620647700156550ustar00rootroot00000000000000# Version history ## 2.1.0 (09/12/2018) ### Breaking changes * Renamed `toArray` to `pack` * Renamed `reduceby` to `reduceBy` * Removed `skip` as alias to `last` * Changed prototype : `each(t, f, ...)` is now `each(t, f)` * Changed prototype : `eachi(t, f, ...)` is now `eachi(t, f)` * Changed prototype : `adjust(t, key, f, ...)` is now `adjust(t, key, f)` * Changed prototype : `countf(t, f, ...)` is now `countf(t, f)` * Changed prototype : `map(t, f, ...)` is now `map(t, f)` * Changed prototype : `reduceBy(t, f, pred, state, ...)` is now `reduceBy(t, f, pred, state)` * Changed prototype : `select(t, f, ...)` is now `select(t, f)` * Changed prototype : `reject(t, f, ...)` is now `reject(t, f)` * Changed prototype : `all(t, f, ...)` is now `all(t, f)` * Changed prototype : `invoke(t, method, ...)` is now `invoke(t, method)` * Changed prototype : `min(t, transform, ...)` is now `min(t, transform)` * Changed prototype : `max(t, transform, ...)` is now `max(t, transform)` * Changed prototype : `countBy(t, iter, ...)` is now `countBy(t, iter)` * Changed prototype : `groupBy(t, iter, ...)` is now `groupBy(t, iter)` * Changed prototype : `selectWhile(array, f, ...)` is now `selectWhile(array, f)` * Changed prototype : `dropWhile(array, f, ...)` is now `dropWhile(array, f)` * Changed prototype : `findIndex(array, pred, ...)` is now `findIndex(array, pred)` * Changed prototype : `findLastIndex(array, pred, ...)` is now `findLastIndex(array, pred)` * Changed prototype : `chunk(array, f, ...)` is now `chunk(array, f)` * Changed prototype : `times(iter, n, ...)` is now `times(iter, n)` * Changed prototype : `template(id, ...)` is now `template(id)` * Changed prototype : `tap(obj, f, ...)` is now `tap(obj, f)` * Changed prototype : `result(obj, method, ...)` is now `result(obj, method)` * Changed prototype : `intersection(array, ...)` is now `intersection(array)` ### Other changes * Renamed `array` to `tabulate`, with no alias * Moved `invert` to object functions ### Additions * Added `best` in table functions * Added `allEqual` in table functions * Added `sortedk` iterator in array functions * Added `sortedv` iterator in array functions * Added `disjoint` in array functions * Added `nsorted` in array functions * Added `duplicates` in array functions * Added `xpairs` in array functions * Added `xpairsRight` in array functions * Added `call` in utility functions * Added `type` in object functions * Added `spreadPath` in object functions * Added `flattenPath` in object functions * Added `thread` in utility functions * Added `threadRight` in utility functions * Added `iterlen` in utility functions * Added `skip` in utility functions * Added `both` in utility functions * Added `either` in utility functions * Added `neither` in utility functions * Added `dispatch` in utility functions * Added `noarg` in utility functions ## 2.0.0 (08/23/2018) ### Breaking changes * library functions now accept iterators prototyped as `f(v, k, ...)` instead of `f(k, v, ...)`. It improves the benefits of chaning and helps writting a clear functional-style code. Library functions affected with this breaking change are : `each`, `eachi`,`countf`, `map`, `reduceby`, `select`, `reject`, `all`, `groupBy`, `countBy`, `selectWhile`, `dropWhile`, `findIndex`, `findLastIndex`, `chunk`. * `reduceby` is now prototyped as `reduceby(t, f, pred, state)` instead of `reduceby(t, f, state, pred)`. * `times` is now prototyped as `times(iter, n, ...)` instead of `times(iter, n, ...)`. * `bindAll` was renamed to `bindall` * `functions` no longer accept optional `sort` third arguments * `sliding` was renamed to `overlapping` * Improved `range` to handle negative progressions and start the count from 1. * `memoize` no longer takes a `hash` function. ### Other changes * Made `shift` a default library function, and `pop` its alias. * Moved `shuffle` from table function to array functions * Made `iterator` to accept an extra optional arg `n` ### Additions #### Added support for operators * Arithmetic operators : `add`, `sub`, `mul`, `div`, `mod`, `exp`, `pow` (alias to `exp`), `unm`, `neg` (alias to `unm`), `floordiv`, `intdiv` * Relational operators : `eq`, `neq`, `lt`, `gt`, `le`, `ge` * Logical operators : `land`, `lor`, `lnot` * Concatenation operator : `concat` * Length operator : `length`, `len` (alias to `length`) #### Added functions * Added `adjust` in table functions * Added `xprod` in array functions * Added `prepend` in array functions * Added `zeros` in array functions * Added `ones` in array functions * Added `vector` in array functions * Added `aperture` in array functions * Added `sum` in array functions * Added `product` in array functions * Added `mean` in array functions * Added `median` in array functions * Added `powerset` in array functions * Added `zipWith` in array functions * Added `pairwise` in array functions * Added `applySpec` in utility functions * Added `nthArg` in utility functions * Added `cond` in utility functions * Added `castArray` in utility functions * Added `unary` in utility functions * Added `ary` in utility functions * Added `rearg` in utility functions * Added `unfold` in utility functions * Added `converge` in utility functions * Added `path` in object functions #### Added function aliases * Added `update` as alias to `adjust` * Added `always` as alias to `constant` * Added `intersperse` as alias to `interpose` * Added `sliding` as alias to `aperture` * Added `tabulate` as alias to `array` * Added `matches` as alias to `isEqual` * Added `average` as alias to `mean` * Added `nAry` as alias to `ary` * Added `transposeWith` as alias to `zipWith` ## 1.6.1 (04/27/17) * Added `_.array` * Added `_.clear` * Added `_.time` * Added `_.before` ## 1.6.0 (14/04/17) * Added `_.toObj` * Added `_.noop` * Added `_.partialRight` * Added `_.flip` * Added `_.overArgs` * Added `_.over` * Added `_.overEvery` * Added `_.overSome` ## 1.5.1 (04/13/17) * Added `_.curry` * Added `_.fill` * Added `.transpose` as an alias to `_.zip` ## 1.5.0 (04/10/17) #### Additions * Added `_.bind2` * Added `_.reduceby` * Added `_.iterator` (and alias `_.iter`) * Added `_.sliding` * Added `_.sample` * Added `_.sampleProb` * Added `_.where` * Added `_.sortBy` * Added `_.findIndex` * Added `_.findLastIndex` * Added `_.bindAll` * Added `_.partial` * Added `_.kvpairs` * Added `_.property` * Added `_.propertyOf` * Added `_.constant` * Added parameter `pad` to `_.partition` #### Changes, bugfixes * Improved `_.select` * Fixed `_.compose` * Made `_.contains` as an alias to `_.include` * Improved `_.all` * Fixed `_.size` * Improved `_.map` to map key-value pairs to key-value pairs * Fixed `_.partition` to generate an error for partition size < 1. ## 1.4.0 (07/14/14) ### Breaking #### Changes * Aliases are available by default * `_.find` is no longer an alias to `_.detect` * Provided a new implementation of `_.unique`, removed argument `_.isSorted` * `_.isNil` now returns true if arg is nil, an empty string or empty table and false otherwise. * `_.size` now returns 0 for empty args instead of `nil` * `_.unique` no longer accepts `iter` argument to transform original array values. * `_.cycle` argument `n` now defaults to 1. * `_.groupBy` no longer handles `iter` as a string #### Renamed * Renamed alias `_.uId` to `_.uid` * Renamed `_.add` to `_.addTop` * Renamed `_.uniq` as alias to `_.unique` * Renamed `_.symmetric_difference` to `_.symmetricDifference` #### Removed * Removed `_.paired` ### Improvements & bugfixes * `_.reduce` now supports an array of booleans * `_.pick` now picks false values * `_.concat` args `i` and `j` defaults explicitely to 1 and array length (for compatibility with LuaJIT) * `_.pop` now takes an optional extra-arg n, to be the number of values to be popped * `_.unshift` now takes an optional extra-arg n, to be the number of values to be retrieved * Moved explicitely `_.toArray` to array functions * `_.functions` accepts an extra-arg to prevent from looking-up for methods in metatables. ### New functions (and aliases) * Added `_.find` * Added `_.pipe` * Added `_.complement` * Added `_.juxtapose` and alias `_.juxt` * Added `_.isunique` and alias `_.isuniq` * Added `_.rep` * Added `_.interleave` * Added `_.interpose` * Added `_.partition` and alias `_.part` * Added `_.permutation` and alias `_.perm` * Added `_.compare` as alias to `_.isEqual` * Added `_.isIterable` * Added `_.toBoolean` * Added `_.pull` and alias `_.remove` * Added `_.at` ### New aliases * Added `_.xor` as alias to `_.symmetricDifference` ## 1.3.2.1 (04/22/13) Renamed global `MOSES_NO_ALIASES` to global `MOSES_ALIASES`. Aliases are not available by default. ## 1.3.2 (04/19/13) Added `_.import`, export library to context or _G Added `noConflict` option to `_.import` Added `MOSES_NO_ALIASES` option when requiring the library Added `_.symmetric_difference` Added `_.eachi` Added `_.isInteger` Added `_.cycle` Added `_.count` Added `_.countf` Added `_.chunk` (inspired from Ruby's Enumerable [#chunk](http://ruby-doc.org/core-2.0/Enumerable.html#method-i-chunk)) Added `_.chop` as alias to `_.removeRange` Added `_.skip` as alias to `_.last` Added `_.diff` as alias to `_.difference` Added `_.symdiff` as alias to `_.symmetric_difference` Added `_.forEachi` as alias to `_.eachi` Added `_.loop` as alias to `_.cycle` Renamed `_.pairs` to `_.paired` Removed `_.count` as alias to `_.range` Changed `_.difference behaviour`, now takes up to two arrays as args Fixed internal inconsistencies with aliases, should not be used internally with regards to `MOSES_NO_ALIASES` option. Fixed `_.each` implementation, should not return anything ## 1.3.1 (04/12/13) * Added chaining interface * Renamed `_.isObject` to `_.isTable` * Added `_.tap`, `_.chain`, `_()` and `_.value` * Added `_.findWhere` * Added `_.contains` * _.functions no longer takes an output table * Changed _.isArray behaviour, returns true only for real Lua arrays * Updated specs * Updated docs and samples ## 1.3.0 (11/12/12) * Removed _.iterate (slower than pairs, ipairs) * Added _.identity * Removed _.curry (was more like a closure, will provide a proper implementation later) * Removed _.iter_to_array * Most of all functions rewritten * _.import/_.mixin now imports library functions to the global env. * Added type checking functions as object functions * Added new functions and aliases : Moses has 85 unique functions, 117 counting aliases. * Added HTML docs * Added Specs * Added samples ## 1.2.1 (08/20/12) * Added `_.takeWhile` (as alias to `_.selectWhile`) * Added `_.dropWhile` and `_.rejectWhile` (as alias) * Updated Moses_Lib_Test.lua * Updated documentation ## 1.2 (08/19/12) * Added `_.selectWhile` * Added `_.mapReduce` and `_.mapr` (as alias) * Added `_.mapReduceRight` and `_.maprr` (as alias) * Added `_.bindn` * Added `_.appendLists` * Updated Moses_Lib_Test.lua * Updated documentation ## 1.1 (08/04/12) * Removed `_.contains` as alias to `_.include` * Added `_.removeRange` (as Array function) * Added `_.sameKeys` and `_.contains` (as Collection functions) * Added `_.bind` (as Utility function) * Updated Moses_Lib_Test.lua * Updated documentation ## 1.0 (08/02/12) * Added `_.append`, `_.invert`, `_.import`, `_.template`, `_.curry` * Updated Moses_Lib_Test.lua * Updated documentation ## 0.1 (07/24/12) * Initial Release Moses-Moses-2.1.0-1/LICENSE000066400000000000000000000020461334620647700150450ustar00rootroot00000000000000Copyright (c) 2012-2018 Roland Yonaba Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Moses-Moses-2.1.0-1/README.md000066400000000000000000000067061334620647700153260ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/Yonaba/Moses.png)](https://travis-ci.org/Yonaba/Moses) [![Latest Stable](https://img.shields.io/badge/Latest_Stable-2.1.0-blue.svg)](https://github.com/Yonaba/Moses/releases/tag/Moses-2.1.0-1) [![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE) [![Lua](https://img.shields.io/badge/Lua-5.1%2C%205.2%2C%205.3%2C%20JIT-blue.svg)]() A Lua utility-belt library for [functional programming](http://en.wikipedia.org/wiki/Functional_programming).
## Examples How can I get the sum of all integers between 1 and 100 ? ```lua local sum = M.sum(M.range(100)) print(sum) -- 5050 ```` Say I am looking for the length of the longest word in some array ? ```lua local words = {'some','words','of','different','lengths'} print(M.max(words, M.op.length)) -- 9 letters ```` What is the sum of all fibonacci numbers for n below or equal 25 ? ```lua local function fib(n) return n < 2 and n or fib(n - 1) + fib(n - 2) end local fibsum = M.sum(M.map(M.range(25), fib)) print(fibsum) -- 196417 ```` Or let us do the same, opbject-oriented style with chaining : ```lua local function fib(n) return n < 2 and n or fib(n - 1) + fib(n - 2) end local fibsum = M.chain(M.range(25)):map(fib):sum():value() print(fibsum) -- 196417 ```` Or even shorter : ```lua local fibsum = M(M.range(25)):map(fib):sum():value() print(fibsum) -- 196417 ```` Feel free to download and try it on your own! ## Download ### Archive * __2.1.0__ *(latest stable)*: [zip](http://github.com/Yonaba/Moses/archive/Moses-2.1.0-1.zip) | [tar.gz](http://github.com/Yonaba/Moses/archive/Moses-2.1.0-1.tar.gz) * __Previous versions__ : [tags](http://github.com/Yonaba/Moses/tags) ### Bash ```bash git clone git://github.com/Yonaba/Moses.git ```` ### LuaRocks ```` luarocks install moses ```` ### MoonRocks ```` moonrocks install moses ```` ## Usage ```lua local M = require "moses" ```` *Note:* the full source [moses.lua](https://github.com/Yonaba/Moses/blob/master/moses.lua) is quite heavy (~92 kiB, 3115 LOC). You can alternatively use the [minified version](https://github.com/Yonaba/Moses/blob/master/moses_min.lua) (~35 kiB, 561 LOC). ## Tutorial Find a complete set of code examples in [tutorial.md](https://github.com/Yonaba/Moses/blob/master/doc/tutorial.md). ## Documentation * Read it [online](http://yonaba.github.io/Moses/doc). ## Credits and Acknowledgement * [Jeremy Ashkenas](https://github.com/jashkenas), for the amazing [Underscore.js](http://documentcloud.github.com/underscore/) * [Marcus Irven](http://mirven.github.com/underscore.lua/)'s and [JT Archie](https://github.com/jtarchie/underscore-lua)'s 1-to-1 ports that also inspired this * [Matthew Rocklin](https://github.com/mrocklin)'s [Toolz](https://github.com/pytoolz/toolz/) from which I borrowed some ideas * [Steve Donovan](https://github.com/stevedonovan)'s [LDoc](https://github.com/stevedonovan/ldoc/), used to generate the current HTML documentation. * [Mark Langen](https://github.com/stravant)'s [LuaMinify](https://github.com/stravant/LuaMinify/), used to generate a minified version of this library. ## Specification Run [spec tests](https://github.com/Yonaba/Moses/blob/master/spec) from Lua using [busted](https://github.com/Olivine-Labs/busted/) with the following command from the root folder: ```` busted ```` ## License This work is under [MIT-LICENSE](http://www.opensource.org/licenses/mit-license.php)
Copyright (c) 2012-2018 Roland Yonaba.
See [LICENSE](LICENSE). Moses-Moses-2.1.0-1/doc/000077500000000000000000000000001334620647700146035ustar00rootroot00000000000000Moses-Moses-2.1.0-1/doc/index.html000066400000000000000000004757021334620647700166170ustar00rootroot00000000000000 Moses documentation

Module moses

Utility-belt library for functional programming in Lua (source)

Info:

Operator functions

operator.add (a, b) Returns a + b.
operator.concat (a, b) Returns concatenation of a and b.
operator.div (a, b) Returns a / b.
operator.eq (a, b) Checks if a equals b.
operator.exp (a, b) Returns a ^ b.
operator.floordiv (a, b) Performs floor division (//) between a and b.
operator.ge (a, b) Returns logical a and b.
operator.ge (a, b) Checks if a is greater or equal to b.
operator.gt (a, b) Checks if a is strictly greater than b.
operator.intdiv (a, b) Performs integer division between a and b.
operator.le (a, b) Checks if a is less or equal to b.
operator.length (a) Returns the length of a.
operator.lnot (a) Returns logical not a.
operator.lor (a, b) Returns logical a or b.
operator.lt (a, b) Checks if a is strictly less than b.
operator.mod (a, b) Returns a % b.
operator.mul (a, b) Returns a * b.
operator.neq (a, b) Checks if a not equals b.
operator.sub (a, b) Returns a - b.
operator.unm (a) Returns -a.

Table functions

adjust (t, key, f) Adjusts the value at a given key using a function or a value.
all (t, f) Checks if all values in a table are passing an iterator test.
allEqual (t[, comp]) Checks if all values in a collection are equal.
at (t, ...) Collects values at given keys and return them wrapped in an array.
best (t, f) Returns the best value passing a selector function.
clear (t) Clears a table.
containsKeys (t, other) Checks if all the keys of other table exists in table t.
count (t[, val]) Counts occurrences of a given value in a table.
countBy (t, iter) Groups values in a collection and counts them.
countf (t, f) Counts the number of values passing a predicate test.
cycle (t[, n]) Loops n times through a table.
detect (t, value) Performs a linear search for a value in a table.
each (t, f) Iterates on key-value pairs, calling f (v, k) at every step.
eachi (t, f) Iterates on integer key-value pairs, calling f(v, k) every step.
findWhere (t, props) Returns the first value having specified keys props.
groupBy (t, iter) Splits a table into subsets groups.
include (t, value) Performs a linear search for a value in a table.
invoke (t, method) Invokes a method on each value in a table.
map (t, f) Maps f (v, k) on value-key pairs, collects and returns the results.
mapReduce (t, f[, state]) Reduces a table while saving intermediate states.
mapReduceRight (t, f[, state]) Reduces a table while saving intermediate states.
max (t[, transform]) Returns the max value in a collection.
min (t[, transform]) Returns the min value in a collection.
pluck (t, key) Extracts values in a table having a given key.
reduce (t, f[, state]) Reduces a table, left-to-right.
reduceBy (t, f, pred[, state[, ...]]) Reduces values in a table passing a given predicate.
reduceRight (t, f[, state]) Reduces a table, right-to-left.
reject (t, f) Clones a table while dropping values passing an iterator test.
same (a, b) Checks if two tables are the same.
sameKeys (tA, tB) Checks if both given tables have the same keys.
select (t, f) Selects and returns values passing an iterator test.
size ([...]) Counts the number of values in a collection.
sort (t[, comp]) Sorts a table, in-place.
sortBy (t[, transform[, comp]]) Sorts a table in-place using a transform.
sortedk (t[, comp]) Iterates on values with respect to key order.
sortedv (t[, comp]) Iterates on values with respect to values order.
where (t, props) Returns all values having specified keys props.

Array functions

addTop (array, ...) Adds all passed-in values at the top of an array.
aperture (array[, n]) Iterator returning sliding partitions of an array.
append (array, other) Clones array and appends values from another array.
chunk (array, f) Chunks together consecutive values.
compact (array) Returns all truthy values (removes falses and nils).
concat (array[, sep[, i[, j]]]) Concatenates values in a given array.
difference (array, another) Returns values from an array not present in all passed-in args.
disjoint (...) Checks if all passed in arrays are disjunct.
dropWhile (array, f) Collects values from a given array.
duplicates (array) Returns an array list of all duplicates in array.
fill (array, value[, i[, j]]) Replaces elements in a given array with a given value.
find (array, value[, from]) Looks for the first occurrence of a given value in an array.
findIndex (array, pred) Returns the first index at which a predicate returns true.
findLastIndex (array, pred) Returns the last index at which a predicate returns true.
first (array[, n]) Returns the first N values in an array.
flatten (array[, shallow]) Flattens a nested array.
indexOf (array, value) Returns the index of the first occurrence of value in an array.
initial (array[, n]) Returns all values in an array excluding the last N values.
interleave (...) Interleaves arrays.
interpose (array, value) Interposes value in-between consecutive pair of values in array.
intersection (...) Returns the intersection of all passed-in arrays.
isunique (array) Checks if a given array contains distinct values.
last (array[, n]) Returns the last N values in an array.
lastIndexOf (array, value) Returns the index of the last occurrence of value in an array.
mean (array) Returns the mean of an array of numbers.
median (array) Returns the median of an array of numbers.
nsorted (array[, n[, comp]]) Returns the n-top values satisfying a predicate.
nth (array, index) Returns the value at a given index.
ones (n) Returns an array of n 1's.
overlapping (array[, n[, pads]]) Iterator returning overlapping partitions of an array.
pack (...) Converts a list of arguments to an array.
pairwise (array) Iterator returning sliding pairs of an array.
partition (array[, n[, pads]]) Iterator returning partitions of an array.
permutation (array) Iterator returning the permutations of an array.
powerset (array) Returns the powerset of array values.
prepend (array, ...) Adds all passed-in values at the top of an array.
product (array) Returns the product of array values.
pull (array, ...) Removes all provided values in a given array.
push (array, ...) Pushes all passed-in values at the end of an array.
range ([from[, to[, step]]]) Produces a flexible list of numbers.
removeRange (array[, start[, finish]]) Removes values at an index within the range [start, finish].
rep (value, n) Creates an array list of n values, repeated.
rest (array[, index]) Returns all values after index.
reverse (array) Returns an array where values are in reverse order.
sample (array[, n[, seed]]) Samples n random values from an array.
sampleProb (array, prob[, seed]) Return elements from a sequence with a given probability.
selectWhile (array, f) Collects values from a given array.
shift (array[, n]) Removes and returns the values at the top of a given array.
shuffle (array[, seed]) Returns a shuffled copy of a given array.
slice (array[, start[, finish]]) Slices values indexed within [start, finish] range.
sortedIndex (array, the[, comp[, sort]]) Returns the index at which a value should be inserted.
sum (array) Returns the sum of array values.
symmetricDifference (array, array2) Performs a symmetric difference.
union (...) Returns the duplicate-free union of all passed in arrays.
unique (array) Produces a duplicate-free version of a given array.
unshift (array[, n]) Removes and returns the values at the end of a given array.
vector (value, n) Returns an array of n times a given value.
xpairs (valua, array) Creates pairs from value and array.
xpairsRight (valua, array) Creates pairs from value and array.
xprod (array, array2) Returns all possible pairs built from given arrays.
zeros (n) Returns an array of n zeros.
zip (...) Merges values of each of the passed-in arrays in subsets.
zipWith (f, ...) Merges values using a given function.

Utility functions

after (f, count) Returns a version of f that runs on the count-th call.
applySpec (specs) Returns a function which applies specs on args.
ary (f[, n]) Returns a function which accepts up to n args.
before (f, count) Returns a version of f that will run no more than count times.
bind (f, v) Binds v to be the first argument to f.
bind2 (f, v) Binds v to be the second argument to f.
bindall (obj, ...) Binds methods to object.
bindn (f, ...) Binds ... to be the N-first arguments to function f.
both (...) Returns a validation function.
call (f[, ...]) Calls f with the supplied arguments.
castArray (value) Casts value as an array if it is not one.
complement (f) Returns the logical complement of a given function.
compose (...) Composes functions.
cond (conds) Returns a function which iterate over a set of conditions.
constant (value) Creates a constant function which returns the same output on every call.
converge (f, g, h) Converges two functions into one.
curry (f[, n_args]) Curries a function.
dispatch (...) Returns a dispatching function.
either (...) Returns a validation function.
flip (f) Creates a function of f with arguments flipped in reverse order.
identity (value) Returns the passed-in value.
iterator (f, value[, n]) Produces an iterator which repeatedly apply a function f onto an input.
iterlen (...) Returns the length of an iterator.
juxtapose (value, ...) Calls a sequence of passed-in functions with the same argument.
memoize (f) Memoizes a given function by caching the computed result.
neither (...) Returns a validation function.
noarg (f) Returns a function with an arity of 0.
noop () The no operation function.
nthArg (n) Returns a function that gets the nth argument.
once (f) Returns a version of f that runs only once.
over (...) Creates a function that runs transforms on all arguments it receives.
overArgs (f, ...) Creates a function that invokes f with its arguments transformed.
overEvery (...) Creates a validation function.
overSome (...) Creates a validation function.
partial (f, ...) Partially apply a function by filling in any number of its arguments.
partialRight (f, ...) Similar to partial, but from the right.
pipe (value, ...) Pipes a value through a series of functions.
rearg (f, indexes) Returns a function which runs with arguments rearranged.
skip (iter[, n]) Consumes the first n values of a iterator then returns it.
tabulate (...) Iterates over an iterator and returns its values in an array.
thread (value, ...) Threads value through a series of functions.
threadRight (value, ...) Threads value through a series of functions.
time (f[, ...]) Returns the execution time of f (...) and its returned values.
times (iter[, n]) Runs iter function n times.
unary (f) Returns a function which accepts up to one arg.
unfold (f, seed) Builds a list from a seed value.
uniqueId ([template]) Generates an unique ID for the current session.
wrap (f, wrapper) Wraps f inside of the wrapper function.

Object functions

chain (value) Returns a wrapped object.
clone (obj[, shallow]) Clones a given object properties.
extend (destObj, ...) Extends an object properties.
flattenPath (obj, ...) Flattens object under property path onto provided object.
functions ([obj]) Returns a sorted list of all methods names found in an object.
has (obj, key) Checks if a given object implements a property.
import ([context[, noConflict]]) Imports all library functions into a context.
invert (obj) Swaps keys with values.
isArray (obj) Checks if the given argument is an array.
isBoolean (obj) Checks if the given argument is a boolean.
isCallable (obj) Checks if the given argument is callable.
isEmpty ([obj]) Checks if the given pbject is empty.
isEqual (objA, objB[, useMt]) Performs a deep comparison test between two objects.
isFinite (obj) Checks if the given argument is a finite number.
isFunction (obj) Checks if the given argument is a function.
isInteger (obj) Checks if the given argument is an integer.
isIterable (obj) Checks if the given object is iterable with pairs (or ipairs).
isNaN (obj) Checks if the given argument is NaN (see Not-A-Number).
isNil (obj) Checks if the given argument is nil.
isNumber (obj) Checks if the given argument is a number.
isString (obj) Checks if the given argument is a string.
isTable (t) Checks if the given arg is a table.
keys (obj) Returns the keys of the object properties.
kvpairs (obj) Converts key-value pairs to an array-list of [k, v] pairs.
obj:value () Extracts the value of a wrapped object.
omit (obj, ...) Returns an object copy without black-listed properties.
path (obj, ...) Returns the value at a given path in an object.
pick (obj, ...) Returns an object copy having white-listed properties.
property (key) Returns a function that will return the key property of any passed-in object.
propertyOf (obj) Returns a function which will return the value of an object property.
result (obj, method) Invokes an object method.
spreadPath (obj, ...) Spreads object under property path onto provided object.
tap (obj, f) Invokes interceptor with the object, and then returns object.
template (obj[, template]) Applies a template to an object, preserving non-nil properties.
toBoolean (value) Converts any given value to a boolean
toObj (kvpairs) Converts an array list of [k,v] pairs to an object.
type (obj) Extends Lua's type function.
values (obj) Returns the values of the object properties.


Operator functions

operator.add (a, b)
Returns a + b. Aliased as op.add.

Parameters:

  • a a value
  • b a value

Returns:

    a + b
operator.concat (a, b)
Returns concatenation of a and b. Aliased as op.concat.

Parameters:

  • a a value
  • b a value

Returns:

    a .. b
operator.div (a, b)
Returns a / b. Aliased as op.div.

Parameters:

  • a a value
  • b a value

Returns:

    a / b
operator.eq (a, b)
Checks if a equals b. Aliased as op.eq.

Parameters:

  • a a value
  • b a value

Returns:

    a == b
operator.exp (a, b)
Returns a ^ b. Aliased as op.exp, op.pow.

Parameters:

  • a a value
  • b a value

Returns:

    a ^ b
operator.floordiv (a, b)
Performs floor division (//) between a and b. It rounds the quotient towards minus infinity. Aliased as op.floordiv.

Parameters:

  • a a value
  • b a value

Returns:

    a // b
operator.ge (a, b)
Returns logical a and b. Aliased as op.land.

Parameters:

  • a a value
  • b a value

Returns:

    a and b
operator.ge (a, b)
Checks if a is greater or equal to b. Aliased as op.ge.

Parameters:

  • a a value
  • b a value

Returns:

    a >= b
operator.gt (a, b)
Checks if a is strictly greater than b. Aliased as op.gt.

Parameters:

  • a a value
  • b a value

Returns:

    a > b
operator.intdiv (a, b)
Performs integer division between a and b. Aliased as op.intdiv.

Parameters:

  • a a value
  • b a value

Returns:

    a / b
operator.le (a, b)
Checks if a is less or equal to b. Aliased as op.le.

Parameters:

  • a a value
  • b a value

Returns:

    a <= b
operator.length (a)
Returns the length of a. Aliased as op.len.

Parameters:

  • a a value

Returns:

    a

operator.lnot (a)
Returns logical not a. Aliased as op.lnot.

Parameters:

  • a a value

Returns:

    not a
operator.lor (a, b)
Returns logical a or b. Aliased as op.lor.

Parameters:

  • a a value
  • b a value

Returns:

    a or b
operator.lt (a, b)
Checks if a is strictly less than b. Aliased as op.lt.

Parameters:

  • a a value
  • b a value

Returns:

    a < b
operator.mod (a, b)
Returns a % b. Aliased as op.mod.

Parameters:

  • a a value
  • b a value

Returns:

    a % b
operator.mul (a, b)
Returns a * b. Aliased as op.mul.

Parameters:

  • a a value
  • b a value

Returns:

    a * b
operator.neq (a, b)
Checks if a not equals b. Aliased as op.neq.

Parameters:

  • a a value
  • b a value

Returns:

    a ~= b
operator.sub (a, b)
Returns a - b. Aliased as op.sub.

Parameters:

  • a a value
  • b a value

Returns:

    a - b
operator.unm (a)
Returns -a. Aliased as op.unm, op.neg.

Parameters:

  • a a value

Returns:

    -a

Table functions

adjust (t, key, f)
Adjusts the value at a given key using a function or a value. In case f is a function, it should be prototyped f(v). It does not mutate the given table, but rather returns a new array. In case the given key does not exist in t, it throws an error.

Parameters:

  • t a table
  • key a key
  • f a function, prototyped as f(v) or a value
all (t, f)
Checks if all values in a table are passing an iterator test.
Aliased as every

Parameters:

  • t a table
  • f an iterator function, prototyped as f (v, k)

Returns:

    true if all values passes the predicate, false otherwise
allEqual (t[, comp])
Checks if all values in a collection are equal. Uses an optional comp function which is used to compare values and defaults to isEqual when not given.
Aliased as alleq.

Parameters:

  • t a table
  • comp a comparison function. Defaults to isEqual (optional)

Returns:

    true when all values in t are equal, false otherwise.

See also:

at (t, ...)
Collects values at given keys and return them wrapped in an array.

Parameters:

  • t a table
  • ... A variable number of keys to collect values

Returns:

    an array-list of values
best (t, f)
Returns the best value passing a selector function. Acts as a special case of reduce, using the first value in t as an initial state. It thens folds the given table, testing each of its values v and selecting the value passing the call f(state,v) every time.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)

Returns:

    the final state of reduction

See also:

clear (t)
Clears a table. All its values become nil.

Parameters:

  • t a table

Returns:

    the given table, cleared.
containsKeys (t, other)
Checks if all the keys of other table exists in table t. It does not compares values. The test is not commutative, i.e table t may contains keys not existing in other.

Parameters:

  • t a table
  • other another table

Returns:

    true or false

See also:

count (t[, val])
Counts occurrences of a given value in a table. Uses isEqual to compare values.

Parameters:

  • t a table
  • val a value to be searched in the table. If not given, the size of the table will be returned (optional)

Returns:

    the count of occurrences of the given value

See also:

countBy (t, iter)
Groups values in a collection and counts them.

Parameters:

  • t a table
  • iter an iterator function, prototyped as iter (v, k)

Returns:

    a table of subsets groups names paired with their count
countf (t, f)
Counts the number of values passing a predicate test. Same as count, but uses an iterator. Returns the count for values passing the test f (v, k)

Parameters:

  • t a table
  • f an iterator function, prototyped as f (v, k)

Returns:

    the count of values validating the predicate

See also:

cycle (t[, n])
Loops n times through a table. In case n is omitted, it will loop forever. In case n is lower or equal to 0, it returns an empty function.
Aliased as loop.

Parameters:

  • t a table
  • n the number of loops (optional)

Returns:

    an iterator function yielding value-key pairs from the passed-in table.
detect (t, value)
Performs a linear search for a value in a table. Returns the key of the value if found. The given value can be a function prototyped as f (v, value) which should return true when any v in the table equals the value being searched. This function is similar to find, which is mostly meant to work with array.

Parameters:

  • t a table
  • value a value to search for

Returns:

    the key of the value when found or nil

See also:

each (t, f)
Iterates on key-value pairs, calling f (v, k) at every step.
Aliased as forEach.

Parameters:

  • t a table
  • f a function, prototyped as f (v, k)

See also:

eachi (t, f)
Iterates on integer key-value pairs, calling f(v, k) every step.
Only applies to values located at integer keys. The table can be a sparse array. Iteration will start from the lowest integer key found to the highest one.
Aliased as forEachi.

Parameters:

  • t a table
  • f a function, prototyped as f (v, k)

See also:

findWhere (t, props)
Returns the first value having specified keys props.

Parameters:

  • t a table
  • props a set of keys

Returns:

    a value from the passed-in table

See also:

groupBy (t, iter)
Splits a table into subsets groups.

Parameters:

  • t a table
  • iter an iterator function, prototyped as iter (v, k)

Returns:

    a table of subsets groups
include (t, value)
Performs a linear search for a value in a table. It does not work for nested tables. The given value can be a function prototyped as f (v, value) which should return true when any v in the table equals the value being searched.
Aliased as any, some, contains

Parameters:

  • t a table
  • value a value to search for

Returns:

    a boolean : true when found, false otherwise

See also:

invoke (t, method)
Invokes a method on each value in a table.

Parameters:

  • t a table
  • method a function, prototyped as f (v, k)

Returns:

    the result of the call f (v, k)

See also:

map (t, f)
Maps f (v, k) on value-key pairs, collects and returns the results.
Aliased as collect.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (v, k)

Returns:

    a table of results
mapReduce (t, f[, state])
Reduces a table while saving intermediate states. Folds the table left-to-right using a given iterator and an initial state. The iterator takes a state and a value, and returns a new state. The result is an array of intermediate states.
Aliased as mapr

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)
  • state an initial state of reduction. Defaults to the first value in the table. (optional)

Returns:

    an array of states

See also:

mapReduceRight (t, f[, state])
Reduces a table while saving intermediate states. Folds the table right-to-left using a given iterator and an initial state. The iterator takes a state and a value, and returns a new state. The result is an array of intermediate states.
Aliased as maprr

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)
  • state an initial state of reduction. Defaults to the last value in the table. (optional)

Returns:

    an array of states

See also:

max (t[, transform])
Returns the max value in a collection. If a transform function is passed, it will be used to evaluate values by which all objects will be sorted.

Parameters:

  • t a table
  • transform a transformation function, prototyped as transform (v, k), defaults to identity (optional)

Returns:

    the max value found

See also:

min (t[, transform])
Returns the min value in a collection. If a transform function is passed, it will be used to evaluate values by which all objects will be sorted.

Parameters:

  • t a table
  • transform a transformation function, prototyped as transform (v, k), defaults to identity (optional)

Returns:

    the min value found

See also:

pluck (t, key)
Extracts values in a table having a given key.

Parameters:

  • t a table
  • key a key, will be used to index in each value: value[key]

Returns:

    an array of values having the given key
reduce (t, f[, state])
Reduces a table, left-to-right. Folds the table from the first element to the last element to a single value, using a given iterator and an initial state. The iterator takes a state and a value and returns a new state.
Aliased as inject, foldl.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)
  • state an initial state of reduction. Defaults to the first value in the table. (optional)

Returns:

    the final state of reduction

See also:

reduceBy (t, f, pred[, state[, ...]])
Reduces values in a table passing a given predicate. Folds the table left-to-right, considering only values validating a given predicate.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)
  • pred a predicate function pred (v, k) to select values to be considered for reduction
  • state an initial state of reduction. Defaults to the first value in the table of selected values. (optional)
  • ... optional args to be passed to pred (optional)

Returns:

    the final state of reduction

See also:

reduceRight (t, f[, state])
Reduces a table, right-to-left. Folds the table from the last element to the first element to single value, using a given iterator and an initial state. The iterator takes a state and a value, and returns a new state.
Aliased as injectr, foldr.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (state, value)
  • state an initial state of reduction. Defaults to the last value in the table. (optional)

Returns:

    the final state of reduction

See also:

reject (t, f)
Clones a table while dropping values passing an iterator test.
Aliased as discard

Parameters:

  • t a table
  • f an iterator function, prototyped as f (v, k)

Returns:

    the remaining values

See also:

same (a, b)
Checks if two tables are the same. It compares if both tables features the same values, but not necessarily at the same keys.

Parameters:

  • a a table
  • b another table

Returns:

    true or false
sameKeys (tA, tB)
Checks if both given tables have the same keys. It does not compares values.

Parameters:

  • tA a table
  • tB another table

Returns:

    true or false

See also:

select (t, f)
Selects and returns values passing an iterator test.
Aliased as filter.

Parameters:

  • t a table
  • f an iterator function, prototyped as f (v, k)

Returns:

    the selected values

See also:

size ([...])
Counts the number of values in a collection. If being passed more than one argument it will return the count of all passed-in arguments.

Parameters:

  • ... Optional variable number of arguments (optional)

Returns:

    a count

See also:

sort (t[, comp])
Sorts a table, in-place. If a comparison function is given, it will be used to sort values.

Parameters:

  • t a table
  • comp a comparison function prototyped as comp (a, b), defaults to < operator. (optional)

Returns:

    the given table, sorted.

See also:

sortBy (t[, transform[, comp]])
Sorts a table in-place using a transform. Values are ranked in a custom order of the results of running transform (v) on all values. transform may also be a string name property sort by. comp is a comparison function.

Parameters:

  • t a table
  • transform a transform function to sort elements prototyped as transform (v). Defaults to identity (optional)
  • comp a comparison function, defaults to the < operator (optional)

Returns:

    a new array of sorted values

See also:

sortedk (t[, comp])
Iterates on values with respect to key order. Keys are sorted using comp function which defaults to math.min. It returns upon each call a key, value pair.

Parameters:

  • t a table
  • comp a comparison function. Defaults to < operator (optional)

Returns:

    an iterator function

See also:

sortedv (t[, comp])
Iterates on values with respect to values order. Values are sorted using comp function which defaults to math.min. It returns upon each call a key, value pair.

Parameters:

  • t a table
  • comp a comparison function. Defaults to < operator (optional)

Returns:

    an iterator function

See also:

where (t, props)
Returns all values having specified keys props.

Parameters:

  • t a table
  • props a set of keys

Returns:

    an array of values from the passed-in table

See also:

Array functions

addTop (array, ...)
Adds all passed-in values at the top of an array. The last elements will bubble to the top of the given array.

Parameters:

  • array an array
  • ... a variable number of arguments

Returns:

    the passed-in array with new values added

See also:

aperture (array[, n])
Iterator returning sliding partitions of an array.
Aliased as sliding

Parameters:

  • array an array
  • n the size of partitions. Defaults to 2 (and then behaves like pairwise) (optional)

Returns:

    an iterator function

See also:

append (array, other)
Clones array and appends values from another array.

Parameters:

  • array an array
  • other an array

Returns:

    a new array
chunk (array, f)
Chunks together consecutive values. Values are chunked on the basis of the return value of a provided predicate f (v, k). Consecutive elements which return the same value are chunked together. Leaves the first argument untouched if it is not an array.

Parameters:

  • array an array
  • f an iterator function prototyped as f (v, k)

Returns:

    a table of chunks (arrays)

See also:

compact (array)
Returns all truthy values (removes falses and nils).

Parameters:

  • array an array

Returns:

    a new array
concat (array[, sep[, i[, j]]])
Concatenates values in a given array. Handles booleans as well. If sep string is passed, it will be used as a separator. Passing i and j will result in concatenating only values within [i, j] range.
Aliased as join

Parameters:

  • array a given array
  • sep a separator string, defaults to the empty string ''. (optional)
  • i the starting index, defaults to 1. (optional)
  • j the final index, defaults to the array length. (optional)

Returns:

    a string
difference (array, another)
Returns values from an array not present in all passed-in args.
Aliased as without and diff

Parameters:

  • array an array
  • another array

Returns:

    a new array

See also:

disjoint (...)
Checks if all passed in arrays are disjunct.

Parameters:

  • ... a variable number of arrays

Returns:

    true if the intersection of all arrays is not empty, false otherwise.

See also:

dropWhile (array, f)
Collects values from a given array. The passed-in array should not be sparse. This function collects values as long as they do not satisfy a given predicate and returns on the first truthy test.
Aliased as rejectWhile

Parameters:

  • array an array
  • f an iterator function prototyped as f (v, k)

Returns:

    a new table containing all values collected

See also:

duplicates (array)
Returns an array list of all duplicates in array.

Parameters:

  • array an array

Returns:

    an array-list of duplicates

See also:

fill (array, value[, i[, j]])
Replaces elements in a given array with a given value. In case i and j are given it will only replaces values at indexes between [i,j]. In case j is greater than the array size, it will append new values, increasing the array size.

Parameters:

  • array an array
  • value a value
  • i the index from which to start replacing values. Defaults to 1. (optional)
  • j the index where to stop replacing values. Defaults to the array size. (optional)

Returns:

    the original array with values changed
find (array, value[, from])
Looks for the first occurrence of a given value in an array. Returns the value index if found. Uses isEqual to compare values.

Parameters:

  • array an array of values
  • value a value to lookup for
  • from the index from where the search will start. Defaults to 1. (optional)

Returns:

    the index of the value if found in the array, nil otherwise.

See also:

findIndex (array, pred)
Returns the first index at which a predicate returns true.

Parameters:

  • array an array
  • pred a predicate function prototyped as pred (v, k)

Returns:

    the index found or nil

See also:

findLastIndex (array, pred)
Returns the last index at which a predicate returns true.

Parameters:

  • array an array
  • pred a predicate function prototyped as pred (k, v)

Returns:

    the index found or nil

See also:

first (array[, n])
Returns the first N values in an array.
Aliased as head, take

Parameters:

  • array an array
  • n the number of values to be collected, defaults to 1. (optional)

Returns:

    a new array

See also:

flatten (array[, shallow])
Flattens a nested array. Passing shallow will only flatten at the first level.

Parameters:

  • array an array
  • shallow specifies the flattening depth. Defaults to false.` (optional)

Returns:

    a flattened array
indexOf (array, value)
Returns the index of the first occurrence of value in an array.

Parameters:

  • array an array
  • value the value to search for

Returns:

    the index of the passed-in value

See also:

initial (array[, n])
Returns all values in an array excluding the last N values.

Parameters:

  • array an array
  • n the number of values to be left, defaults to the array length. (optional)

Returns:

    a new array

See also:

interleave (...)
Interleaves arrays. It returns a single array made of values from all passed in arrays in their given order, interleaved.

Parameters:

  • ... a variable list of arrays

Returns:

    a new array

See also:

interpose (array, value)
Interposes value in-between consecutive pair of values in array.
Aliased as intersperse

Parameters:

  • array an array
  • value a value

Returns:

    a new array

See also:

intersection (...)
Returns the intersection of all passed-in arrays. Each value in the result is present in each of the passed-in arrays.

Parameters:

  • ... a variable number of array arguments

Returns:

    a new array

See also:

isunique (array)
Checks if a given array contains distinct values. Such an array is made of distinct elements, which only occur once in this array.
Aliased as isuniq

Parameters:

  • array an array

Returns:

    true if the given array is unique, false otherwise.

See also:

last (array[, n])
Returns the last N values in an array.

Parameters:

  • array an array
  • n the number of values to be collected, defaults to the array length. (optional)

Returns:

    a new array

See also:

lastIndexOf (array, value)
Returns the index of the last occurrence of value in an array.

Parameters:

  • array an array
  • value the value to search for

Returns:

    the index of the last occurrence of the passed-in value or nil

See also:

mean (array)
Returns the mean of an array of numbers.
Aliased as average

Parameters:

  • array an array of numbers

Returns:

    a number

See also:

median (array)
Returns the median of an array of numbers.

Parameters:

  • array an array of numbers

Returns:

    a number

See also:

nsorted (array[, n[, comp]])
Returns the n-top values satisfying a predicate. It takes a comparison function comp used to sort array values, and then picks the top n-values. It leaves the original array untouched.

Parameters:

  • array an array
  • n a number of values to retrieve. Defaults to 1. (optional)
  • comp a comparison function. Defaults to < operator. (optional)

Returns:

    an array of top n values
nth (array, index)
Returns the value at a given index.

Parameters:

  • array an array
  • index an index

Returns:

    the value at the given index
ones (n)
Returns an array of n 1's.

Parameters:

  • n a number

Returns:

    an array

See also:

overlapping (array[, n[, pads]])
Iterator returning overlapping partitions of an array.
If the last subsequence has lower elements than n and pad is supplied, it will be adjusted to n elements with pad value.

Parameters:

  • array an array
  • n the size of partitions. Defaults to 2. (optional)
  • pads a value to adjust the last subsequence to the n elements (optional)

Returns:

    an iterator function

See also:

pack (...)
Converts a list of arguments to an array.

Parameters:

  • ... a list of arguments

Returns:

    an array of all passed-in args
pairwise (array)
Iterator returning sliding pairs of an array.

Parameters:

  • array an array

Returns:

    an iterator function

See also:

partition (array[, n[, pads]])
Iterator returning partitions of an array. It returns arrays of length n made of values from the given array. If the last partition has lower elements than n and pad is supplied, it will be adjusted to n of elements with pad value.

Parameters:

  • array an array
  • n the size of partitions. Defaults to 1. (optional)
  • pads a value to adjust the last subsequence to the n elements (optional)

Returns:

    an iterator function

See also:

permutation (array)
Iterator returning the permutations of an array. It returns arrays made of all values from the passed-in array, with values permuted.

Parameters:

  • array an array

Returns:

    an iterator function
powerset (array)
Returns the powerset of array values. For instance, when given the set {1,2,3}, returns {{1},{2},{3},{1,2},{2,3},{1,2,3}}.

Parameters:

  • array an array

Returns:

    an array
prepend (array, ...)
Adds all passed-in values at the top of an array. As opposed to addTop, it preserves the order of the passed-in elements.

Parameters:

  • array an array
  • ... a variable number of arguments

Returns:

    the passed-in array with new values added

See also:

product (array)
Returns the product of array values.

Parameters:

  • array a given array

Returns:

    the product of array values
pull (array, ...)
Removes all provided values in a given array.
Aliased as remove

Parameters:

  • array an array
  • ... a variable number of values to be removed from the array

Returns:

    the passed-in array with values removed
push (array, ...)
Pushes all passed-in values at the end of an array.

Parameters:

  • array an array
  • ... a variable number of arguments

Returns:

    the passed-in array with new added values

See also:

range ([from[, to[, step]]])
Produces a flexible list of numbers. If one value is passed, will count from 1 to that value, with a default step of 1 (or -1). If two values are passed, will count from the first one to the second one, using a default step of 1 (or -1). A third value passed will be considered a step value.

Parameters:

  • from the initial value of the range (optional)
  • to the final value of the range (optional)
  • step the step of count. Defaults to 1 or -1. (optional)

Returns:

    a new array of numbers
removeRange (array[, start[, finish]])
Removes values at an index within the range [start, finish].
Aliased as rmRange, chop

Parameters:

  • array an array
  • start the lower bound index, defaults to the first index in the array. (optional)
  • finish the upper bound index, defaults to the array length. (optional)

Returns:

    the passed-in array with values removed
rep (value, n)
Creates an array list of n values, repeated.

Parameters:

  • value a value to be repeated
  • n the number of repetitions of value.

Returns:

    a new array of n values
rest (array[, index])
Returns all values after index.
Aliased as tail

Parameters:

  • array an array
  • index an index, defaults to 1 (optional)

Returns:

    a new array

See also:

reverse (array)
Returns an array where values are in reverse order. The passed-in array should not be sparse.

Parameters:

  • array an array

Returns:

    a reversed array
sample (array[, n[, seed]])
Samples n random values from an array. If n is not specified, returns a single element. It uses internally shuffle to shuffle the array before sampling values. If seed is passed, it will be used for shuffling.

Parameters:

  • array an array
  • n a number of elements to be sampled. Defaults to 1. (optional)
  • seed an optional seed for shuffling (optional)

Returns:

    an array of selected values

See also:

sampleProb (array, prob[, seed])
Return elements from a sequence with a given probability. It considers each value independently. Providing a seed will result in deterministic sampling. Given the same seed it will return the same sample every time.

Parameters:

  • array an array
  • prob a probability for each element in array to be selected
  • seed an optional seed for deterministic sampling (optional)

Returns:

    an array of selected values

See also:

selectWhile (array, f)
Collects values from a given array. The passed-in array should not be sparse. This function collects values as long as they satisfy a given predicate and returns on the first falsy test.
Aliased as takeWhile

Parameters:

  • array an array
  • f an iterator function prototyped as f (v, k)

Returns:

    a new table containing all values collected

See also:

shift (array[, n])
Removes and returns the values at the top of a given array.
Aliased as pop

Parameters:

  • array an array
  • n the number of values to be popped. Defaults to 1. (optional)

Returns:

    the popped values

See also:

shuffle (array[, seed])
Returns a shuffled copy of a given array. If a seed is provided, it will be used to init the built-in pseudo random number generator (using math.randomseed).

Parameters:

  • array an array
  • seed a seed (optional)

Returns:

    a shuffled copy of the given array
slice (array[, start[, finish]])
Slices values indexed within [start, finish] range.
Aliased as M.sub

Parameters:

  • array an array
  • start the lower bound index, defaults to the first index in the array. (optional)
  • finish the upper bound index, defaults to the array length. (optional)

Returns:

    a new array of sliced values
sortedIndex (array, the[, comp[, sort]])
Returns the index at which a value should be inserted. This index is evaluated so that it maintains the sort. If a comparison function is passed, it will be used to sort values.

Parameters:

  • array an array
  • the value to be inserted
  • comp an comparison function prototyped as f (a, b), defaults to < operator. (optional)
  • sort whether or not the passed-in array should be sorted (optional)

Returns:

    number the index at which the passed-in value should be inserted
sum (array)
Returns the sum of array values.

Parameters:

  • array a given array

Returns:

    the sum of array values
symmetricDifference (array, array2)
Performs a symmetric difference. Returns values from array not present in array2 and also values from array2 not present in array.
Aliased as symdiff

Parameters:

  • array an array
  • array2 another array

Returns:

    a new array

See also:

union (...)
Returns the duplicate-free union of all passed in arrays.

Parameters:

  • ... a variable number of arrays arguments

Returns:

    a new array

See also:

unique (array)
Produces a duplicate-free version of a given array.
Aliased as uniq

Parameters:

  • array an array

Returns:

    a new array, duplicate-free

See also:

unshift (array[, n])
Removes and returns the values at the end of a given array.

Parameters:

  • array an array
  • n the number of values to be unshifted. Defaults to 1. (optional)

Returns:

    the values

See also:

vector (value, n)
Returns an array of n times a given value.

Parameters:

  • value a value
  • n a number

Returns:

    an array

See also:

xpairs (valua, array)
Creates pairs from value and array. Value is always prepended to the pair.

Parameters:

  • valua a value
  • array an array

Returns:

    an array list of all pairs
xpairsRight (valua, array)
Creates pairs from value and array. Value is always appended as the last item to the pair.

Parameters:

  • valua a value
  • array an array

Returns:

    an array list of all pairs
xprod (array, array2)
Returns all possible pairs built from given arrays.

Parameters:

  • array a first array
  • array2 a second array

Returns:

    an array list of all pairs
zeros (n)
Returns an array of n zeros.

Parameters:

  • n a number

Returns:

    an array

See also:

zip (...)
Merges values of each of the passed-in arrays in subsets. Only values indexed with the same key in the given arrays are merged in the same subset.
Aliased as transpose

Parameters:

  • ... a variable number of array arguments

Returns:

    a new array

See also:

zipWith (f, ...)
Merges values using a given function. Only values indexed with the same key in the given arrays are merged in the same subset. Function f is used to combine values.
Aliased as transposeWith

Parameters:

  • f a function
  • ... a variable number of array arguments

Returns:

    a flat array of results

See also:

Utility functions

after (f, count)
Returns a version of f that runs on the count-th call. Useful when dealing with asynchronous tasks.

Parameters:

  • f a function
  • count the number of calls before f will start running.

Returns:

    a new function

See also:

applySpec (specs)
Returns a function which applies specs on args. This function produces an object having the same structure than specs by mapping each property to the result of calling its associated function with the supplied arguments

Parameters:

  • specs a table

Returns:

    a function
ary (f[, n])
Returns a function which accepts up to n args. It ignores any additional arguments.
Aliased as nAry.

Parameters:

  • f a function
  • n a number. Defaults to 1. (optional)

Returns:

    a function

See also:

before (f, count)
Returns a version of f that will run no more than count times. Next calls will keep yielding the results of the count-th call.

Parameters:

  • f a function
  • count a count

Returns:

    a new function

See also:

bind (f, v)
Binds v to be the first argument to f. Calling f (...) will result to f (v, ...).

Parameters:

  • f a function
  • v a value

Returns:

    a function

See also:

bind2 (f, v)
Binds v to be the second argument to f. Calling f (a, ...) will result to f (a, v, ...).

Parameters:

  • f a function
  • v a value

Returns:

    a function

See also:

bindall (obj, ...)
Binds methods to object. As such, whenever any of these methods is invoked, it always receives the object as its first argument.

Parameters:

  • obj an abject
  • ... a variable number of method names

Returns:

    the passed-in object with all methods bound to the object itself.

See also:

bindn (f, ...)
Binds ... to be the N-first arguments to function f.
Calling f (a1, a2, ..., aN) will result to f (..., a1, a2, ...,aN).

Parameters:

  • f a function
  • ... a variable number of arguments

Returns:

    a function

See also:

both (...)
Returns a validation function. Given a set of functions, the validation function evaluates to true only when all its funcs returns true.

Parameters:

  • ... an array list of functions

Returns:

    true when all given funcs returns true with input, false otherwise
call (f[, ...])
Calls f with the supplied arguments. Returns the results of f(...).

Parameters:

  • f a function
  • ... a vararg list of args to f (optional)

Returns:

    the result of f(...) call.
castArray (value)
Casts value as an array if it is not one.

Parameters:

  • value a value

Returns:

    an array containing the given value
complement (f)
Returns the logical complement of a given function. For a given input, the returned function will output false if the original function would have returned true, and vice-versa.

Parameters:

  • f a function

Returns:

    the logical complement of the given function f.
compose (...)
Composes functions. Each passed-in function consumes the return value of the function that follows. In math terms, composing the functions f, g, and h produces the function f(g(h(...))).

Parameters:

  • ... a variable number of functions

Returns:

    a new function

See also:

cond (conds)
Returns a function which iterate over a set of conditions. It invokes each predicate, passing it given values. It returns the value of the corresponding function of the first predicate to return a non-nil value.

Parameters:

  • conds an array list of predicate-function pairs

Returns:

    the result of invoking f(...) of the first predicate to return a non-nil value
constant (value)
Creates a constant function which returns the same output on every call.
Aliased as always

Parameters:

  • value a constant value

Returns:

    a constant function
converge (f, g, h)
Converges two functions into one.

Parameters:

  • f a function
  • g a function
  • h a function

Returns:

    a new version of function f
curry (f[, n_args])
Curries a function. If the given function f takes multiple arguments, it returns another version of f that takes a single argument (the first of the arguments to the original function) and returns a new function that takes the remainder of the arguments and returns the result.

Parameters:

  • f a function
  • n_args the number of arguments expected for f. Defaults to 2. (optional)

Returns:

    a curried version of f

See also:

dispatch (...)
Returns a dispatching function. When called with arguments, this function invokes each of its functions in the passed-in order and returns the results of the first non-nil evaluation.

Parameters:

  • ... a vararg list of functions

Returns:

    a dispatch function
either (...)
Returns a validation function. Given a set of functions, the validation function evaluates to true when at least one of its funcs returns true.

Parameters:

  • ... an array list of functions

Returns:

    true when one of the given funcs returns true with input, false otherwise
flip (f)
Creates a function of f with arguments flipped in reverse order.

Parameters:

  • f a function

Returns:

    a function
identity (value)
Returns the passed-in value. This function is used internally as a default iterator.

Parameters:

  • value a value

Returns:

    the passed-in value
iterator (f, value[, n])
Produces an iterator which repeatedly apply a function f onto an input.
Yields value, then f(value), then f(f(value)), continuously.
Aliased as iter.

Parameters:

  • f a function
  • value an initial input to f
  • n the number of times the iterator should run (optional)

Returns:

    an iterator function
iterlen (...)
Returns the length of an iterator. It consumes the iterator itself.

Parameters:

  • ... an iterator function (returning a generator, a state and a value)

Returns:

    the iterator length
juxtapose (value, ...)
Calls a sequence of passed-in functions with the same argument. Returns a sequence of results.
Aliased as juxt

Parameters:

  • value a value
  • ... a variable number of functions

Returns:

    a list of results
memoize (f)
Memoizes a given function by caching the computed result. Useful for speeding-up slow-running functions.
Aliased as cache

Parameters:

  • f a function

Returns:

    a new function
neither (...)
Returns a validation function. Given a set of functions, the validation function evaluates to true when neither of its func return true.

Parameters:

  • ... an array list of functions

Returns:

    true when neither of the given funcs returns true with input, false otherwise
noarg (f)
Returns a function with an arity of 0. The new function ignores any arguments passed to it.

Parameters:

  • f a function

Returns:

    a new function
noop ()
The no operation function.

Returns:

    nothing
nthArg (n)
Returns a function that gets the nth argument.
If n is negative, the nth argument from the end is returned.

Parameters:

  • n a number

Returns:

    a function
once (f)
Returns a version of f that runs only once. Successive calls to f will keep yielding the same output, no matter what the passed-in arguments are. It can be used to initialize variables.

Parameters:

  • f a function

Returns:

    a new function

See also:

over (...)
Creates a function that runs transforms on all arguments it receives.

Parameters:

  • ... a set of functions which will receive all arguments to the returned function

Returns:

    a function

See also:

overArgs (f, ...)
Creates a function that invokes f with its arguments transformed. 1rst arguments will be passed to the 1rst transform, 2nd arg to the 2nd transform, etc. Remaining arguments will not be transformed.

Parameters:

  • f a function
  • ... a list of transforms funcs prototyped as f (v)

Returns:

    the result of running f with its transformed arguments

See also:

overEvery (...)
Creates a validation function. The returned function checks if all of the given predicates return truthy when invoked with the arguments it receives.

Parameters:

  • ... a list of predicate functions

Returns:

    a new function

See also:

overSome (...)
Creates a validation function. The return function checks if any of a given predicates return truthy when invoked with the arguments it receives.

Parameters:

  • ... a list of predicate functions

Returns:

    a new function

See also:

partial (f, ...)
Partially apply a function by filling in any number of its arguments.
One may pass a string 'M' as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but left open to be supplied at call-time.

Parameters:

  • f a function
  • ... a list of partial arguments to f

Returns:

    a new version of function f having some of it original arguments filled

See also:

partialRight (f, ...)
Similar to partial, but from the right.

Parameters:

  • f a function
  • ... a list of partial arguments to f

Returns:

    a new version of function f having some of it original arguments filled

See also:

pipe (value, ...)
Pipes a value through a series of functions. In math terms, given some functions f, g, and h in that order, it returns f(g(h(value))).

Parameters:

  • value a value
  • ... a variable number of functions

Returns:

    the result of the composition of function calls.

See also:

rearg (f, indexes)
Returns a function which runs with arguments rearranged. Arguments are passed to the returned function in the order of supplied indexes at call-time.

Parameters:

  • f a function
  • indexes an array list of indexes

Returns:

    a function
skip (iter[, n])
Consumes the first n values of a iterator then returns it.

Parameters:

  • iter an iterator function
  • n a number. Defaults to 1. (optional)

Returns:

    the given iterator
tabulate (...)
Iterates over an iterator and returns its values in an array.

Parameters:

  • ... an iterator function (returning a generator, a state and a value)

Returns:

    an array of results
thread (value, ...)
Threads value through a series of functions. If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. The value is used as the first input.

Parameters:

  • value a value
  • ... a vararg list of functions or arrays

Returns:

    a value

See also:

threadRight (value, ...)
Threads value through a series of functions. If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. The value is used as the last input.

Parameters:

  • value a value
  • ... a vararg list of functions or arrays

Returns:

    a value

See also:

time (f[, ...])
Returns the execution time of f (...) and its returned values.

Parameters:

  • f a function
  • ... optional args to f (optional)

Returns:

    the execution time and the results of f (...)
times (iter[, n])
Runs iter function n times. Collects the results of each run and returns them in an array.

Parameters:

  • iter an iterator function, prototyped as iter (i)
  • n the number of times iter should be called. Defaults to 1. (optional)

Returns:

    table an array of results
unary (f)
Returns a function which accepts up to one arg. It ignores any additional arguments.

Parameters:

  • f a function

Returns:

    a function

See also:

unfold (f, seed)
Builds a list from a seed value. Accepts an iterator function, which returns either nil to stop iteration or two values : the value to add to the list of results and the seed to be used in the next call to the iterator function.

Parameters:

  • f an iterator function
  • seed a seed value

Returns:

    an array of values
uniqueId ([template])
Generates an unique ID for the current session. If given a string template, it will use this template for output formatting. Otherwise, if template is a function, it will evaluate template (id).
Aliased as uid.

Parameters:

  • template either a string or a function template to format the ID (optional)

Returns:

    value an ID
wrap (f, wrapper)
Wraps f inside of the wrapper function. It passes f as the first argument to wrapper. This allows the wrapper to execute code before and after f runs, adjust the arguments, and execute it conditionally.

Parameters:

  • f a function to be wrapped, prototyped as f (...)
  • wrapper a wrapper function, prototyped as wrapper (f, ...)

Returns:

    the results

Object functions

chain (value)
Returns a wrapped object. Calling library functions as methods on this object will continue to return wrapped objects until obj:value is used. Can be aliased as M(value).

Parameters:

  • value a value to be wrapped

Returns:

    a wrapped object
clone (obj[, shallow])
Clones a given object properties. If shallow is passed will also clone nested array properties.

Parameters:

  • obj an object
  • shallow whether or not nested array-properties should be cloned, defaults to false. (optional)

Returns:

    a copy of the passed-in object
extend (destObj, ...)
Extends an object properties. It copies the properties of extra passed-in objects into the destination object, and returns the destination object. The last objects will override properties of the same name.

Parameters:

  • destObj a destination object
  • ... a list of objects

Returns:

    the destination object extended
flattenPath (obj, ...)
Flattens object under property path onto provided object.
It is similar to spreadPath, but preserves object under the property path.

Parameters:

  • obj an object
  • ... a property path given as a vararg list

Returns:

    the passed-in object with changes

See also:

functions ([obj])
Returns a sorted list of all methods names found in an object. If the given object has a metatable implementing an __index field pointing to another table, will also recurse on this table if recurseMt is provided. If obj is omitted, it defaults to the library functions.
Aliased as methods.

Parameters:

  • obj an object. Defaults to Moses library functions. (optional)

Returns:

    an array-list of methods names
has (obj, key)
Checks if a given object implements a property.

Parameters:

  • obj an object
  • key a key property to be checked

Returns:

    true or false
import ([context[, noConflict]])
Imports all library functions into a context.

Parameters:

  • context a context. Defaults to _ENV or _G`` (current environment). (optional)
  • noConflict if supplied, will not import conflicting functions in the destination context. (optional)

Returns:

    the passed-in context
invert (obj)
Swaps keys with values. Produces a new object where previous keys are now values, while previous values are now keys.
Aliased as mirror

Parameters:

  • obj a given object

Returns:

    a new object
isArray (obj)
Checks if the given argument is an array. Assumes obj is an array if is a table with consecutive integer keys starting at 1.

Parameters:

  • obj an object

Returns:

    true or false
isBoolean (obj)
Checks if the given argument is a boolean.

Parameters:

  • obj an object

Returns:

    true or false
isCallable (obj)
Checks if the given argument is callable. Assumes obj is callable if it is either a function or a table having a metatable implementing __call metamethod.

Parameters:

  • obj an object

Returns:

    true or false
isEmpty ([obj])
Checks if the given pbject is empty. If obj is a string, will return true if #obj == 0. Otherwise, if obj is a table, will return whether or not this table is empty. If obj is nil, it will return true.

Parameters:

  • obj an object (optional)

Returns:

    true or false
isEqual (objA, objB[, useMt])
Performs a deep comparison test between two objects. Can compare strings, functions (by reference), nil, booleans. Compares tables by reference or by values. If useMt is passed, the equality operator == will be used if one of the given objects has a metatable implementing __eq.
Aliased as M.compare, M.matches

Parameters:

  • objA an object
  • objB another object
  • useMt whether or not __eq should be used, defaults to false. (optional)

Returns:

    true or false

See also:

isFinite (obj)
Checks if the given argument is a finite number.

Parameters:

  • obj an object

Returns:

    true or false
isFunction (obj)
Checks if the given argument is a function.

Parameters:

  • obj an object

Returns:

    true or false
isInteger (obj)
Checks if the given argument is an integer.

Parameters:

  • obj an object

Returns:

    true or false
isIterable (obj)
Checks if the given object is iterable with pairs (or ipairs).

Parameters:

  • obj an object

Returns:

    true if the object can be iterated with pairs (or ipairs), false otherwise
isNaN (obj)
Checks if the given argument is NaN (see Not-A-Number).

Parameters:

  • obj an object

Returns:

    true or false

See also:

isNil (obj)
Checks if the given argument is nil.

Parameters:

  • obj an object

Returns:

    true or false
isNumber (obj)
Checks if the given argument is a number.

Parameters:

  • obj an object

Returns:

    true or false

See also:

isString (obj)
Checks if the given argument is a string.

Parameters:

  • obj an object

Returns:

    true or false
isTable (t)
Checks if the given arg is a table.

Parameters:

  • t a value to be tested

Returns:

    true or false
keys (obj)
Returns the keys of the object properties.

Parameters:

  • obj an object

Returns:

    an array
kvpairs (obj)
Converts key-value pairs to an array-list of [k, v] pairs.

Parameters:

  • obj an object

Returns:

    an array list of key-value pairs

See also:

obj:value ()
Extracts the value of a wrapped object. Must be called on an chained object (see chain).

Returns:

    the value previously wrapped
omit (obj, ...)
Returns an object copy without black-listed properties.
Aliased as drop.

Parameters:

  • obj an object
  • ... a variable number of string keys

Returns:

    the filtered object
path (obj, ...)
Returns the value at a given path in an object.
Path is given as a vararg list of keys.

Parameters:

  • obj an object
  • ... a vararg list of keys

Returns:

    a value or nil
pick (obj, ...)
Returns an object copy having white-listed properties.
Aliased as choose.

Parameters:

  • obj an object
  • ... a variable number of string keys

Returns:

    the filtered object
property (key)
Returns a function that will return the key property of any passed-in object.

Parameters:

  • key a key property name

Returns:

    a function which should accept an object as argument

See also:

propertyOf (obj)
Returns a function which will return the value of an object property.

Parameters:

  • obj an object

Returns:

    a function which should accept a key property argument

See also:

result (obj, method)
Invokes an object method. It passes the object itself as the first argument. if method is not callable, will return obj[method].

Parameters:

  • obj an object
  • method a string key to index in object obj.

Returns:

    the returned value of method (obj) call
spreadPath (obj, ...)
Spreads object under property path onto provided object.
It is similar to flattenPath, but removes object under the property path.

Parameters:

  • obj an object
  • ... a property path given as a vararg list

Returns:

    the passed-in object with changes

See also:

tap (obj, f)
Invokes interceptor with the object, and then returns object. The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.

Parameters:

  • obj an object
  • f an interceptor function, should be prototyped as f (obj)

Returns:

    the passed-in object
template (obj[, template])
Applies a template to an object, preserving non-nil properties.
Aliased as defaults.

Parameters:

  • obj an object
  • template a template object. If nil, leaves obj untouched. (optional)

Returns:

    the passed-in object filled
toBoolean (value)
Converts any given value to a boolean

Parameters:

  • value a value. Can be of any type

Returns:

    true if value is true, false otherwise (false or nil).
toObj (kvpairs)
Converts an array list of [k,v] pairs to an object. Keys are taken from the 1rst column in the [k,v] pairs sequence, associated with values in the 2nd column.

Parameters:

  • kvpairs an array-list of [k,v] pairs

Returns:

    an object

See also:

type (obj)
Extends Lua's type function. It returns the type of the given object and also recognises file userdata

Parameters:

  • obj an object

Returns:

    the given object type
values (obj)
Returns the values of the object properties.

Parameters:

  • obj an object

Returns:

    an array of values
generated by LDoc 1.4.6 Last updated 2018-09-12 11:33:43
Moses-Moses-2.1.0-1/doc/manual/000077500000000000000000000000001334620647700160605ustar00rootroot00000000000000Moses-Moses-2.1.0-1/doc/manual/tutorial.md.html000066400000000000000000004415241334620647700212220ustar00rootroot00000000000000 Moses documentation
Moses: a utility-belt library for functional programming in Lua

Moses is a Lua utility library which provides support for functional programming. It complements built-in Lua functions, making easier common operations on tables, arrays, lists, collections, objects, and a lot more.

Sections

Drop the file moses.lua into your project and add it to your code with the require function:

local M = require ("moses")

Moses provides a large set of functions that can be classified into four categories:

[⬆]

Table functions

clear (t)

Clears a table. All its values becomes nil. Returns the passed-in table.

M.clear({1,2,'hello',true}) -- => {}

each (t, f)

*Aliases: forEach*.

Iterates over each value-key pair in the passed-in table.

M.each({4,2,1},print)

-- => 4 1
-- => 2 2
-- => 1 3

The table can be map-like (both array part and hash part).

M.each({one = 1, two = 2, three = 3},print)

-- => 1 one
-- => 2 two
-- => 3 three

Can index and assign in an outer table or in the passed-in table:

t = {'a','b','c'}
M.each(t,function(v,i)
  t[i] = v:rep(2)
  print(t[i])
end)

-- => aa
-- => bb
-- => cc

eachi (t, f)

*Aliases: forEachi*.

Iterates only on integer keys in an array table. It returns value-key pairs.

M.eachi({4,2,1},print)

-- => 4 1
-- => 2 2
-- => 1 3

The given array can be sparse, or even have a hash-like part.

local t = {a = 1, b = 2, [0] = 1, [-1] = 6, 3, x = 4, 5}
M.eachi(t,print)

-- => 6 -1
-- => 1 0
-- => 3 1
-- => 5 2

at (t, ...)

Collects values at given keys and returns them in an array.

local t = {4,5,6}
M.at(t,1,3) -- => "{4,6}"

local t = {a = 4, bb = true, ccc = false}
M.at(t,'a', 'ccc') -- => "{4, false}"

adjust (t, key, f)

Adjusts the value at a given key using a function or a value. In case f is a function, it should be prototyped f(v). It does not mutate the given table, but rather returns a new array.

local t = {1,2,3}
M.adjust(t, 2, math.sin) -- => {1, 0.90929, 3}

local v = {x = 1}
 M.adjust(t, 'x', 4) -- => {x = 4}

In case the given key does not exist in t, it throws an error.

count (t [, val])

Counts the number of occurences of a given value in a table.

M.count({1,1,2,3,3,3,2,4,3,2},1) -- => 2
M.count({1,1,2,3,3,3,2,4,3,2},2) -- => 3
M.count({1,1,2,3,3,3,2,4,3,2},3) -- => 4
M.count({false, false, true},false) -- => 2
M.count({false, false, true},true) -- => 1

Returns the size of the list in case no value was provided.

M.count({1,1,2,3,3}) -- => 5

countf (t, f)

Counts the number of values passing an iterator test.

M.countf({1,2,3,4,5,6}, function(v)
  return v%2==0
end) -- => 3

M.countf({print, pairs, os, assert, ipairs}, function(v)
  return type(v)=='function'
end) -- => 4

allEqual (t [, comp])

*Aliases: alleq*.

Checks if all values in a collection are equal. Uses M.isEqual by default to compare values.

M.allEqual({1,1,1,1,1}, comp) -- => true
M.allEqual({1,1,2,1,1}, comp) -- => false

local t1 = {1, 2, {3}}
local t2 = {1, 2, {3}}
M.allEqual({t1, t2}) -- => true

Can take an optional comp function which will be used to compare values.

local t1 = {x = 1, y = 0}
local t2 = {x = 1, y = 0}
local t3 = {x = 1, y = 2}
local t4 = {x = 1, y = 2}
local function compx(a, b) return a.x == b.x end
local function compy(a, b) return a.y == b.y end

M.allEqual({t1, t2}, compx) -- => true
M.allEqual({t1, t2}, compy) -- => true
M.allEqual({t3, t4}, compx) -- => true
M.allEqual({t3, t4}, compy) -- => true
M.allEqual({t1, t2, t3, t4}, compx) -- => true
M.allEqual({t1, t2, t3, t4}, compy) -- => false

cycle (t [, n = 1])

*Aliases: loop*.

Returns a function which iterates on each value-key pair in a given table (similarly to M.each), except that it restarts iterating again n times. If n is not provided, it defaults to 1.

local t = {'a','b','c'}
for v in M.cycle(t, 2) do
  print(v)
end

-- => 'a'
-- => 'b'
-- => 'c'
-- => 'a'
-- => 'b'
-- => 'c'

Supports array-like tables and map-like tables.

local t = {x = 1, y = 2, z = 3}
for v in M.cycle(t) do
  print(v)
end

-- => 2
-- => 1
-- => 3

map (t, f)

*Aliases: collect*.

Executes a function on each value in a given array.

M.map({1,2,3},function(v)
  return v+10
end) -- => "{11,12,13}"
M.map({a = 1, b = 2},function(v, k)
  return k..v
end) -- => "{a = 'a1', b = 'b2'}"

It also maps both keys and values.

M.map({a = 1, b = 2},function(v, k)
  return k..k, v*2
end) -- => "{aa = 2, bb = 4}"

reduce (t, f [, state = next(t)])

*Aliases: inject, foldl*.

Can sum all values in a table. In case state is not provided, it defaults to the first value in the given table t.

local function add(a,b) return a+b end
M.reduce({1,2,3,4},add) -- => 10

Or concatenates all values.

local function concat(a,b) return a..b end
M.reduce({'a','b','c','d'},concat) -- => abcd   

best (t, f)

Returns the best value passing a selector function. Acts as a special case of reduce, using the first value in t as an initial state. It thens folds the given table, testing each of its values v and selecting the value passing the call f(state,v) every time.

local words = {'Lua', 'Programming', 'Language'}
M.best(words, function(a,b) return #a > #b end) -- => 'Programming'
M.best(words, function(a,b) return #a < #b end) -- => 'Lua'

reduceBy (t, f, pred [, state = next(t)])

Reduces a table considering only values matching a predicate. For example,let us define a set of values.

local val = {-1, 8, 0, -6, 3, -1, 7, 1, -9}

And a reduction function which will add up values.

local function add(a,b) return a+b end

We can also define some predicate functions.

-- predicate for negative values
local function neg(v) return v<=0 end

-- predicate for positive values
local function pos(v) return v>=0 end

Then we can perform reduction considering only negative or positive values :

M.reduceBy(val, add, neg) -- => -17
M.reduceBy(val, add, pos) -- => 19

An initial state can be passed in.

M.reduceBy(val, add, neg, 17) -- => 0
M.reduceBy(val, add, pos, -19) -- => 0

reduceRight (t, f [, state = next(t)])

*Aliases: injectr, foldr*.

Similar to M.reduce, but performs from right to left.

local initial_state = 256
local function div(a,b) return a/b end
M.reduceRight({1,2,4,16},div,initial_state) -- => 2

mapReduce (t, f [, state = next(t)])

*Aliases: mapr*.

Reduces while saving intermediate states.

local function concat(a,b) return a..b end
M.mapReduce({'a','b','c'},concat) -- => "{'a', 'ab', 'abc'}"

mapReduceRight (t, f [, state = next(t)])

*Aliases: maprr*.

Reduces from right to left, while saving intermediate states.

local function concat(a,b) return a..b end
M.mapReduceRight({'a','b','c'},concat) -- => "{'c', 'cb', 'cba'}"

include (t, value)

*Aliases: any, some, contains*.

Looks for a value in a table.

M.include({6,8,10,16,29},16) -- => true
M.include({6,8,10,16,29},1) -- => false

local complex_table = {18,{2,{3}}}
local collection = {6,{18,{2,6}},10,{18,{2,{3}}},29}
M.include(collection, complex_table) -- => true

Handles iterator functions.

local function isUpper(v) return v:upper()== v end
M.include({'a','B','c'},isUpper) -- => true

detect (t, value)

Returns the index of a value in a table.

M.detect({6,8,10,16},8) -- => 2
M.detect({nil,true,0,true,true},false) -- => nil

local complex_table = {18,{2,6}}
local collection = {6,{18,{2,6}},10,{18,{2,{3}}},29}
M.detect(collection, complex_table) -- => 2

Handles iterator functions.

local function isUpper(v)
  return v:upper()==v
end
M.detect({'a','B','c'},isUpper) -- => 2

where (t, props)

Looks through a table and returns all the values that matches all of the key-value pairs listed in props.

local items = {
  {height = 10, weight = 8, price = 500},
  {height = 10, weight = 15, price = 700},
  {height = 15, weight = 15, price = 3000},
  {height = 10, weight = 8, price = 3000},
}
M.where(items, {height = 10}) -- => {items[1], items[2], items[4]}
M.where(items, {weight = 15}) -- => {items[2], items[3]}
M.where(items, {prince = 3000}) -- => {items[3], items[4]}
M.where(items, {height = 10, weight = 15, prince = 700}) -- => {items[2]}

findWhere (t, props)

Looks through a table and returns the first value found that matches all of the key-value pairs listed in props.

local a = {a = 1, b = 2, c = 3}
local b = {a = 2, b = 3, d = 4}
local c = {a = 3, b = 4, e = 5}
M.findWhere({a, b, c}, {a = 3, b = 4}) == c -- => true

select (t, f)

*Aliases: filter*.

Collects values passing a validation test.

local function isEven(v) return v%2==0 end
local function isOdd(v) return v%2~=0 end

M.select({1,2,3,4,5,6,7}, isEven) -- => "{2,4,6}"
M.select({1,2,3,4,5,6,7}, isOdd) -- => "{1,3,5,7}"

reject (t, f)

*Aliases: reject*.

Removes all values failing (returning false or nil) a validation test:

local function isEven(v) return v%2==0 end
local function isOdd(v) return v%2~=0 end

M.reject({1,2,3,4,5,6,7}, isEven) -- => "{1,3,5,7}"
M.reject({1,2,3,4,5,6,7}, isOdd) -- => "{2,4,6}"

all (t, f)

*Aliases: every*.

Checks whether or not all elements pass a validation test.

local function isEven(v) return v%2==0 end
M.all({2,4,6}, isEven) -- => true

invoke (t, method)

Invokes a given function on each value in a table.

M.invoke({'a','bea','cdhza'},string.len) -- => "{1,3,5}"

Can reference the method of the same name in each value.

local a, b, c, d = {id = 'a'}, {id = 'b'}, {id = 'c'}, {id = 'd'}
local function call(self) return self.id end
M.invoke({a,b,c,d},call) -- => "{'a','b','c','d'}"

pluck (t, property)

Fetches all values indexed with specific key in a table of objects.

local peoples = {
  {name = 'John', age = 23},{name = 'Peter', age = 17},
  {name = 'Steve', age = 15},{age = 33}}

M.pluck(peoples,'age') -- => "{23,17,15,33}"
M.pluck(peoples,'name') -- => "{'John', 'Peter', 'Steve'}"

max (t [, transform])

Returns the maximum value in a collection.

M.max {1,2,3} -- => 3
M.max {'a','b','c'} -- => 'c'

Can take an iterator function to extract a specific property.

local peoples = {
  {name = 'John', age = 23},{name = 'Peter', age = 17},
  {name = 'Steve', age = 15},{age = 33}}
M.max(peoples,function(people) return people.age end) -- => 33

min (t [, transform])

Returns the minimum value in a collection.

M.min {1,2,3} -- => 1
M.min {'a','b','c'} -- => 'a'

Can take an iterator function to extract a specific property.

local peoples = {
  {name = 'John', age = 23},{name = 'Peter', age = 17},
  {name = 'Steve', age = 15},{age = 33}}
M.min(peoples,function(people) return people.age end) -- => 15

same (a, b)

Tests whether or not all values in each of the passed-in tables exists in both tables.

local a = {'a','b','c','d'}
local b = {'b','a','d','c'}
M.same(a,b) -- => true

b[#b+1] = 'e'
M.same(a,b) -- => false

sort (t [, comp = math.min])

Sorts a collection.

M.sort({'b','a','d','c'}) -- => "{'a','b','c','d'}"

Handles custom comparison functions.

M.sort({'b','a','d','c'}, function(a,b)
  return a:byte() > b:byte()
end) -- => "{'d','c','b','a'}"

sortedk (t [, comp])

Iterates on values with respect to key order. Keys are sorted using comp function which defaults to math.min. It returns upon each call a key, value pair.

local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12
for k, v in M.sortedk(tbl) do print(k, v) end

-- => 1    12
-- => 2 6
-- => 3 5
-- => 4 10
-- => 5 8

local function comp(a,b) return a > b end
for k, v in M.sortedk(tbl, comp) do print(k, v) end

-- => 5    8
-- => 4 10
-- => 3 5
-- => 2 6
-- => 1 12

sortedv (t [, comp])

Iterates on values with respect to key order. Keys are sorted using comp function which defaults to math.min. It returns upon each call a key, value pair.

local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12
for k, v in M.sortedv(tbl) do print(k, v) end

-- => 3    5
-- => 2 6
-- => 5 8
-- => 4 10
-- => 1 12

local function comp(a,b) return a > b end
for k, v in M.sortedv(tbl, comp) do print(k, v) end

-- => 1    12
-- => 4 10
-- => 5 8
-- => 2 6
-- => 3 5

sortBy (t [, transform [, comp = math.min]])

Sorts items in a collection based on the result of running a transform function through every item in the collection.

local r = M.sortBy({1,2,3,4,5}, math.sin)
print(table.concat(r,','))

-- => {5,4,3,1,2}

The transform function can also be a string name property.

local people = {
    {name = 'albert', age = 40},
    {name = 'louis', age = 55},
    {name = 'steve', age = 35},
    {name = 'henry', age = 19},
}
local r = M.sortBy(people, 'age')
M.each(r, function(v) print(v.age, v.name) end)

-- => 19   henry
-- => 35    steve
-- => 40    albert
-- => 55    louis

As seen above, the defaut comparison function is the '<' operator. For example, let us supply a different one to sort the list of people by decreasing age order :

local people = {
    {name = 'albert', age = 40},
    {name = 'louis', age = 55},
    {name = 'steve', age = 35},
    {name = 'henry', age = 19},
}
local r = M.sortBy(people, 'age', function(a,b) return a > b end)
M.each(r, function(v) print(v.age, v.name) end)

-- => 55   louis
-- => 40    albert
-- => 35    steve
-- => 19    henry

The transform function defaults to M.indentity and in that case, M.sortBy behaves like M.sort.

local r = M.sortBy({1,2,3,4,5})
print(table.concat(r,','))

-- => {1,2,3,4,5}

groupBy (t, iter)

Groups values in a collection depending on their return value when passed to a predicate test.

M.groupBy({0,1,2,3,4,5,6},function(v)
  return v%2==0 and 'even' or 'odd'
end)
-- => "{odd = {1,3,5}, even = {0,2,4,6}}"

M.groupBy({0,'a',true, false,nil,b,0.5},type)
-- => "{number = {0,0.5}, string = {'a'}, boolean = {true, false}}"        

countBy (t, iter)

Splits a table in subsets and provide the count for each subset.

M.countBy({0,1,2,3,4,5,6},function(v)
  return v%2==0 and 'even' or 'odd'
end) -- => "{odd = 3, even = 4}"

size (...)

When given a table, provides the count for the very number of values in that table.

M.size {1,2,3} -- => 3
M.size {one = 1, two = 2} -- => 2

When given a vararg list of arguments, returns the count of these arguments.

M.size(1,2,3) -- => 3
M.size('a','b',{}, function() end) -- => 4

containsKeys (t, other)

Checks whether a table has all the keys existing in another table.

M.contains({1,2,3,4},{1,2,3}) -- => true
M.contains({1,2,'d','b'},{1,2,3,5}) -- => true
M.contains({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => true

sameKeys (tA, tB)

Checks whether both tables features the same keys:

M.sameKeys({1,2,3,4},{1,2,3}) -- => false
M.sameKeys({1,2,'d','b'},{1,2,3,5}) -- => true
M.sameKeys({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => false

[⬆]

Array functions

sample (array [, n = 1 [, seed]])

Samples n values from array.

local array = M.range(1,20)
local sample = M.sample(array, 3)
print(table.concat(sample,','))

-- => {12,11,15}

n defaults to 1. In that case, a single value will be returned.

local array = M.range(1,20)
local sample = M.sample(array)
print(sample)

-- => 12

An optional 3rd argument seed can be passed for deterministic random sampling.

sampleProb (array, prob [, seed])

Returns an array of values randomly selected from a given array. In case seed is provided, it is used for deterministic sampling.

local array = M.range(1,20)
local sample = M.sampleProb(array, 0.2)
print(table.concat(sample,','))

-- => 5,11,12,15

sample = M.sampleProb(array, 0.2, os.time())
print(table.concat(sample,','))

-- => 1,6,10,12,15,20 (or similar)

nsorted (array [, n = 1[, comp]])

Returns the n-top values satisfying a predicate. It takes a comparison function comp used to sort array values, and then picks the top n-values. It leaves the original array untouched.

local function comp(a,b) return a > b end
M.nsorted(array,5, comp) -- => {5,4,3,2,1}

n defaults to 1 and comp defaults to the < operator.

local array = M.range(1,20)
M.nsorted(array) -- => {1}

shuffle (array [, seed])

Shuffles a given array.

local list = M.shuffle {1,2,3,4,5,6} -- => "{3,2,6,4,1,5}"
M.each(list,print)

pack (...)

Converts a vararg list of arguments to an array.

M.pack(1,2,8,'d','a',0) -- => "{1,2,8,'d','a',0}"

find (array, value [, from = 1])

Looks for a value in a given array and returns the position of the first occurence.

local value = {3}
M.find({{4},{3},{2},{1}},value) -- => 2

It can also start the search at a specific position in the array:

-- search value 4 starting from index 3
M.find({1,4,2,3,4,5},4,3) -- => 5

reverse (array)

Reverses an array.

M.reverse({1,2,3,'d'}) -- => "{'d',3,2,1}"

fill (array, value [, i = 1 [, j = #array]])

Replaces all elements in a given array with a given value.

local array = M.range(1,5)
M.fill(array, 0) -- => {0,0,0,0,0}

It can start replacing value at a specific index.

local array = M.range(1,5)
M.fill(array,0,3) -- => {1,2,0,0,0}

It can replace only values within a specific range.

local array = M.range(1,5)
M.fill(array,0,2,4) -- => {1,0,0,0,5}

In case the upper bound index i greather than the array size, it will enlarge the array.

local array = M.range(1,5)
M.fill(array,0,5,10) -- => {1,2,3,4,0,0,0,0,0,0}

zeros (n)

Returns an array of n zeros.

M.zeros(4) -- => {0,0,0,0}

ones (n)

Returns an array of n 1's.

M.ones(3) -- => {1,1,1}

vector (value, n)

Returns an array of n times a given value.

M.vector(10, 4) -- => {10,10,10,10}

selectWhile (array, f [, ...])

*Aliases: takeWhile*.

Collects values as long as they pass a given test. Stops on the first non-passing test.

M.selectWhile({2,4,5,8}, function(v)
  return v%2==0
end) -- => "{2,4}"

dropWhile (array, f [, ...])

*Aliases: rejectWhile*.

Removes values as long as they pass a given test. Stops on the first non-passing test.

M.dropWhile({2,4,5,8}, function(v)
  return v%2==0
end) -- => "{5,8}"

sortedIndex (array, value [, comp = math.min [, sort = nil]])

Returns the index at which a value should be inserted to preserve order.

M.sortedIndex({1,2,3},4) -- => 4

Can take a custom comparison functions.

local comp = function(a,b) return a<b end
M.sortedIndex({-5,0,4,4},3,comp) -- => 3

indexOf (array, value)

Returns the index of a value in an array.

M.indexOf({1,2,3},2) -- => 2

lastIndexOf (array, value)

Returns the index of the last occurence of a given value in an array.

M.lastIndexOf({1,2,2,3},2) -- => 3

findIndex (array, pred)

Returns the first index at which a predicate passes a truth test.

local array = {1,2,3,4,5,6}
local function multipleOf3(v) return v%3==0 end
M.findIndex(array, multipleOf3) -- => 3

findLastIndex (array, pred)

Returns the last index at which a predicate passes a truthy test.

local array = {1,2,3,4,5,6}
local function multipleOf3(v) return v%3==0 end
M.findLastIndex(array, multipleOf3) -- => 6

addTop (array, ...)

Adds given values at the top of an array. The latter values bubbles at the top.

local array = {1}
M.addTop(array,1,2,3,4) -- => "{4,3,2,1,1}"

prepend (array, ...)

Adds given values at the top of an array, preserving the order at which elements are passed-in.

local array = {'old_val'}
M.prepend(array,1,2,3,4) -- => "{1,2,3,4,'old_val'}"

push (array, ...)

Adds given values at the end of an array.

local array = {1}
M.push(array,1,2,3,4) -- => "{1,1,2,3,4}"

shift (array [, n = 1])

*Aliases: pop*.

Removes and returns the first value in an array.

local array = {1,2,3}
local shift = M.shift(array) -- => "shift = 1", "array = {2,3}"

If n is supplied, returns n values.

local array = {1,2,3,4,5}
local a, b = M.shift(array, 2) -- => "a = 1, b = 2", "array = {3,4,5}"

unshift (array [, n = 1])

Removes and returns the last value in an array.

local array = {1,2,3}
local value = M.unshift(array) -- => "value = 3", "array = {1,2}"

pull (array, ...)

*Aliases: remove*.

Removes all provided values from a given array.

M.pull({1,2,1,2,3,4,3},1,2,3) -- => "{4}"

removeRange (array [, start = 1 [, finish = #array]])

*Aliases: rmRange, M.chop*.

Trims out all values index within a range.

local array = {1,2,3,4,5,6,7,8,9}
M.removeRange(array, 3,8) -- => "{1,2,9}"

chunk (array, f)

Iterates over an array aggregating consecutive values in subsets tables, on the basis of the return value of f(v, k, ...). Consecutive elements which return the same value are chunked together.

local t = {1,1,2,3,3,4}
M.chunk(t, function(v) return v%2==0 end) -- => "{{1,1},{2},{3,3},{4}}"

slice (array [, start = 1 [, finish = #array]])

*Aliases: sub*.

Slices and returns a part of an array.

local array = {1,2,3,4,5,6,7,8,9}
M.slice(array, 3,6) -- => "{3,4,5,6}"

first (array [, n = 1])

*Aliases: head, M.take*.

Returns the first N elements in an array.

local array = {1,2,3,4,5,6,7,8,9}
M.first(array,3) -- => "{1,2,3}"

initial (array [, n = #array])

Excludes the last N elements in an array.

local array = {1,2,3,4,5,6,7,8,9}
M.initial(array,5) -- => "{1,2,3,4}"

last (array [, n = #array])

Returns the last N elements in an array.

local array = {1,2,3,4,5,6,7,8,9}
M.last(array,3) -- => "{7,8,9}"

rest (array [, index = 1])

*Aliases: tail*.

Returns all values after index, including the given index itself.

local array = {1,2,3,4,5,6,7,8,9}
M.rest(array,6) -- => "{6,7,8,9}"

nth (array, index)

Returns the value at index.

local array = {1,2,3,4,5,6}
M.nth(array,3) -- => "3"

compact (array)

Trims out all falsy values.

M.compact {a,'aa',false,'bb',true} -- => "{'aa','bb',true}"

flatten (array [, shallow = false])

Flattens a nested array.

M.flatten({1,{2,3},{4,5,{6,7}}}) -- => "{1,2,3,4,5,6,7}"

When given arg shallow, flatten only at the first level.

M.flatten({1,{2},{{3}}},true) -- => "{1,{2},{{3}}}"

difference (array, array2)

*Aliases: without, diff*.

Returns values in the given array not present in a second array.

local array = {1,2,'a',4,5}
M.difference(array,{1,'a'}) -- => "{2,4,5}"

union (...)

Produces a duplicate-free union of all passed-in arrays.

local A = {'a'}
local B = {'a',1,2,3}
local C = {2,10}
M.union(A,B,C) -- => "{'a',1,2,3,10}"

intersection (...)

Returns the intersection (common-part) of all passed-in arrays:

local A = {'a'}
local B = {'a',1,2,3}
local C = {2,10,1,'a'}
M.intersection(A,B,C) -- => "{'a'}"

disjoint (...)

Checks if all passed in arrays are disjoint.

local A = {'a'}
local B = {'a',1,3}
local C = {3,10,2}

M.disjoint(A,B) -- => false
M.disjoint(A,C) -- => true
M.disjoint(B,C) -- => false

symmetricDifference (array, array2)

*Aliases: symdiff,xor*.

Returns values in the first array not present in the second and also values in the second array not present in the first one.

local array = {1,2,3}
local array2 = {1,4,5}
M.symmetricDifference(array, array2) -- => "{2,3,4,5}"

unique (array)

*Aliases: uniq*.

Makes an array duplicate-free.

M.unique {1,1,2,2,3,3,4,4,4,5} -- => "{1,2,3,4,5}"

isunique (array)

*Aliases: isuniq*.

Checks if a given array contains no duplicate value.

M.isunique({1,2,3,4,5}) -- => true
M.isunique({1,2,3,4,4}) -- => false

duplicates (array)

Returns an array list of all duplicates in array.

M.duplicates({1,2,3,3,8,8,3,2,4}) -- => {2,3,8}

zip (...)

*Aliases: transpose*.

Zips values from different arrays, on the basis on their common keys.

local names = {'Bob','Alice','James'}
local ages = {22, 23}
M.zip(names,ages) -- => "{{'Bob',22},{'Alice',23},{'James'}}"

zipWith (f, ...)

*Aliases: transposeWith*.

Merges values using a given function. Only values indexed with the same key in the given arrays are merged in the same subset. Function f is used to combine values.

local names = {'Bob','Alice','James'}; local ages = {22, 23, 25}
local function introduce(name, age) return 'I am '..name..' and I am '..age..' years old.' end
local t = M.zipWith(introduce,names,ages)
-- => {
-- =>  'I am Bob and I am 22 years old.'
-- =>  'I am Alice and I am 23 years old.'
-- =>  'I am James and I am 25 years old.'
-- => }

append (array, other)

Appends two arrays.

M.append({1,2,3},{'a','b'}) -- => "{1,2,3,'a','b'}"

interleave (...)

Interleaves values from passed-in arrays.

t1 = {1, 2, 3}
t2 = {'a', 'b', 'c'}
M.interleave(t1, t2) -- => "{1,'a',2,'b',3,'c'}"

interpose (array, value)

*Aliases: intersperce*.

Interposes a value between consecutive values in an arrays.

M.interleave('a', {1,2,3}) -- => "{1,'a',2,'a',3}"

range ([from [, to [, step]]])

Generates an arithmetic sequence.

M.range(1,4) -- => "{1,2,3,4}"

In case a single value is provided, it generates a sequence from 1 to that value.

M.range(3) -- => "{1,2,3}"

The incremental step can also be provided as third argument.

M.range(0,2,0.7) -- => "{0,0.7,1.4}"

It also handles negative progressions.

M.range(-5) -- => "{-1,-2,-3,-4,-5}"
M.range(5,1) -- => "{5,4,3,2,1}"

rep (value, n)

Generates a list of n repetitions of a value.

M.rep(4,3) -- => "{4,4,4}"

powerset (array)

Returns the powerset of an array.

M.powerset {1,2,3} -- => "{{1},{2},{3},{1,2},{2,3},{1,2,3}}"

partition (array [, n = 1 [, pad]])

*Aliases: part*.

Returns an iterator function for partitions of a given array.

local t = {1,2,3,4,5,6}
for p in M.partition(t,2) do
  print(table.concat(p, ','))
end

-- => 1,2
-- => 3,4
-- => 5,6

local t = {1,2,3,4,5,6}
for p in M.partition(t,4) do
  print(table.concat(p, ','))
end

-- => 1,2,3,4
-- => 5,6

In case the last partition has less elements than desired, a 3rd argument can be supplied to adjust the partition size.

local t = {1,2,3,4,5,6}
for p in M.partition(t,4,0) do
  print(table.concat(p, ','))
end

-- => 1,2,3,4
-- => 5,6,0,0

overlapping (array [, n = 2 [, pad]])

Returns an iterator function which provides overlapping subsequences of a given array.

local t = {1,2,3,4,5,6,7}
for p in M.overlapping(t,3) do
    print(table.concat(p,','))
end

-- => 1,2,3
-- => 3,4,5
-- => 5,6,7

for p in M.overlapping(t,4) do
    print(table.concat(p,','))
end

-- => 1,2,3,4
-- => 4,5,6,7

for p in M.overlapping(t,5) do
    print(table.concat(p,','))
end

-- => 1,2,3,4,5
-- => 5,6,7

In case the last subsequence wil not match the exact desired length, it can be adjusted with a 3rd argument pad.

local t = {1,2,3,4,5,6,7}
for p in M.overlapping(t,5,0) do
    print(table.concat(p,','))
end

-- => 1,2,3,4,5
-- => 5,6,7,0,0

aperture (array [, n = 2])

*Aliases: sliding*.

Returns an iterator function which provides sliding partitions of a given array.

local t = {1,2,3,4,5}
for p in M.aperture(t,4) do
  print(table.concat(p,','))
end

-- => 1,2,3,4
-- => 2,3,4,5

for p in M.aperture(t,3) do
  print(table.concat(p,','))
end

-- => 1,2,3
-- => 2,3,4
-- => 3,4,5

pairwise (array)

Iterator returning sliding pairs of an array.

local t = M.range(5)
for p in pairwise(t) do
  print(table.concat(p,','))
end

-- => 1,2
-- => 2,3
-- => 3,4
-- => 4,5

permutation (array)

*Aliases: perm*.

Returns an iterator function for permutations of a given array.

t = {'a','b','c'}
for p in M.permutation(t) do
  print(table.concat(p))
end

-- => 'bca'
-- => 'cba'
-- => 'cab'
-- => 'acb'
-- => 'bac'
-- => 'abc'

concat (array [, sep = '' [, i = 1 [, j = #array]]])

*Aliases: join*.

Concatenates a given array values:

M.concat({'a',1,0,1,'b'}) -- => 'a101b'

xprod (array, array2)

Returns all possible pairs built from given arrays.

local t = M.xprod({1,2},{'a','b'})
-- => {{1,'a'},{1,'b'},{2,'a'},{2,'b'}}

xpairs (value, array)

Creates pairs from value and array. Value is always prepended to the pair.

local t = M.xpairs(1, {1, 2, 3})
-- => {{1,1},{1,2},{1,3}}

xpairsRight (value, array)

Creates pairs from value and array. Value is always appended as the last item to the pair.

local t = M.xpairsRight(1, {1, 2, 3})
-- => {{1,1},{2,1},{3,1}}

sum (array)

Returns the sum of array values.

M.sum({1,2,3,4,5}) -- => 15

product (array)

Returns the product of array values.

M.product({1,2,3,4,5}) -- => 120

mean (array)

Returns the mean of array values.

M.mean({1,2,3,4,5}) -- => 3

median (array)

Returns the median of array values.

M.median({1,2,3,4,5}) -- => 3
M.median({1,2,3,4}) -- => 2.5

[⬆]

Utility functions

noop ()

The no-operation function. Takes nothing, returns nothing. It is being used internally.

M.noop() -- => nil

identity (value)

Returns the passed-in value.
This function is internally used as a default transformation function.

M.identity(1)-- => 1
M.identity(false) -- => false
M.identity('hello!') -- => 'hello!'

call (f [, ...])

Calls f with the supplied arguments. Returns the results of f(...).

M.call(math.pow, 2, 3) -- => 8
M.call(string.len, 'hello' ) -- => 5
M.call(table.concat, {1,2,3,4,5}, ',', 2, 4) -- => {2,3,4}

constant (value)

Creates a constant function. This function will continuously yield the same output.

local pi = M.constant(math.pi)
pi(1) -- => 3.1415926535898
pi(2) -- => 3.1415926535898
pi(math.pi) -- => 3.1415926535898

applySpec (specs)

Returns a function which applies specs on args. This function will produce an object having the same structure than specs by mapping each property to the result of calling its associated function with the supplied arguments.

local stats = M.applySpec({
  min = function(...) return math.min(...) end,
  max = function(...) return math.max(...) end,
})

stats(5,4,10,1,8) -- => {min = 1, max = 10}

thread (value [, ...])

Threads value through a series of functions.

local function inc(x) return x + 1 end
local function double(x) return 2 * x end
local function square(x) return x * x end
M.thread(2, inc, double, square) -- => 36
M.thread(3, double, inc, square) -- => 49
M.thread(4, square, double, inc) -- => 33
M.thread(5, square, inc, double) -- => 52

If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded.

local function inc(x) return x + 1 end
local function add(x, y) return x * y end
local function pow(x, y) return x ^ y end
M.thread(2, inc, {add, 3}, {pow, 2}) -- => 36
M.thread(2, {add, 4}, inc, {pow, 2}) -- => 49

threadRight (value [, ...])

Threads value through a series of functions. If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. The value is used as the last input.

local function inc(x) return x + 1 end
local function add(x, y) return x * y end
local function pow(x, y) return x ^ y end
M.threadRight(2, inc, {add, 3}, {pow, 2}) -- => 64
M.threadRight(2, {add, 4}, inc, {pow, 2}) -- => 128

dispatch (...)

Returns a dispatching function. When called with arguments, this function invokes each of its functions in the passed-in order and returns the results of the first non-nil evaluation.

local f = M.dispatch(
  function() return nil end,
  function (v) return v+1 end,
  function (v) return 2*v end
)
f(5) -- => 6
f(7) -- => 8

memoize (f)

*Aliases: cache*.

Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body.

local function fibonacci(n)
  return n < 2 and n or fibonacci(n-1)+fibonacci(n-2)
end
local mem_fibonacci = M.memoize(fibonacci)
fibonacci(20) -- => 6765 (but takes some time)
mem_fibonacci(20) -- => 6765 (takes less time)

unfold (f, seed)

Builds a list from a seed value. Accepts an iterator function, which returns either nil to stop iteration or two values : the value to add to the list of results and the seed to be used in the next call to the iterator function.

local function f(v)
  if v < 100 then return v, v * 2 end
end
local t = M.unfold(f, 10) -- => {10,20,40,80}

once (f)

Produces a function that runs only once. Successive calls to this function will still yield the same input.

local sq = M.once(function(a) return a*a end)
sq(1) -- => 1
sq(2) -- => 1
sq(3) -- => 1
sq(4) -- => 1
sq(5) -- => 1

before (f, count)

Returns a version of f that will run no more than count times. Next calls will keep yielding the results of the (n-th)-1 call.

local function greet(someone) return 'hello '..someone end
local greetOnly3people = M.before(greet, 3)
greetOnly3people('John') -- => 'hello John'
greetOnly3people('Moe') -- => 'hello Moe'
greetOnly3people('James') -- => 'hello James'
greetOnly3people('Joseph') -- => 'hello James'
greetOnly3people('Allan') -- => 'hello James'

after (f, count)

Produces a function that will respond only after a given number of calls.

local f = M.after(M.identity,3)
f(1) -- => nil
f(2) -- => nil
f(3) -- => 3
f(4) -- => 4

compose (...)

Composes functions. Each function consumes the return value of the one that follows.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
local compositae = M.compose(f,g,h)
compositae(10) -- => 36
compositae(20) -- => 121

pipe (value, ...)

Pipes a value through a series of functions.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
M.pipe(10,f,g,h) -- => 36
M.pipe(20,f,g,h) -- => 121

complement (f)

Returns a function which returns the logical complement of a given function.

M.complement(function() return true end)() -- => false

juxtapose (value, ...)

*Aliases: juxt*.

Calls a sequence of functions with the same input.

local function f(x) return x^2 end
local function g(x) return x+1 end
local function h(x) return x/2 end
M.juxtapose(10, f, g, h) -- => 100, 11, 5

wrap (f, wrapper)

Wraps a function inside a wrapper. Allows the wrapper to execute code before and after function run.

local greet = function(name) return "hi: " .. name end
local greet_backwards = M.wrap(greet, function(f,arg)
  return f(arg) ..'\nhi: ' .. arg:reverse()
end)
greet_backwards('John')

-- => hi: John
-- => hi: nhoJ

times (iter [, n])

Calls a given function n times.

local f = ('Lua programming'):gmatch('.')
M.times(f, 3) -- => {'L','u','a'}

bind (f, v)

Binds a value to be the first argument to a function.

local sqrt2 = M.bind(math.sqrt,2)
sqrt2() -- => 1.4142135623731

bind2 (f, v)

Binds a value to be the second argument to a function.

local last2 = M.bind(M.last,2)
last2({1,2,3,4,5,6}) -- => {5,6}

bindn (f, ...)

Binds a variable number of values to be the first arguments to a function.

local function out(...) return table.concat {...} end
local out = M.bindn(out,'OutPut',':',' ')
out(1,2,3) -- => OutPut: 123
out('a','b','c','d') -- => OutPut: abcd

bindall (obj, ...)

Binds methods to object. As such, when calling any of these methods, they will receive object as a first argument.

local window = {
    setPos = function(w,x,y) w.x, w.y = x, y end,
    setName = function(w,name) w.name = name end,
    getName = function(w) return w.name end,
}
window = M.bindall(window, 'setPos', 'setName', 'getName')
window.setPos(10,15)
print(window.x, window.y) -- => 10,15

window.setName('fooApp')
print(window.name) -- => 'fooApp'

print(window.getName()) -- => 'fooApp'

cond (conds)

Returns a function which iterate over an array list of conditions. It invokes each predicate, passing it given values. It returns the value of the corresponding function of the first predicate to return a non-nil value

local multipleOf = M.cond({
  {function(v) return v%2==0 end, function(v) return v..' is multiple of 2' end},
  {function(v) return v%3==0 end, function(v) return v..' is multiple of 3' end},
  {function(v) return v%5==0 end, function(v) return v..' is multiple of 5' end},
  {function() return true end, function(v) return 'could not find an answer for '..v end}
})
for i = 15, 20 do
  print(multipleOf(i))
end

-- => 15 is multiple of 3
-- => 16 is multiple of 2
-- => could not find an answer for 17
-- => 18 is multiple of 2
-- => could not find an answer for 19
-- => 20 is multiple of 2

both (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true only when all its funcs returns true.

local f = M.both(
    function(x) return x > 0 end,
    function(x) return x < 10 end,
    function(x) return x % 2 == 0 end
)
f(2) -- => true
f(8) -- => true
f(9) -- => false

either (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true when one of its funcs returns true.

local f = M.either(
    function(x) return x > 0 end,
    function(x) return x % 2 == 0 end
)
f(0) -- => true
f(-3) -- => false

neither (...)

Returns a validation function. Given a set of functions, the validation function evaluates to true when neither of its funcs returns true.

local f = M.neither(
    function(x) return x > 10 end,
    function(x) return x % 2 == 0 end
)
f(12) -- => false
f(8) -- => false
f(7) -- => true

uniqueId ([template])

*Aliases: uid*.

Returns an unique integer ID.

M.uniqueId() -- => 1

Can handle string templates for formatted output.

M.uniqueId('ID%s') -- => 'ID2'

Or a function, for the same purpose.

local formatter = function(ID) return '$'..ID..'$' end
M.uniqueId(formatter) -- => '$ID1$'

iterator(f, value [, n])

*Aliases: iter*.

Returns an iterator function which constinuously applies a function f onto an input value. For example, let us go through the powers of two using iterator.

local function po2(x) return x*2 end
local function iter_po2 = M.iterator(po2, 1)
iter_po2() -- => 2
iter_po2() -- => 4
iter_po2() -- => 8

if n is supplied, it will run at maximum n times.

local function po2(x) return x*2 end
local function iter_po2 = M.iterator(po2, 1, 3)
iter_po2() -- => 2
iter_po2() -- => 4
iter_po2() -- => 8
iter_po2() -- => nil

skip (iter [, n = 1])

Consumes the first n values of a iterator then returns it.

local w = "hello"
local char = string.gmatch(w,'.')
local iter = M.skip(char, 3)
for w in iter do print(w) end -- => 'l', 'o'

n defaults to 1 when not given.

local w = "hello"
local char = string.gmatch(w,'.')
local iter = M.skip(char)
for w in iter do print(w) end -- => 'e', 'l', 'l', 'o'

tabulate (...)

Iterates a given iterator function and returns its values packed in an array.

local text = 'letters'
local chars = string.gmatch(text, '.')
M.tabulate(chars) -- => {'l','e','t','t','e','r','s'}

iterlen (...)

Returns the length of an iterator.

local text = 'letters'
local chars = string.gmatch(text, '.')
M.iterlen(chars) -- => 7

It consumes the iterator itself.

local text = 'lua'
local chars = string.gmatch(text, '.')
M.iterlen(chars) -- => 3
chars() -- => nil

castArray (value)

Casts the passed-in value to an array containing the value itself.

M.castArray(true) -- => {true}
M.castArray(2) -- => {2}

It leaves the given value untouched in case it is already a table.

local t = {1}
print(M.castArray(t) == t) -- => true

flip (f)

Creates a function of f with arguments flipped in reverse order.

local function f(...) return table.concat({...}) end
local flipped = M.flip(f)
flipped('a','b','c') -- => 'cba'

nthArg(n)

Returns a function that gets the nth argument.

local f = M.nthArg(3)
f('a','b','c') -- => 'c'

If n is negative, the nth argument from the end is returned.

local f = M.nthArg(-2)
f('a','b','c') -- => 'b'

unary (f)

Returns a function which accepts up to one argument. It ignores any additional arguments.

local f = M.unary(function (...) return ... end)
f('a') - ==> 'a'
f('a','b','c') -- => 'a'

ary (f [, n = 1])

*Aliases: nAry*.

Returns a function which accepts up to n args. It ignores any additional arguments.

local f = M.ary(function (...) return ... end, 2)
f(1,2) - ==> 1,2
f(1,2,3,4) -- => 1,2

If n is not given, it defaults to 1.

local f = M.unary(function (...) return ... end)
f('a','b','c') -- => 'a'

noarg (f)

Returns a function with an arity of 0. The new function ignores any arguments passed to it.

local f = M.noarg(function (x) return x or 'default' end)
f(1) -- => 'default'
f(function() end, 3) -- => 'default'

rearg (f, indexes)

Returns a function which runs with arguments arranged according to given indexes.

local f = M.rearg(function (...) return ... end, {5,4,3,2,1})
f('a','b','c','d','e') -- => 'e','d','c','b','a'

over (...)

Creates a function that invokes a set of transforms with the arguments it receives.
One can use use for example to get the tuple of min and max values from a set of values

local minmax = M.over(math.min, math.max)
minmax(5,10,12,4,3) -- => {3,12}

overEvery (...)

Creates a validation function. The returned function checks if all of the given predicates return truthy when invoked with the arguments it receives.

local function alleven(...)
    for i, v in ipairs({...}) do
        if v%2~=0 then return false end
    end
    return true
end

local function allpositive(...)
    for i, v in ipairs({...}) do
        if v < 0 then return false end
    end
    return true
end

local allok = M.overEvery(alleven, allpositive)

allok(2,4,-1,8) -- => false
allok(10,3,2,6) -- => false
allok(8,4,6,10) -- => true

overSome (...)

Creates a validation function. The returned function checks if any of the given predicates return truthy when invoked with the arguments it receives.

local function alleven(...)
    for i, v in ipairs({...}) do
        if v%2~=0 then return false end
    end
    return true
end

local function allpositive(...)
    for i, v in ipairs({...}) do
        if v < 0 then return false end
    end
    return true
end

local anyok = M.overSome(alleven,allpositive)

anyok(2,4,-1,8) -- => false
anyok(10,3,2,6) -- => true
anyok(-1,-5,-3) -- => false

overArgs (f, ...)

Creates a function that invokes f with its arguments transformed

local function f(x, y) return x, y end
local function triple(x) retun x*3 end
local function square(x) retun x^2 end
local new_f = M.overArgs(f, triple, square)

new_f(1,2) -- => 3, 4
new_f(10,10) -- => 30, 100

In case the number of arguments is greater than the number of transforms, the remaining args will be left as-is.

local function f(x, y, z) return x, y, z end
local function triple(x) retun x*3 end
local function square(x) retun x^2 end
local new_f = M.overArgs(f, triple, square)

new_f(1,2,3) -- => 3, 4, 3
new_f(10,10,10) -- => 30, 100, 10

converge (f, g, h)

Converges two functions into one.

local function pow2(x) return x*x end
local function pow3(x) return x*x*x end
local function sum(a,b) return a+b end
local poly = M.converge(sum, pow2, pow3)
poly(5) -- => 150 (ie. 5*5 + 5*5*5)

partial (f, ...)

Partially apply a function by filling in any number of its arguments.

local function diff(a, b) return a - b end
local diffFrom20 = M.partial(diff, 20) -- arg 'a' will be 20 by default
diffFrom20(5) -- => 15

The string '_' can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time.

local function diff(a, b) return a - b end
local remove5 = M.partial(diff, '_', 5) -- arg 'a' will be given at call-time, but 'b' is set to 5
remove5(20) -- => 15

partialRight (f, ...)

Like M.partial, it partially applies a function by filling in any number of its arguments, but from the right.

local function concat(...) return table.concat({...},',') end
local concat_right = M.partialRight(concat,'a','b','c')
concat_right('d') -- => d,a,b,c

concat_right = M.partialRight(concat,'a','b')
concat_right('c','d') -- => c,d,a,b

concat_right = M.partialRight(concat,'a')
concat_right('b','c','d') -- => b,c,d,a

The string '_', as always, can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time. In that case, the first args supplied at runtime will be used to fill the initial list of args while the remaining will be prepended.

local function concat(...) return table.concat({...},',') end
local concat_right = M.partialRight(concat,'a','_','c')
concat_right('d','b') -- => b,a,d,c

concat_right = M.partialRight(concat,'a','b','_')
concat_right('c','d') -- => d,a,b,c

concat_right = M.partialRight(concat,'_','a')
concat_right('b','c','d') -- => c,d,b,a

curry (f [, n_args = 2])

Curries a function. If the given function f takes multiple arguments, it returns another version of f that takes a single argument (the first of the arguments to the original function) and returns a new function that takes the remainder of the arguments and returns the result.

local function sumOf3args(x,y,z) return x + y + z end
local curried_sumOf3args = M.curry(sumOf3args, 3)
sumOf3args(1)(2)(3)) -- => 6
sumOf3args(0)(6)(9)) -- => 15

n_args defaults to 2.

local function product(x,y) return x * y end
local curried_product = M.curry(product)
curried_product(5)(4) -- => 20
curried_product(3)(-5) -- => -15
curried_product(0)(1) -- => 0

time (f [, ...])

Returns the execution time of f (...) in seconds and its results.

local function wait_count(n)
    local i = 0
    while i < n do i = i + 1 end
    return i
end

local time, i = M.time(wait_count, 1e6) -- => 0.002 1000000
local time, i = M.time(wait_count, 1e7) -- => 0.018 10000000

[⬆]

Object functions

keys (obj)

Collects the names of an object attributes.

M.keys({1,2,3}) -- => "{1,2,3}"
M.keys({x = 0, y = 1}) -- => "{'y','x'}"

values (obj)

Collects the values of an object attributes.

M.values({1,2,3}) -- => "{1,2,3}"
M.values({x = 0, y = 1}) -- => "{1,0}"

path (obj, ...)

Returns the value at a given path in an object.

local entity = {
  pos = {x = 1, y = 2},
  engine = {
    left = {status = 'active', damage = 5},
    right = {status = 'off', damage = 10}
  },
  boost = false
}

M.path(entity,'pos','x') -- => 1
M.path(entity,'pos','y') -- => 2
M.path(entity,'engine','left','status') -- => 'active'
M.path(entity,'engine','right','damage') -- => 10
M.path(entity,'boost') -- => false

spreadPath (obj, ...)

Spreads object under property path onto provided object. It is similar to flattenPath, but removes object under the property path.

local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}}
M.spreadPath(obj, 'c', 'f')
-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {f = {}}}

flattenPath (obj, ...)

Flattens object under property path onto provided object. It is similar to spreadPath, but preserves object under the property path.

local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}}
M.spreadPath(obj, 'c', 'f')
-- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}}

kvpairs (obj)

Converts an object to an array-list of key-value pairs.

local obj = {x = 1, y = 2, z = 3}
M.each(M.kvpairs(obj), function(v,k)
    print(k, table.concat(v,','))
end)

-- => 1    y,2
-- => 2 x,1
-- => 3 z,3

toObj (kvpairs)

Converts an array list of kvpairs to an object where keys are taken from the 1rst column in the kvpairs sequence, associated with values in the 2nd column.

local list_pairs = {{'x',1},{'y',2},{'z',3}}
obj = M.toObj(list_pairs)

-- => {x = 1, y = 2, z = 3}

invert (obj)

*Aliases: mirror*.

Switches key-value pairs:

M.invert {'a','b','c'} -- => "{a=1, b=2, c=3}"
M.invert {x = 1, y = 2} -- => "{'x','y'}"

property (key)

Returns a function that will return the key property of any passed-in object.

local who = M.property('name')
local people = {name = 'Henry'}
who(people) -- => 'Henry'

propertyOf (obj)

Returns a function that will return the key property of any passed-in object.

local people = {name = 'Henry'}
print(M.propertyOf(people)('name')) -- => 'Henry'

toBoolean (value)

Converts a given value to a boolean.

M.toBoolean(true) -- => true
M.toBoolean(false) -- => false
M.toBoolean(nil) -- => false
M.toBoolean({}) -- => true
M.toBoolean(1) -- => true

extend (destObj, ...)

Extends a destination object with the properties of some source objects.

M.extend({},{a = 'b', c = 'd'}) -- => "{a = 'b', c = 'd'}"

functions (obj [, recurseMt])

*Aliases: methods*.

Returns all functions names within an object.

M.functions(coroutine)
-- => "{'yield','wrap','status','resume','running','create'}"

When given recurseMt, will also include obj metatable's functions.

local mt = {print = print}
local t = {assert = assert}
setmetatable(t, {__index = mt})
M.functions(t, true) -- => "{'assert','print'}"

clone (obj [, shallow])

Clones a given object.

local obj = {1,2,3}
local obj2 = M.clone(obj)
print(obj2 == obj) -- => false
print(M.isEqual(obj2, obj)) -- => true

tap (obj, f)

Invokes a given interceptor function on some object, and then returns the object itself. Useful to tap into method chaining to hook intermediate results. The passed-in interceptor should be prototyped as f(obj,...).

local v = M.chain({1,2,3,4,5,6,7,8,9,10})
  :filter(function(v) return v%2~=0 end) -- retain odd values
  :tap(function(v) print('Max is', M.max(v) end) -- Tap max value
  :map(function(v) return v^2 end)
  :value() -- =>    Max is 89

has (obj, key)

Checks if an object has a given attribute.

M.has(_,'has') -- => true
M.has(coroutine,'resume') -- => true
M.has(math,'random') -- => true

pick (obj, ...)

*Aliases: choose*.

Collects whilelisted properties of a given object.

local object = {a = 1, b = 2, c = 3}
M.pick(object,'a','c') -- => "{a = 1, c = 3}"

omit (obj, ...)

*Aliases: drop*.

Omits blacklisted properties of a given object.

local object = {a = 1, b = 2, c = 3}
M.omit(object,'a','c') -- => "{b = 2}"

template (obj [, template])

*Aliases: defaults*.

Applies a template on an object, preserving existing properties.

local obj = {a = 0}
M.template(obj,{a = 1, b = 2, c = 3}) -- => "{a=0, c=3, b=2}"

isEqual (objA, objB [, useMt])

*Aliases: compare, M.matches*.

Compares objects:

M.isEqual(1,1) -- => true
M.isEqual(true,false) -- => false
M.isEqual(3.14,math.pi) -- => false
M.isEqual({3,4,5},{3,4,{5}}) -- => false

result (obj, method)

Calls an object method, passing it as a first argument the object itself.

M.result('abc','len') -- => 3
M.result({'a','b','c'},table.concat) -- => 'abc'

isTable (t)

Is the given argument an object (i.e a table) ?

M.isTable({}) -- => true
M.isTable(math) -- => true
M.isTable(string) -- => true

isCallable (obj)

Is the given argument callable ?

M.isCallable(print) -- => true
M.isCallable(function() end) -- => true
M.isCallable(setmetatable({},{__index = string}).upper) -- => true
M.isCallable(setmetatable({},{__call = function() return end})) -- => true

isArray (obj)

Is the given argument an array (i.e. a sequence) ?

M.isArray({}) -- => true
M.isArray({1,2,3}) -- => true
M.isArray({'a','b','c'}) -- => true

isIterable (obj)

Checks if the given object is iterable with pairs.

M.isIterable({}) -- => true
M.isIterable(function() end) -- => false
M.isIterable(false) -- => false
M.isIterable(1) -- => false

type (obj)

Extends Lua's type function. It returns the type of the given object and also recognises 'file' userdata

M.type('string') -- => 'string'
M.type(table) -- => 'table'
M.type(function() end) -- => 'function'
M.type(io.open('f','w')) -- => 'file'

isEmpty ([obj])

Is the given argument empty ?

M.isEmpty('') -- => true
M.isEmpty({})  -- => true
M.isEmpty({'a','b','c'}) -- => false

isString (obj)

Is the given argument a string ?

M.isString('') -- => true
M.isString('Hello') -- => false
M.isString({}) -- => false

isFunction (obj)

Is the given argument a function ?

M.isFunction(print) -- => true
M.isFunction(function() end) -- => true
M.isFunction({}) -- => false

isNil (obj)

Is the given argument nil ?

M.isNil(nil) -- => true
M.isNil() -- => true
M.isNil({}) -- => false

isNumber (obj)

Is the given argument a number ?

M.isNumber(math.pi) -- => true
M.isNumber(math.huge) -- => true
M.isNumber(0/0) -- => true
M.isNumber() -- => false

isNaN (obj)

Is the given argument NaN ?

M.isNaN(1) -- => false
M.isNaN(0/0) -- => true

isFinite (obj)

Is the given argument a finite number ?

M.isFinite(99e99) -- => true
M.isFinite(math.pi) -- => true
M.isFinite(math.huge) -- => false
M.isFinite(1/0) -- => false
M.isFinite(0/0) -- => false

isBoolean (obj)

Is the given argument a boolean ?

M.isBoolean(true) -- => true
M.isBoolean(false) -- => true
M.isBoolean(1==1) -- => true
M.isBoolean(print) -- => false

isInteger (obj)

Is the given argument an integer ?

M.isInteger(math.pi) -- => false
M.isInteger(1) -- => true
M.isInteger(-1) -- => true

[⬆]

Chaining

Method chaining (also known as name parameter idiom), is a technique for invoking consecutively method calls in object-oriented style. Each method returns an object, and method calls are chained together. Moses offers chaining for your perusal.

Let's use chaining to get the count of evey single word in some lyrics (case won't matter here).

local lyrics = {
  "I am a lumberjack and I am okay",
  "I sleep all night and I work all day",
  "He is a lumberjack and he is okay",
  "He sleeps all night and he works all day"
}

-- split a text into words
local function words(line)
  local t = {}
  for w in line:gmatch('(%w+)') do t[#t+1] = w end
  return t
end

local stats = M.chain(lyrics)
  :map(words)
  :flatten()
  :countBy(string.lower)
  :value()

-- => "{
-- =>    sleep = 1, night = 2, works = 1, am = 2, is = 2,
-- =>    he = 2, and = 4, I = 4, he = 2, day = 2, a = 2,
-- =>    work = 1, all = 4, okay = 2
-- =>  }"

For convenience, you can also use M(value) to start chaining methods, instead of M.chain(value).

Note that one can use :value() to unwrap a chained object.

local t = {1,2,3}
print(_(t):value() == t) -- => true

[⬆]

Import

All library functions can be imported in a context using import into a specified context.

local context = {}
M.import(context)

context.each({1,2,3},print)

-- => 1 1
-- => 2 2
-- => 3 3

When no context was provided, it defaults to the current environment, _ENV or _G.

M.import()

each({1,2,3},print)

-- => 1 1
-- => 2 2
-- => 3 3

Passing noConflict argument leaves untouched conflicting keys while importing into the context.

local context = {each = 1}
M.import(context, true)

print(context.each) -- => 1
context.eachi({1,2,3},print)

-- => 1 1
-- => 2 2
-- => 3 3

[⬆]

generated by LDoc 1.4.6 Last updated 2018-09-12 11:33:43
Moses-Moses-2.1.0-1/doc/tutorial.md000066400000000000000000001617401334620647700170010ustar00rootroot00000000000000*Moses: a utility-belt library for functional programming in Lua* __Moses__ is a Lua utility library which provides support for functional programming. It complements built-in Lua functions, making easier common operations on tables, arrays, lists, collections, objects, and a lot more.

# Sections * [Adding *Moses* to your project](#adding) * [Table functions](#table) * [Array functions](#array) * [Utility functions](#utility) * [Object functions](#object) * [Chaining](#chaining) * [Import](#import)

# Adding *Moses* to your project Drop the file [moses.lua](http://github.com/Yonaba/Moses/blob/master/moses.lua) into your project and add it to your code with the *require* function: ```lua local M = require ("moses") ```` *Moses* provides a large set of functions that can be classified into four categories: * [__Table functions__](#table), which are mostly meant for tables, i.e Lua tables which contains both an array-part and a hash-part, * [__Array functions__](#array), meant for array lists (or sequences), * [__Utility functions__](#utility), * [__Object functions__](#object). **[[⬆]](#TOC)** ## Table functions ### clear (t) Clears a table. All its values becomes nil. Returns the passed-in table. ```lua M.clear({1,2,'hello',true}) -- => {} ```` ### each (t, f) *Aliases: `forEach`*. Iterates over each value-key pair in the passed-in table. ```lua M.each({4,2,1},print) -- => 4 1 -- => 2 2 -- => 1 3 ```` The table can be map-like (both array part and hash part). ```lua M.each({one = 1, two = 2, three = 3},print) -- => 1 one -- => 2 two -- => 3 three ```` Can index and assign in an outer table or in the passed-in table: ```lua t = {'a','b','c'} M.each(t,function(v,i) t[i] = v:rep(2) print(t[i]) end) -- => aa -- => bb -- => cc ```` ### eachi (t, f) *Aliases: `forEachi`*. Iterates only on integer keys in an array table. It returns value-key pairs. ```lua M.eachi({4,2,1},print) -- => 4 1 -- => 2 2 -- => 1 3 ```` The given array can be sparse, or even have a hash-like part. ```lua local t = {a = 1, b = 2, [0] = 1, [-1] = 6, 3, x = 4, 5} M.eachi(t,print) -- => 6 -1 -- => 1 0 -- => 3 1 -- => 5 2 ```` ### at (t, ...) Collects values at given keys and returns them in an array. ```lua local t = {4,5,6} M.at(t,1,3) -- => "{4,6}" local t = {a = 4, bb = true, ccc = false} M.at(t,'a', 'ccc') -- => "{4, false}" ```` ### adjust (t, key, f) Adjusts the value at a given key using a function or a value. In case `f` is a function, it should be prototyped `f(v)`. It does not mutate the given table, but rather returns a new array. ```lua local t = {1,2,3} M.adjust(t, 2, math.sin) -- => {1, 0.90929, 3} local v = {x = 1} M.adjust(t, 'x', 4) -- => {x = 4} ```` In case the given `key` does not exist in `t`, it throws an error. ### count (t [, val]) Counts the number of occurences of a given value in a table. ```lua M.count({1,1,2,3,3,3,2,4,3,2},1) -- => 2 M.count({1,1,2,3,3,3,2,4,3,2},2) -- => 3 M.count({1,1,2,3,3,3,2,4,3,2},3) -- => 4 M.count({false, false, true},false) -- => 2 M.count({false, false, true},true) -- => 1 ```` Returns the size of the list in case no value was provided. ```lua M.count({1,1,2,3,3}) -- => 5 ```` ### countf (t, f) Counts the number of values passing an iterator test. ```lua M.countf({1,2,3,4,5,6}, function(v) return v%2==0 end) -- => 3 M.countf({print, pairs, os, assert, ipairs}, function(v) return type(v)=='function' end) -- => 4 ```` ### allEqual (t [, comp]) *Aliases: `alleq`*. Checks if all values in a collection are equal. Uses `M.isEqual` by default to compare values. ```lua M.allEqual({1,1,1,1,1}, comp) -- => true M.allEqual({1,1,2,1,1}, comp) -- => false local t1 = {1, 2, {3}} local t2 = {1, 2, {3}} M.allEqual({t1, t2}) -- => true ```` Can take an optional `comp` function which will be used to compare values. ```lua local t1 = {x = 1, y = 0} local t2 = {x = 1, y = 0} local t3 = {x = 1, y = 2} local t4 = {x = 1, y = 2} local function compx(a, b) return a.x == b.x end local function compy(a, b) return a.y == b.y end M.allEqual({t1, t2}, compx) -- => true M.allEqual({t1, t2}, compy) -- => true M.allEqual({t3, t4}, compx) -- => true M.allEqual({t3, t4}, compy) -- => true M.allEqual({t1, t2, t3, t4}, compx) -- => true M.allEqual({t1, t2, t3, t4}, compy) -- => false ```` ### cycle (t [, n = 1]) *Aliases: `loop`*. Returns a function which iterates on each value-key pair in a given table (similarly to `M.each`), except that it restarts iterating again `n` times. If `n` is not provided, it defaults to 1. ```lua local t = {'a','b','c'} for v in M.cycle(t, 2) do print(v) end -- => 'a' -- => 'b' -- => 'c' -- => 'a' -- => 'b' -- => 'c' ```` Supports array-like tables and map-like tables. ```lua local t = {x = 1, y = 2, z = 3} for v in M.cycle(t) do print(v) end -- => 2 -- => 1 -- => 3 ```` ### map (t, f) *Aliases: `collect`*. Executes a function on each value in a given array. ```lua M.map({1,2,3},function(v) return v+10 end) -- => "{11,12,13}" ```` ```lua M.map({a = 1, b = 2},function(v, k) return k..v end) -- => "{a = 'a1', b = 'b2'}" ```` It also maps both keys and values. ```lua M.map({a = 1, b = 2},function(v, k) return k..k, v*2 end) -- => "{aa = 2, bb = 4}" ```` ### reduce (t, f [, state = next(t)]) *Aliases: `inject`, `foldl`*. Can sum all values in a table. In case `state` is not provided, it defaults to the first value in the given table `t`. ```lua local function add(a,b) return a+b end M.reduce({1,2,3,4},add) -- => 10 ```` Or concatenates all values. ```lua local function concat(a,b) return a..b end M.reduce({'a','b','c','d'},concat) -- => abcd ```` ### best (t, f) Returns the best value passing a selector function. Acts as a special case of `reduce`, using the first value in `t` as an initial state. It thens folds the given table, testing each of its values `v` and selecting the value passing the call `f(state,v)` every time. ```lua local words = {'Lua', 'Programming', 'Language'} M.best(words, function(a,b) return #a > #b end) -- => 'Programming' M.best(words, function(a,b) return #a < #b end) -- => 'Lua' ```` ### reduceBy (t, f, pred [, state = next(t)]) Reduces a table considering only values matching a predicate. For example,let us define a set of values. ```lua local val = {-1, 8, 0, -6, 3, -1, 7, 1, -9} ```` And a reduction function which will add up values. ```lua local function add(a,b) return a+b end ```` We can also define some predicate functions. ```lua -- predicate for negative values local function neg(v) return v<=0 end -- predicate for positive values local function pos(v) return v>=0 end ```` Then we can perform reduction considering only negative or positive values : ```lua M.reduceBy(val, add, neg) -- => -17 M.reduceBy(val, add, pos) -- => 19 ```` An initial state can be passed in. ```lua M.reduceBy(val, add, neg, 17) -- => 0 M.reduceBy(val, add, pos, -19) -- => 0 ```` ### reduceRight (t, f [, state = next(t)]) *Aliases: `injectr`, `foldr`*. Similar to `M.reduce`, but performs from right to left. ```lua local initial_state = 256 local function div(a,b) return a/b end M.reduceRight({1,2,4,16},div,initial_state) -- => 2 ```` ### mapReduce (t, f [, state = next(t)]) *Aliases: `mapr`*. Reduces while saving intermediate states. ```lua local function concat(a,b) return a..b end M.mapReduce({'a','b','c'},concat) -- => "{'a', 'ab', 'abc'}" ```` ### mapReduceRight (t, f [, state = next(t)]) *Aliases: `maprr`*. Reduces from right to left, while saving intermediate states. ```lua local function concat(a,b) return a..b end M.mapReduceRight({'a','b','c'},concat) -- => "{'c', 'cb', 'cba'}" ```` ### include (t, value) *Aliases: `any`, `some`, `contains`*. Looks for a value in a table. ```lua M.include({6,8,10,16,29},16) -- => true M.include({6,8,10,16,29},1) -- => false local complex_table = {18,{2,{3}}} local collection = {6,{18,{2,6}},10,{18,{2,{3}}},29} M.include(collection, complex_table) -- => true ```` Handles iterator functions. ```lua local function isUpper(v) return v:upper()== v end M.include({'a','B','c'},isUpper) -- => true ```` ### detect (t, value) Returns the index of a value in a table. ```lua M.detect({6,8,10,16},8) -- => 2 M.detect({nil,true,0,true,true},false) -- => nil local complex_table = {18,{2,6}} local collection = {6,{18,{2,6}},10,{18,{2,{3}}},29} M.detect(collection, complex_table) -- => 2 ```` Handles iterator functions. ```lua local function isUpper(v) return v:upper()==v end M.detect({'a','B','c'},isUpper) -- => 2 ```` ### where (t, props) Looks through a table and returns all the values that matches all of the key-value pairs listed in `props`. ```lua local items = { {height = 10, weight = 8, price = 500}, {height = 10, weight = 15, price = 700}, {height = 15, weight = 15, price = 3000}, {height = 10, weight = 8, price = 3000}, } M.where(items, {height = 10}) -- => {items[1], items[2], items[4]} M.where(items, {weight = 15}) -- => {items[2], items[3]} M.where(items, {prince = 3000}) -- => {items[3], items[4]} M.where(items, {height = 10, weight = 15, prince = 700}) -- => {items[2]} ```` ### findWhere (t, props) Looks through a table and returns the first value found that matches all of the key-value pairs listed in `props`. ```lua local a = {a = 1, b = 2, c = 3} local b = {a = 2, b = 3, d = 4} local c = {a = 3, b = 4, e = 5} M.findWhere({a, b, c}, {a = 3, b = 4}) == c -- => true ```` ### select (t, f) *Aliases: `filter`*. Collects values passing a validation test. ```lua local function isEven(v) return v%2==0 end local function isOdd(v) return v%2~=0 end M.select({1,2,3,4,5,6,7}, isEven) -- => "{2,4,6}" M.select({1,2,3,4,5,6,7}, isOdd) -- => "{1,3,5,7}" ```` ### reject (t, f) *Aliases: `reject`*. Removes all values failing (returning false or nil) a validation test: ```lua local function isEven(v) return v%2==0 end local function isOdd(v) return v%2~=0 end M.reject({1,2,3,4,5,6,7}, isEven) -- => "{1,3,5,7}" M.reject({1,2,3,4,5,6,7}, isOdd) -- => "{2,4,6}" ```` ### all (t, f) *Aliases: `every`*. Checks whether or not all elements pass a validation test. ```lua local function isEven(v) return v%2==0 end M.all({2,4,6}, isEven) -- => true ```` ### invoke (t, method) Invokes a given function on each value in a table. ```lua M.invoke({'a','bea','cdhza'},string.len) -- => "{1,3,5}" ```` Can reference the method of the same name in each value. ```lua local a, b, c, d = {id = 'a'}, {id = 'b'}, {id = 'c'}, {id = 'd'} local function call(self) return self.id end M.invoke({a,b,c,d},call) -- => "{'a','b','c','d'}" ```` ### pluck (t, property) Fetches all values indexed with specific key in a table of objects. ```lua local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} M.pluck(peoples,'age') -- => "{23,17,15,33}" M.pluck(peoples,'name') -- => "{'John', 'Peter', 'Steve'}" ```` ### max (t [, transform]) Returns the maximum value in a collection. ```lua M.max {1,2,3} -- => 3 M.max {'a','b','c'} -- => 'c' ```` Can take an iterator function to extract a specific property. ```lua local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} M.max(peoples,function(people) return people.age end) -- => 33 ```` ### min (t [, transform]) Returns the minimum value in a collection. ```lua M.min {1,2,3} -- => 1 M.min {'a','b','c'} -- => 'a' ```` Can take an iterator function to extract a specific property. ```lua local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} M.min(peoples,function(people) return people.age end) -- => 15 ```` ### same (a, b) Tests whether or not all values in each of the passed-in tables exists in both tables. ```lua local a = {'a','b','c','d'} local b = {'b','a','d','c'} M.same(a,b) -- => true b[#b+1] = 'e' M.same(a,b) -- => false ```` ### sort (t [, comp = math.min]) Sorts a collection. ```lua M.sort({'b','a','d','c'}) -- => "{'a','b','c','d'}" ```` Handles custom comparison functions. ```lua M.sort({'b','a','d','c'}, function(a,b) return a:byte() > b:byte() end) -- => "{'d','c','b','a'}" ```` ### sortedk (t [, comp]) Iterates on values with respect to key order. Keys are sorted using `comp` function which defaults to `math.min`. It returns upon each call a `key, value` pair. ```lua local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 for k, v in M.sortedk(tbl) do print(k, v) end -- => 1 12 -- => 2 6 -- => 3 5 -- => 4 10 -- => 5 8 local function comp(a,b) return a > b end for k, v in M.sortedk(tbl, comp) do print(k, v) end -- => 5 8 -- => 4 10 -- => 3 5 -- => 2 6 -- => 1 12 ```` ### sortedv (t [, comp]) Iterates on values with respect to key order. Keys are sorted using `comp` function which defaults to `math.min`. It returns upon each call a `key, value` pair. ```lua local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 for k, v in M.sortedv(tbl) do print(k, v) end -- => 3 5 -- => 2 6 -- => 5 8 -- => 4 10 -- => 1 12 local function comp(a,b) return a > b end for k, v in M.sortedv(tbl, comp) do print(k, v) end -- => 1 12 -- => 4 10 -- => 5 8 -- => 2 6 -- => 3 5 ```` ### sortBy (t [, transform [, comp = math.min]]) Sorts items in a collection based on the result of running a transform function through every item in the collection. ```lua local r = M.sortBy({1,2,3,4,5}, math.sin) print(table.concat(r,',')) -- => {5,4,3,1,2} ```` The transform function can also be a string name property. ```lua local people = { {name = 'albert', age = 40}, {name = 'louis', age = 55}, {name = 'steve', age = 35}, {name = 'henry', age = 19}, } local r = M.sortBy(people, 'age') M.each(r, function(v) print(v.age, v.name) end) -- => 19 henry -- => 35 steve -- => 40 albert -- => 55 louis ```` As seen above, the defaut comparison function is the '<' operator. For example, let us supply a different one to sort the list of people by decreasing age order : ```lua local people = { {name = 'albert', age = 40}, {name = 'louis', age = 55}, {name = 'steve', age = 35}, {name = 'henry', age = 19}, } local r = M.sortBy(people, 'age', function(a,b) return a > b end) M.each(r, function(v) print(v.age, v.name) end) -- => 55 louis -- => 40 albert -- => 35 steve -- => 19 henry ```` The `transform` function defaults to `M.indentity` and in that case, `M.sortBy` behaves like `M.sort`. ```lua local r = M.sortBy({1,2,3,4,5}) print(table.concat(r,',')) -- => {1,2,3,4,5} ```` ### groupBy (t, iter) Groups values in a collection depending on their return value when passed to a predicate test. ```lua M.groupBy({0,1,2,3,4,5,6},function(v) return v%2==0 and 'even' or 'odd' end) -- => "{odd = {1,3,5}, even = {0,2,4,6}}" M.groupBy({0,'a',true, false,nil,b,0.5},type) -- => "{number = {0,0.5}, string = {'a'}, boolean = {true, false}}" ```` ### countBy (t, iter) Splits a table in subsets and provide the count for each subset. ```lua M.countBy({0,1,2,3,4,5,6},function(v) return v%2==0 and 'even' or 'odd' end) -- => "{odd = 3, even = 4}" ```` ### size (...) When given a table, provides the count for the very number of values in that table. ```lua M.size {1,2,3} -- => 3 M.size {one = 1, two = 2} -- => 2 ```` When given a vararg list of arguments, returns the count of these arguments. ```lua M.size(1,2,3) -- => 3 M.size('a','b',{}, function() end) -- => 4 ```` ### containsKeys (t, other) Checks whether a table has all the keys existing in another table. ```lua M.contains({1,2,3,4},{1,2,3}) -- => true M.contains({1,2,'d','b'},{1,2,3,5}) -- => true M.contains({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => true ```` ### sameKeys (tA, tB) Checks whether both tables features the same keys: ```lua M.sameKeys({1,2,3,4},{1,2,3}) -- => false M.sameKeys({1,2,'d','b'},{1,2,3,5}) -- => true M.sameKeys({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => false ```` **[[⬆]](#TOC)** ## Array functions ### sample (array [, n = 1 [, seed]]) Samples `n` values from array. ```lua local array = M.range(1,20) local sample = M.sample(array, 3) print(table.concat(sample,',')) -- => {12,11,15} ```` `n` defaults to 1. In that case, a single value will be returned. ```lua local array = M.range(1,20) local sample = M.sample(array) print(sample) -- => 12 ```` An optional 3rd argument `seed` can be passed for deterministic random sampling. ### sampleProb (array, prob [, seed]) Returns an array of values randomly selected from a given array. In case `seed` is provided, it is used for deterministic sampling. ```lua local array = M.range(1,20) local sample = M.sampleProb(array, 0.2) print(table.concat(sample,',')) -- => 5,11,12,15 sample = M.sampleProb(array, 0.2, os.time()) print(table.concat(sample,',')) -- => 1,6,10,12,15,20 (or similar) ```` ### nsorted (array [, n = 1[, comp]]) Returns the n-top values satisfying a predicate. It takes a comparison function `comp` used to sort array values, and then picks the top n-values. It leaves the original array untouched. ```lua local function comp(a,b) return a > b end M.nsorted(array,5, comp) -- => {5,4,3,2,1} ```` `n` defaults to 1 and `comp` defaults to the `<` operator. ```lua local array = M.range(1,20) M.nsorted(array) -- => {1} ```` ### shuffle (array [, seed]) Shuffles a given array. ```lua local list = M.shuffle {1,2,3,4,5,6} -- => "{3,2,6,4,1,5}" M.each(list,print) ```` ### pack (...) Converts a vararg list of arguments to an array. ```lua M.pack(1,2,8,'d','a',0) -- => "{1,2,8,'d','a',0}" ```` ### find (array, value [, from = 1]) Looks for a value in a given array and returns the position of the first occurence. ```lua local value = {3} M.find({{4},{3},{2},{1}},value) -- => 2 ```` It can also start the search at a specific position in the array: ```lua -- search value 4 starting from index 3 M.find({1,4,2,3,4,5},4,3) -- => 5 ```` ### reverse (array) Reverses an array. ```lua M.reverse({1,2,3,'d'}) -- => "{'d',3,2,1}" ```` ### fill (array, value [, i = 1 [, j = #array]]) Replaces all elements in a given array with a given value. ```lua local array = M.range(1,5) M.fill(array, 0) -- => {0,0,0,0,0} ```` It can start replacing value at a specific index. ```lua local array = M.range(1,5) M.fill(array,0,3) -- => {1,2,0,0,0} ```` It can replace only values within a specific range. ```lua local array = M.range(1,5) M.fill(array,0,2,4) -- => {1,0,0,0,5} ```` In case the upper bound index i greather than the array size, it will enlarge the array. ```lua local array = M.range(1,5) M.fill(array,0,5,10) -- => {1,2,3,4,0,0,0,0,0,0} ```` ### zeros (n) Returns an array of `n` zeros. ```lua M.zeros(4) -- => {0,0,0,0} ```` ### ones (n) Returns an array of `n` 1's. ```lua M.ones(3) -- => {1,1,1} ```` ### vector (value, n) Returns an array of `n` times a given value. ```lua M.vector(10, 4) -- => {10,10,10,10} ```` ### selectWhile (array, f [, ...]) *Aliases: `takeWhile`*. Collects values as long as they pass a given test. Stops on the first non-passing test. ```lua M.selectWhile({2,4,5,8}, function(v) return v%2==0 end) -- => "{2,4}" ```` ### dropWhile (array, f [, ...]) *Aliases: `rejectWhile`*. Removes values as long as they pass a given test. Stops on the first non-passing test. ```lua M.dropWhile({2,4,5,8}, function(v) return v%2==0 end) -- => "{5,8}" ```` ### sortedIndex (array, value [, comp = math.min [, sort = nil]]) Returns the index at which a value should be inserted to preserve order. ```lua M.sortedIndex({1,2,3},4) -- => 4 ```` Can take a custom comparison functions. ```lua local comp = function(a,b) return a 3 ```` ### indexOf (array, value) Returns the index of a value in an array. ```lua M.indexOf({1,2,3},2) -- => 2 ```` ### lastIndexOf (array, value) Returns the index of the last occurence of a given value in an array. ```lua M.lastIndexOf({1,2,2,3},2) -- => 3 ```` ### findIndex (array, pred) Returns the first index at which a predicate passes a truth test. ```lua local array = {1,2,3,4,5,6} local function multipleOf3(v) return v%3==0 end M.findIndex(array, multipleOf3) -- => 3 ```` ### findLastIndex (array, pred) Returns the last index at which a predicate passes a truthy test. ```lua local array = {1,2,3,4,5,6} local function multipleOf3(v) return v%3==0 end M.findLastIndex(array, multipleOf3) -- => 6 ```` ### addTop (array, ...) Adds given values at the top of an array. The latter values bubbles at the top. ```lua local array = {1} M.addTop(array,1,2,3,4) -- => "{4,3,2,1,1}" ```` ### prepend (array, ...) Adds given values at the top of an array, preserving the order at which elements are passed-in. ```lua local array = {'old_val'} M.prepend(array,1,2,3,4) -- => "{1,2,3,4,'old_val'}" ```` ### push (array, ...) Adds given values at the end of an array. ```lua local array = {1} M.push(array,1,2,3,4) -- => "{1,1,2,3,4}" ```` ### shift (array [, n = 1]) *Aliases: `pop`*. Removes and returns the first value in an array. ```lua local array = {1,2,3} local shift = M.shift(array) -- => "shift = 1", "array = {2,3}" ```` If `n` is supplied, returns `n` values. ```lua local array = {1,2,3,4,5} local a, b = M.shift(array, 2) -- => "a = 1, b = 2", "array = {3,4,5}" ```` ### unshift (array [, n = 1]) Removes and returns the last value in an array. ```lua local array = {1,2,3} local value = M.unshift(array) -- => "value = 3", "array = {1,2}" ```` ### pull (array, ...) *Aliases: `remove`*. Removes all provided values from a given array. ```lua M.pull({1,2,1,2,3,4,3},1,2,3) -- => "{4}" ```` ### removeRange (array [, start = 1 [, finish = #array]]) *Aliases: `rmRange`, `M.chop`*. Trims out all values index within a range. ```lua local array = {1,2,3,4,5,6,7,8,9} M.removeRange(array, 3,8) -- => "{1,2,9}" ```` ### chunk (array, f) Iterates over an array aggregating consecutive values in subsets tables, on the basis of the return value of `f(v, k, ...)`. Consecutive elements which return the same value are chunked together. ```lua local t = {1,1,2,3,3,4} M.chunk(t, function(v) return v%2==0 end) -- => "{{1,1},{2},{3,3},{4}}" ```` ### slice (array [, start = 1 [, finish = #array]]) *Aliases: `sub`*. Slices and returns a part of an array. ```lua local array = {1,2,3,4,5,6,7,8,9} M.slice(array, 3,6) -- => "{3,4,5,6}" ```` ### first (array [, n = 1]) *Aliases: `head`, `M.take`*. Returns the first N elements in an array. ```lua local array = {1,2,3,4,5,6,7,8,9} M.first(array,3) -- => "{1,2,3}" ```` ### initial (array [, n = #array]) Excludes the last N elements in an array. ```lua local array = {1,2,3,4,5,6,7,8,9} M.initial(array,5) -- => "{1,2,3,4}" ```` ### last (array [, n = #array]) Returns the last N elements in an array. ```lua local array = {1,2,3,4,5,6,7,8,9} M.last(array,3) -- => "{7,8,9}" ```` ### rest (array [, index = 1]) *Aliases: `tail`*. Returns all values after *index*, including the given *index* itself. ```lua local array = {1,2,3,4,5,6,7,8,9} M.rest(array,6) -- => "{6,7,8,9}" ```` ### nth (array, index) Returns the value at *index*. ```lua local array = {1,2,3,4,5,6} M.nth(array,3) -- => "3" ```` ### compact (array) Trims out all falsy values. ```lua M.compact {a,'aa',false,'bb',true} -- => "{'aa','bb',true}" ```` ### flatten (array [, shallow = false]) Flattens a nested array. ```lua M.flatten({1,{2,3},{4,5,{6,7}}}) -- => "{1,2,3,4,5,6,7}" ```` When given arg `shallow`, flatten only at the first level. ```lua M.flatten({1,{2},{{3}}},true) -- => "{1,{2},{{3}}}" ```` ### difference (array, array2) *Aliases: `without`, `diff`*. Returns values in the given array not present in a second array. ```lua local array = {1,2,'a',4,5} M.difference(array,{1,'a'}) -- => "{2,4,5}" ```` ### union (...) Produces a duplicate-free union of all passed-in arrays. ```lua local A = {'a'} local B = {'a',1,2,3} local C = {2,10} M.union(A,B,C) -- => "{'a',1,2,3,10}" ```` ### intersection (...) Returns the intersection (common-part) of all passed-in arrays: ```lua local A = {'a'} local B = {'a',1,2,3} local C = {2,10,1,'a'} M.intersection(A,B,C) -- => "{'a'}" ```` ### disjoint (...) Checks if all passed in arrays are disjoint. ```lua local A = {'a'} local B = {'a',1,3} local C = {3,10,2} M.disjoint(A,B) -- => false M.disjoint(A,C) -- => true M.disjoint(B,C) -- => false ```` ### symmetricDifference (array, array2) *Aliases: `symdiff`,`xor`*. Returns values in the first array not present in the second and also values in the second array not present in the first one. ```lua local array = {1,2,3} local array2 = {1,4,5} M.symmetricDifference(array, array2) -- => "{2,3,4,5}" ```` ### unique (array) *Aliases: `uniq`*. Makes an array duplicate-free. ```lua M.unique {1,1,2,2,3,3,4,4,4,5} -- => "{1,2,3,4,5}" ```` ### isunique (array) *Aliases: `isuniq`*. Checks if a given array contains no duplicate value. ```lua M.isunique({1,2,3,4,5}) -- => true M.isunique({1,2,3,4,4}) -- => false ```` ### duplicates (array) Returns an array list of all duplicates in array. ```lua M.duplicates({1,2,3,3,8,8,3,2,4}) -- => {2,3,8} ```` ### zip (...) *Aliases: `transpose`*. Zips values from different arrays, on the basis on their common keys. ```lua local names = {'Bob','Alice','James'} local ages = {22, 23} M.zip(names,ages) -- => "{{'Bob',22},{'Alice',23},{'James'}}" ```` ### zipWith (f, ...) *Aliases: `transposeWith`*. Merges values using a given function. Only values indexed with the same key in the given arrays are merged in the same subset. Function `f` is used to combine values. ```lua local names = {'Bob','Alice','James'}; local ages = {22, 23, 25} local function introduce(name, age) return 'I am '..name..' and I am '..age..' years old.' end local t = M.zipWith(introduce,names,ages) -- => { -- => 'I am Bob and I am 22 years old.' -- => 'I am Alice and I am 23 years old.' -- => 'I am James and I am 25 years old.' -- => } ```` ### append (array, other) Appends two arrays. ```lua M.append({1,2,3},{'a','b'}) -- => "{1,2,3,'a','b'}" ```` ### interleave (...) Interleaves values from passed-in arrays. ```lua t1 = {1, 2, 3} t2 = {'a', 'b', 'c'} M.interleave(t1, t2) -- => "{1,'a',2,'b',3,'c'}" ```` ### interpose (array, value) *Aliases: `intersperce`*. Interposes a value between consecutive values in an arrays. ```lua M.interleave('a', {1,2,3}) -- => "{1,'a',2,'a',3}" ```` ### range ([from [, to [, step]]]) Generates an arithmetic sequence. ```lua M.range(1,4) -- => "{1,2,3,4}" ```` In case a single value is provided, it generates a sequence from 1 to that value. ```` M.range(3) -- => "{1,2,3}" ```` The incremental step can also be provided as third argument. ```lua M.range(0,2,0.7) -- => "{0,0.7,1.4}" ```` It also handles negative progressions. ```lua M.range(-5) -- => "{-1,-2,-3,-4,-5}" M.range(5,1) -- => "{5,4,3,2,1}" ```` ### rep (value, n) Generates a list of n repetitions of a value. ```lua M.rep(4,3) -- => "{4,4,4}" ```` ### powerset (array) Returns the powerset of an array. ```lua M.powerset {1,2,3} -- => "{{1},{2},{3},{1,2},{2,3},{1,2,3}}" ```` ### partition (array [, n = 1 [, pad]]) *Aliases: `part`*. Returns an iterator function for partitions of a given array. ```lua local t = {1,2,3,4,5,6} for p in M.partition(t,2) do print(table.concat(p, ',')) end -- => 1,2 -- => 3,4 -- => 5,6 local t = {1,2,3,4,5,6} for p in M.partition(t,4) do print(table.concat(p, ',')) end -- => 1,2,3,4 -- => 5,6 ```` In case the last partition has less elements than desired, a 3rd argument can be supplied to adjust the partition size. ```lua local t = {1,2,3,4,5,6} for p in M.partition(t,4,0) do print(table.concat(p, ',')) end -- => 1,2,3,4 -- => 5,6,0,0 ```` ### overlapping (array [, n = 2 [, pad]]) Returns an iterator function which provides overlapping subsequences of a given array. ```lua local t = {1,2,3,4,5,6,7} for p in M.overlapping(t,3) do print(table.concat(p,',')) end -- => 1,2,3 -- => 3,4,5 -- => 5,6,7 for p in M.overlapping(t,4) do print(table.concat(p,',')) end -- => 1,2,3,4 -- => 4,5,6,7 for p in M.overlapping(t,5) do print(table.concat(p,',')) end -- => 1,2,3,4,5 -- => 5,6,7 ```` In case the last subsequence wil not match the exact desired length, it can be adjusted with a 3rd argument `pad`. ```lua local t = {1,2,3,4,5,6,7} for p in M.overlapping(t,5,0) do print(table.concat(p,',')) end -- => 1,2,3,4,5 -- => 5,6,7,0,0 ```` ### aperture (array [, n = 2]) *Aliases: `sliding`*. Returns an iterator function which provides sliding partitions of a given array. ```lua local t = {1,2,3,4,5} for p in M.aperture(t,4) do print(table.concat(p,',')) end -- => 1,2,3,4 -- => 2,3,4,5 for p in M.aperture(t,3) do print(table.concat(p,',')) end -- => 1,2,3 -- => 2,3,4 -- => 3,4,5 ```` ### pairwise (array) Iterator returning sliding pairs of an array. ```lua local t = M.range(5) for p in pairwise(t) do print(table.concat(p,',')) end -- => 1,2 -- => 2,3 -- => 3,4 -- => 4,5 ```` ### permutation (array) *Aliases: `perm`*. Returns an iterator function for permutations of a given array. ```lua t = {'a','b','c'} for p in M.permutation(t) do print(table.concat(p)) end -- => 'bca' -- => 'cba' -- => 'cab' -- => 'acb' -- => 'bac' -- => 'abc' ```` ### concat (array [, sep = '' [, i = 1 [, j = #array]]]) *Aliases: `join`*. Concatenates a given array values: ```lua M.concat({'a',1,0,1,'b'}) -- => 'a101b' ```` ### xprod (array, array2) Returns all possible pairs built from given arrays. ```lua local t = M.xprod({1,2},{'a','b'}) -- => {{1,'a'},{1,'b'},{2,'a'},{2,'b'}} ```` ### xpairs (value, array) Creates pairs from value and array. Value is always prepended to the pair. ```lua local t = M.xpairs(1, {1, 2, 3}) -- => {{1,1},{1,2},{1,3}} ```` ### xpairsRight (value, array) Creates pairs from value and array. Value is always appended as the last item to the pair. ```lua local t = M.xpairsRight(1, {1, 2, 3}) -- => {{1,1},{2,1},{3,1}} ```` ### sum (array) Returns the sum of array values. ```lua M.sum({1,2,3,4,5}) -- => 15 ```` ### product (array) Returns the product of array values. ```lua M.product({1,2,3,4,5}) -- => 120 ```` ### mean (array) Returns the mean of array values. ```lua M.mean({1,2,3,4,5}) -- => 3 ```` ### median (array) Returns the median of array values. ```lua M.median({1,2,3,4,5}) -- => 3 M.median({1,2,3,4}) -- => 2.5 ```` **[[⬆]](#TOC)** ## Utility functions ### noop () The no-operation function. Takes nothing, returns nothing. It is being used internally. ```lua M.noop() -- => nil ```` ### identity (value) Returns the passed-in value.
This function is internally used as a default transformation function. ```lua M.identity(1)-- => 1 M.identity(false) -- => false M.identity('hello!') -- => 'hello!' ```` ### call (f [, ...]) Calls `f` with the supplied arguments. Returns the results of `f(...)`. ```lua M.call(math.pow, 2, 3) -- => 8 M.call(string.len, 'hello' ) -- => 5 M.call(table.concat, {1,2,3,4,5}, ',', 2, 4) -- => {2,3,4} ```` ### constant (value) Creates a constant function. This function will continuously yield the same output. ```lua local pi = M.constant(math.pi) pi(1) -- => 3.1415926535898 pi(2) -- => 3.1415926535898 pi(math.pi) -- => 3.1415926535898 ```` ### applySpec (specs) Returns a function which applies `specs` on args. This function will produce an object having the same structure than `specs` by mapping each property to the result of calling its associated function with the supplied arguments. ```lua local stats = M.applySpec({ min = function(...) return math.min(...) end, max = function(...) return math.max(...) end, }) stats(5,4,10,1,8) -- => {min = 1, max = 10} ```` ### thread (value [, ...]) Threads `value` through a series of functions. ```lua local function inc(x) return x + 1 end local function double(x) return 2 * x end local function square(x) return x * x end M.thread(2, inc, double, square) -- => 36 M.thread(3, double, inc, square) -- => 49 M.thread(4, square, double, inc) -- => 33 M.thread(5, square, inc, double) -- => 52 ```` If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. ```lua local function inc(x) return x + 1 end local function add(x, y) return x * y end local function pow(x, y) return x ^ y end M.thread(2, inc, {add, 3}, {pow, 2}) -- => 36 M.thread(2, {add, 4}, inc, {pow, 2}) -- => 49 ```` ### threadRight (value [, ...]) Threads `value` through a series of functions. If a function expects more than one args, it can be specified using an array list, where the first item is the function and the following are the remaining args neeeded. The value is used as the last input. ```lua local function inc(x) return x + 1 end local function add(x, y) return x * y end local function pow(x, y) return x ^ y end M.threadRight(2, inc, {add, 3}, {pow, 2}) -- => 64 M.threadRight(2, {add, 4}, inc, {pow, 2}) -- => 128 ```` ### dispatch (...) Returns a dispatching function. When called with arguments, this function invokes each of its functions in the passed-in order and returns the results of the first non-nil evaluation. ```lua local f = M.dispatch( function() return nil end, function (v) return v+1 end, function (v) return 2*v end ) f(5) -- => 6 f(7) -- => 8 ```` ### memoize (f) *Aliases: `cache`*. Memoizes a slow-running function. It caches the result for a specific input, so that the next time the function is called with the same input, it will lookup the result in its cache, instead of running again the function body. ```lua local function fibonacci(n) return n < 2 and n or fibonacci(n-1)+fibonacci(n-2) end local mem_fibonacci = M.memoize(fibonacci) fibonacci(20) -- => 6765 (but takes some time) mem_fibonacci(20) -- => 6765 (takes less time) ```` ### unfold (f, seed) Builds a list from a seed value. Accepts an iterator function, which returns either nil to stop iteration or two values : the value to add to the list of results and the seed to be used in the next call to the iterator function. ```lua local function f(v) if v < 100 then return v, v * 2 end end local t = M.unfold(f, 10) -- => {10,20,40,80} ```` ### once (f) Produces a function that runs only once. Successive calls to this function will still yield the same input. ```lua local sq = M.once(function(a) return a*a end) sq(1) -- => 1 sq(2) -- => 1 sq(3) -- => 1 sq(4) -- => 1 sq(5) -- => 1 ```` ### before (f, count) Returns a version of `f` that will run no more than `count` times. Next calls will keep yielding the results of the (n-th)-1 call. ```lua local function greet(someone) return 'hello '..someone end local greetOnly3people = M.before(greet, 3) greetOnly3people('John') -- => 'hello John' greetOnly3people('Moe') -- => 'hello Moe' greetOnly3people('James') -- => 'hello James' greetOnly3people('Joseph') -- => 'hello James' greetOnly3people('Allan') -- => 'hello James' ```` ### after (f, count) Produces a function that will respond only after a given number of calls. ```lua local f = M.after(M.identity,3) f(1) -- => nil f(2) -- => nil f(3) -- => 3 f(4) -- => 4 ```` ### compose (...) Composes functions. Each function consumes the return value of the one that follows. ```lua local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end local compositae = M.compose(f,g,h) compositae(10) -- => 36 compositae(20) -- => 121 ```` ### pipe (value, ...) Pipes a value through a series of functions. ```lua local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end M.pipe(10,f,g,h) -- => 36 M.pipe(20,f,g,h) -- => 121 ```` ### complement (f) Returns a function which returns the logical complement of a given function. ```lua M.complement(function() return true end)() -- => false ```` ### juxtapose (value, ...) *Aliases: `juxt`*. Calls a sequence of functions with the same input. ```lua local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end M.juxtapose(10, f, g, h) -- => 100, 11, 5 ```` ### wrap (f, wrapper) Wraps a function inside a wrapper. Allows the wrapper to execute code before and after function run. ```lua local greet = function(name) return "hi: " .. name end local greet_backwards = M.wrap(greet, function(f,arg) return f(arg) ..'\nhi: ' .. arg:reverse() end) greet_backwards('John') -- => hi: John -- => hi: nhoJ ```` ### times (iter [, n]) Calls a given function `n` times. ```lua local f = ('Lua programming'):gmatch('.') M.times(f, 3) -- => {'L','u','a'} ```` ### bind (f, v) Binds a value to be the first argument to a function. ```lua local sqrt2 = M.bind(math.sqrt,2) sqrt2() -- => 1.4142135623731 ```` ### bind2 (f, v) Binds a value to be the second argument to a function. ```lua local last2 = M.bind(M.last,2) last2({1,2,3,4,5,6}) -- => {5,6} ```` ### bindn (f, ...) Binds a variable number of values to be the first arguments to a function. ```lua local function out(...) return table.concat {...} end local out = M.bindn(out,'OutPut',':',' ') out(1,2,3) -- => OutPut: 123 out('a','b','c','d') -- => OutPut: abcd ```` ### bindall (obj, ...) Binds methods to object. As such, when calling any of these methods, they will receive object as a first argument. ```lua local window = { setPos = function(w,x,y) w.x, w.y = x, y end, setName = function(w,name) w.name = name end, getName = function(w) return w.name end, } window = M.bindall(window, 'setPos', 'setName', 'getName') window.setPos(10,15) print(window.x, window.y) -- => 10,15 window.setName('fooApp') print(window.name) -- => 'fooApp' print(window.getName()) -- => 'fooApp' ```` ### cond (conds) Returns a function which iterate over an array list of conditions. It invokes each predicate, passing it given values. It returns the value of the corresponding function of the first predicate to return a non-nil value ```lua local multipleOf = M.cond({ {function(v) return v%2==0 end, function(v) return v..' is multiple of 2' end}, {function(v) return v%3==0 end, function(v) return v..' is multiple of 3' end}, {function(v) return v%5==0 end, function(v) return v..' is multiple of 5' end}, {function() return true end, function(v) return 'could not find an answer for '..v end} }) for i = 15, 20 do print(multipleOf(i)) end -- => 15 is multiple of 3 -- => 16 is multiple of 2 -- => could not find an answer for 17 -- => 18 is multiple of 2 -- => could not find an answer for 19 -- => 20 is multiple of 2 ```` ### both (...) Returns a validation function. Given a set of functions, the validation function evaluates to `true` only when all its funcs returns `true`. ```lua local f = M.both( function(x) return x > 0 end, function(x) return x < 10 end, function(x) return x % 2 == 0 end ) f(2) -- => true f(8) -- => true f(9) -- => false ```` ### either (...) Returns a validation function. Given a set of functions, the validation function evaluates to `true` when one of its funcs returns `true`. ```lua local f = M.either( function(x) return x > 0 end, function(x) return x % 2 == 0 end ) f(0) -- => true f(-3) -- => false ```` ### neither (...) Returns a validation function. Given a set of functions, the validation function evaluates to `true` when neither of its funcs returns `true`. ```lua local f = M.neither( function(x) return x > 10 end, function(x) return x % 2 == 0 end ) f(12) -- => false f(8) -- => false f(7) -- => true ```` ### uniqueId ([template]) *Aliases: `uid`*. Returns an unique integer ID. ```lua M.uniqueId() -- => 1 ```` Can handle string templates for formatted output. ```lua M.uniqueId('ID%s') -- => 'ID2' ```` Or a function, for the same purpose. ```lua local formatter = function(ID) return '$'..ID..'$' end M.uniqueId(formatter) -- => '$ID1$' ```` ### iterator(f, value [, n]) *Aliases: `iter`*. Returns an iterator function which constinuously applies a function `f` onto an input `value`. For example, let us go through the powers of two using `iterator`. ```lua local function po2(x) return x*2 end local function iter_po2 = M.iterator(po2, 1) iter_po2() -- => 2 iter_po2() -- => 4 iter_po2() -- => 8 ```` if `n` is supplied, it will run at maximum `n` times. ```lua local function po2(x) return x*2 end local function iter_po2 = M.iterator(po2, 1, 3) iter_po2() -- => 2 iter_po2() -- => 4 iter_po2() -- => 8 iter_po2() -- => nil ```` ### skip (iter [, n = 1]) Consumes the first `n` values of a iterator then returns it. ```lua local w = "hello" local char = string.gmatch(w,'.') local iter = M.skip(char, 3) for w in iter do print(w) end -- => 'l', 'o' ```` `n` defaults to 1 when not given. ```lua local w = "hello" local char = string.gmatch(w,'.') local iter = M.skip(char) for w in iter do print(w) end -- => 'e', 'l', 'l', 'o' ```` ### tabulate (...) Iterates a given iterator function and returns its values packed in an array. ```lua local text = 'letters' local chars = string.gmatch(text, '.') M.tabulate(chars) -- => {'l','e','t','t','e','r','s'} ```` ### iterlen (...) Returns the length of an iterator. ```lua local text = 'letters' local chars = string.gmatch(text, '.') M.iterlen(chars) -- => 7 ```` It consumes the iterator itself. ```lua local text = 'lua' local chars = string.gmatch(text, '.') M.iterlen(chars) -- => 3 chars() -- => nil ```` ### castArray (value) Casts the passed-in value to an array containing the value itself. ```lua M.castArray(true) -- => {true} M.castArray(2) -- => {2} ```` It leaves the given value untouched in case it is already a table. ```lua local t = {1} print(M.castArray(t) == t) -- => true ```` ### flip (f) Creates a function of `f` with arguments flipped in reverse order. ```lua local function f(...) return table.concat({...}) end local flipped = M.flip(f) flipped('a','b','c') -- => 'cba' ```` ### nthArg(n) Returns a function that gets the nth argument. ```lua local f = M.nthArg(3) f('a','b','c') -- => 'c' ```` If n is negative, the nth argument from the end is returned. ```lua local f = M.nthArg(-2) f('a','b','c') -- => 'b' ```` ### unary (f) Returns a function which accepts up to one argument. It ignores any additional arguments. ```lua local f = M.unary(function (...) return ... end) f('a') - ==> 'a' f('a','b','c') -- => 'a' ```` ### ary (f [, n = 1]) *Aliases: `nAry`*. Returns a function which accepts up to `n` args. It ignores any additional arguments. ```lua local f = M.ary(function (...) return ... end, 2) f(1,2) - ==> 1,2 f(1,2,3,4) -- => 1,2 ```` If `n` is not given, it defaults to `1`. ```lua local f = M.unary(function (...) return ... end) f('a','b','c') -- => 'a' ```` ### noarg (f) Returns a function with an arity of 0. The new function ignores any arguments passed to it. ```lua local f = M.noarg(function (x) return x or 'default' end) f(1) -- => 'default' f(function() end, 3) -- => 'default' ```` ### rearg (f, indexes) Returns a function which runs with arguments arranged according to given `indexes`. ```lua local f = M.rearg(function (...) return ... end, {5,4,3,2,1}) f('a','b','c','d','e') -- => 'e','d','c','b','a' ```` ### over (...) Creates a function that invokes a set of transforms with the arguments it receives.
One can use use for example to get the tuple of min and max values from a set of values ```lua local minmax = M.over(math.min, math.max) minmax(5,10,12,4,3) -- => {3,12} ```` ### overEvery (...) Creates a validation function. The returned function checks if all of the given predicates return truthy when invoked with the arguments it receives. ```lua local function alleven(...) for i, v in ipairs({...}) do if v%2~=0 then return false end end return true end local function allpositive(...) for i, v in ipairs({...}) do if v < 0 then return false end end return true end local allok = M.overEvery(alleven, allpositive) allok(2,4,-1,8) -- => false allok(10,3,2,6) -- => false allok(8,4,6,10) -- => true ```` ### overSome (...) Creates a validation function. The returned function checks if any of the given predicates return truthy when invoked with the arguments it receives. ```lua local function alleven(...) for i, v in ipairs({...}) do if v%2~=0 then return false end end return true end local function allpositive(...) for i, v in ipairs({...}) do if v < 0 then return false end end return true end local anyok = M.overSome(alleven,allpositive) anyok(2,4,-1,8) -- => false anyok(10,3,2,6) -- => true anyok(-1,-5,-3) -- => false ```` ### overArgs (f, ...) Creates a function that invokes `f` with its arguments transformed ```lua local function f(x, y) return x, y end local function triple(x) retun x*3 end local function square(x) retun x^2 end local new_f = M.overArgs(f, triple, square) new_f(1,2) -- => 3, 4 new_f(10,10) -- => 30, 100 ```` In case the number of arguments is greater than the number of transforms, the remaining args will be left as-is. ```lua local function f(x, y, z) return x, y, z end local function triple(x) retun x*3 end local function square(x) retun x^2 end local new_f = M.overArgs(f, triple, square) new_f(1,2,3) -- => 3, 4, 3 new_f(10,10,10) -- => 30, 100, 10 ```` ### converge (f, g, h) Converges two functions into one. ```lua local function pow2(x) return x*x end local function pow3(x) return x*x*x end local function sum(a,b) return a+b end local poly = M.converge(sum, pow2, pow3) poly(5) -- => 150 (ie. 5*5 + 5*5*5) ```` ### partial (f, ...) Partially apply a function by filling in any number of its arguments. ```lua local function diff(a, b) return a - b end local diffFrom20 = M.partial(diff, 20) -- arg 'a' will be 20 by default diffFrom20(5) -- => 15 ```` The string `'_'` can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time. ```lua local function diff(a, b) return a - b end local remove5 = M.partial(diff, '_', 5) -- arg 'a' will be given at call-time, but 'b' is set to 5 remove5(20) -- => 15 ```` ### partialRight (f, ...) Like `M.partial`, it partially applies a function by filling in any number of its arguments, but from the right. ```lua local function concat(...) return table.concat({...},',') end local concat_right = M.partialRight(concat,'a','b','c') concat_right('d') -- => d,a,b,c concat_right = M.partialRight(concat,'a','b') concat_right('c','d') -- => c,d,a,b concat_right = M.partialRight(concat,'a') concat_right('b','c','d') -- => b,c,d,a ``` The string `'_'`, as always, can be used as a placeholder in the list of arguments to specify an argument that should not be pre-filled, but is rather left open to be supplied at call-time. In that case, the first args supplied at runtime will be used to fill the initial list of args while the remaining will be prepended. ```lua local function concat(...) return table.concat({...},',') end local concat_right = M.partialRight(concat,'a','_','c') concat_right('d','b') -- => b,a,d,c concat_right = M.partialRight(concat,'a','b','_') concat_right('c','d') -- => d,a,b,c concat_right = M.partialRight(concat,'_','a') concat_right('b','c','d') -- => c,d,b,a ```` ### curry (f [, n_args = 2]) Curries a function. If the given function `f` takes multiple arguments, it returns another version of `f` that takes a single argument (the first of the arguments to the original function) and returns a new function that takes the remainder of the arguments and returns the result. ```lua local function sumOf3args(x,y,z) return x + y + z end local curried_sumOf3args = M.curry(sumOf3args, 3) sumOf3args(1)(2)(3)) -- => 6 sumOf3args(0)(6)(9)) -- => 15 ```` `n_args` defaults to 2. ```lua local function product(x,y) return x * y end local curried_product = M.curry(product) curried_product(5)(4) -- => 20 curried_product(3)(-5) -- => -15 curried_product(0)(1) -- => 0 ```` ### time (f [, ...]) Returns the execution time of `f (...)` in seconds and its results. ```lua local function wait_count(n) local i = 0 while i < n do i = i + 1 end return i end local time, i = M.time(wait_count, 1e6) -- => 0.002 1000000 local time, i = M.time(wait_count, 1e7) -- => 0.018 10000000 ```` **[[⬆]](#TOC)** ## Object functions ### keys (obj) Collects the names of an object attributes. ```lua M.keys({1,2,3}) -- => "{1,2,3}" M.keys({x = 0, y = 1}) -- => "{'y','x'}" ```` ### values (obj) Collects the values of an object attributes. ```lua M.values({1,2,3}) -- => "{1,2,3}" M.values({x = 0, y = 1}) -- => "{1,0}" ```` ### path (obj, ...) Returns the value at a given path in an object. ```lua local entity = { pos = {x = 1, y = 2}, engine = { left = {status = 'active', damage = 5}, right = {status = 'off', damage = 10} }, boost = false } M.path(entity,'pos','x') -- => 1 M.path(entity,'pos','y') -- => 2 M.path(entity,'engine','left','status') -- => 'active' M.path(entity,'engine','right','damage') -- => 10 M.path(entity,'boost') -- => false ```` ### spreadPath (obj, ...) Spreads object under property path onto provided object. It is similar to `flattenPath`, but removes object under the property path. ```lua local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} M.spreadPath(obj, 'c', 'f') -- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {f = {}}} ```` ### flattenPath (obj, ...) Flattens object under property path onto provided object. It is similar to `spreadPath`, but preserves object under the property path. ```lua local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} M.spreadPath(obj, 'c', 'f') -- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}} ```` ### kvpairs (obj) Converts an object to an array-list of key-value pairs. ```lua local obj = {x = 1, y = 2, z = 3} M.each(M.kvpairs(obj), function(v,k) print(k, table.concat(v,',')) end) -- => 1 y,2 -- => 2 x,1 -- => 3 z,3 ```` ### toObj (kvpairs) Converts an array list of `kvpairs` to an object where keys are taken from the 1rst column in the `kvpairs` sequence, associated with values in the 2nd column. ```lua local list_pairs = {{'x',1},{'y',2},{'z',3}} obj = M.toObj(list_pairs) -- => {x = 1, y = 2, z = 3} ```` ### invert (obj) *Aliases: `mirror`*. Switches key-value pairs: ```lua M.invert {'a','b','c'} -- => "{a=1, b=2, c=3}" M.invert {x = 1, y = 2} -- => "{'x','y'}" ```` ### property (key) Returns a function that will return the key property of any passed-in object. ```lua local who = M.property('name') local people = {name = 'Henry'} who(people) -- => 'Henry' ```` ### propertyOf (obj) Returns a function that will return the key property of any passed-in object. ```lua local people = {name = 'Henry'} print(M.propertyOf(people)('name')) -- => 'Henry' ```` ### toBoolean (value) Converts a given value to a boolean. ```lua M.toBoolean(true) -- => true M.toBoolean(false) -- => false M.toBoolean(nil) -- => false M.toBoolean({}) -- => true M.toBoolean(1) -- => true ```` ### extend (destObj, ...) Extends a destination object with the properties of some source objects. ```lua M.extend({},{a = 'b', c = 'd'}) -- => "{a = 'b', c = 'd'}" ```` ### functions (obj [, recurseMt]) *Aliases: `methods`*. Returns all functions names within an object. ```lua M.functions(coroutine) -- => "{'yield','wrap','status','resume','running','create'}" ```` When given `recurseMt`, will also include `obj` metatable's functions. ````lua local mt = {print = print} local t = {assert = assert} setmetatable(t, {__index = mt}) M.functions(t, true) -- => "{'assert','print'}" ```` ### clone (obj [, shallow]) Clones a given object. ```lua local obj = {1,2,3} local obj2 = M.clone(obj) print(obj2 == obj) -- => false print(M.isEqual(obj2, obj)) -- => true ```` ### tap (obj, f) Invokes a given interceptor function on some object, and then returns the object itself. Useful to tap into method chaining to hook intermediate results. The passed-in interceptor should be prototyped as `f(obj,...)`. ```lua local v = M.chain({1,2,3,4,5,6,7,8,9,10}) :filter(function(v) return v%2~=0 end) -- retain odd values :tap(function(v) print('Max is', M.max(v) end) -- Tap max value :map(function(v) return v^2 end) :value() -- => Max is 89 ```` ### has (obj, key) Checks if an object has a given attribute. ```lua M.has(_,'has') -- => true M.has(coroutine,'resume') -- => true M.has(math,'random') -- => true ```` ### pick (obj, ...) *Aliases: `choose`*. Collects whilelisted properties of a given object. ```lua local object = {a = 1, b = 2, c = 3} M.pick(object,'a','c') -- => "{a = 1, c = 3}" ```` ### omit (obj, ...) *Aliases: `drop`*. Omits blacklisted properties of a given object. ```lua local object = {a = 1, b = 2, c = 3} M.omit(object,'a','c') -- => "{b = 2}" ```` ### template (obj [, template]) *Aliases: `defaults`*. Applies a template on an object, preserving existing properties. ```lua local obj = {a = 0} M.template(obj,{a = 1, b = 2, c = 3}) -- => "{a=0, c=3, b=2}" ```` ### isEqual (objA, objB [, useMt]) *Aliases: `compare`, `M.matches`*. Compares objects: ```lua M.isEqual(1,1) -- => true M.isEqual(true,false) -- => false M.isEqual(3.14,math.pi) -- => false M.isEqual({3,4,5},{3,4,{5}}) -- => false ```` ### result (obj, method) Calls an object method, passing it as a first argument the object itself. ```lua M.result('abc','len') -- => 3 M.result({'a','b','c'},table.concat) -- => 'abc' ```` ### isTable (t) Is the given argument an object (i.e a table) ? ```lua M.isTable({}) -- => true M.isTable(math) -- => true M.isTable(string) -- => true ```` ### isCallable (obj) Is the given argument callable ? ```lua M.isCallable(print) -- => true M.isCallable(function() end) -- => true M.isCallable(setmetatable({},{__index = string}).upper) -- => true M.isCallable(setmetatable({},{__call = function() return end})) -- => true ```` ### isArray (obj) Is the given argument an array (i.e. a sequence) ? ```lua M.isArray({}) -- => true M.isArray({1,2,3}) -- => true M.isArray({'a','b','c'}) -- => true ```` ### isIterable (obj) Checks if the given object is iterable with `pairs`. ```lua M.isIterable({}) -- => true M.isIterable(function() end) -- => false M.isIterable(false) -- => false M.isIterable(1) -- => false ```` ### type (obj) Extends Lua's `type` function. It returns the type of the given object and also recognises 'file' userdata ```lua M.type('string') -- => 'string' M.type(table) -- => 'table' M.type(function() end) -- => 'function' M.type(io.open('f','w')) -- => 'file' ```` ### isEmpty ([obj]) Is the given argument empty ? ```lua M.isEmpty('') -- => true M.isEmpty({}) -- => true M.isEmpty({'a','b','c'}) -- => false ```` ### isString (obj) Is the given argument a string ? ```lua M.isString('') -- => true M.isString('Hello') -- => false M.isString({}) -- => false ```` ### isFunction (obj) Is the given argument a function ? ```lua M.isFunction(print) -- => true M.isFunction(function() end) -- => true M.isFunction({}) -- => false ```` ### isNil (obj) Is the given argument nil ? ```lua M.isNil(nil) -- => true M.isNil() -- => true M.isNil({}) -- => false ```` ### isNumber (obj) Is the given argument a number ? ```lua M.isNumber(math.pi) -- => true M.isNumber(math.huge) -- => true M.isNumber(0/0) -- => true M.isNumber() -- => false ```` ### isNaN (obj) Is the given argument NaN ? ```lua M.isNaN(1) -- => false M.isNaN(0/0) -- => true ```` ### isFinite (obj) Is the given argument a finite number ? ```lua M.isFinite(99e99) -- => true M.isFinite(math.pi) -- => true M.isFinite(math.huge) -- => false M.isFinite(1/0) -- => false M.isFinite(0/0) -- => false ```` ### isBoolean (obj) Is the given argument a boolean ? ```lua M.isBoolean(true) -- => true M.isBoolean(false) -- => true M.isBoolean(1==1) -- => true M.isBoolean(print) -- => false ```` ### isInteger (obj) Is the given argument an integer ? ```lua M.isInteger(math.pi) -- => false M.isInteger(1) -- => true M.isInteger(-1) -- => true ```` **[[⬆]](#TOC)** ## Chaining *Method chaining* (also known as *name parameter idiom*), is a technique for invoking consecutively method calls in object-oriented style. Each method returns an object, and method calls are chained together. Moses offers chaining for your perusal.
Let's use chaining to get the count of evey single word in some lyrics (case won't matter here). ```lua local lyrics = { "I am a lumberjack and I am okay", "I sleep all night and I work all day", "He is a lumberjack and he is okay", "He sleeps all night and he works all day" } -- split a text into words local function words(line) local t = {} for w in line:gmatch('(%w+)') do t[#t+1] = w end return t end local stats = M.chain(lyrics) :map(words) :flatten() :countBy(string.lower) :value() -- => "{ -- => sleep = 1, night = 2, works = 1, am = 2, is = 2, -- => he = 2, and = 4, I = 4, he = 2, day = 2, a = 2, -- => work = 1, all = 4, okay = 2 -- => }" ```` For convenience, you can also use `M(value)` to start chaining methods, instead of `M.chain(value)`. Note that one can use `:value()` to unwrap a chained object. ```lua local t = {1,2,3} print(_(t):value() == t) -- => true ```` **[[⬆]](#TOC)** ## Import All library functions can be imported in a context using `import` into a specified context. ```lua local context = {} M.import(context) context.each({1,2,3},print) -- => 1 1 -- => 2 2 -- => 3 3 ```` When no `context` was provided, it defaults to the current environment, `_ENV` or `_G`. ```lua M.import() each({1,2,3},print) -- => 1 1 -- => 2 2 -- => 3 3 ```` Passing `noConflict` argument leaves untouched conflicting keys while importing into the context. ```lua local context = {each = 1} M.import(context, true) print(context.each) -- => 1 context.eachi({1,2,3},print) -- => 1 1 -- => 2 2 -- => 3 3 ```` **[[⬆]](#TOC)** Moses-Moses-2.1.0-1/moses.lua000066400000000000000000002611411334620647700156740ustar00rootroot00000000000000--- Utility-belt library for functional programming in Lua ([source](http://github.com/Yonaba/Moses)) -- @author [Roland Yonaba](http://github.com/Yonaba) -- @copyright 2012-2018 -- @license [MIT](http://www.opensource.org/licenses/mit-license.php) -- @release 2.1.0 -- @module moses -- @set sort=true local _MODULEVERSION = '2.1.0' -- Internalisation local next, type, pcall = next, type, pcall local setmetatable, getmetatable = setmetatable, getmetatable local t_insert, t_sort = table.insert, table.sort local t_remove,t_concat = table.remove, table.concat local randomseed, random, huge = math.randomseed, math.random, math.huge local floor, max, min, ceil = math.floor, math.max, math.min, math.ceil local wrap = coroutine.wrap local yield = coroutine.yield local rawget = rawget local unpack = table.unpack or unpack local pairs,ipairs = pairs,ipairs local error = error local clock = os.clock local M = {} -- ======== Private helpers local function f_max(a,b) return a>b end local function f_min(a,b) return a0 then while (#s < n and pad) do s[#s+1] = pad end f(s) end end end local function partgen2(t, n, f, pad) -- generates overlapping array partitions for i = 0, #t, n-1 do local s = M.slice(t, i+1, i+n) if #s>0 and i+1<#t then while (#s < n and pad) do s[#s+1] = pad end f(s) end end end local function partgen3(t, n, f, pad) -- generates sliding array partitions for i = 0, #t, 1 do local s = M.slice(t, i+1, i+n) if #s>0 and i+n<=#t then while (#s < n and pad) do s[#s+1] = pad end f(s) end end end local function permgen(t, n, f) -- taken from PiL: http://www.lua.org/pil/9.3.html if n == 0 then f(t) end for i = 1,n do t[n], t[i] = t[i], t[n] permgen(t, n-1, f) t[n], t[i] = t[i], t[n] end end local function signum(a) return a>=0 and 1 or -1 end -- Internal counter for unique ids generation local unique_id_counter = -1 --- Operator functions -- @section Operator functions M.operator = {} --- Returns a + b. Aliased as `op.add`. -- @name operator.add -- @param a a value -- @param b a value -- @return a + b M.operator.add = function(a,b) return a + b end --- Returns a - b. Aliased as `op.sub`. -- @name operator.sub -- @param a a value -- @param b a value -- @return a - b M.operator.sub = function(a,b) return a - b end --- Returns a * b. Aliased as `op.mul`. -- @name operator.mul -- @param a a value -- @param b a value -- @return a * b M.operator.mul = function(a,b) return a * b end --- Returns a / b. Aliased as `op.div`. -- @name operator.div -- @param a a value -- @param b a value -- @return a / b M.operator.div = function(a,b) return a / b end --- Returns a % b. Aliased as `op.mod`. -- @name operator.mod -- @param a a value -- @param b a value -- @return a % b M.operator.mod = function(a,b) return a % b end --- Returns a ^ b. Aliased as `op.exp`, `op.pow`. -- @name operator.exp -- @param a a value -- @param b a value -- @return a ^ b M.operator.exp = function(a,b) return a ^ b end M.operator.pow = M.operator.exp --- Returns -a. Aliased as `op.unm`, `op.neg`. -- @name operator.unm -- @param a a value -- @return -a M.operator.unm = function(a) return -a end M.operator.neg = M.operator.unm --- Performs floor division (//) between `a` and `b`. It rounds the quotient towards minus infinity. -- Aliased as `op.floordiv`. -- @name operator.floordiv -- @param a a value -- @param b a value -- @return a // b M.operator.floordiv = function(a, b) return floor(a/b) end --- Performs integer division between `a` and `b`. Aliased as `op.intdiv`. -- @name operator.intdiv -- @param a a value -- @param b a value -- @return a / b M.operator.intdiv = function(a,b) return a>=0 and floor(a/b) or ceil(a/b) end --- Checks if a equals b. Aliased as `op.eq`. -- @name operator.eq -- @param a a value -- @param b a value -- @return a == b M.operator.eq = function(a,b) return a == b end --- Checks if a not equals b. Aliased as `op.neq`. -- @name operator.neq -- @param a a value -- @param b a value -- @return a ~= b M.operator.neq = function(a,b) return a ~= b end --- Checks if a is strictly less than b. Aliased as `op.lt`. -- @name operator.lt -- @param a a value -- @param b a value -- @return a < b M.operator.lt = function(a,b) return a < b end --- Checks if a is strictly greater than b. Aliased as `op.gt`. -- @name operator.gt -- @param a a value -- @param b a value -- @return a > b M.operator.gt = function(a,b) return a > b end --- Checks if a is less or equal to b. Aliased as `op.le`. -- @name operator.le -- @param a a value -- @param b a value -- @return a <= b M.operator.le = function(a,b) return a <= b end --- Checks if a is greater or equal to b. Aliased as `op.ge`. -- @name operator.ge -- @param a a value -- @param b a value -- @return a >= b M.operator.ge = function(a,b) return a >= b end --- Returns logical a and b. Aliased as `op.land`. -- @name operator.ge -- @param a a value -- @param b a value -- @return a and b M.operator.land = function(a,b) return a and b end --- Returns logical a or b. Aliased as `op.lor`. -- @name operator.lor -- @param a a value -- @param b a value -- @return a or b M.operator.lor = function(a,b) return a or b end --- Returns logical not a. Aliased as `op.lnot`. -- @name operator.lnot -- @param a a value -- @return not a M.operator.lnot = function(a) return not a end --- Returns concatenation of a and b. Aliased as `op.concat`. -- @name operator.concat -- @param a a value -- @param b a value -- @return a .. b M.operator.concat = function(a,b) return a..b end --- Returns the length of a. Aliased as `op.len`. -- @name operator.length -- @param a a value -- @return #a M.operator.length = function(a) return #a end M.operator.len = M.operator.length --- Table functions -- @section Table functions --- Clears a table. All its values become nil. -- @name clear -- @param t a table -- @return the given table, cleared. function M.clear(t) for k in pairs(t) do t[k] = nil end return t end --- Iterates on key-value pairs, calling `f (v, k)` at every step. --
Aliased as `forEach`. -- @name each -- @param t a table -- @param f a function, prototyped as `f (v, k)` -- @see eachi function M.each(t, f) for index,value in pairs(t) do f(value, index) end end --- Iterates on integer key-value pairs, calling `f(v, k)` every step. -- Only applies to values located at integer keys. The table can be a sparse array. -- Iteration will start from the lowest integer key found to the highest one. --
Aliased as `forEachi`. -- @name eachi -- @param t a table -- @param f a function, prototyped as `f (v, k)` -- @see each function M.eachi(t, f) local lkeys = M.sort(M.select(M.keys(t), M.isInteger)) for k, key in ipairs(lkeys) do f(t[key], key) end end --- Collects values at given keys and return them wrapped in an array. -- @name at -- @param t a table -- @param ... A variable number of keys to collect values -- @return an array-list of values function M.at(t, ...) local values = {} for i, key in ipairs({...}) do values[#values+1] = t[key] end return values end --- Adjusts the value at a given key using a function or a value. In case `f` is a function, -- it should be prototyped `f(v)`. It does not mutate the given table, but rather -- returns a new array. In case the given `key` does not exist in `t`, it throws an error. -- @param t a table -- @param key a key -- @param f a function, prototyped as `f(v)` or a value function M.adjust(t, key, f) if (t[key] == nil) then error("key not existing in table") end local _t = M.clone(t) _t[key] = type(f) == 'function' and f(_t[key]) or f return _t end --- Counts occurrences of a given value in a table. Uses @{isEqual} to compare values. -- @name count -- @param t a table -- @param[opt] val a value to be searched in the table. If not given, the @{size} of the table will be returned -- @return the count of occurrences of the given value -- @see countf -- @see size function M.count(t, val) if val == nil then return M.size(t) end local count = 0 for k, v in pairs(t) do if M.isEqual(v, val) then count = count + 1 end end return count end --- Counts the number of values passing a predicate test. Same as @{count}, but uses an iterator. -- Returns the count for values passing the test `f (v, k)` -- @name countf -- @param t a table -- @param f an iterator function, prototyped as `f (v, k)` -- @return the count of values validating the predicate -- @see count -- @see size function M.countf(t, f) local count = 0 for k, v in pairs(t) do if f(v, k) then count = count + 1 end end return count end --- Checks if all values in a collection are equal. Uses an optional `comp` function which is used -- to compare values and defaults to @{isEqual} when not given. --
Aliased as `alleq`. -- @name allEqual -- @param t a table -- @param[opt] comp a comparison function. Defaults to `isEqual` -- @return `true` when all values in `t` are equal, `false` otherwise. -- @see isEqual function M.allEqual(t, comp) local k, pivot = next(t) for k, v in pairs(t) do if comp then if not comp(pivot, v) then return false end else if not M.isEqual(pivot, v) then return false end end end return true end --- Loops `n` times through a table. In case `n` is omitted, it will loop forever. -- In case `n` is lower or equal to 0, it returns an empty function. --
Aliased as `loop`. -- @name cycle -- @param t a table -- @param[opt] n the number of loops -- @return an iterator function yielding value-key pairs from the passed-in table. function M.cycle(t, n) n = n or 1 if n<=0 then return M.noop end local k, fk local i = 0 while true do return function() k = k and next(t,k) or next(t) fk = not fk and k or fk if n then i = (k==fk) and i+1 or i if i > n then return end end return t[k], k end end end --- Maps `f (v, k)` on value-key pairs, collects and returns the results. --
Aliased as `collect`. -- @name map -- @param t a table -- @param f an iterator function, prototyped as `f (v, k)` -- @return a table of results function M.map(t, f) local _t = {} for index,value in pairs(t) do local k, kv, v = index, f(value, index) _t[v and kv or k] = v or kv end return _t end --- Reduces a table, left-to-right. Folds the table from the first element to the last element -- to a single value, using a given iterator and an initial state. -- The iterator takes a state and a value and returns a new state. --
Aliased as `inject`, `foldl`. -- @name reduce -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @param[opt] state an initial state of reduction. Defaults to the first value in the table. -- @return the final state of reduction -- @see best -- @see reduceRight -- @see reduceBy function M.reduce(t, f, state) for k,value in pairs(t) do if state == nil then state = value else state = f(state,value) end end return state end --- Returns the best value passing a selector function. Acts as a special case of -- @{reduce}, using the first value in `t` as an initial state. It thens folds the given table, -- testing each of its values `v` and selecting the value passing the call `f(state,v)` every time. -- @name best -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @return the final state of reduction -- @see reduce -- @see reduceRight -- @see reduceBy function M.best(t, f) local _, state = next(t) for k,value in pairs(t) do if state == nil then state = value else state = f(state,value) and state or value end end return state end --- Reduces values in a table passing a given predicate. Folds the table left-to-right, considering -- only values validating a given predicate. -- @name reduceBy -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @param pred a predicate function `pred (v, k)` to select values to be considered for reduction -- @param[opt] state an initial state of reduction. Defaults to the first value in the table of selected values. -- @param[optchain] ... optional args to be passed to `pred` -- @return the final state of reduction -- @see reduce -- @see best -- @see reduceRight function M.reduceBy(t, f, pred, state) return M.reduce(M.select(t, pred), f, state) end --- Reduces a table, right-to-left. Folds the table from the last element to the first element -- to single value, using a given iterator and an initial state. -- The iterator takes a state and a value, and returns a new state. --
Aliased as `injectr`, `foldr`. -- @name reduceRight -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @param[opt] state an initial state of reduction. Defaults to the last value in the table. -- @return the final state of reduction -- @see reduce -- @see best -- @see reduceBy function M.reduceRight(t, f, state) return M.reduce(M.reverse(t),f,state) end --- Reduces a table while saving intermediate states. Folds the table left-to-right -- using a given iterator and an initial state. The iterator takes a state and a value, -- and returns a new state. The result is an array of intermediate states. --
Aliased as `mapr` -- @name mapReduce -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @param[opt] state an initial state of reduction. Defaults to the first value in the table. -- @return an array of states -- @see mapReduceRight function M.mapReduce(t, f, state) local _t = {} for i,value in pairs(t) do _t[i] = not state and value or f(state,value) state = _t[i] end return _t end --- Reduces a table while saving intermediate states. Folds the table right-to-left -- using a given iterator and an initial state. The iterator takes a state and a value, -- and returns a new state. The result is an array of intermediate states. --
Aliased as `maprr` -- @name mapReduceRight -- @param t a table -- @param f an iterator function, prototyped as `f (state, value)` -- @param[opt] state an initial state of reduction. Defaults to the last value in the table. -- @return an array of states -- @see mapReduce function M.mapReduceRight(t, f, state) return M.mapReduce(M.reverse(t),f,state) end --- Performs a linear search for a value in a table. It does not work for nested tables. -- The given value can be a function prototyped as `f (v, value)` which should return true when -- any v in the table equals the value being searched. --
Aliased as `any`, `some`, `contains` -- @name include -- @param t a table -- @param value a value to search for -- @return a boolean : `true` when found, `false` otherwise -- @see detect function M.include(t, value) local _iter = (type(value) == 'function') and value or M.isEqual for k,v in pairs(t) do if _iter(v,value) then return true end end return false end --- Performs a linear search for a value in a table. Returns the key of the value if found. -- The given value can be a function prototyped as `f (v, value)` which should return true when -- any v in the table equals the value being searched. This function is similar to @{find}, -- which is mostly meant to work with array. -- @name detect -- @param t a table -- @param value a value to search for -- @return the key of the value when found or __nil__ -- @see include -- @see find function M.detect(t, value) local _iter = (type(value) == 'function') and value or M.isEqual for key,arg in pairs(t) do if _iter(arg,value) then return key end end end --- Returns all values having specified keys `props`. -- @name where -- @param t a table -- @param props a set of keys -- @return an array of values from the passed-in table -- @see findWhere function M.where(t, props) local r = M.select(t, function(v) for key in pairs(props) do if v[key] ~= props[key] then return false end end return true end) return #r > 0 and r or nil end --- Returns the first value having specified keys `props`. -- @name findWhere -- @param t a table -- @param props a set of keys -- @return a value from the passed-in table -- @see where function M.findWhere(t, props) local index = M.detect(t, function(v) for key in pairs(props) do if props[key] ~= v[key] then return false end end return true end) return index and t[index] end --- Selects and returns values passing an iterator test. --
Aliased as `filter`. -- @name select -- @param t a table -- @param f an iterator function, prototyped as `f (v, k)` -- @return the selected values -- @see reject function M.select(t, f) local _t = {} for index,value in pairs(t) do if f(value,index) then _t[#_t+1] = value end end return _t end --- Clones a table while dropping values passing an iterator test. --
Aliased as `discard` -- @name reject -- @param t a table -- @param f an iterator function, prototyped as `f (v, k)` -- @return the remaining values -- @see select function M.reject(t, f) local _t = {} for index,value in pairs (t) do if not f(value,index) then _t[#_t+1] = value end end return _t end --- Checks if all values in a table are passing an iterator test. --
Aliased as `every` -- @name all -- @param t a table -- @param f an iterator function, prototyped as `f (v, k)` -- @return `true` if all values passes the predicate, `false` otherwise function M.all(t, f) for index,value in pairs(t) do if not f(value,index) then return false end end return true end --- Invokes a method on each value in a table. -- @name invoke -- @param t a table -- @param method a function, prototyped as `f (v, k)` -- @return the result of the call `f (v, k)` -- @see pluck function M.invoke(t, method) return M.map(t, function(v, k) if (type(v) == 'table') then if v[method] then if M.isCallable(v[method]) then return v[method](v,k) else return v[method] end else if M.isCallable(method) then return method(v,k) end end elseif M.isCallable(method) then return method(v,k) end end) end --- Extracts values in a table having a given key. -- @name pluck -- @param t a table -- @param key a key, will be used to index in each value: `value[key]` -- @return an array of values having the given key function M.pluck(t, key) local _t = {} for k, v in pairs(t) do if v[key] then _t[#_t+1] = v[key] end end return _t end --- Returns the max value in a collection. If a `transform` function is passed, it will -- be used to evaluate values by which all objects will be sorted. -- @name max -- @param t a table -- @param[opt] transform a transformation function, prototyped as `transform (v, k)`, defaults to @{identity} -- @return the max value found -- @see min function M.max(t, transform) return extract(t, f_max, transform) end --- Returns the min value in a collection. If a `transform` function is passed, it will -- be used to evaluate values by which all objects will be sorted. -- @name min -- @param t a table -- @param[opt] transform a transformation function, prototyped as `transform (v, k)`, defaults to @{identity} -- @return the min value found -- @see max function M.min(t, transform) return extract(t, f_min, transform) end --- Checks if two tables are the same. It compares if both tables features the same values, -- but not necessarily at the same keys. -- @name same -- @param a a table -- @param b another table -- @return `true` or `false` function M.same(a, b) return M.all(a, function(v) return M.include(b,v) end) and M.all(b, function(v) return M.include(a,v) end) end --- Sorts a table, in-place. If a comparison function is given, it will be used to sort values. -- @name sort -- @param t a table -- @param[opt] comp a comparison function prototyped as `comp (a, b)`, defaults to < operator. -- @return the given table, sorted. -- @see sortBy function M.sort(t, comp) t_sort(t, comp) return t end --- Iterates on values with respect to key order. Keys are sorted using `comp` function -- which defaults to `math.min`. It returns upon each call a `key, value` pair. -- @name sortedk -- @param t a table -- @param[opt] comp a comparison function. Defaults to `<` operator -- @return an iterator function -- @see sortedv function M.sortedk(t, comp) local keys = M.keys(t) t_sort(keys, comp) local i = 0 return function () i = i + 1 return keys[i], t[keys[i]] end end --- Iterates on values with respect to values order. Values are sorted using `comp` function -- which defaults to `math.min`. It returns upon each call a `key, value` pair. -- @name sortedv -- @param t a table -- @param[opt] comp a comparison function. Defaults to `<` operator -- @return an iterator function -- @see sortedk function M.sortedv(t, comp) local keys = M.keys(t) comp = comp or f_min t_sort(keys, function(a,b) return comp(t[a],t[b]) end) local i = 0 return function () i = i + 1 return keys[i], t[keys[i]] end end --- Sorts a table in-place using a transform. Values are ranked in a custom order of the results of -- running `transform (v)` on all values. `transform` may also be a string name property sort by. -- `comp` is a comparison function. -- @name sortBy -- @param t a table -- @param[opt] transform a `transform` function to sort elements prototyped as `transform (v)`. Defaults to @{identity} -- @param[optchain] comp a comparison function, defaults to the `<` operator -- @return a new array of sorted values -- @see sort function M.sortBy(t, transform, comp) local f = transform or M.identity if (type(transform) == 'string') then f = function(t) return t[transform] end end comp = comp or f_min t_sort(t, function(a,b) return comp(f(a), f(b)) end) return t end --- Splits a table into subsets groups. -- @name groupBy -- @param t a table -- @param iter an iterator function, prototyped as `iter (v, k)` -- @return a table of subsets groups function M.groupBy(t, iter) local _t = {} for k,v in pairs(t) do local _key = iter(v,k) if _t[_key] then _t[_key][#_t[_key]+1] = v else _t[_key] = {v} end end return _t end --- Groups values in a collection and counts them. -- @name countBy -- @param t a table -- @param iter an iterator function, prototyped as `iter (v, k)` -- @return a table of subsets groups names paired with their count function M.countBy(t, iter) local stats = {} for i,v in pairs(t) do local key = iter(v,i) stats[key] = (stats[key] or 0)+1 end return stats end --- Counts the number of values in a collection. If being passed more than one argument -- it will return the count of all passed-in arguments. -- @name size -- @param[opt] ... Optional variable number of arguments -- @return a count -- @see count -- @see countf function M.size(...) local args = {...} local arg1 = args[1] return (type(arg1) == 'table') and count(args[1]) or count(args) end --- Checks if all the keys of `other` table exists in table `t`. It does not -- compares values. The test is not commutative, i.e table `t` may contains keys -- not existing in `other`. -- @name containsKeys -- @param t a table -- @param other another table -- @return `true` or `false` -- @see sameKeys function M.containsKeys(t, other) for key in pairs(other) do if not t[key] then return false end end return true end --- Checks if both given tables have the same keys. It does not compares values. -- @name sameKeys -- @param tA a table -- @param tB another table -- @return `true` or `false` -- @see containsKeys function M.sameKeys(tA, tB) for key in pairs(tA) do if not tB[key] then return false end end for key in pairs(tB) do if not tA[key] then return false end end return true end --- Array functions -- @section Array functions --- Samples `n` random values from an array. If `n` is not specified, returns a single element. -- It uses internally @{shuffle} to shuffle the array before sampling values. If `seed` is passed, -- it will be used for shuffling. -- @name sample -- @param array an array -- @param[opt] n a number of elements to be sampled. Defaults to 1. -- @param[optchain] seed an optional seed for shuffling -- @return an array of selected values -- @see sampleProb function M.sample(array, n, seed) n = n or 1 if n == 0 then return {} end if n == 1 then if seed then randomseed(seed) end return {array[random(1, #array)]} end return M.slice(M.shuffle(array, seed), 1, n) end --- Return elements from a sequence with a given probability. It considers each value independently. -- Providing a seed will result in deterministic sampling. Given the same seed it will return the same sample -- every time. -- @name sampleProb -- @param array an array -- @param prob a probability for each element in array to be selected -- @param[opt] seed an optional seed for deterministic sampling -- @return an array of selected values -- @see sample function M.sampleProb(array, prob, seed) if seed then randomseed(seed) end local t = {} for k, v in ipairs(array) do if random() < prob then t[#t+1] = v end end return t end --- Returns the n-top values satisfying a predicate. It takes a comparison function -- `comp` used to sort array values, and then picks the top n-values. It leaves the original array untouched. -- @name nsorted -- @param array an array -- @param[opt] n a number of values to retrieve. Defaults to 1. -- @param[optchain] comp a comparison function. Defaults to `<` operator. -- @return an array of top n values function M.nsorted(array, n, comp) comp = comp or f_min n = n or 1 local values, count = {}, 0 for k, v in M.sortedv(array, comp) do if count < n then count = count + 1 values[count] = v end end return values end --- Returns a shuffled copy of a given array. If a seed is provided, it will -- be used to init the built-in pseudo random number generator (using `math.randomseed`). -- @name shuffle -- @param array an array -- @param[opt] seed a seed -- @return a shuffled copy of the given array function M.shuffle(array, seed) if seed then randomseed(seed) end local _shuffled = {} for index, value in ipairs(array) do local randPos = floor(random()*index)+1 _shuffled[index] = _shuffled[randPos] _shuffled[randPos] = value end return _shuffled end --- Converts a list of arguments to an array. -- @name pack -- @param ... a list of arguments -- @return an array of all passed-in args function M.pack(...) return {...} end --- Looks for the first occurrence of a given value in an array. Returns the value index if found. -- Uses @{isEqual} to compare values. -- @name find -- @param array an array of values -- @param value a value to lookup for -- @param[opt] from the index from where the search will start. Defaults to 1. -- @return the index of the value if found in the array, `nil` otherwise. -- @see detect function M.find(array, value, from) for i = from or 1, #array do if M.isEqual(array[i], value) then return i end end end --- Returns an array where values are in reverse order. The passed-in array should not be sparse. -- @name reverse -- @param array an array -- @return a reversed array function M.reverse(array) local _array = {} for i = #array,1,-1 do _array[#_array+1] = array[i] end return _array end --- Replaces elements in a given array with a given value. In case `i` and `j` are given -- it will only replaces values at indexes between `[i,j]`. In case `j` is greater than the array -- size, it will append new values, increasing the array size. -- @name fill -- @param array an array -- @param value a value -- @param[opt] i the index from which to start replacing values. Defaults to 1. -- @param[optchain] j the index where to stop replacing values. Defaults to the array size. -- @return the original array with values changed function M.fill(array, value, i, j) j = j or M.size(array) for i = i or 1, j do array[i] = value end return array end --- Returns an array of `n` zeros. -- @name zeros -- @param n a number -- @return an array -- @see ones -- @see vector function M.zeros(n) return M.fill({}, 0, 1, n) end --- Returns an array of `n` 1's. -- @name ones -- @param n a number -- @return an array -- @see zeros -- @see vector function M.ones(n) return M.fill({}, 1, 1, n) end --- Returns an array of `n` times a given value. -- @name vector -- @param value a value -- @param n a number -- @return an array -- @see zeros -- @see ones function M.vector(value, n) return M.fill({}, value, 1, n) end --- Collects values from a given array. The passed-in array should not be sparse. -- This function collects values as long as they satisfy a given predicate and returns on the first falsy test. --
Aliased as `takeWhile` -- @name selectWhile -- @param array an array -- @param f an iterator function prototyped as `f (v, k)` -- @return a new table containing all values collected -- @see dropWhile function M.selectWhile(array, f) local t = {} for i,v in ipairs(array) do if f(v,i) then t[i] = v else break end end return t end --- Collects values from a given array. The passed-in array should not be sparse. -- This function collects values as long as they do not satisfy a given predicate and returns on the first truthy test. --
Aliased as `rejectWhile` -- @name dropWhile -- @param array an array -- @param f an iterator function prototyped as `f (v, k)` -- @return a new table containing all values collected -- @see selectWhile function M.dropWhile(array, f) local _i for i,v in ipairs(array) do if not f(v, i) then _i = i break end end if (_i == nil) then return {} end return M.rest(array,_i) end --- Returns the index at which a value should be inserted. This index is evaluated so -- that it maintains the sort. If a comparison function is passed, it will be used to sort -- values. -- @name sortedIndex -- @param array an array -- @param the value to be inserted -- @param[opt] comp an comparison function prototyped as `f (a, b)`, defaults to < operator. -- @param[optchain] sort whether or not the passed-in array should be sorted -- @return number the index at which the passed-in value should be inserted function M.sortedIndex(array, value, comp, sort) local _comp = comp or f_min if (sort == true) then t_sort(array,_comp) end for i = 1,#array do if not _comp(array[i],value) then return i end end return #array+1 end --- Returns the index of the first occurrence of value in an array. -- @name indexOf -- @param array an array -- @param value the value to search for -- @return the index of the passed-in value -- @see lastIndexOf function M.indexOf(array, value) for k = 1,#array do if array[k] == value then return k end end end --- Returns the index of the last occurrence of value in an array. -- @name lastIndexOf -- @param array an array -- @param value the value to search for -- @return the index of the last occurrence of the passed-in value or __nil__ -- @see indexOf function M.lastIndexOf(array, value) local key = M.indexOf(M.reverse(array),value) if key then return #array-key+1 end end --- Returns the first index at which a predicate returns true. -- @name findIndex -- @param array an array -- @param pred a predicate function prototyped as `pred (v, k)` -- @return the index found or __nil__ -- @see findLastIndex function M.findIndex(array, pred) for k = 1, #array do if pred(array[k],k) then return k end end end --- Returns the last index at which a predicate returns true. -- @name findLastIndex -- @param array an array -- @param pred a predicate function prototyped as `pred (k, v)` -- @return the index found or __nil__ -- @see findIndex function M.findLastIndex(array, pred) local key = M.findIndex(M.reverse(array),pred) if key then return #array-key+1 end end --- Adds all passed-in values at the top of an array. The last elements will bubble to the -- top of the given array. -- @name addTop -- @param array an array -- @param ... a variable number of arguments -- @return the passed-in array with new values added -- @see prepend -- @see push function M.addTop(array, ...) for k,v in ipairs({...}) do t_insert(array,1,v) end return array end --- Adds all passed-in values at the top of an array. As opposed to @{addTop}, it preserves the order -- of the passed-in elements. -- @name prepend -- @param array an array -- @param ... a variable number of arguments -- @return the passed-in array with new values added -- @see addTop -- @see push function M.prepend(array, ...) return M.append({...}, array) end --- Pushes all passed-in values at the end of an array. -- @name push -- @param array an array -- @param ... a variable number of arguments -- @return the passed-in array with new added values -- @see addTop -- @see prepend function M.push(array, ...) local args = {...} for k,v in ipairs({...}) do array[#array+1] = v end return array end --- Removes and returns the values at the top of a given array. --
Aliased as `pop` -- @name shift -- @param array an array -- @param[opt] n the number of values to be popped. Defaults to 1. -- @return the popped values -- @see unshift function M.shift(array, n) n = min(n or 1, #array) local ret = {} for i = 1, n do local retValue = array[1] ret[#ret + 1] = retValue t_remove(array,1) end return unpack(ret) end --- Removes and returns the values at the end of a given array. -- @name unshift -- @param array an array -- @param[opt] n the number of values to be unshifted. Defaults to 1. -- @return the values -- @see shift function M.unshift(array, n) n = min(n or 1, #array) local ret = {} for i = 1, n do local retValue = array[#array] ret[#ret + 1] = retValue t_remove(array) end return unpack(ret) end --- Removes all provided values in a given array. --
Aliased as `remove` -- @name pull -- @param array an array -- @param ... a variable number of values to be removed from the array -- @return the passed-in array with values removed function M.pull(array, ...) local values = {...} for i = #array, 1, -1 do local remval = false for k, rmValue in ipairs(values) do if (remval == false) then if M.isEqual(array[i], rmValue) then t_remove(array, i) remval = true end end end end return array end --- Removes values at an index within the range `[start, finish]`. --
Aliased as `rmRange`, `chop` -- @name removeRange -- @param array an array -- @param[opt] start the lower bound index, defaults to the first index in the array. -- @param[optchain] finish the upper bound index, defaults to the array length. -- @return the passed-in array with values removed function M.removeRange(array, start, finish) start = start or 1 finish = finish or #array if start > finish then error("start cannot be greater than finish.") end for i = finish, start, -1 do t_remove(array, i) end return array end --- Chunks together consecutive values. Values are chunked on the basis of the return -- value of a provided predicate `f (v, k)`. Consecutive elements which return -- the same value are chunked together. Leaves the first argument untouched if it is not an array. -- @name chunk -- @param array an array -- @param f an iterator function prototyped as `f (v, k)` -- @return a table of chunks (arrays) -- @see zip function M.chunk(array, f) local ch, ck, prev, val = {}, 0 for k,v in ipairs(array) do val = f(v, k) prev = (prev==nil) and val or prev ck = ((val~=prev) and (ck+1) or ck) if not ch[ck] then ch[ck] = {array[k]} else ch[ck][#ch[ck]+1] = array[k] end prev = val end return ch end --- Slices values indexed within `[start, finish]` range. --
Aliased as `M.sub` -- @name slice -- @param array an array -- @param[opt] start the lower bound index, defaults to the first index in the array. -- @param[optchain] finish the upper bound index, defaults to the array length. -- @return a new array of sliced values function M.slice(array, start, finish) local t = {} for k = start or 1, finish or #array do t[#t+1] = array[k] end return t end --- Returns the first N values in an array. --
Aliased as `head`, `take` -- @name first -- @param array an array -- @param[opt] n the number of values to be collected, defaults to 1. -- @return a new array -- @see initial -- @see last -- @see rest function M.first(array, n) n = n or 1 local t = {} for k = 1, n do t[k] = array[k] end return t end --- Returns all values in an array excluding the last N values. -- @name initial -- @param array an array -- @param[opt] n the number of values to be left, defaults to the array length. -- @return a new array -- @see first -- @see last -- @see rest function M.initial(array, n) local l = #array n = n and l-(min(n,l)) or l-1 local t = {} for k = 1, n do t[k] = array[k] end return t end --- Returns the last N values in an array. -- @name last -- @param array an array -- @param[opt] n the number of values to be collected, defaults to the array length. -- @return a new array -- @see first -- @see initial -- @see rest function M.last(array, n) local l = #array n = n and l-min(n-1,l-1) or 2 local t = {} for k = n, l do t[#t+1] = array[k] end return t end --- Returns all values after index. --
Aliased as `tail` -- @name rest -- @param array an array -- @param[opt] index an index, defaults to 1 -- @return a new array -- @see first -- @see initial -- @see last function M.rest(array, index) local t = {} for k = index or 1, #array do t[#t+1] = array[k] end return t end --- Returns the value at a given index. -- @name nth -- @param array an array -- @param index an index -- @return the value at the given index function M.nth(array, index) return array[index] end --- Returns all truthy values (removes `falses` and `nils`). -- @name compact -- @param array an array -- @return a new array function M.compact(array) local t = {} for k,v in pairs(array) do if v then t[#t+1] = v end end return t end --- Flattens a nested array. Passing `shallow` will only flatten at the first level. -- @name flatten -- @param array an array -- @param[opt] shallow specifies the flattening depth. Defaults to `false`.` -- @return a flattened array function M.flatten(array, shallow) shallow = shallow or false local new_flattened local _flat = {} for key,value in ipairs(array) do if type(value) == 'table' then new_flattened = shallow and value or M.flatten (value) for k,item in ipairs(new_flattened) do _flat[#_flat+1] = item end else _flat[#_flat+1] = value end end return _flat end --- Returns values from an array not present in all passed-in args. --
Aliased as `without` and `diff` -- @name difference -- @param array an array -- @param another array -- @return a new array -- @see union -- @see intersection -- @see symmetricDifference function M.difference(array, array2) if not array2 then return M.clone(array) end return M.select(array,function(value) return not M.include(array2,value) end) end --- Returns the duplicate-free union of all passed in arrays. -- @name union -- @param ... a variable number of arrays arguments -- @return a new array -- @see difference -- @see intersection -- @see symmetricDifference function M.union(...) return M.unique(M.flatten({...})) end --- Returns the intersection of all passed-in arrays. -- Each value in the result is present in each of the passed-in arrays. -- @name intersection -- @param ... a variable number of array arguments -- @return a new array -- @see difference -- @see union -- @see symmetricDifference function M.intersection(...) local arg = {...} local array = arg[1] t_remove(arg, 1) local _intersect = {} for i,value in ipairs(array) do if M.all(arg,function(v) return M.include(v,value) end) then _intersect[#_intersect+1] = value end end return _intersect end --- Checks if all passed in arrays are disjunct. -- @name disjoint -- @param ... a variable number of arrays -- @return `true` if the intersection of all arrays is not empty, `false` otherwise. -- @see intersection function M.disjoint(...) return (#M.intersection(...) == 0) end --- Performs a symmetric difference. Returns values from `array` not present in `array2` and also values -- from `array2` not present in `array`. --
Aliased as `symdiff` -- @name symmetricDifference -- @param array an array -- @param array2 another array -- @return a new array -- @see difference -- @see union -- @see intersection function M.symmetricDifference(array, array2) return M.difference( M.union(array, array2), M.intersection(array,array2) ) end --- Produces a duplicate-free version of a given array. --
Aliased as `uniq` -- @name unique -- @param array an array -- @return a new array, duplicate-free -- @see isunique -- @see duplicates function M.unique(array) local ret = {} for i = 1, #array do if not M.find(ret, array[i]) then ret[#ret+1] = array[i] end end return ret end --- Checks if a given array contains distinct values. Such an array is made of distinct elements, -- which only occur once in this array. --
Aliased as `isuniq` -- @name isunique -- @param array an array -- @return `true` if the given array is unique, `false` otherwise. -- @see unique -- @see duplicates function M.isunique(array) return #array == #(M.unique(array)) end --- Returns an array list of all duplicates in array. -- @name duplicates -- @param array an array -- @return an array-list of duplicates -- @see unique function M.duplicates(array) local dict = M.invert(array) local dups = {} for k, v in ipairs(array) do if dict[v] ~= k and not M.find(dups, v) then dups[#dups+1] = v end end return dups end --- Merges values of each of the passed-in arrays in subsets. -- Only values indexed with the same key in the given arrays are merged in the same subset. --
Aliased as `transpose` -- @name zip -- @param ... a variable number of array arguments -- @return a new array -- @see zipWith function M.zip(...) local args = {...} local n = M.max(args, function(array) return #array end) local _ans = {} for i = 1,n do if not _ans[i] then _ans[i] = {} end for k, array in ipairs(args) do if array[i] then _ans[i][#_ans[i]+1] = array[i] end end end return _ans end --- Merges values using a given function. -- Only values indexed with the same key in the given arrays are merged in the same subset. -- Function `f` is used to combine values. --
Aliased as `transposeWith` -- @name zipWith -- @param f a function -- @param ... a variable number of array arguments -- @return a flat array of results -- @see zip function M.zipWith(f, ...) local args = {...} local n = M.max(args, function(array) return #array end) local _ans = {} for i = 1,n do _ans[i] = f(unpack(M.pluck(args,i))) end return _ans end --- Clones array and appends values from another array. -- @name append -- @param array an array -- @param other an array -- @return a new array function M.append(array, other) local t = {} for i,v in ipairs(array) do t[i] = v end for i,v in ipairs(other) do t[#t+1] = v end return t end --- Interleaves arrays. It returns a single array made of values from all -- passed in arrays in their given order, interleaved. -- @name interleave -- @param ... a variable list of arrays -- @return a new array -- @see interpose function M.interleave(...) local args = {...} local n = M.max(args, M.size) local t = {} for i = 1, n do for k, array in ipairs(args) do if array[i] then t[#t+1] = array[i] end end end return t end --- Interposes value in-between consecutive pair of values in array. --
Aliased as `intersperse` -- @name interpose -- @param array an array -- @param value a value -- @return a new array -- @see interleave function M.interpose(array, value) for k = #array, 2,-1 do t_insert(array, k, value) end return array end --- Produces a flexible list of numbers. If one value is passed, will count from 1 to that value, -- with a default step of 1 (or -1). If two values are passed, will count from the first one to the second one, -- using a default step of 1 (or -1). A third value passed will be considered a step value. -- @name range -- @param[opt] from the initial value of the range -- @param[optchain] to the final value of the range -- @param[optchain] step the step of count. Defaults to 1 or -1. -- @return a new array of numbers function M.range(from, to, step) if (from == nil) and (to == nil) and (step ==nil) then return {} elseif (from ~= nil) and (to == nil) and (step == nil) then from, to, step = signum(from), from, signum(from) elseif (from ~= nil) and (to ~= nil) and (step == nil) then step = signum(to - from) end local _ranged = {from} local steps = max(floor((to-from)/step),0) for i=1,steps do _ranged[#_ranged+1] = from+step*i end return _ranged end --- Creates an array list of `n` values, repeated. -- @name rep -- @param value a value to be repeated -- @param n the number of repetitions of value. -- @return a new array of `n` values function M.rep(value, n) local ret = {} for i = 1, n do ret[i] = value end return ret end --- Returns the powerset of array values. For instance, when given the set {1,2,3}, -- returns `{{1},{2},{3},{1,2},{2,3},{1,2,3}}`. -- @name powerset -- @param array an array -- @return an array function M.powerset(array) local n = #array if n == 0 then return {{}} end local t = {} for l = 1, n do for s = 1, n-l+1 do t[#t+1] = M.slice(array,s,s+l-1) end end return t end --- Iterator returning partitions of an array. It returns arrays of length `n` -- made of values from the given array. If the last partition has lower elements than `n` and -- `pad` is supplied, it will be adjusted to `n` of elements with `pad` value. -- @name partition -- @param array an array -- @param[opt] n the size of partitions. Defaults to 1. -- @param[optchain] pads a value to adjust the last subsequence to the `n` elements -- @return an iterator function -- @see overlapping -- @see aperture function M.partition(array, n, pad) if n<=0 then return end return wrap(function() partgen(array, n or 1, yield, pad) end) end --- Iterator returning overlapping partitions of an array. -- If the last subsequence has lower elements than `n` and `pad` is -- supplied, it will be adjusted to `n` elements with `pad` value. -- @name overlapping -- @param array an array -- @param[opt] n the size of partitions. Defaults to 2. -- @param[optchain] pads a value to adjust the last subsequence to the `n` elements -- @return an iterator function -- @see partition -- @see aperture function M.overlapping(array, n, pad) if n<=1 then return end return wrap(function() partgen2(array, n or 2, yield, pad) end) end --- Iterator returning sliding partitions of an array. --
Aliased as `sliding` -- @name aperture -- @param array an array -- @param[opt] n the size of partitions. Defaults to 2 (and then behaves like @{pairwise}) -- @return an iterator function -- @see partition -- @see overlapping -- @see pairwise function M.aperture(array, n) if n<=1 then return end return wrap(function() partgen3(array, n or 2, yield) end) end --- Iterator returning sliding pairs of an array. -- @name pairwise -- @param array an array -- @return an iterator function -- @see overlapping function M.pairwise(array) return M.aperture(array, 2) end --- Iterator returning the permutations of an array. It returns arrays made of all values -- from the passed-in array, with values permuted. -- @name permutation -- @param array an array -- @return an iterator function function M.permutation(array) return wrap(function() permgen(array, #array, yield) end) end --- Concatenates values in a given array. Handles booleans as well. If `sep` string is -- passed, it will be used as a separator. Passing `i` and `j` will result in concatenating -- only values within `[i, j]` range. --
Aliased as `join` -- @name concat -- @param array a given array -- @param[opt] sep a separator string, defaults to the empty string `''`. -- @param[optchain] i the starting index, defaults to 1. -- @param[optchain] j the final index, defaults to the array length. -- @return a string function M.concat(array, sep, i, j) return t_concat(M.map(array,tostring),sep,i,j) end --- Returns all possible pairs built from given arrays. -- @name xprod -- @param array a first array -- @param array2 a second array -- @return an array list of all pairs function M.xprod(array, array2) local p = {} for i, v1 in ipairs(array) do for j, v2 in ipairs(array2) do p[#p+1] = {v1, v2} end end return p end --- Creates pairs from value and array. Value is always prepended to the pair. -- @name xpairs -- @param valua a value -- @param array an array -- @return an array list of all pairs function M.xpairs(value, array) local xpairs = {} for k, v in ipairs(array) do xpairs[k] = {value, v} end return xpairs end --- Creates pairs from value and array. Value is always appended as the last item to the pair. -- @name xpairsRight -- @param valua a value -- @param array an array -- @return an array list of all pairs function M.xpairsRight(value, array) local xpairs = {} for k, v in ipairs(array) do xpairs[k] = {v, value} end return xpairs end --- Returns the sum of array values. -- @name sum -- @param array a given array -- @return the sum of array values function M.sum(array) local s = 0 for k, v in ipairs(array) do s = s + v end return s end --- Returns the product of array values. -- @name product -- @param array a given array -- @return the product of array values function M.product(array) local p = 1 for k, v in ipairs(array) do p = p * v end return p end --- Returns the mean of an array of numbers. --
Aliased as `average` -- @name mean -- @param array an array of numbers -- @return a number -- @see sum -- @see product -- @see median function M.mean(array) return M.sum(array)/(#array) end --- Returns the median of an array of numbers. -- @name median -- @param array an array of numbers -- @return a number -- @see sum -- @see product -- @see mean function M.median(array) local t = M.sort(M.clone(array)) local n = #t if n == 0 then return elseif n==1 then return t[1] end local mid = ceil(n/2) return n%2==0 and (t[mid] + t[mid+1])/2 or t[mid] end --- Utility functions -- @section Utility functions --- The no operation function. -- @name noop -- @return nothing function M.noop() return end --- Returns the passed-in value. This function is used internally -- as a default iterator. -- @name identity -- @param value a value -- @return the passed-in value function M.identity(value) return value end --- Calls `f` with the supplied arguments. Returns the results of `f(...)`. -- @name call -- @param f a function -- @param[opt] ... a vararg list of args to `f` -- @return the result of `f(...)` call. function M.call(f, ...) return f(...) end --- Creates a constant function which returns the same output on every call. --
Aliased as `always` -- @name constant -- @param value a constant value -- @return a constant function function M.constant(value) return function() return value end end --- Returns a function which applies `specs` on args. This function produces an object having -- the same structure than `specs` by mapping each property to the result of calling its -- associated function with the supplied arguments -- @name applySpec -- @param specs a table -- @return a function function M.applySpec(specs) return function (...) local spec = {} for i, f in pairs(specs) do spec[i] = f(...) end return spec end end --- Threads `value` through a series of functions. If a function expects more than one args, -- it can be specified using an array list, where the first item is the function and the following -- are the remaining args neeeded. The value is used as the first input. -- @name thread -- @param value a value -- @param ... a vararg list of functions or arrays -- @return a value -- @see threadRight function M.thread(value, ...) local state = value local arg = {...} for k, t in ipairs(arg) do if type(t) == 'function' then state = t(state) elseif type(t) == 'table' then local f = t[1] t_remove(t, 1) state = M.reduce(t, f, state) end end return state end --- Threads `value` through a series of functions. If a function expects more than one args, -- it can be specified using an array list, where the first item is the function and the following -- are the remaining args neeeded. The value is used as the last input. -- @name threadRight -- @param value a value -- @param ... a vararg list of functions or arrays -- @return a value -- @see thread function M.threadRight(value, ...) local state = value local arg = {...} for k, t in ipairs(arg) do if type(t) == 'function' then state = t(state) elseif type(t) == 'table' then local f = t[1] t_remove(t, 1) t_insert(t, state) state = M.reduce(t, f) end end return state end --- Returns a dispatching function. When called with arguments, this function invokes each of its functions -- in the passed-in order and returns the results of the first non-nil evaluation. -- @name dispatch -- @param ... a vararg list of functions -- @return a dispatch function function M.dispatch(...) local funcs = {...} return function (...) for k, f in ipairs(funcs) do local r = {f(...)} if #r > 0 then return unpack(r) end end end end --- Memoizes a given function by caching the computed result. -- Useful for speeding-up slow-running functions. --
Aliased as `cache` -- @name memoize -- @param f a function -- @return a new function function M.memoize(f) local _cache = setmetatable({},{__mode = 'kv'}) return function (key) if (_cache[key] == nil) then _cache[key] = f(key) end return _cache[key] end end --- Builds a list from a seed value. Accepts an iterator function, which -- returns either nil to stop iteration or two values : the value to add to the list -- of results and the seed to be used in the next call to the iterator function. -- @name unfold -- @param f an iterator function -- @param seed a seed value -- @return an array of values function M.unfold(f, seed) local t, result = {} while true do result, seed = f(seed) if result ~= nil then t[#t+1] = result else break end end return t end --- Returns a version of `f` that runs only once. Successive calls to `f` -- will keep yielding the same output, no matter what the passed-in arguments are. -- It can be used to initialize variables. -- @name once -- @param f a function -- @return a new function -- @see before -- @see after function M.once(f) local _internal = 0 local _args = {} return function(...) _internal = _internal+1 if _internal <= 1 then _args = {...} end return f(unpack(_args)) end end --- Returns a version of `f` that will run no more than count times. Next calls will -- keep yielding the results of the count-th call. -- @name before -- @param f a function -- @param count a count -- @return a new function -- @see once -- @see after function M.before(f, count) local _internal = 0 local _args = {} return function(...) _internal = _internal+1 if _internal <= count then _args = {...} end return f(unpack(_args)) end end --- Returns a version of `f` that runs on the `count-th` call. -- Useful when dealing with asynchronous tasks. -- @name after -- @param f a function -- @param count the number of calls before `f` will start running. -- @return a new function -- @see once -- @see before function M.after(f, count) local _limit,_internal = count, 0 return function(...) _internal = _internal+1 if _internal >= _limit then return f(...) end end end --- Composes functions. Each passed-in function consumes the return value of the function that follows. -- In math terms, composing the functions `f`, `g`, and `h` produces the function `f(g(h(...)))`. -- @name compose -- @param ... a variable number of functions -- @return a new function -- @see pipe function M.compose(...) -- See: https://github.com/Yonaba/Moses/pull/15#issuecomment-139038895 local f = M.reverse {...} return function (...) local first, _temp = true for i, func in ipairs(f) do if first then first = false _temp = func(...) else _temp = func(_temp) end end return _temp end end --- Pipes a value through a series of functions. In math terms, -- given some functions `f`, `g`, and `h` in that order, it returns `f(g(h(value)))`. -- @name pipe -- @param value a value -- @param ... a variable number of functions -- @return the result of the composition of function calls. -- @see compose function M.pipe(value, ...) return M.compose(...)(value) end --- Returns the logical complement of a given function. For a given input, the returned -- function will output `false` if the original function would have returned `true`, -- and vice-versa. -- @name complement -- @param f a function -- @return the logical complement of the given function `f`. function M.complement(f) return function(...) return not f(...) end end --- Calls a sequence of passed-in functions with the same argument. -- Returns a sequence of results. --
Aliased as `juxt` -- @name juxtapose -- @param value a value -- @param ... a variable number of functions -- @return a list of results function M.juxtapose(value, ...) local res = {} for i, func in ipairs({...}) do res[i] = func(value) end return unpack(res) end --- Wraps `f` inside of the `wrapper` function. It passes `f` as the first argument to `wrapper`. -- This allows the wrapper to execute code before and after `f` runs, -- adjust the arguments, and execute it conditionally. -- @name wrap -- @param f a function to be wrapped, prototyped as `f (...)` -- @param wrapper a wrapper function, prototyped as `wrapper (f, ...)` -- @return the results function M.wrap(f, wrapper) return function (...) return wrapper(f,...) end end --- Runs `iter` function `n` times. Collects the results of each run and returns them in an array. -- @name times -- @param iter an iterator function, prototyped as `iter (i)` -- @param[opt] n the number of times `iter` should be called. Defaults to 1. -- @return table an array of results function M.times(iter, n) local results = {} for i = 1, (n or 1) do results[i] = iter(i) end return results end --- Binds `v` to be the first argument to `f`. Calling `f (...)` will result to `f (v, ...)`. -- @name bind -- @param f a function -- @param v a value -- @return a function -- @see bind2 -- @see bindn -- @see bindall function M.bind(f, v) return function (...) return f(v,...) end end --- Binds `v` to be the second argument to `f`. Calling `f (a, ...)` will result to `f (a, v, ...)`. -- @name bind2 -- @param f a function -- @param v a value -- @return a function -- @see bind -- @see bindn -- @see bindall function M.bind2(f, v) return function (t, ...) return f(t, v, ...) end end --- Binds `...` to be the N-first arguments to function `f`. -- Calling `f (a1, a2, ..., aN)` will result to `f (..., a1, a2, ...,aN)`. -- @name bindn -- @param f a function -- @param ... a variable number of arguments -- @return a function -- @see bind -- @see bind2 -- @see bindall function M.bindn(f, ...) local args = {...} return function (...) return f(unpack(M.append(args,{...}))) end end --- Binds methods to object. As such, whenever any of these methods is invoked, it -- always receives the object as its first argument. -- @name bindall -- @param obj an abject -- @param ... a variable number of method names -- @return the passed-in object with all methods bound to the object itself. -- @see bind -- @see bind2 -- @see bindn function M.bindall(obj, ...) local methodNames = {...} for i, methodName in ipairs(methodNames) do local method = obj[methodName] if method then obj[methodName] = M.bind(method, obj) end end return obj end --- Returns a function which iterate over a set of conditions. It invokes each predicate, -- passing it given values. It returns the value of the corresponding function of the first -- predicate to return a non-nil value. -- @name cond -- @param conds an array list of predicate-function pairs -- @return the result of invoking `f(...)` of the first predicate to return a non-nil value function M.cond(conds) return function(...) for k, condset in ipairs(conds) do if condset[1](...) then return condset[2](...) end end end end --- Returns a validation function. Given a set of functions, the validation function evaluates -- to `true` only when all its funcs returns `true`. -- @name both -- @param ... an array list of functions -- @return `true` when all given funcs returns true with input, false otherwise function M.both(...) local funcs = {...} return function (...) for k, f in ipairs(funcs) do if not f(...) then return false end end return true end end --- Returns a validation function. Given a set of functions, the validation function evaluates -- to `true` when at least one of its funcs returns `true`. -- @name either -- @param ... an array list of functions -- @return `true` when one of the given funcs returns `true` with input, `false` otherwise function M.either(...) local funcs = {...} return function (...) for k, f in ipairs(funcs) do if f(...) then return true end end return false end end --- Returns a validation function. Given a set of functions, the validation function evaluates -- to `true` when neither of its func return `true`. -- @name neither -- @param ... an array list of functions -- @return `true` when neither of the given funcs returns `true` with input, `false` otherwise function M.neither(...) local funcs = {...} return function (...) for k, f in ipairs(funcs) do if f(...) then return false end end return true end end --- Generates an unique ID for the current session. If given a string `template`, it -- will use this template for output formatting. Otherwise, if `template` is a function, it -- will evaluate `template (id)`. --
Aliased as `uid`. -- @name uniqueId -- @param[opt] template either a string or a function template to format the ID -- @return value an ID function M.uniqueId(template) unique_id_counter = unique_id_counter + 1 if template then if type(template) == 'string' then return template:format(unique_id_counter) elseif type(template) == 'function' then return template(unique_id_counter) end end return unique_id_counter end --- Produces an iterator which repeatedly apply a function `f` onto an input. -- Yields `value`, then `f(value)`, then `f(f(value))`, continuously. --
Aliased as `iter`. -- @name iterator -- @param f a function -- @param value an initial input to `f` -- @param[opt] n the number of times the iterator should run -- @return an iterator function function M.iterator(f, value, n) local cnt = 0 return function() cnt = cnt + 1 if n and cnt > n then return end value = f(value) return value end end --- Consumes the first `n` values of a iterator then returns it. -- @name skip -- @param iter an iterator function -- @param[opt] n a number. Defaults to 1. -- @return the given iterator function M.skip(iter, n) for i = 1, (n or 1) do if iter() == nil then return end end return iter end --- Iterates over an iterator and returns its values in an array. -- @name tabulate -- @param ... an iterator function (returning a generator, a state and a value) -- @return an array of results function M.tabulate(...) local r = {} for v in ... do r[#r+1] = v end return r end --- Returns the length of an iterator. It consumes the iterator itself. -- @name iterlen -- @param ... an iterator function (returning a generator, a state and a value) -- @return the iterator length function M.iterlen(...) local l = 0 for v in ... do l = l + 1 end return l end --- Casts value as an array if it is not one. -- @name castArray -- @param value a value -- @return an array containing the given value function M.castArray(value) return (type(value)~='table') and {value} or value end --- Creates a function of `f` with arguments flipped in reverse order. -- @name flip -- @param f a function -- @return a function function M.flip(f) return function(...) return f(unpack(M.reverse({...}))) end end --- Returns a function that gets the nth argument. -- If n is negative, the nth argument from the end is returned. -- @name nthArg -- @param n a number -- @return a function function M.nthArg(n) return function (...) local args = {...} return args[(n < 0) and (#args + n + 1) or n] end end --- Returns a function which accepts up to one arg. It ignores any additional arguments. -- @name unary -- @param f a function -- @return a function -- @see ary function M.unary(f) return function (...) local args = {...} return f(args[1]) end end --- Returns a function which accepts up to `n` args. It ignores any additional arguments. --
Aliased as `nAry`. -- @name ary -- @param f a function -- @param[opt] n a number. Defaults to 1. -- @return a function -- @see unary function M.ary(f, n) n = n or 1 return function (...) local args = {...} local fargs = {} for i = 1, n do fargs[i] = args[i] end return f(unpack(fargs)) end end --- Returns a function with an arity of 0. The new function ignores any arguments passed to it. -- @name noarg -- @param f a function -- @return a new function function M.noarg(f) return function () return f() end end --- Returns a function which runs with arguments rearranged. Arguments are passed to the -- returned function in the order of supplied `indexes` at call-time. -- @name rearg -- @param f a function -- @param indexes an array list of indexes -- @return a function function M.rearg(f, indexes) return function(...) local args = {...} local reargs = {} for i, arg in ipairs(indexes) do reargs[i] = args[arg] end return f(unpack(reargs)) end end --- Creates a function that runs transforms on all arguments it receives. -- @name over -- @param ... a set of functions which will receive all arguments to the returned function -- @return a function -- @see overEvery -- @see overSome -- @see overArgs function M.over(...) local transforms = {...} return function(...) local r = {} for i,transform in ipairs(transforms) do r[#r+1] = transform(...) end return r end end --- Creates a validation function. The returned function checks if *all* of the given predicates return -- truthy when invoked with the arguments it receives. -- @name overEvery -- @param ... a list of predicate functions -- @return a new function -- @see over -- @see overSome -- @see overArgs function M.overEvery(...) local f = M.over(...) return function(...) return M.reduce(f(...),function(state,v) return state and v end) end end --- Creates a validation function. The return function checks if *any* of a given predicates return -- truthy when invoked with the arguments it receives. -- @name overSome -- @param ... a list of predicate functions -- @return a new function -- @see over -- @see overEvery -- @see overArgs function M.overSome(...) local f = M.over(...) return function(...) return M.reduce(f(...),function(state,v) return state or v end) end end --- Creates a function that invokes `f` with its arguments transformed. 1rst arguments will be passed to -- the 1rst transform, 2nd arg to the 2nd transform, etc. Remaining arguments will not be transformed. -- @name overArgs -- @param f a function -- @param ... a list of transforms funcs prototyped as `f (v)` -- @return the result of running `f` with its transformed arguments -- @see over -- @see overEvery -- @see overSome function M.overArgs(f,...) local _argf = {...} return function(...) local _args = {...} for i = 1,#_argf do local func = _argf[i] if _args[i] then _args[i] = func(_args[i]) end end return f(unpack(_args)) end end --- Converges two functions into one. -- @name converge -- @param f a function -- @param g a function -- @param h a function -- @return a new version of function f function M.converge(f, g, h) return function(...) return f(g(...),h(...)) end end --- Partially apply a function by filling in any number of its arguments. -- One may pass a string `'M'` as a placeholder in the list of arguments to specify an argument -- that should not be pre-filled, but left open to be supplied at call-time. -- @name partial -- @param f a function -- @param ... a list of partial arguments to `f` -- @return a new version of function f having some of it original arguments filled -- @see partialRight -- @see curry function M.partial(f,...) local partial_args = {...} return function (...) local n_args = {...} local f_args = {} for k,v in ipairs(partial_args) do f_args[k] = (v == '_') and M.shift(n_args) or v end return f(unpack(M.append(f_args,n_args))) end end --- Similar to @{partial}, but from the right. -- @name partialRight -- @param f a function -- @param ... a list of partial arguments to `f` -- @return a new version of function f having some of it original arguments filled -- @see partialRight -- @see curry function M.partialRight(f,...) local partial_args = {...} return function (...) local n_args = {...} local f_args = {} for k = 1,#partial_args do f_args[k] = (partial_args[k] == '_') and M.shift(n_args) or partial_args[k] end return f(unpack(M.append(n_args, f_args))) end end --- Curries a function. If the given function `f` takes multiple arguments, it returns another version of -- `f` that takes a single argument (the first of the arguments to the original function) and returns a new -- function that takes the remainder of the arguments and returns the result. -- @name curry -- @param f a function -- @param[opt] n_args the number of arguments expected for `f`. Defaults to 2. -- @return a curried version of `f` -- @see partial -- @see partialRight function M.curry(f, n_args) n_args = n_args or 2 local _args = {} local function scurry(v) if n_args == 1 then return f(v) end if v ~= nil then _args[#_args+1] = v end if #_args < n_args then return scurry else local r = {f(unpack(_args))} _args = {} return unpack(r) end end return scurry end --- Returns the execution time of `f (...)` and its returned values. -- @name time -- @param f a function -- @param[opt] ... optional args to `f` -- @return the execution time and the results of `f (...)` function M.time(f, ...) local stime = clock() local r = {f(...)} return clock() - stime, unpack(r) end --- Object functions -- @section Object functions --- Returns the keys of the object properties. -- @name keys -- @param obj an object -- @return an array function M.keys(obj) local keys = {} for key in pairs(obj) do keys[#keys+1] = key end return keys end --- Returns the values of the object properties. -- @name values -- @param obj an object -- @return an array of values function M.values(obj) local values = {} for key, value in pairs(obj) do values[#values+1] = value end return values end --- Returns the value at a given path in an object. -- Path is given as a vararg list of keys. -- @name path -- @param obj an object -- @param ... a vararg list of keys -- @return a value or nil function M.path(obj, ...) local value, path = obj, {...} for i, p in ipairs(path) do if (value[p] == nil) then return end value = value[p] end return value end --- Spreads object under property path onto provided object. -- It is similar to @{flattenPath}, but removes object under the property path. -- @name spreadPath -- @param obj an object -- @param ... a property path given as a vararg list -- @return the passed-in object with changes -- @see flattenPath function M.spreadPath(obj, ...) local path = {...} for _, p in ipairs(path) do if obj[p] then for k, v in pairs(obj[p]) do obj[k] = v obj[p][k] = nil end end end return obj end --- Flattens object under property path onto provided object. -- It is similar to @{spreadPath}, but preserves object under the property path. -- @name flattenPath -- @param obj an object -- @param ... a property path given as a vararg list -- @return the passed-in object with changes -- @see spreadPath function M.flattenPath(obj, ...) local path = {...} for _, p in ipairs(path) do if obj[p] then for k, v in pairs(obj[p]) do obj[k] = v end end end return obj end --- Converts key-value pairs to an array-list of `[k, v]` pairs. -- @name kvpairs -- @param obj an object -- @return an array list of key-value pairs -- @see toObj function M.kvpairs(obj) local t = {} for k,v in pairs(obj) do t[#t+1] = {k,v} end return t end --- Converts an array list of `[k,v]` pairs to an object. Keys are taken -- from the 1rst column in the `[k,v]` pairs sequence, associated with values in the 2nd -- column. -- @name toObj -- @param kvpairs an array-list of `[k,v]` pairs -- @return an object -- @see kvpairs function M.toObj(kvpairs) local obj = {} for k, v in ipairs(kvpairs) do obj[v[1]] = v[2] end return obj end --- Swaps keys with values. Produces a new object where previous keys are now values, -- while previous values are now keys. --
Aliased as `mirror` -- @name invert -- @param obj a given object -- @return a new object function M.invert(obj) local _ret = {} for k, v in pairs(obj) do _ret[v] = k end return _ret end --- Returns a function that will return the key property of any passed-in object. -- @name property -- @param key a key property name -- @return a function which should accept an object as argument -- @see propertyOf function M.property(key) return function(obj) return obj[key] end end --- Returns a function which will return the value of an object property. -- @name propertyOf -- @param obj an object -- @return a function which should accept a key property argument -- @see property function M.propertyOf(obj) return function(key) return obj[key] end end --- Converts any given value to a boolean -- @name toBoolean -- @param value a value. Can be of any type -- @return `true` if value is true, `false` otherwise (false or nil). function M.toBoolean(value) return not not value end --- Extends an object properties. It copies the properties of extra passed-in objects -- into the destination object, and returns the destination object. The last objects -- will override properties of the same name. -- @name extend -- @param destObj a destination object -- @param ... a list of objects -- @return the destination object extended function M.extend(destObj, ...) local sources = {...} for k, source in ipairs(sources) do if type(source) == 'table' then for key, value in pairs(source) do destObj[key] = value end end end return destObj end --- Returns a sorted list of all methods names found in an object. If the given object -- has a metatable implementing an `__index` field pointing to another table, will also recurse on this -- table if `recurseMt` is provided. If `obj` is omitted, it defaults to the library functions. --
Aliased as `methods`. -- @name functions -- @param[opt] obj an object. Defaults to Moses library functions. -- @return an array-list of methods names function M.functions(obj, recurseMt) obj = obj or M local _methods = {} for key, value in pairs(obj) do if type(value) == 'function' then _methods[#_methods+1] = key end end if recurseMt then local mt = getmetatable(obj) if mt and mt.__index then local mt_methods = M.functions(mt.__index, recurseMt) for k, fn in ipairs(mt_methods) do _methods[#_methods+1] = fn end end end return _methods end --- Clones a given object properties. If `shallow` is passed will also clone nested array properties. -- @name clone -- @param obj an object -- @param[opt] shallow whether or not nested array-properties should be cloned, defaults to false. -- @return a copy of the passed-in object function M.clone(obj, shallow) if type(obj) ~= 'table' then return obj end local _obj = {} for i,v in pairs(obj) do if type(v) == 'table' then if not shallow then _obj[i] = M.clone(v,shallow) else _obj[i] = v end else _obj[i] = v end end return _obj end --- Invokes interceptor with the object, and then returns object. -- The primary purpose of this method is to "tap into" a method chain, in order to perform operations -- on intermediate results within the chain. -- @name tap -- @param obj an object -- @param f an interceptor function, should be prototyped as `f (obj)` -- @return the passed-in object function M.tap(obj, f) f(obj) return obj end --- Checks if a given object implements a property. -- @name has -- @param obj an object -- @param key a key property to be checked -- @return `true` or `false` function M.has(obj, key) return obj[key]~=nil end --- Returns an object copy having white-listed properties. --
Aliased as `choose`. -- @name pick -- @param obj an object -- @param ... a variable number of string keys -- @return the filtered object function M.pick(obj, ...) local whitelist = M.flatten {...} local _picked = {} for key, property in pairs(whitelist) do if (obj[property])~=nil then _picked[property] = obj[property] end end return _picked end --- Returns an object copy without black-listed properties. --
Aliased as `drop`. -- @name omit -- @param obj an object -- @param ... a variable number of string keys -- @return the filtered object function M.omit(obj, ...) local blacklist = M.flatten {...} local _picked = {} for key, value in pairs(obj) do if not M.include(blacklist,key) then _picked[key] = value end end return _picked end --- Applies a template to an object, preserving non-nil properties. --
Aliased as `defaults`. -- @name template -- @param obj an object -- @param[opt] template a template object. If `nil`, leaves `obj` untouched. -- @return the passed-in object filled function M.template(obj, template) if not template then return obj end for i, v in pairs(template) do if not obj[i] then obj[i] = v end end return obj end --- Performs a deep comparison test between two objects. Can compare strings, functions -- (by reference), nil, booleans. Compares tables by reference or by values. If `useMt` -- is passed, the equality operator `==` will be used if one of the given objects has a -- metatable implementing `__eq`. --
Aliased as `M.compare`, `M.matches` -- @name isEqual -- @param objA an object -- @param objB another object -- @param[opt] useMt whether or not `__eq` should be used, defaults to false. -- @return `true` or `false` -- @see allEqual function M.isEqual(objA, objB, useMt) local typeObjA = type(objA) local typeObjB = type(objB) if typeObjA~=typeObjB then return false end if typeObjA~='table' then return (objA==objB) end local mtA = getmetatable(objA) local mtB = getmetatable(objB) if useMt then if (mtA or mtB) and (mtA.__eq or mtB.__eq) then return mtA.__eq(objA, objB) or mtB.__eq(objB, objA) or (objA==objB) end end if M.size(objA)~=M.size(objB) then return false end local vB for i,vA in pairs(objA) do vB = objB[i] if vB == nil or not M.isEqual(vA, vB, useMt) then return false end end for i in pairs(objB) do if objA[i] == nil then return false end end return true end --- Invokes an object method. It passes the object itself as the first argument. if `method` is not -- callable, will return `obj[method]`. -- @name result -- @param obj an object -- @param method a string key to index in object `obj`. -- @return the returned value of `method (obj)` call function M.result(obj, method) if obj[method] then if M.isCallable(obj[method]) then return obj[method](obj) else return obj[method] end end if M.isCallable(method) then return method(obj) end end --- Checks if the given arg is a table. -- @name isTable -- @param t a value to be tested -- @return `true` or `false` function M.isTable(t) return type(t) == 'table' end --- Checks if the given argument is callable. Assumes `obj` is callable if -- it is either a function or a table having a metatable implementing `__call` metamethod. -- @name isCallable -- @param obj an object -- @return `true` or `false` function M.isCallable(obj) return ((type(obj) == 'function') or ((type(obj) == 'table') and getmetatable(obj) and getmetatable(obj).__call~=nil) or false) end --- Checks if the given argument is an array. Assumes `obj` is an array -- if is a table with consecutive integer keys starting at 1. -- @name isArray -- @param obj an object -- @return `true` or `false` function M.isArray(obj) if not (type(obj) == 'table') then return false end -- Thanks @Wojak and @Enrique García Cota for suggesting this -- See : http://love2d.org/forums/viewtopic.php?f=3&t=77255&start=40#p163624 local i = 0 for k in pairs(obj) do i = i + 1 if obj[i] == nil then return false end end return true end --- Checks if the given object is iterable with `pairs` (or `ipairs`). -- @name isIterable -- @param obj an object -- @return `true` if the object can be iterated with `pairs` (or `ipairs`), `false` otherwise function M.isIterable(obj) return M.toBoolean((pcall(pairs, obj))) end --- Extends Lua's `type` function. It returns the type of the given object and also recognises -- file userdata -- @name type -- @param obj an object -- @return the given object type function M.type(obj) local tp = type(obj) if tp == 'userdata' then local mt = getmetatable(obj) if mt == getmetatable(io.stdout) then return 'file' end end return tp end --- Checks if the given pbject is empty. If `obj` is a string, will return `true` -- if `#obj == 0`. Otherwise, if `obj` is a table, will return whether or not this table -- is empty. If `obj` is `nil`, it will return true. -- @name isEmpty -- @param[opt] obj an object -- @return `true` or `false` function M.isEmpty(obj) if (obj == nil) then return true end if type(obj) == 'string' then return #obj==0 end if type(obj) == 'table' then return next(obj)==nil end return true end --- Checks if the given argument is a string. -- @name isString -- @param obj an object -- @return `true` or `false` function M.isString(obj) return type(obj) == 'string' end --- Checks if the given argument is a function. -- @name isFunction -- @param obj an object -- @return `true` or `false` function M.isFunction(obj) return type(obj) == 'function' end --- Checks if the given argument is nil. -- @name isNil -- @param obj an object -- @return `true` or `false` function M.isNil(obj) return obj==nil end --- Checks if the given argument is a number. -- @name isNumber -- @param obj an object -- @return `true` or `false` -- @see isNaN function M.isNumber(obj) return type(obj) == 'number' end --- Checks if the given argument is NaN (see [Not-A-Number](http://en.wikipedia.org/wiki/NaN)). -- @name isNaN -- @param obj an object -- @return `true` or `false` -- @see isNumber function M.isNaN(obj) return type(obj) == 'number' and obj~=obj end --- Checks if the given argument is a finite number. -- @name isFinite -- @param obj an object -- @return `true` or `false` function M.isFinite(obj) if type(obj) ~= 'number' then return false end return obj > -huge and obj < huge end --- Checks if the given argument is a boolean. -- @name isBoolean -- @param obj an object -- @return `true` or `false` function M.isBoolean(obj) return type(obj) == 'boolean' end --- Checks if the given argument is an integer. -- @name isInteger -- @param obj an object -- @return `true` or `false` function M.isInteger(obj) return type(obj) == 'number' and floor(obj)==obj end -- Aliases do -- Table functions aliases M.forEach = M.each M.forEachi = M.eachi M.update = M.adjust M.alleq = M.allEqual M.loop = M.cycle M.collect = M.map M.inject = M.reduce M.foldl = M.reduce M.injectr = M.reduceRight M.foldr = M.reduceRight M.mapr = M.mapReduce M.maprr = M.mapReduceRight M.any = M.include M.some = M.include M.contains = M.include M.filter = M.select M.discard = M.reject M.every = M.all -- Array functions aliases M.takeWhile = M.selectWhile M.rejectWhile = M.dropWhile M.pop = M.shift M.remove = M.pull M.rmRange = M.removeRange M.chop = M.removeRange M.sub = M.slice M.head = M.first M.take = M.first M.tail = M.rest M.without = M.difference M.diff = M.difference M.symdiff = M.symmetricDifference M.xor = M.symmetricDifference M.uniq = M.unique M.isuniq = M.isunique M.transpose = M.zip M.part = M.partition M.perm = M.permutation M.transposeWith = M.zipWith M.intersperse = M.interpose M.sliding = M.aperture M.mirror = M.invert M.join = M.concat M.average = M.mean -- Utility functions aliases M.always = M.constant M.cache = M.memoize M.juxt = M.juxtapose M.uid = M.uniqueid M.iter = M.iterator M.nAry = M.ary -- Object functions aliases M.methods = M.functions M.choose = M.pick M.drop = M.omit M.defaults = M.template M.compare = M.isEqual M.matches = M.isEqual end -- Setting chaining and building interface do -- Wrapper to Moses local f = {} -- Will be returned upon requiring, indexes into the wrapper local Moses = {} Moses.__index = f -- Wraps a value into an instance, and returns the wrapped object local function new(value) return setmetatable({_value = value, _wrapped = true}, Moses) end setmetatable(Moses,{ __call = function(self,v) return new(v) end, -- Calls returns to instantiation __index = function(t,key,...) return f[key] end -- Redirects to the wrapper }) --- Returns a wrapped object. Calling library functions as methods on this object -- will continue to return wrapped objects until @{obj:value} is used. Can be aliased as `M(value)`. -- @class function -- @name chain -- @param value a value to be wrapped -- @return a wrapped object function Moses.chain(value) return new(value) end --- Extracts the value of a wrapped object. Must be called on an chained object (see @{chain}). -- @class function -- @name obj:value -- @return the value previously wrapped function Moses:value() return self._value end -- Register chaining methods into the wrapper f.chain, f.value = Moses.chain, Moses.value -- Register all functions into the wrapper for fname,fct in pairs(M) do if fname ~= 'operator' then -- Prevents from wrapping op functions f[fname] = function(v, ...) local wrapped = type(v) == 'table' and rawget(v,'_wrapped') or false if wrapped then local _arg = v._value local _rslt = fct(_arg,...) return new(_rslt) else return fct(v,...) end end end end -- Exports all op functions f.operator = M.operator f.op = M.operator --- Imports all library functions into a context. -- @name import -- @param[opt] context a context. Defaults to `_ENV or `_G`` (current environment). -- @param[optchain] noConflict if supplied, will not import conflicting functions in the destination context. -- @return the passed-in context f.import = function(context, noConflict) context = context or _ENV or _G local funcs = M.functions() for k, fname in ipairs(funcs) do if rawget(context, fname)~= nil then if not noConflict then rawset(context, fname, M[fname]) end else rawset(context, fname, M[fname]) end end return context end -- Descriptive tags Moses._VERSION = 'Moses v'.._MODULEVERSION Moses._URL = 'http://github.com/Yonaba/Moses' Moses._LICENSE = 'MIT ' Moses._DESCRIPTION = 'utility-belt library for functional programming in Lua' return Moses end Moses-Moses-2.1.0-1/moses_min.lua000066400000000000000000001027771334620647700165500ustar00rootroot00000000000000local SWFtRywD='2.1.0'local e,v,l6Sm5=next,type,pcall;local oUA,QFKEzBf=setmetatable,getmetatable local odpE,p=table.insert,table.sort;local lIpFkbLI,JdUtcU=table.remove,table.concat local GQLN,toXyq,S9TO=math.randomseed,math.random,math.huge;local pS78Y,BCf7,RlMSrmdD,VCD=math.floor,math.max,math.min,math.ceil local OV7=coroutine.wrap;local X83a=coroutine.yield;local PizLA9mj=rawget local hUL=table.unpack or unpack;local l,kyWtqIf0=pairs,ipairs;local zupvsz=error;local Mw=os.clock;local S1wg_DG={}local function sf0(cmWo_v,RoXZEsn) return cmWo_v>RoXZEsn end local function qxZa6ozV(BKLwtAVx,BMZNmf0)return BKLwtAVx0 then while(#ZmzyNm0 and cpdLk+1 <#akG0mUnS then while (#FbQX0 and gUfudNUg+eS0X<=#ejMVLYZd then while (#d3 =0 and 1 or-1 end local qJExeUn2=-1;S1wg_DG.operator={} S1wg_DG.operator.add=function(fBI,wMSY)return fBI+wMSY end S1wg_DG.operator.sub=function(_nD2rl,aVh8xSly)return _nD2rl-aVh8xSly end S1wg_DG.operator.mul=function(i,P_NNVDyt)return i*P_NNVDyt end S1wg_DG.operator.div=function(cVEyN,uj2AiF)return cVEyN/uj2AiF end S1wg_DG.operator.mod=function(W,lbHN2)return W%lbHN2 end S1wg_DG.operator.exp=function(PwgW3lfq,z)return PwgW3lfq^z end;S1wg_DG.operator.pow=S1wg_DG.operator.exp;S1wg_DG.operator.unm=function(K)return -K end S1wg_DG.operator.neg=S1wg_DG.operator.unm S1wg_DG.operator.floordiv=function(xx,aYb)return pS78Y(xx/aYb)end S1wg_DG.operator.intdiv=function(JM2,bmAjLT)return JM2 >=0 and pS78Y(JM2/bmAjLT)or VCD(JM2/bmAjLT)end S1wg_DG.operator.eq=function(eExYnwnh,XMBmJyiP)return eExYnwnh==XMBmJyiP end S1wg_DG.operator.neq=function(nowqEU6m,iKD8V)return nowqEU6m~=iKD8V end S1wg_DG.operator.lt=function(YtRS,A)return YtRSQ57BJ end S1wg_DG.operator.le=function(vM,JeGCDX)return vM<=JeGCDX end S1wg_DG.operator.ge=function(A,UFZlp)return A>=UFZlp end S1wg_DG.operator.land=function(VsrKM,uhIq)return VsrKM and uhIq end S1wg_DG.operator.lor=function(EEOUzhy,hbrt)return EEOUzhy or hbrt end;S1wg_DG.operator.lnot=function(D)return not D end;S1wg_DG.operator.concat=function(Q,mRqle)return Q..mRqle end;S1wg_DG.operator.length=function(sBEZ8)return #sBEZ8 end S1wg_DG.operator.len=S1wg_DG.operator.length;function S1wg_DG.clear(WhHB0ygh)for rYSD0 in l(WhHB0ygh)do WhHB0ygh[rYSD0]=nil end return WhHB0ygh end;function S1wg_DG.each(BIL5,GQLlkH)for aN4J2zRQ,eWca in l(BIL5)do GQLlkH(eWca,aN4J2zRQ)end end function S1wg_DG.eachi(AGUR2QK,FK) local _=S1wg_DG.sort(S1wg_DG.select(S1wg_DG.keys(AGUR2QK),S1wg_DG.isInteger)) for YQZ729qQ,rZh2wG in kyWtqIf0(_)do FK(AGUR2QK[rZh2wG],rZh2wG)end end;function S1wg_DG.at(sef4eW6Q,...)local Z={} for UacO6D,FdnzjW in kyWtqIf0({...})do Z[#Z+1]=sef4eW6Q[FdnzjW]end;return Z end function S1wg_DG.adjust(o,lMAL,CpQ) if( o[lMAL]==nil)then zupvsz("key not existing in table")end;local L=S1wg_DG.clone(o)L[lMAL]= v(CpQ)=='function'and CpQ(L[lMAL])or CpQ;return L end function S1wg_DG.count(HnQS_Z,rib) if rib==nil then return S1wg_DG.size(HnQS_Z)end;local hgW2H5=0;for w,YT6wZ in l(HnQS_Z)do if S1wg_DG.isEqual(YT6wZ,rib)then hgW2H5=hgW2H5+1 end end;return hgW2H5 end function S1wg_DG.countf(VYv,gU)local hgW2H5=0;for JzG8W4Ya,dZ54oc in l(VYv)do if gU(dZ54oc,JzG8W4Ya)then hgW2H5=hgW2H5+1 end end;return hgW2H5 end function S1wg_DG.allEqual(v_LoR,gRY)local z,ad=e(v_LoR) for z,Ui0Qa in l(v_LoR)do if gRY then if not gRY(ad,Ui0Qa)then return false end else if not S1wg_DG.isEqual(ad,Ui0Qa)then return false end end end;return true end function S1wg_DG.cycle(g,Itx)Itx=Itx or 1;if Itx<=0 then return S1wg_DG.noop end local JpoaGH,cyAcCT;local RCA=0 while true do return function()JpoaGH=JpoaGH and e(g,JpoaGH)or e(g)cyAcCT=not cyAcCT and JpoaGH or cyAcCT;if Itx then RCA= (JpoaGH==cyAcCT)and RCA+1 or RCA if RCA>Itx then return end end;return g[JpoaGH],JpoaGH end end end function S1wg_DG.map(L46S,GKTYT)local hXSTz8FJ={} for C24r7o4G,b_4Q38cU in l(L46S)do local N,JbPw,j=C24r7o4G,GKTYT(b_4Q38cU,C24r7o4G)hXSTz8FJ[ j and JbPw or N]=j or JbPw end;return hXSTz8FJ end function S1wg_DG.reduce(S,cg4FV7bl,flf9sWX) for uNoS,ZWoH9V08 in l(S)do if flf9sWX==nil then flf9sWX=ZWoH9V08 else flf9sWX=cg4FV7bl(flf9sWX,ZWoH9V08)end end;return flf9sWX end function S1wg_DG.best(RWo,GWBQL)local PCldTUn9,sO_=e(RWo) for ALbdmINL,b in l(RWo)do if sO_==nil then sO_=b else sO_=GWBQL(sO_,b)and sO_ or b end end;return sO_ end function S1wg_DG.reduceBy(DUgF0E,vGxJ6f,a4ga2I,syGyB_)return S1wg_DG.reduce(S1wg_DG.select(DUgF0E,a4ga2I),vGxJ6f,syGyB_)end;function S1wg_DG.reduceRight(VO,J1r,iBcU3_7D) return S1wg_DG.reduce(S1wg_DG.reverse(VO),J1r,iBcU3_7D)end function S1wg_DG.mapReduce(N,M4V,_feve)local OPz_7bk={}for H64aD,ny7 in l(N)do OPz_7bk[H64aD]=not _feve and ny7 or M4V(_feve,ny7)_feve=OPz_7bk[H64aD]end;return OPz_7bk end function S1wg_DG.mapReduceRight(QDj6GAX,k6pXzd,hsLwu)return S1wg_DG.mapReduce(S1wg_DG.reverse(QDj6GAX),k6pXzd,hsLwu)end function S1wg_DG.include(R,JKZ) local yHbsh=(v(JKZ)=='function')and JKZ or S1wg_DG.isEqual;for d4z,i in l(R)do if yHbsh(i,JKZ)then return true end end return false end function S1wg_DG.detect(HyEk4lbh,PhU) local rWwbNge=(v(PhU)=='function')and PhU or S1wg_DG.isEqual for SKxD,o3uQKvJ in l(HyEk4lbh)do if rWwbNge(o3uQKvJ,PhU)then return SKxD end end end function S1wg_DG.where(vAZm,q) local fFuE=S1wg_DG.select(vAZm,function(KypMW)for JJT4nKO in l(q)do if KypMW[JJT4nKO]~=q[JJT4nKO]then return false end end;return true end)return#fFuE>0 and fFuE or nil end function S1wg_DG.findWhere(TFLF,hEoAa) local PGN=S1wg_DG.detect(TFLF,function(K2_kF5)for YpimJ in l(hEoAa)do if hEoAa[YpimJ]~=K2_kF5[YpimJ]then return false end end;return true end)return PGN and TFLF[PGN]end function S1wg_DG.select(Gg7Ttui,_)local EGeAf={}for ymP,z5pHKyoa in l(Gg7Ttui)do if _(z5pHKyoa,ymP)then EGeAf[#EGeAf+1]=z5pHKyoa end end return EGeAf end function S1wg_DG.reject(h,xwT)local y33ux={}for Ut,GOijBp in l(h)do if not xwT(GOijBp,Ut)then y33ux[#y33ux+1]=GOijBp end end;return y33ux end;function S1wg_DG.all(oUi,b2a3) for xer,SQHAAR in l(oUi)do if not b2a3(SQHAAR,xer)then return false end end;return true end function S1wg_DG.invoke(qybRcP1,z) return S1wg_DG.map(qybRcP1,function(N0NaR,FBfW) if( v(N0NaR)=='table')then if N0NaR[z]then if S1wg_DG.isCallable(N0NaR[z])then return N0NaR[z](N0NaR,FBfW)else return N0NaR[z]end else if S1wg_DG.isCallable(z)then return z(N0NaR,FBfW)end end elseif S1wg_DG.isCallable(z)then return z(N0NaR,FBfW)end end)end function S1wg_DG.pluck(lnM4,_oDmX_)local t={}for K,ppm021I in l(lnM4)do if ppm021I[_oDmX_]then t[#t+1]=ppm021I[_oDmX_]end end;return t end;function S1wg_DG.max(ASUXhD,KCm)return z5i2i(ASUXhD,sf0,KCm)end;function S1wg_DG.min(u,fDk)return z5i2i(u,qxZa6ozV,fDk)end function S1wg_DG.same(gxYY,sVMxk)return S1wg_DG.all(gxYY,function(SyD)return S1wg_DG.include(sVMxk,SyD)end)and S1wg_DG.all(sVMxk,function(v4)return S1wg_DG.include(gxYY,v4)end)end;function S1wg_DG.sort(j7siW,Hl)p(j7siW,Hl)return j7siW end function S1wg_DG.sortedk(AP060rq,DIEKD10) local lLJ=S1wg_DG.keys(AP060rq)p(lLJ,DIEKD10)local EicsS=0;return function()EicsS=EicsS+1 return lLJ[EicsS],AP060rq[lLJ[EicsS]]end end function S1wg_DG.sortedv(JubU,L)local JKci=S1wg_DG.keys(JubU)L=L or qxZa6ozV p(JKci,function(o,ZOmcmO)return L(JubU[o],JubU[ZOmcmO])end)local SsBe=0;return function()SsBe=SsBe+1;return JKci[SsBe],JubU[JKci[SsBe]]end end function S1wg_DG.sortBy(_G19JrRB,m0r3_J,MLrs)local hP5=m0r3_J or S1wg_DG.identity if (v(m0r3_J)=='string')then hP5=function(_G19JrRB)return _G19JrRB[m0r3_J]end end;MLrs=MLrs or qxZa6ozV p(_G19JrRB,function(oqjhEZb0,Pha) return MLrs(hP5(oqjhEZb0),hP5(Pha))end)return _G19JrRB end function S1wg_DG.groupBy(G,MOrzq4)local bEMp={} for dd,MOQN in l(G)do local O=MOrzq4(MOQN,dd)if bEMp[O]then bEMp[O][#bEMp[O]+1]=MOQN else bEMp[O]={MOQN}end end;return bEMp end function S1wg_DG.countBy(FEpet,P)local G={}for EcLLM,wo in l(FEpet)do local ur=P(wo,EcLLM) G[ur]=(G[ur]or 0)+1 end;return G end;function S1wg_DG.size(...)local XTX={...}local wc8hjKp1=XTX[1] return(v(wc8hjKp1)=='table')and hgW2H5(XTX[1])or hgW2H5(XTX)end function S1wg_DG.containsKeys(f,Hjag)for Yg in l(Hjag)do if not f[Yg]then return false end end;return true end function S1wg_DG.sameKeys(uc,bw) for ad in l(uc)do if not bw[ad]then return false end end for EG344W in l(bw)do if not uc[EG344W]then return false end end;return true end function S1wg_DG.sample(MVlUhPEM,LT,pfiWYrg)LT=LT or 1;if LT==0 then return{}end if LT==1 then if pfiWYrg then GQLN(pfiWYrg)end;return{MVlUhPEM[toXyq(1,#MVlUhPEM)]}end return S1wg_DG.slice(S1wg_DG.shuffle(MVlUhPEM,pfiWYrg),1,LT)end function S1wg_DG.sampleProb(smnX9H6,FzRhHR,mMBxOoQa)if mMBxOoQa then GQLN(mMBxOoQa)end;local xYSLIT={}for Eae7ILmk,Jy23ZRAA in kyWtqIf0(smnX9H6)do if toXyq()sDjMr then zupvsz("start cannot be greater than finish.")end for biQX3Ut=sDjMr,HSav,-1 do lIpFkbLI(BZmaGN,biQX3Ut)end;return BZmaGN end function S1wg_DG.chunk(BLEXN_,Ljc)local fpN7T,FNSk_,LmE,pZTFVP={},0 for XL,L5vC0Jx in kyWtqIf0(BLEXN_)do pZTFVP=Ljc(L5vC0Jx,XL)LmE= (LmE==nil)and pZTFVP or LmE;FNSk_=( (pZTFVP~=LmE)and(FNSk_+1)or FNSk_)if not fpN7T[FNSk_]then fpN7T[FNSk_]={BLEXN_[XL]}else fpN7T[FNSk_][#fpN7T[FNSk_]+1]=BLEXN_[XL]end;LmE=pZTFVP end;return fpN7T end function S1wg_DG.slice(vpONJ,A,LN)local dA14qP={}for JcQc=A or 1,LN or#vpONJ do dA14qP[#dA14qP+1]=vpONJ[JcQc]end;return dA14qP end function S1wg_DG.first(hDih6_D,QKbZ464i)QKbZ464i=QKbZ464i or 1;local F1TsZ={}for uF2=1,QKbZ464i do F1TsZ[uF2]=hDih6_D[uF2]end;return F1TsZ end function S1wg_DG.initial(T,pC_)local ju=#T pC_=pC_ and ju- (RlMSrmdD(pC_,ju))or ju-1;local deu1={}for IgZ6=1,pC_ do deu1[IgZ6]=T[IgZ6]end;return deu1 end function S1wg_DG.last(kVRiv3F,kWMf)local DawC=#kVRiv3F;kWMf= kWMf and DawC-RlMSrmdD(kWMf-1,DawC-1)or 2;local cP={}for w=kWMf,DawC do cP[#cP+1]=kVRiv3F[w]end;return cP end;function S1wg_DG.rest(UZ,tdH)local ymt={} for WxGA=tdH or 1,#UZ do ymt[#ymt+1]=UZ[WxGA]end;return ymt end;function S1wg_DG.nth(jBuHkH,E3)return jBuHkH[E3]end function S1wg_DG.compact(CZi_zK)local _6KCMph={}for PY3VqYZ8,V in l(CZi_zK)do if V then _6KCMph[#_6KCMph+1]=V end end;return _6KCMph end function S1wg_DG.flatten(y,QF)QF=QF or false;local hN;local hVflx4kh={} for GP,oCZYv2dT in kyWtqIf0(y)do if v(oCZYv2dT)=='table'then hN= QF and oCZYv2dT or S1wg_DG.flatten(oCZYv2dT) for RLaqM3,PoH in kyWtqIf0(hN)do hVflx4kh[#hVflx4kh+1]=PoH end else hVflx4kh[#hVflx4kh+1]=oCZYv2dT end end;return hVflx4kh end function S1wg_DG.difference(xM709D,z50) if not z50 then return S1wg_DG.clone(xM709D)end;return S1wg_DG.select(xM709D,function(sAPD)return not S1wg_DG.include(z50,sAPD)end)end;function S1wg_DG.union(...) return S1wg_DG.unique(S1wg_DG.flatten({...}))end function S1wg_DG.intersection(...)local AVFi={...} local GGKI=AVFi[1]lIpFkbLI(AVFi,1)local gWaGu={} for SFKM,j6jQmlbr in kyWtqIf0(GGKI)do if S1wg_DG.all(AVFi,function(m403CY)return S1wg_DG.include(m403CY,j6jQmlbr)end)then gWaGu[#gWaGu+1]=j6jQmlbr end end;return gWaGu end;function S1wg_DG.disjoint(...)return (#S1wg_DG.intersection(...)==0)end function S1wg_DG.symmetricDifference(dL,PrTsHeT)return S1wg_DG.difference(S1wg_DG.union(dL,PrTsHeT),S1wg_DG.intersection(dL,PrTsHeT))end function S1wg_DG.unique(eNI3MT7)local Rfoo={}for eUJhGD=1,#eNI3MT7 do if not S1wg_DG.find(Rfoo,eNI3MT7[eUJhGD])then Rfoo[#Rfoo+1]=eNI3MT7[eUJhGD]end end;return Rfoo end;function S1wg_DG.isunique(wot8)return #wot8 ==# (S1wg_DG.unique(wot8))end function S1wg_DG.duplicates(j9vJ) local J6Qr27Mh=S1wg_DG.invert(j9vJ)local AwxW8Do={}for _u,B in kyWtqIf0(j9vJ)do if J6Qr27Mh[B]~=_u and not S1wg_DG.find(AwxW8Do,B)then AwxW8Do[#AwxW8Do+1]=B end end;return AwxW8Do end function S1wg_DG.zip(...)local cdxFVpZw={...} local Y=S1wg_DG.max(cdxFVpZw,function(BuX1r)return#BuX1r end)local o9Uh={} for Wyf83f2=1,Y do if not o9Uh[Wyf83f2]then o9Uh[Wyf83f2]={}end for P0olj,z in kyWtqIf0(cdxFVpZw)do if z[Wyf83f2]then o9Uh[Wyf83f2][#o9Uh[Wyf83f2]+1]=z[Wyf83f2]end end end;return o9Uh end function S1wg_DG.zipWith(EHCCkt,...)local x={...} local xNWVmS=S1wg_DG.max(x,function(Pkis6H28)return#Pkis6H28 end)local kGWnkgDu={}for tSE=1,xNWVmS do kGWnkgDu[tSE]=EHCCkt(hUL(S1wg_DG.pluck(x,tSE)))end;return kGWnkgDu end function S1wg_DG.append(abKH,LDp)local GWouUlzZ={} for MqJhIr,Q9 in kyWtqIf0(abKH)do GWouUlzZ[MqJhIr]=Q9 end for c,qnZ81I in kyWtqIf0(LDp)do GWouUlzZ[#GWouUlzZ+1]=qnZ81I end;return GWouUlzZ end function S1wg_DG.interleave(...)local N9uN={...} local QGC=S1wg_DG.max(N9uN,S1wg_DG.size)local K8iFU={} for gbU=1,QGC do for h,hS7 in kyWtqIf0(N9uN)do if hS7[gbU]then K8iFU[#K8iFU+1]=hS7[gbU]end end end;return K8iFU end;function S1wg_DG.interpose(KQjMKhN,R6PYgHHE) for ZwCXrLO=#KQjMKhN,2,-1 do odpE(KQjMKhN,ZwCXrLO,R6PYgHHE)end;return KQjMKhN end function S1wg_DG.range(lI,iMSMP5Lp,WoARZdZ3) if ( lI==nil)and(iMSMP5Lp==nil)and(WoARZdZ3 ==nil)then return{}elseif (lI~=nil)and(iMSMP5Lp==nil)and(WoARZdZ3 ==nil)then lI,iMSMP5Lp,WoARZdZ3=Ub(lI),lI,Ub(lI)elseif (lI~=nil)and(iMSMP5Lp~=nil)and(WoARZdZ3 ==nil)then WoARZdZ3=Ub(iMSMP5Lp-lI)end;local n={lI} local Uj=BCf7(pS78Y((iMSMP5Lp-lI)/WoARZdZ3),0)for HpN_N=1,Uj do n[#n+1]=lI+WoARZdZ3*HpN_N end;return n end function S1wg_DG.rep(yP3QEJ,pwi)local QP={}for Iy=1,pwi do QP[Iy]=yP3QEJ end;return QP end function S1wg_DG.powerset(O9P0mj)local eFGwPxi=#O9P0mj;if eFGwPxi==0 then return{{}}end;local m4x8ZsD4={}for _witc0Pe=1,eFGwPxi do for Y8E=1, eFGwPxi-_witc0Pe+1 do m4x8ZsD4[#m4x8ZsD4+1]=S1wg_DG.slice(O9P0mj,Y8E, Y8E+_witc0Pe-1)end end return m4x8ZsD4 end;function S1wg_DG.partition(h,EnMMG,HzO7UpZ)if EnMMG<=0 then return end return OV7(function() MGSnnzOI(h,EnMMG or 1,X83a,HzO7UpZ)end)end function S1wg_DG.overlapping(B,RNTu,Q_)if RNTu<=1 then return end;return OV7(function()B0o5xpg7(B,RNTu or 2,X83a,Q_)end)end function S1wg_DG.aperture(S8GB,W7yjGm)if W7yjGm<=1 then return end;return OV7(function() VQT(S8GB,W7yjGm or 2,X83a)end)end function S1wg_DG.pairwise(X)return S1wg_DG.aperture(X,2)end;function S1wg_DG.permutation(Y) return OV7(function()Id(Y,#Y,X83a)end)end function S1wg_DG.concat(qqvEf3,Wriu,I0Pxr5F,ukGf_)return JdUtcU(S1wg_DG.map(qqvEf3,tostring),Wriu,I0Pxr5F,ukGf_)end function S1wg_DG.xprod(uZpt01P,hJk0n8bR)local o9DTTJig={} for v4,Uaq2_Xzk in kyWtqIf0(uZpt01P)do for S0DM,GHasi5 in kyWtqIf0(hJk0n8bR)do o9DTTJig[#o9DTTJig+1]={Uaq2_Xzk,GHasi5}end end;return o9DTTJig end;function S1wg_DG.xpairs(QeX_U9tm,Dp9m)local sJjNM={} for GnSs,XP in kyWtqIf0(Dp9m)do sJjNM[GnSs]={QeX_U9tm,XP}end;return sJjNM end function S1wg_DG.xpairsRight(Sj,yKj1) local F9WZ={}for A5,nY_O in kyWtqIf0(yKj1)do F9WZ[A5]={nY_O,Sj}end;return F9WZ end function S1wg_DG.sum(QAJAyj5)local EZ=0;for n,M in kyWtqIf0(QAJAyj5)do EZ=EZ+M end;return EZ end;function S1wg_DG.product(AADiL1)local Arw=1 for b,_ZM1Yj3 in kyWtqIf0(AADiL1)do Arw=Arw*_ZM1Yj3 end;return Arw end;function S1wg_DG.mean(rmSU)return S1wg_DG.sum(rmSU)/ (#rmSU)end function S1wg_DG.median(L2RHrI) local XW7Y5Rz=S1wg_DG.sort(S1wg_DG.clone(L2RHrI))local C=#XW7Y5Rz;if C==0 then return elseif C==1 then return XW7Y5Rz[1]end local NhwEkTd=VCD(C/2)return C%2 ==0 and (XW7Y5Rz[NhwEkTd]+XW7Y5Rz[NhwEkTd+1])/2 or XW7Y5Rz[NhwEkTd]end;function S1wg_DG.noop()return end;function S1wg_DG.identity(XGz)return XGz end;function S1wg_DG.call(Tf4P2eIf,...)return Tf4P2eIf(...)end;function S1wg_DG.constant(TF3Htu) return function()return TF3Htu end end function S1wg_DG.applySpec(K5yUw1t)return function(...)local Mi={}for WWyrqnSL,gVTyP in l(K5yUw1t)do Mi[WWyrqnSL]=gVTyP(...)end;return Mi end end function S1wg_DG.thread(Ck,...)local CRG=Ck;local dkz={...} for zrCq,azXMvVdM in kyWtqIf0(dkz)do if v(azXMvVdM)=='function'then CRG=azXMvVdM(CRG)elseif v(azXMvVdM)=='table'then local CBgxHfbq=azXMvVdM[1]lIpFkbLI(azXMvVdM,1) CRG=S1wg_DG.reduce(azXMvVdM,CBgxHfbq,CRG)end end;return CRG end function S1wg_DG.threadRight(WO,...)local H=WO;local C28NuJ3={...} for sz,qH in kyWtqIf0(C28NuJ3)do if v(qH)=='function'then H=qH(H)elseif v(qH)=='table'then local u=qH[1]lIpFkbLI(qH,1)odpE(qH,H) H=S1wg_DG.reduce(qH,u)end end;return H end function S1wg_DG.dispatch(...)local u={...}return function(...)for J1Vn4uYP,Z in kyWtqIf0(u)do local pJ={Z(...)} if#pJ>0 then return hUL(pJ)end end end end;function S1wg_DG.memoize(NAjg)local con=oUA({},{__mode='kv'}) return function(I)if(con[I]==nil)then con[I]=NAjg(I)end;return con[I]end end function S1wg_DG.unfold(TxmZR6UE,I1b4o) local nAt,pNJ={}while true do pNJ,I1b4o=TxmZR6UE(I1b4o) if pNJ~=nil then nAt[#nAt+1]=pNJ else break end end;return nAt end function S1wg_DG.once(RQ)local wnZcHKf=0;local Lv_8={} return function(...)wnZcHKf=wnZcHKf+1 if wnZcHKf<=1 then Lv_8={...}end;return RQ(hUL(Lv_8))end end function S1wg_DG.before(UQ,hgW2H5)local FG=0;local vLzqjJw={} return function(...)FG=FG+1;if FG<=hgW2H5 then vLzqjJw={...}end;return UQ(hUL(vLzqjJw))end end function S1wg_DG.after(v2dsC21,hgW2H5)local O,wx=hgW2H5,0;return function(...)wx=wx+1;if wx>=O then return v2dsC21(...)end end end function S1wg_DG.compose(...)local u=S1wg_DG.reverse{...} return function(...)local V_84V,qF=true for IZbOX7TW,Dd6ZLpU in kyWtqIf0(u)do if V_84V then V_84V=false;qF=Dd6ZLpU(...)else qF=Dd6ZLpU(qF)end end;return qF end end function S1wg_DG.pipe(MP,...)return S1wg_DG.compose(...)(MP)end function S1wg_DG.complement(w4c)return function(...)return not w4c(...)end end function S1wg_DG.juxtapose(C58,...)local Jk6Nh={} for s1Ws,desLYv in kyWtqIf0({...})do Jk6Nh[s1Ws]=desLYv(C58)end;return hUL(Jk6Nh)end;function S1wg_DG.wrap(COq2NY9I,aoBEg65S) return function(...)return aoBEg65S(COq2NY9I,...)end end function S1wg_DG.times(x6,t3cNa2l)local Ik={}for SeHOs=1,(t3cNa2l or 1) do Ik[SeHOs]=x6(SeHOs)end;return Ik end function S1wg_DG.bind(P2rGsUx,c)return function(...)return P2rGsUx(c,...)end end;function S1wg_DG.bind2(v12AhMm,F2uxGC) return function(Xs0,...)return v12AhMm(Xs0,F2uxGC,...)end end;function S1wg_DG.bindn(QK8ibF,...)local TEio7k0z={...} return function(...)return QK8ibF(hUL(S1wg_DG.append(TEio7k0z,{...})))end end function S1wg_DG.bindall(u,...) local N={...}for O2YgxDc,VLsC67 in kyWtqIf0(N)do local OHw4=u[VLsC67] if OHw4 then u[VLsC67]=S1wg_DG.bind(OHw4,u)end end;return u end function S1wg_DG.cond(FKZ)return function(...)for Fl,QhS8FvKI in kyWtqIf0(FKZ)do if QhS8FvKI[1](...)then return QhS8FvKI[2](...)end end end end function S1wg_DG.both(...)local FaZIJL={...} return function(...) for sOT2O5,x in kyWtqIf0(FaZIJL)do if not x(...)then return false end end;return true end end function S1wg_DG.either(...)local Wswd_OC={...} return function(...) for E,A0Un in kyWtqIf0(Wswd_OC)do if A0Un(...)then return true end end;return false end end function S1wg_DG.neither(...)local nRHrI={...} return function(...) for kZp,A in kyWtqIf0(nRHrI)do if A(...)then return false end end;return true end end function S1wg_DG.uniqueId(_L_)qJExeUn2=qJExeUn2+1;if _L_ then if v(_L_)=='string'then return _L_:format(qJExeUn2)elseif v(_L_)=='function'then return _L_(qJExeUn2)end end;return qJExeUn2 end function S1wg_DG.iterator(WHpm,g,HiR3yiw)local KeKbiDqN=0;return function()KeKbiDqN=KeKbiDqN+1;if HiR3yiw and KeKbiDqN>HiR3yiw then return end;g=WHpm(g)return g end end;function S1wg_DG.skip(WfrZqHH8,YX9s9O) for y64dF=1,(YX9s9O or 1)do if WfrZqHH8()==nil then return end end;return WfrZqHH8 end function S1wg_DG.tabulate(...) local sNSsH={}for K in...do sNSsH[#sNSsH+1]=K end;return sNSsH end function S1wg_DG.iterlen(...)local o8T=0;for xeP in...do o8T=o8T+1 end;return o8T end function S1wg_DG.castArray(Tv_3VlmX)return(v(Tv_3VlmX)~='table')and{Tv_3VlmX}or Tv_3VlmX end function S1wg_DG.flip(BT)return function(...) return BT(hUL(S1wg_DG.reverse({...})))end end;function S1wg_DG.nthArg(_y3z) return function(...)local rdl={...}return rdl[(_y3z<0)and(#rdl+_y3z+1)or _y3z]end end;function S1wg_DG.unary(NAP_5jYs) return function(...) local BZnlpW={...}return NAP_5jYs(BZnlpW[1])end end function S1wg_DG.ary(isN,yRADzw1v) yRADzw1v=yRADzw1v or 1;return function(...)local Jafp={...}local XWh8Ee={} for kpezL1e=1,yRADzw1v do XWh8Ee[kpezL1e]=Jafp[kpezL1e]end;return isN(hUL(XWh8Ee))end end;function S1wg_DG.noarg(h)return function()return h()end end function S1wg_DG.rearg(R7yfz_l9,D35PFLu) return function(...) local wK={...}local qeEwE={} for cbtvFnSa,fYKH_ in kyWtqIf0(D35PFLu)do qeEwE[cbtvFnSa]=wK[fYKH_]end;return R7yfz_l9(hUL(qeEwE))end end;function S1wg_DG.over(...)local W={...} return function(...)local o={} for Mm99M,l6YH in kyWtqIf0(W)do o[#o+1]=l6YH(...)end;return o end end function S1wg_DG.overEvery(...) local gf2=S1wg_DG.over(...)return function(...)return S1wg_DG.reduce(gf2(...),function(F744Ew,zgxKF4)return F744Ew and zgxKF4 end)end end function S1wg_DG.overSome(...)local UlvVvSBR=S1wg_DG.over(...) return function(...) return S1wg_DG.reduce(UlvVvSBR(...),function(i2i,uRGAL)return i2i or uRGAL end)end end function S1wg_DG.overArgs(UUlqXyb6,...)local fOR92g8={...} return function(...)local jU26={...}for WIPTsAPz=1,#fOR92g8 do local DgUx8=fOR92g8[WIPTsAPz] if jU26[WIPTsAPz]then jU26[WIPTsAPz]=DgUx8(jU26[WIPTsAPz])end end;return UUlqXyb6(hUL(jU26))end end function S1wg_DG.converge(imac,xX,Mfb6Kb)return function(...)return imac(xX(...),Mfb6Kb(...))end end function S1wg_DG.partial(RRjV,...)local TDOaFo={...} return function(...)local tLo4={...}local m72l={}for npM3DSU,HGp4e1 in kyWtqIf0(TDOaFo)do m72l[npM3DSU]= (HGp4e1 =='_')and S1wg_DG.shift(tLo4)or HGp4e1 end;return RRjV(hUL(S1wg_DG.append(m72l,tLo4)))end end function S1wg_DG.partialRight(uzJt7E,...)local sRe5S32N={...} return function(...)local Bp={...}local rg={}for S=1,#sRe5S32N do rg[S]= (sRe5S32N[S]=='_')and S1wg_DG.shift(Bp)or sRe5S32N[S]end;return uzJt7E(hUL(S1wg_DG.append(Bp,rg)))end end function S1wg_DG.curry(Fem,cHmVGY)cHmVGY=cHmVGY or 2;local g29sXR={} local function Vat(sfnkWAy8) if cHmVGY==1 then return Fem(sfnkWAy8)end if sfnkWAy8 ~=nil then g29sXR[#g29sXR+1]=sfnkWAy8 end;if#g29sXR-S9TO and ZDP5SDwL= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua" } }Moses-Moses-2.1.0-1/rockspec/moses-1.3-1.rockspec000066400000000000000000000014101334620647700211610ustar00rootroot00000000000000package = "moses" version = "1.3-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.3.0.tar.gz", dir = "Moses-Moses-1.3.0" } description = { summary = "Utility library for functional programming in Lua", detailed = [[ A utility library provinding handy resources for common programming tasks and support for functional programming. It extends the built-in Lua table library, making easier operations on arrays, lists, collections and objects, through 85 weird, bizarre and odd functions. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { moses = "moses.lua" } } Moses-Moses-2.1.0-1/rockspec/moses-1.3.1-1.rockspec000066400000000000000000000015341334620647700213270ustar00rootroot00000000000000package = "moses" version = "1.3.1-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.3.1-1.tar.gz", dir = "Moses-Moses-1.3.1-1" } description = { summary = "Utility library for functional programming in Lua", detailed = [[ A utility library provinding handy functions for common programming tasks and support for functional programming. It complements the built-in Lua table library, making easier operations on arrays, lists, collections and objects, through 88 weird, bizarre and odd functions. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"docs","specs"} }Moses-Moses-2.1.0-1/rockspec/moses-1.3.2-1.rockspec000066400000000000000000000015341334620647700213300ustar00rootroot00000000000000package = "moses" version = "1.3.2-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.3.2-1.tar.gz", dir = "Moses-Moses-1.3.2-1" } description = { summary = "Utility library for functional programming in Lua", detailed = [[ A utility library provinding handy functions for common programming tasks and support for functional programming. It complements the built-in Lua table library, making easier operations on arrays, lists, collections and objects, through 88 weird, bizarre and odd functions. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"docs","specs"} }Moses-Moses-2.1.0-1/rockspec/moses-1.3.2.1-1.rockspec000066400000000000000000000015421334620647700214660ustar00rootroot00000000000000package = "moses" version = "1.3.2.1-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.3.2.1-1.tar.gz", dir = "Moses-Moses-1.3.2.1-1" } description = { summary = "Utility library for functional programming in Lua", detailed = [[ A utility library provinding handy functions for common programming tasks and support for functional programming. It complements the built-in Lua table library, making easier operations on arrays, lists, collections and objects, through 88 weird, bizarre and odd functions. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"docs","specs"} }Moses-Moses-2.1.0-1/rockspec/moses-1.4.0-1.rockspec000066400000000000000000000013471334620647700213310ustar00rootroot00000000000000package = "moses" version = "1.4.0-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.4.0-1.tar.gz", dir = "Moses-Moses-1.4.0-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-1.5.0-1.rockspec000066400000000000000000000013471334620647700213320ustar00rootroot00000000000000package = "moses" version = "1.5.0-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.5.0-1.tar.gz", dir = "Moses-Moses-1.5.0-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-1.5.1-1.rockspec000066400000000000000000000013471334620647700213330ustar00rootroot00000000000000package = "moses" version = "1.5.1-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.5.1-1.tar.gz", dir = "Moses-Moses-1.5.1-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-1.6.0-1.rockspec000066400000000000000000000013471334620647700213330ustar00rootroot00000000000000package = "moses" version = "1.6.0-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.6.0-1.tar.gz", dir = "Moses-Moses-1.6.0-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-1.6.1-1.rockspec000066400000000000000000000013471334620647700213340ustar00rootroot00000000000000package = "moses" version = "1.6.1-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-1.6.1-1.tar.gz", dir = "Moses-Moses-1.6.1-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-2.0.0-1.rockspec000066400000000000000000000013561334620647700213260ustar00rootroot00000000000000package = "moses" version = "2.0.0-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-2.0.0-1.tar.gz", dir = "Moses-Moses-2.0.0-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1, < 5.4" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/rockspec/moses-2.1.0-1.rockspec000066400000000000000000000013561334620647700213270ustar00rootroot00000000000000package = "moses" version = "2.1.0-1" source = { url = "https://github.com/Yonaba/Moses/archive/Moses-2.1.0-1.tar.gz", dir = "Moses-Moses-2.1.0-1" } description = { summary = "Utility-belt library for functional programming in Lua", detailed = [[ A utility-belt library for functional programming, which complements the built-in Lua table library, making easier operations on arrays, lists, collections. ]], homepage = "http://yonaba.github.com/Moses/", license = "MIT " } dependencies = { "lua >= 5.1, < 5.4" } build = { type = "builtin", modules = { ["moses"] = "moses.lua", ["moses_min"] = "moses_min.lua", }, copy_directories = {"doc","spec"} }Moses-Moses-2.1.0-1/spec/000077500000000000000000000000001334620647700147705ustar00rootroot00000000000000Moses-Moses-2.1.0-1/spec/array_spec.lua000066400000000000000000000663751334620647700176440ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Array functions specs', function() describe('sample', function() it('samples n values from array', function() local array = M.range(1,20) local sample = M.sample(array, 5) assert.equal(#sample, 5) M.each(sample, function(__,v) assert.is_true(M.include(array, v)) end) end) it('when not given, n defaults to 1', function() local array = M.range(1,20) local sample = M.sample(array) assert.equal(#sample, 1) assert.is_true(M.include(array, sample[1])) end) it('if n == 0, returns an empty array', function() local array = M.range(1,5) local sample = M.sample(array, 0) assert.is_true(#sample == 0) end) it('if n < 0, returns an empty array', function() local array = M.range(1,5) assert.is_true(#M.sample(array, -1) == 0) end) end) describe('sampleProb', function() it('returns a sample of an array values', function() local array = M.range(1,20) local sample = M.sampleProb(array, 0.2) M.each(sample, function(__,v) assert.is_true(M.include(array, v)) end) end) end) describe('nsorted', function() it('returns the top n-values from an array', function() local array = M.range(1,20) assert.is_true(M.isEqual(M.nsorted(array,5),{1,2,3,4,5})) local function comp(a,b) return a > b end assert.is_true(M.isEqual(M.nsorted(array,3,comp),{20,19,18})) end) end) describe('shuffle', function() it('shuffles values and objects in a collection', function() local values = {'a','b','c','d'} assert.is_true(M.same(M.shuffle (values),values)) end) it('can accept a seed value to init randomization', function() local values = {'a','b','c','d'} local seed = os.time() assert.is_true(M.same(M.shuffle(values,seed),values)) end) it('shuffled table has the same elements in a different order', function() local values = {'a','b','c','d'} assert.is_true(M.same(M.shuffle(values),values)) assert.is_true(M.same(M.shuffle(values),values)) end) end) describe('pack', function() it('converts a vararg list to an array', function() assert.is_true(M.isArray(M.pack(1,2,3,4))) assert.is_true(M.isEqual(M.pack(1,2,8,'d','a',0),{1,2,8,'d','a',0})) end) it('preserves input order', function() local args = M.pack(1,2,3,4,5) for i = 1, 5 do assert.equal(args[i], i) end end) end) describe('find', function() it('looks for a value in a given array and returns its position', function() assert.equal(M.find({4,3,2,1},2), 3) end) it('uses M.isEqual to compare values', function() assert.equal(M.find({{4},{3},{2},{1}},{3}), 2) end) it('returns the index of the first occurence', function() assert.equal(M.find({4,4,3,3,2,2,1,1},2),5) end) it('can start the search at a specific position', function() assert.equal(M.find({4,4,3,3,2,1,2,1,1},2,6),7) end) end) describe('reverse', function() it('reverse values and objects in a given array', function() assert.is_true(M.isEqual(M.reverse({1,2,3,'d'}),{'d',3,2,1})) end) end) describe('fill', function() it('fills an array with a value', function() local array = M.range(1,5) assert.is_true(M.isEqual(M.fill(array,0),{0,0,0,0,0})) end) it('fills an array starting from an index', function() local array = M.range(1,5) assert.is_true(M.isEqual(M.fill(array,0,4),{1,2,3,0,0})) end) it('fills an array replacing values inside a range', function() local array = M.range(1,5) assert.is_true(M.isEqual(M.fill(array,0,3,4),{1,2,0,0,5})) end) it('enlarges the array when the last index is greater than array size', function() local array = M.range(1,5) assert.is_true(M.isEqual(M.fill(array,0,3,8),{1,2,0,0,0,0,0,0})) end) end) describe('zeros', function() it('returns an array of n zeros', function() assert.is_true(M.isEqual(M.zeros(5), {0,0,0,0,0})) assert.is_true(M.isEqual(M.zeros(2), {0,0})) assert.is_true(M.isEqual(M.zeros(1), {0})) end) end) describe('ones', function() it('returns an array of n zeros', function() assert.is_true(M.isEqual(M.ones(5), {1,1,1,1,1})) assert.is_true(M.isEqual(M.ones(3), {1,1,1})) assert.is_true(M.isEqual(M.ones(1), {1})) end) end) describe('vector', function() it('returns an array of n times a given value', function() assert.is_true(M.isEqual(M.vector(false,4), {false, false, false, false})) local f = function() end assert.is_true(M.isEqual(M.vector(f,2), {f, f})) end) end) describe('selectWhile', function() it('collect values from an array while they pass a thruth test', function() assert.is_true(M.isEqual(M.selectWhile({2,4,6,8}, function(v)return v%2==0 end),{2,4,6,8})) end) it('breaks as soon as one value do not pass the test', function() assert.is_true(M.isEqual(M.selectWhile({2,4,6,8,9,10,12}, function(v) return v%2==0 end),{2,4,6,8})) end) end) describe('dropWhile', function() it('rejects values from an array while they pass a thruth test', function() assert.is_true(M.isEqual(M.dropWhile({2,4,6,8}, function(v) return v%2==0 end),{})) end) it('breaks as soon as one value do not pass the test', function() assert.is_true(M.isEqual(M.dropWhile({2,4,6,8,9,10,12}, function(v) return v%2==0 end),{9,10,12})) end) end) describe('sortedIndex', function() it('returns the index at which a value should be inserted to preserve order', function() local comp = function(a,b) return a5 end)) end) end) describe('findLastIndex', function() it('returns the last index at which a predicate passes a truth test', function() assert.equal(M.findLastIndex({1,2,3,4,5},function(_,v) return v%2==0 end),4) end) it('returns nil when nothing was found', function() assert.is_nil(M.findLastIndex({1,2,3,4,5},function(_,v) return v>5 end)) end) end) describe('addTop', function() it('adds values at the top of an array', function() assert.is_true(M.isEqual(M.addTop({},1,2,3),{3,2,1})) assert.is_true(M.isEqual(M.addTop({},'a',true,3),{3,true,'a'})) end) it('preserves the existing elements', function() assert.is_true(M.isEqual(M.addTop({1,2},1,2,3),{3,2,1,1,2})) assert.is_true(M.isEqual(M.addTop({'i','j'},'a',true,3),{3,true,'a','i','j'})) end) end) describe('prepend', function() it('adds values at the top of an array, preserving order', function() assert.is_true(M.isEqual(M.prepend({},1,2,3),{1,2,3})) assert.is_true(M.isEqual(M.prepend({},'a',true,3),{'a',true,3})) end) it('preserves the existing elements', function() assert.is_true(M.isEqual(M.prepend({1,2},1,2,3),{1,2,3,1,2})) assert.is_true(M.isEqual(M.prepend({'i','j'},'a',true,3),{'a',true,3,'i','j'})) end) end) describe('push', function() it('appends values at the end of an array', function() assert.is_true(M.isEqual(M.push({},1,2,3),{1,2,3})) assert.is_true(M.isEqual(M.push({},'a',true,3),{'a',true,3})) end) it('preserves the existing elements', function() assert.is_true(M.isEqual(M.push({1,2},1,2,3),{1,2,1,2,3})) assert.is_true(M.isEqual(M.push({'i','j'},'a',true,3),{'i','j','a',true,3})) end) end) describe('shift', function() it('returns the value at the top of a given array', function() assert.equal(M.shift {1,7,9} ,1) end) it('also removes this value from the given array', function() local array = {1,7,9} assert.equal(M.shift(array),1) assert.is_true(M.isEqual(array,{7,9})) end) end) describe('unshift', function() it('returns the value at the end of a given array', function() assert.equal(M.unshift {1,7,9} ,9) end) it('also removes this value from the given array', function() local array = {1,7,9} assert.equal(M.unshift(array),9) assert.is_true(M.isEqual(array,{1,7})) end) end) describe('pull', function() it('removes all listed values in a given array', function() assert.is_true(M.same(M.pull({1,4,3,1,2,3},1),{4,3,2,3})) assert.is_true(M.same(M.pull({1,4,3,1,2,3},1,3),{4,2})) end) end) describe('removeRange', function() it('removes all values within "start" and "finish" indexes', function() assert.is_true(M.isEqual(M.removeRange({1,2,3,4,5,6},2,4),{1,5,6})) end) it('arg "finish" defaults to the end of the array when not given ', function() assert.is_true(M.isEqual(M.removeRange({1,2,3,4,5,6},3),{1,2})) end) it('arg "start" defaults to the initial index when not given ', function() assert.is_true(M.isEqual(M.removeRange({1,2,3,4,5,6}),{})) end) it('throws an error when "finish" < "start"', function() assert.error(function()M.removeRange({1,2,3,4,5,6},4,2) end) end) end) describe('chunk', function() it('chunks in blocks consecutive values returning the same value from a given function', function() local t = {1,2,2,3,3,4,4} local v = M.chunk(t, function(v) return v%2==0 end) assert.equal(#v, 4) assert.is_true(M.isEqual(v[1], {1})) assert.is_true(M.isEqual(v[2], {2,2})) assert.is_true(M.isEqual(v[3], {3,3})) assert.is_true(M.isEqual(v[4], {4,4})) end) end) describe('slice',function() it('slices a portion of an array',function() assert.is_true(M.isEqual(M.slice({'a','b','c','d','e'},2,3),{'b','c'})) end) it('arg "right" bound defaults to the array length when not given',function() assert.is_true(M.isEqual(M.slice({'a','b','c','d','e'},3),{'c','d','e'})) end) it('arg "left" bound defaults to the initial index when not given',function() assert.is_true(M.isEqual(M.slice({'a','b','c','d','e'}),{'a','b','c','d','e'})) end) end) describe('first',function() it('returns the n-first elements', function() assert.is_true(M.isEqual(M.first({5,8,12,20},2),{5,8})) end) it('arg "n" defaults 1 when not given', function() assert.is_true(M.isEqual(M.first({5,8,12,20}),{5})) end) end) describe('initial',function() it('exludes the last N elements', function() assert.is_true(M.isEqual(M.initial({5,8,12,20},3),{5})) assert.is_true(M.isEqual(M.initial({5,8,12,20},4),{})) end) it('returns all values but the last one if arg "n" was not given', function() assert.is_true(M.isEqual(M.initial({5,8,12,20}),{5,8,12})) end) it('passing "n" greather than the array size returns an empty', function() assert.is_true(M.isEqual(M.initial({5,8,12,20},5),{})) end) it('returns the whole array when "n" equals 0', function() assert.is_true(M.isEqual(M.initial({5,8,12,20},0),{5,8,12,20})) end) end) describe('last',function() it('returns the last N elements', function() assert.is_true(M.isEqual(M.last({5,8,12,20},3),{8,12,20})) assert.is_true(M.isEqual(M.last({5,8,12,20},1),{20})) assert.is_true(M.isEqual(M.last({5,8,12,20},2),{12,20})) assert.is_true(M.isEqual(M.last({5,8,12,20},4),{5,8,12,20})) end) it('returns all values but the first one if arg "n" was not given', function() assert.is_true(M.isEqual(M.last({5,8,12,20}),{8,12,20})) end) it('if arg "n" is lower than the array size, returns all values', function() assert.is_true(M.isEqual(M.last({5,8,12,20},5),{5,8,12,20})) end) end) describe('rest',function() it('excludes all values before a given index', function() assert.is_true(M.isEqual(M.rest({5,8,12,20},2),{8,12,20})) assert.is_true(M.isEqual(M.rest({5,8,12,20},1),{5,8,12,20})) assert.is_true(M.isEqual(M.rest({5,8,12,20},4),{20})) end) it('returns an empty array when arg "index" > #array', function() assert.is_true(M.isEqual(M.rest({5,8,12,20},5),{})) end) it('returns all values if arg "index" <= 0', function() assert.is_true(M.isEqual(M.rest({5,8,12,20},0),{5,8,12,20})) assert.is_true(M.isEqual(M.rest({5,8,12,20},-1),{5,8,12,20})) end) end) describe('nth', function() it('returns the value at "index"', function() assert.equal(3, M.nth({1,2,3,4,5,6}, 3)) end) end) describe('compact',function() it('trims out all falsy values from an array', function() assert.is_true(M.isEqual(M.compact({a,'a',false,'b',true}),{'a','b',true})) end) end) describe('flatten',function() it('flattens nested arrays', function() assert.is_true(M.isEqual(M.flatten({1,{2,3},{4,5,{6,7}}}),{1,2,3,4,5,6,7})) end) it('when given arg "shallow", flatten only first level', function() assert.is_true(M.isEqual(M.flatten({1,{2,3},{4,5,{6,7}}},true),{1,2,3,4,5,{6,7}})) end) end) describe('difference',function() it('returns values in the first array not present in the second array', function() local array = {1,2,'a',4,5} assert.is_true(M.isEqual(M.difference(array,{1,'a'}),{2,4,5})) assert.is_true(M.isEqual(M.difference(array,{5}),{1,2,'a',4})) end) it('ignores values in the second array not found in the first array', function() local array = {1,2,'a',4,5} assert.is_true(M.isEqual(M.difference(array,{1,'a','b','c'}),{2,4,5})) end) it('leaves array untouched when given no extra-args', function() assert.is_true(M.isEqual(M.difference({1,2,'a',4,5}),{1,2,'a',4,5})) end) end) describe('union',function() it('returns the duplicate-free union of all passed-in arrays', function() local a = {"a"}; local b = {1,2,3}; local c = {2,10} assert.is_true(M.isEqual(M.union(a,b,c),{'a',1,2,3,10})) end) it('accepts nested arrays as well', function() local a = {"a",{"b","c"}}; local b = {1,{2},3}; local c = {2,10} assert.is_true(M.isEqual(M.union(a,b,c),{'a','b','c',1,2,3,10})) end) end) describe('intersection',function() it('returns the intersection of all passed-in arrays', function() local a = {1,3}; local b = {4,2,3}; local c = {2,3,10} assert.is_true(M.isEqual(M.intersection(a,b,c),{3})) end) it('fails with nested arrays', function() local a = {1,{3}}; local b = {4,2,3}; local c = {2,3,10} assert.is_true(M.isEqual(M.intersection(a,b,c),{})) end) end) describe('disjoint',function() it('checks if all passed-in arrays are disjoint', function() local A = {'a'} local B = {'a',1,3} local C = {3,10,2} assert.is_false(M.disjoint(A,B)) assert.is_true(M.disjoint(A,C)) assert.is_false(M.disjoint(B,C)) end) end) describe('symmetricDifference',function() it('returns the symmetric difference from two arrays', function() local a = {1,3}; local b = {4,2,3}; local c = {2,3,10} assert.is_true(M.same(M.symmetricDifference(a, b), {1,4,2})) assert.is_true(M.same(M.symmetricDifference(a, c), {1,2,10})) assert.is_true(M.same(M.symmetricDifference(b, c), {4,10})) end) end) describe('unique',function() it('returns a duplicate-free array',function() assert.is_true(M.isEqual(M.unique({1,1,2,2,3,3,4,4,4,5}),{1,2,3,4,5})) end) end) describe('isunique',function() it('Checks if a given array is duplicate-free',function() assert.is_true(M.isunique({1,2,3,4,5})) assert.is_false(M.isunique({1,2,3,4,4})) end) end) describe('duplicates',function() it('returns a list of all duplicates in array', function() assert.is_true(M.isEqual(M.duplicates({1,2,3,3,8,8,3,2,4}),{2,3,8})) assert.is_true(M.isEqual(M.duplicates({true, false, true, 1, '5', '1', '5'}),{true, '5'})) end) end) describe('zip',function() it('zips together values from different arrays sharing the same index', function() local names = {'Bob','Alice','James'}; local ages = {22, 23} assert.is_true(M.isEqual(M.zip(names,ages),{{'Bob',22},{'Alice',23},{'James'}})) end) end) describe('zipWith',function() it('zips together values from different arrays sharing the same index using a function', function() local names = {'Bob','Alice','James'}; local ages = {22, 23, 25} local function introduce(name, age) return 'My name is '..name..' and I am '..age..' years old.' end local t = M.zipWith(introduce,names,ages) assert.equal(t[1],'My name is Bob and I am 22 years old.') assert.equal(t[2],'My name is Alice and I am 23 years old.') assert.equal(t[3],'My name is James and I am 25 years old.') end) end) describe('append',function() it('appends two arrays together', function() assert.is_true(M.isEqual(M.append({1,2,3},{'a','b'}),{1,2,3,'a','b'})) end) end) describe('interleave',function() it('interleaves values from passed-in arrays', function() assert.is_true(M.isEqual(M.interleave({1,2,3},{'a','b','c'}),{1,'a',2,'b',3,'c'})) assert.is_true(M.isEqual(M.interleave({1},{'a','b','c'}),{1,'a','b','c'})) end) end) describe('interpose',function() it('interposes a value in-between values from a passed-in array', function() assert.is_true(M.isEqual(M.interpose({1,2,3},'a'),{1,'a',2,'a',3})) assert.is_true(M.isEqual(M.interpose({5,5,5,5}, false),{5,false,5,false,5,false,5})) end) it('leaves the array untouched if containing a single element', function() assert.is_true(M.isEqual(M.interpose({1},'a'),{1})) end) end) describe('range',function() it('generate an arithmetic progression', function() assert.is_true(M.isEqual(M.range(1,5,1),{1,2,3,4,5})) assert.is_true(M.isEqual(M.range(-2,5,1),{-2,-1,0,1,2,3,4,5})) assert.is_true(M.isEqual(M.range(1,5,2),{1,3,5})) end) it('arg "step" default to 1 or -1 when no given', function() assert.is_true(M.isEqual(M.range(1,5),{1,2,3,4,5})) assert.is_true(M.isEqual(M.range(5,1),{5,4,3,2,1})) end) it('handles real values as well', function() assert.is_true(M.isEqual(M.range(3.2,5,0.5),{3.2,3.7,4.2,4.7})) end) it('when only one arg is passed, counts from 1', function() assert.is_true(M.isEqual(M.range(3),{1,2,3})) assert.is_true(M.isEqual(M.range(-3),{-1,-2,-3})) end) end) describe('rep',function() it('generates a list of n repetitions of a value', function() assert.is_true(M.isEqual(M.rep('a',4),{'a','a','a','a'})) assert.is_true(M.isEqual(M.rep(false,3),{false, false, false})) end) end) describe('powerset',function() it('generates the powerset of a given array', function() assert.is_true(M.isEqual(M.powerset({1,2,3}),{{1},{2},{3},{1,2},{2,3},{1,2,3}})) assert.is_true(M.isEqual(M.powerset({1,2,3,4}),{{1},{2},{3},{4},{1,2},{2,3},{3,4},{1,2,3},{2,3,4},{1,2,3,4}})) end) end) describe('partition',function() it('iterates on partitions of a given array', function() local array = M.range(1,10) local split5 = {M.range(1,5), M.range(6,10)} local split3 = {M.range(1,3), M.range(4,6), M.range(7,9), {10}} local i = 0 for p in M.partition(array,5) do i = i + 1 assert.is_true(M.isEqual(p, split5[i])) end i = 0 for p in M.partition(array,3) do i = i + 1 assert.is_true(M.isEqual(p, split3[i])) end end) it('if a 3rd argument pad is supplied, will adjust the last partition', function() local array = M.range(1,10) local split4 = {{1,2,3,4},{5,6,7,8},{9,10,0,0}} local i = 0 for p in M.partition(array,4,0) do i = i + 1 assert.is_true(M.isEqual(p, split4[i])) end end) end) describe('overlapping',function() it('returns overlapping subsequences', function() local array = M.range(1,10) local sliding2 = {{1,2},{2,3},{3,4},{4,5},{5,6},{6,7},{7,8},{8,9},{9,10}} local sliding3 = {{1,2,3},{3,4,5},{5,6,7},{7,8,9},{9,10}} local sliding5 = {{1,2,3,4,5},{5,6,7,8,9},{9,10}} local i = 0 for p in M.overlapping(array,2) do i = i + 1 assert.is_true(M.isEqual(p, sliding2[i])) end i = 0 for p in M.overlapping(array,3) do i = i + 1 assert.is_true(M.isEqual(p, sliding3[i])) end i = 0 for p in M.overlapping(array,5) do i = i + 1 assert.is_true(M.isEqual(p, sliding5[i])) end end) it('if a 3rd argument pad is supplied, will adjust the last subsequence', function() local array = M.range(1,10) local sliding3 = {{1,2,3},{3,4,5},{5,6,7},{7,8,9},{9,10,0}} local sliding5 = {{1,2,3,4,5},{5,6,7,8,9},{9,10,0,0,0}} local i = 0 for p in M.overlapping(array,3,0) do i = i + 1 assert.is_true(M.isEqual(p, sliding3[i])) end i = 0 for p in M.overlapping(array,5,0) do i = i + 1 assert.is_true(M.isEqual(p, sliding5[i])) end end) end) describe('aperture', function() it('returns sliding partitions of a given array', function() local array = M.range(1,5) local slides2 = {{1,2},{2,3},{3,4},{4,5}} local slides3 = {{1,2,3},{2,3,4},{3,4,5}} local slides4 = {{1,2,3,4},{2,3,4,5}} local slides5 = {{1,2,3,4,5}} local i = 0 for p in M.aperture(array, 2) do i = i + 1 assert.is_true(M.isEqual(p, slides2[i])) end i = 0 for p in M.aperture(array, 3) do i = i + 1 assert.is_true(M.isEqual(p, slides3[i])) end i = 0 for p in M.aperture(array, 4) do i = i + 1 assert.is_true(M.isEqual(p, slides4[i])) end i = 0 for p in M.aperture(array, 5) do i = i + 1 assert.is_true(M.isEqual(p, slides5[i])) end end) end) describe('pairwise', function() it('returns sliding partitions of a given array', function() local array = M.range(1,5) local pw = {{1,2},{2,3},{3,4},{4,5}} local i = 0 for p in M.pairwise(array) do i = i + 1 assert.is_true(M.isEqual(p, pw[i])) end end) end) describe('permutation',function() it('iterates on permutations of a given array', function() local array = {'a','b', 'c'} local perm = {'abc','acb', 'bac', 'bca', 'cab', 'cba'} for p in M.permutation(array) do local strp = M.concat(p) M.pull(perm, strp) end assert.is_true(#perm == 0) end) end) describe('concat',function() it('concatenates an array contents', function() assert.equal(M.concat({1,2,3,4}),'1234') assert.equal(M.concat({'a',1,0,1,'b'}),'a101b') end) it('handles boolean values', function() assert.equal(M.concat({1,true,3,false}),'1true3false') end) it('when arg "sep" is given, uses "sep" as a separator', function() assert.equal(M.concat({1,3,false,'A'},' '),'1 3 false A') assert.equal(M.concat({1,3,false,'A'},', '),'1, 3, false, A') end) it('when args "i" and/or "j" are given, concats values within "i" and "j" indexes', function() assert.equal(M.concat({1,3,false,'A'},' ',2,3),'3 false') assert.equal(M.concat({1,3,false,'A'},', ',2,3),'3, false') assert.equal(M.concat({1,3,false,'A','K'},' ',2),'3 false A K') end) end) describe('xprod',function() it('returns all possible pairs', function() local r = M.xprod({1,2,3},{'a','b'}) assert.is_true(M.isEqual(r[1],{1,'a'})) assert.is_true(M.isEqual(r[2],{1,'b'})) assert.is_true(M.isEqual(r[3],{2,'a'})) assert.is_true(M.isEqual(r[4],{2,'b'})) assert.is_true(M.isEqual(r[5],{3,'a'})) assert.is_true(M.isEqual(r[6],{3,'b'})) end) end) describe('xpairs',function() it('create pairs by prepending value to array values', function() local r = M.xpairs(1,{1,2,3}) assert.is_true(M.isEqual(r[1],{1,1})) assert.is_true(M.isEqual(r[2],{1,2})) assert.is_true(M.isEqual(r[3],{1,3})) end) end) describe('xpairsRight',function() it('create pairs by appending value to array values', function() local r = M.xpairsRight(1,{1,2,3}) assert.is_true(M.isEqual(r[1],{1,1})) assert.is_true(M.isEqual(r[2],{2,1})) assert.is_true(M.isEqual(r[3],{3,1})) end) end) describe('sum',function() it('returns the sum of array values', function() assert.equal(M.sum {1,2,3,4,5}, 15) assert.equal(M.sum {1,2,3,4}, 10) assert.equal(M.sum {1,2,3}, 6) end) end) describe('product',function() it('returns the product of array values', function() assert.equal(M.product {1,2,3,4,5}, 120) assert.equal(M.product {1,2,3,4}, 24) assert.equal(M.product {1,2,3}, 6) end) end) describe('mean',function() it('returns the mean of array values', function() assert.equal(M.mean {1,2,3,4,5}, 3) assert.equal(M.mean {1,2,3,4}, 2.5) end) end) describe('meadian',function() it('returns the median of array values', function() assert.equal(M.median {1,2,3,4,5}, 3) assert.equal(M.median {1,2,3,4}, 2.5) end) end) end)Moses-Moses-2.1.0-1/spec/chaining_spec.lua000066400000000000000000000013431334620647700202660ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Chaining specs', function() describe('chain', function() it('Chains a value',function() local v = M.chain({1,2,3,4}) :filter(function(k) return k%2~=0 end) :max() :value() assert.equal(v, 3) end) it('M(value) is the same as M.chain(value)', function() local v = M({1,2,3,4}) :filter(function(k) return k%2~=0 end) :max() :value() assert.equal(v, 3) end) end) describe('value', function() it('Unwraps a chained object',function() local t = {1,2,3} assert.equal(M.chain(t):value(), t) assert.equal(M(t):value(), t) end) end) end)Moses-Moses-2.1.0-1/spec/func_spec.lua000066400000000000000000000546121334620647700174500ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Utility functions specs', function() describe('noop', function() it('the no-operation function',function() assert.is_nil(M.noop()) assert.is_nil(M.noop(nil)) assert.is_nil(M.noop(false)) assert.is_nil(M.noop({})) assert.is_nil(M.noop(function() end)) assert.is_nil(M.noop(M.noop)) end) end) describe('identity', function() it('returns the received value',function() assert.equal(M.identity(1),1) local v = {x = 0} assert.equal(M.identity(v),v) assert.is_not.equals(v,{x = 0}) end) end) describe('call', function() it('calls f(...) and returns the results',function() assert.equal(M.call(math.pow, 2, 3), 8) assert.equal(M.call(string.len, 'hello' ), 5) assert.equal(M.call(table.concat, {1,2,3,4,5}, ',', 2, 4),"2,3,4") end) end) describe('applySpec', function() it('returns a spec function which produces objects',function() local stats = M.applySpec({ min = function(...) return math.min(...) end, max = function(...) return math.max(...) end, }) for i = 1, 10 do local mn, mx = math.random(1,10), math.random(11,20) local t = M.range(mn, mx) table.sort(t) local unpack = unpack or table.unpack local r = stats(unpack(t)) assert.equal(r.min, t[1]) assert.equal(r.max, t[#t]) end end) end) describe('thread', function() it('threads a value through functions',function() local function inc(x) return x + 1 end local function double(x) return 2 * x end local function square(x) return x * x end assert.equal(M.thread(2, inc, double, square), 36) assert.equal(M.thread(3, double, inc, square), 49) assert.equal(M.thread(4, square, double, inc), 33) assert.equal(M.thread(5, square, inc, double), 52) end) it('accepts funcs taking more than one arg',function() local function inc(x) return x + 1 end local function add(x, y) return x + y end local function pow(x, y) return x ^ y end assert.equal(M.thread(2, inc, {add, 3}, {pow, 2}), 36) assert.equal(M.thread(2, {add, 4}, inc, {pow, 2}), 49) end) end) describe('threadRight', function() it('threads a value through functions',function() local function inc(x) return x + 1 end local function double(x) return 2 * x end local function square(x) return x * x end assert.equal(M.threadRight(2, inc, double, square), 36) assert.equal(M.threadRight(3, double, inc, square), 49) assert.equal(M.threadRight(4, square, double, inc), 33) assert.equal(M.threadRight(5, square, inc, double), 52) end) it('accepts funcs taking more than one arg',function() local function inc(x) return x + 1 end local function add(x, y) return x + y end local function pow(x, y) return x ^ y end assert.equal(M.threadRight(2, inc, {add, 3}, {pow, 2}), 64) assert.equal(M.threadRight(2, {add, 4}, inc, {pow, 2}), 128) end) end) describe('dispatch', function() it('produces a dispatch function',function() local f = M.dispatch( function() return nil end, function (v) return v+1 end, function (v) return 2*v end ) assert.equal(f(5),6) assert.equal(f(7),8) end) end) describe('memoize', function() local fib_time, fib_value, mfib_time, mfib_value local fib, mfib it('memoizes an expensive function by caching its results',function() local function fib(n) return n < 2 and n or fib(n-1)+fib(n-2) end local mfib = M.memoize(fib) assert.equal(fib(10), mfib(10)) assert.equal(fib(15), mfib(15)) assert.equal(fib(8), mfib(8)) assert.equal(fib(13), mfib(13)) end) end) describe('unfold', function() it('builds a list from a seed value using a iterator',function() local function iter(seed) if seed < 100 then return seed, seed * 2 end end assert.is_true(M.isEqual(M.unfold(iter,1),{1,2,4,8,16,32,64})) assert.is_true(M.isEqual(M.unfold(iter,5),{5, 10,20,40,80})) assert.is_true(M.isEqual(M.unfold(iter,10),{10,20,40,80})) end) end) describe('once', function() it('returns a version of a function that runs once',function() local sq = M.once(function(a) return a*a end) assert.equal(sq(2),4) end) it('successive calls will keep yielding the original answer',function() local sq = M.once(function(a) return a*a end) for i = 1,10 do assert.equal(sq(i),1) end end) end) describe('before', function() it('returns a version of a function that runs no more than count-th calls',function() local function say(something) return something end local speak3times = M.before(say, 3) assert.equal(speak3times('a'), 'a') assert.equal(speak3times('b'), 'b') assert.equal(speak3times('c'), 'c') assert.equal(speak3times('d'), 'c') assert.equal(speak3times('e'), 'c') assert.equal(speak3times('f'), 'c') end) end) describe('after', function() it('returns a function that will respond on its count-th call',function() local function a(r) return (r) end a = M.after(a,5) for i = 1,10 do if i < 5 then assert.is_nil(a(i)) else assert.equal(a(i),i) end end end) end) describe('compose', function() it('can compose commutative functions',function() local greet = function(name) return "hi: " .. name end local exclaim = function(sentence) return sentence .. "!" end assert.equal(M.compose(greet,exclaim)('moe'),'hi: moe!') assert.equal(M.compose(exclaim,greet)('moe'),'hi: moe!') end) it('composes mutiple functions',function() local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end local compositae = M.compose(f,g,h) assert.equal(compositae(10),36) assert.equal(compositae(20),121) end) it('compose non commutative functions in reverse order',function() local function f(s) return (s or '')..'f' end local function g(s) return (s or '')..'g' end local function h(s) return (s or '')..'h' end assert.equal(M.compose(f,g,h)(),'hgf') assert.equal(M.compose(h,g,f)(),'fgh') assert.equal(M.compose(f,h,g)(),'ghf') assert.equal(M.compose(g,h,f)(),'fhg') end) end) describe('pipe', function() it('pipes a value through a series of functions',function() local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end assert.equal(M.pipe(10,f,g,h),36) assert.equal(M.pipe(20,f,g,h),121) end) end) describe('complement', function() it('returns a function which returns the logical complement of a given function',function() assert.is_false(M.complement(function() return true end)()) assert.is_true(M.complement(function() return false end)()) assert.is_true(M.complement(function() return nil end)()) assert.is_false(M.complement(function() return 1 end)()) end) end) describe('juxtapose', function() it('calls a sequence of functions with the same set of args',function() local function f(x) return x^2 end local function g(x) return x+1 end local function h(x) return x/2 end local rf, rg, rh = M.juxtapose(10, f, g, h) assert.equal(rf, 100) assert.equal(rg, 11) assert.equal(rh, 5) end) end) describe('wrap', function() it('wraps a function and passes args',function() local greet = function(name) return "hi: " .. name end local backwards = M.wrap(greet, function(f,arg) return f(arg) ..'\nhi: ' .. arg:reverse() end) assert.equal(backwards('john'),'hi: john\nhi: nhoj') end) end) describe('times', function() it('calls a given function n times',function() local f = ('Lua programming'):gmatch('.') local r = M.times(f, 3) assert.is_true(M.isEqual(r,{'L','u','a'})) local count = 0 local function counter() count = count+1 end M.times(counter, 10) assert.equal(count,10) end) end) describe('bind', function() it('binds a value to the first arg of a function',function() local sqrt2 = M.bind(math.sqrt,2) assert.equal(sqrt2(),math.sqrt(2)) end) end) describe('bind2', function() it('binds a value to the second arg of a function',function() local last2 = M.bind2(M.last,2) local r = last2({1,2,3,4,5,6}) assert.is_true(M.isEqual(r, {5,6})) end) end) describe('bindn', function() it('binds n values to as the n-first args of a function',function() local function out(...) return table.concat {...} end out = M.bindn(out,'OutPut',':',' ') assert.equal(out(1,2,3),'OutPut: 123') assert.equal(out('a','b','c','d'),'OutPut: abcd') end) end) describe('bindall', function() it('binds methods to object',function() local window = { setPos = function(w,x,y) w.x, w.y = x, y end, setName = function(w,name) w.name = name end, getName = function(w) return w.name end, } window = M.bindall(window, 'setPos', 'setName', 'getName') window.setPos(10,15) window.setName('fooApp') assert.equal(window.x, 10) assert.equal(window.y, 15) assert.equal(window.name, 'fooApp') assert.equal(window.getName(), 'fooApp') end) end) describe('cond', function() it('return a function which runs a set of predicates',function() local multipleOf = M.cond({ {function(v) return v%2==0 end, function(v) return v..' is multiple of 2' end}, {function(v) return v%3==0 end, function(v) return v..' is multiple of 3' end}, {function(v) return v%5==0 end, function(v) return v..' is multiple of 5' end}, {function() return true end, function(v) return 'could not find an answer for '..v end} }) for i = 15, 20 do assert.equal(multipleOf(i), i%2 == 0 and i..' is multiple of 2' or i%3 == 0 and i..' is multiple of 3' or 'could not find an answer for '..i) end end) end) describe('both', function() it('returns a truthy func when all funcs returns true',function() local f = M.both( function(x) return x > 0 end, function(x) return x < 10 end, function(x) return x % 2 == 0 end ) assert.is_true(f(2)) assert.is_true(f(8)) assert.is_false(f(9)) end) end) describe('either', function() it('returns a truthy func when at least one of its funcs returns true',function() local f = M.either( function(x) return x > 0 end, function(x) return x % 2 == 0 end ) assert.is_true(f(0)) assert.is_false(f(-3)) end) end) describe('neither', function() it('returns a truthy func when neither of its funcs returns true',function() local f = M.neither( function(x) return x > 10 end, function(x) return x % 2 == 0 end ) assert.is_false(f(12)) assert.is_false(f(8)) assert.is_true(f(7)) end) end) describe('uniqueId', function() it('returns an unique (for the current session) integer Id',function() local ids = {} for i = 1,100 do local newId = M.uniqueId() assert.is_false(M.include(ids,newId)) M.push(ids,newId) end end) it('accepts a string template to format the returned id',function() local ids = {} for i = 1,100 do local newId = M.uniqueId('ID:%s') assert.equal(newId,'ID:'..newId:sub(4)) assert.is_false(M.include(ids,newId)) M.push(ids,newId) end end) it('accepts a function as argument to format the returned id',function() local ids = {} local formatter = function(ID) return '$'..ID..'$' end for i = 1,100 do local newId = M.uniqueId(formatter) assert.is_true(newId:match('^%$%d+%$$') ~= nil) assert.is_false(M.include(ids,newId)) M.push(ids,newId) end end) end) describe('iterator', function() it('creates an iterator which continuously applies f on an input',function() local next_even = M.iterator(function(x) return x + 2 end, 0) assert.equal(next_even(), 2) assert.equal(next_even(), 4) assert.equal(next_even(), 6) assert.equal(next_even(), 8) assert.equal(next_even(),10) end) it('can be set to run up to a maximum number of calls',function() local next_even = M.iterator(function(x) return x + 2 end, 0, 3) assert.equal(next_even(), 2) assert.equal(next_even(), 4) assert.equal(next_even(), 6) assert.is_nil(next_even()) end) end) describe('skip', function() it('consumes the first n values of an iterator',function() local w = "hello" local char = string.gmatch(w,'.') local iter = M.skip(char, 3) assert.equal(iter(), 'l') assert.equal(iter(), 'o') end) it('consumes the first n values of an iterator',function() local w = "lua" local char = string.gmatch(w,'.') local iter = M.skip(char) assert.equal(iter(), 'u') assert.equal(iter(), 'a') end) end) describe('tabulate', function() it('iterates a given iterator and returns its values in an array',function() local letters = M.tabulate(('Lua'):gmatch('.')) assert.is_true(M.isEqual(letters,{'L','u','a'})) local numbers = M.tabulate(pairs(M.range(1,10))) assert.is_true(M.isEqual(numbers,M.range(1,10))) end) end) describe('iterlen', function() it('returns the iterator length',function() local text = 'letters' local chars = string.gmatch(text, '.') assert.equal(M.iterlen(chars),7) end) it('it consumes the iterator',function() local text = 'lua' local chars = string.gmatch(text, '.') assert.equal(M.iterlen(chars),3) assert.is_nil(chars()) end) end) describe('castArray', function() it('converts value to an array',function() assert.is_true(M.isEqual(M.castArray(1),{1})) assert.is_true(M.isEqual(M.castArray(print),{print})) assert.is_true(M.isEqual(M.castArray(true),{true})) end) it('leaves given value untouched if it is an array',function() local t1 = {1,2} local t2 = {nil, true, false} assert.is_true(M.isEqual(M.castArray(t1),t1)) assert.is_true(M.isEqual(M.castArray(t2),t2)) end) end) describe('flip', function() it('creates a function which runs f with arguments flipped',function() local function f(...) return table.concat({...}) end local flipped = M.flip(f) assert.equal(flipped('a','b','c'),'cba') end) end) describe('nthArg', function() it('creates a function which returns the nth arg',function() local f2 = M.nthArg(2) local f3 = M.nthArg(3) local f4 = M.nthArg(4) assert.equal(f2(4,8,5,4,6),8) assert.equal(f3(4,8,5,4,6),5) assert.equal(f4(4,8,5,4,6),4) end) it('if n is negative, will count from the end',function() local f2 = M.nthArg(-2) local f3 = M.nthArg(-3) local f4 = M.nthArg(-4) assert.equal(f2(4,8,5,4,6),4) assert.equal(f3(4,8,5,4,6),5) assert.equal(f4(4,8,5,4,6),8) end) end) describe('unary', function() it('creates a function which accepts only one arg',function() local f = M.unary(function(...) return ... end) assert.equal(f(1),1) assert.equal(f(1,2),1) assert.equal(f(1,2,3),1) end) end) describe('ary', function() it('creates a function which accepts up to n args',function() local f = M.ary(function(...) return ... end, 2) assert.is_true(M.isEqual({f(1,2)},{1,2})) assert.is_true(M.isEqual({f(1,2,3)},{1,2})) assert.is_true(M.isEqual({f(1,2,3,4)},{1,2})) end) end) describe('noarg', function() it('returns a function with an arity of 0',function() local f = M.noarg(function (x) return x or 'default' end) assert.equal(f(1), 'default') assert.equal(f(function() end, 3), 'default') assert.equal(f(nil), 'default') end) end) describe('rearg', function() it('creates a function with args reordered',function() local f = M.rearg(function(...) return ... end, {3,2,1}) assert.is_true(M.isEqual({f(1,2,3)},{3,2,1})) assert.is_true(M.isEqual({f(2,1,3)},{3,1,2})) assert.is_true(M.isEqual({f(3,2,1)},{1,2,3})) end) end) describe('over', function() it('returns a function which applies a set of transforms to its args',function() local minmax = M.over(math.min, math.max) local maxmin = M.over(math.max, math.min) assert.is_true(M.isEqual(minmax(5,10,12,4,3),{3,12})) assert.is_true(M.isEqual(maxmin(5,10,12,4,3),{12,3})) end) end) describe('overEvery', function() local alleven, allpositive alleven = function(...) for i, v in ipairs({...}) do if v%2~=0 then return false end end return true end allpositive = function(...) for i, v in ipairs({...}) do if v < 0 then return false end end return true end it('checks if all predicates passes truth with args. ',function() local allok = M.overEvery(alleven, allpositive) assert.is_false(allok(2,4,-1,8)) assert.is_false(allok(10,3,2,6)) assert.is_true(allok(8,4,6,10)) end) end) describe('overSome', function() local alleven, allpositive alleven = function(...) for i, v in ipairs({...}) do if v%2~=0 then return false end end return true end allpositive = function(...) for i, v in ipairs({...}) do if v < 0 then return false end end return true end it('checks if all predicates passes truth with args. ',function() local anyok = M.overSome(alleven, allpositive) assert.is_false(anyok(2,4,-1,8)) assert.is_true(anyok(10,3,2,6)) assert.is_false(anyok(-1,-5,-3)) end) end) describe('overArgs', function() it('Creates a function that invokes `f` with its arguments transformed',function() local function f(x, y) return {x, y} end local function triple(x) return x*3 end local function square(x) return x^2 end local new_f = M.overArgs(f, triple, square) assert.is_true(M.isEqual(new_f(1,2), {3,4})) assert.is_true(M.isEqual(new_f(10,10), {30,100})) end) it('when supplied more args than transforms, remaining are left as-is',function() local function f(x, y, z, k) return {x, y, z, k} end local function triple(x) return x*3 end local function square(x) return x^2 end local new_f = M.overArgs(f, triple, square) assert.is_true(M.isEqual(new_f(1,2,3,4), {3,4,3,4})) assert.is_true(M.isEqual(new_f(10,10,10,10), {30,100,10,10})) end) end) describe('converge', function() it('', function() local function pow2(x) return x*x end local function pow3(x) return x*x*x end local function sum(a,b) return a+b end local poly = M.converge(sum, pow2, pow3) assert.equal(poly(5), 150) assert.equal(poly(1), 2) assert.equal(poly(3), 36) end) end) describe('partial', function() it('applies partially f',function() local function diff(a, b) return a - b end local diffFrom20 = M.partial(diff, 20) assert.equal(diffFrom20(5), 15) assert.equal(diffFrom20(10), 10) assert.equal(diffFrom20(-5), 25) end) it('\'_\' can be used as a placeholder',function() local function diff(a, b) return a - b end local remove10 = M.partial(diff, '_',10) assert.equal(remove10(5), -5) assert.equal(remove10(10), 0) assert.equal(remove10(15), 5) end) end) describe('partialRight', function() it('applies partial but from the right',function() local function concat(a,b,c,d) return a..b..c..d end assert.equal(M.partialRight(concat,'a','b','c')('d'), 'dabc') assert.equal(M.partialRight(concat,'a','b')('c','d'), 'cdab') assert.equal(M.partialRight(concat,'a')('b','c','d'), 'bcda') end) it('\'_\' can be used as a placeholder',function() local function concat(a,b,c,d) return a..b..c..d end assert.equal(M.partialRight(concat,'a','_','c')('d','b'), 'badc') assert.equal(M.partialRight(concat,'a','b','_')('c','d'), 'dabc') assert.equal(M.partialRight(concat,'_','a')('b','c','d'), 'cdba') end) end) describe('curry', function() it('curries a function for a specific number of args',function() local function sumOf5args(a,b,c,d,e) return a+b+c+d+e end local curried_sumOf5args = M.curry(sumOf5args, 5) assert.equal(curried_sumOf5args(1)(2)(3)(4)(5),15) assert.equal(curried_sumOf5args(8)(-2)(4)(-10)(1),1) end) it('n_args defaults to 2 when not supplied',function() local function prod(x,y) return x*y end local curried_prod = M.curry(prod) assert.equal(curried_prod(2)(3), (M.curry(prod,2))(2)(3)) assert.equal(curried_prod(-2)(6), (M.curry(prod,2))(-2)(6)) end) it('n_args can be equal to 1',function() local curried_identity = M.curry(M.identity,1) assert.equal(curried_identity('value'), 'value') assert.equal(curried_identity(1), 1) assert.equal(curried_identity(true), true) assert.equal(curried_identity(false), false) end) it('giving more args than n_args will raise an error',function() local function add(a,b) return a+b end local curried_add = M.curry(add, 2) assert.error(function() curried_add(1)(2)(3) end) assert.error(function() curried_add(4)(5)(6)(7)(8) end) end) it('When given less than n_args, it will wait for missing args',function() local function add(a,b,c) return a+b+c end local curried_add = M.curry(add, 3) local c1 = curried_add(1) local c2 = c1(2) local c3 = c2(3) assert.equal(type(c1), 'function') assert.equal(type(c2), 'function') assert.equal(c3, 6) end) end) describe('time', function() it('returns the execution time of a function and its results', function() local function f(...) return ... end local duration, r = M.time(f, 'a') assert.equal(type(duration), 'number') assert.equal(r, 'a') local duration, a, b, c = M.time(f, 1, 2, 3) assert.equal(type(duration), 'number') assert.is_true(a == 1 and b == 2 and c == 3) end) end) end)Moses-Moses-2.1.0-1/spec/import_spec.lua000066400000000000000000000011521334620647700200160ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Import specs', function() it('imports all library function to a given context', function() local funcs = M.functions() local context = M.import({}) assert.is_true(M.all(funcs, function(n) return M.has(context, n) end)) end) it('passing "noConflict" will preserve already existing keys', function() local funcs = M.functions() local context = M.import({each = 1, all = 2}, true) assert.is_true(M.all(funcs, function(n) return M.has(context, n) end)) assert.equal(context.each, 1) assert.equal(context.all, 2) end) end)Moses-Moses-2.1.0-1/spec/object_spec.lua000066400000000000000000000511531334620647700177600ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Object functions specs', function() describe('keys', function() it('collects a given object attributes',function() assert.is_true(M.isEqual(M.keys({1,2,3}),{1,2,3})) assert.is_true(M.isEqual(M.keys({4,5,6}),{1,2,3})) assert.is_true(M.same(M.keys({x = 1, y = 2, 3}),{'x','y',1})) end) end) describe('values', function() it('collects an given object values',function() assert.is_true(M.isEqual(M.values({1,2,3}),{1,2,3})) assert.is_true(M.isEqual(M.values({4,5,6}),{4,5,6})) assert.is_true(M.same(M.values({x = 1, y = 2, 3}),{1,2,3})) end) end) describe('path', function() it('return the value at a given path in object',function() local entity = { pos = {x = 1}, engine = { left = {status = 'active'}, right = {damage = 10} }, boost = false } assert.equal(M.path(entity, 'pos','x'), 1) assert.equal(M.path(entity, 'engine','left','status'), 'active') assert.equal(M.path(entity, 'engine','right','damage'), 10) assert.equal(M.path(entity, 'boost'), false) assert.is_nil(M.path(entity, 'x')) end) end) describe('spreadPath', function() it('spreads objects under property path',function() local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} M.spreadPath(obj, 'c', 'f') assert.equal(obj.a, 1) assert.equal(obj.b, 2) assert.equal(obj.d, 3) assert.equal(obj.e, 4) assert.equal(obj.g, 5) assert.is_true(M.isEmpty(obj.c)) assert.is_true(M.isEmpty(obj.c.f)) end) end) describe('flattenPath', function() it('flattens objects under property path',function() local obj = {a = 1, b = 2, c = {d = 3, e = 4, f = {g = 5}}} M.flattenPath(obj, 'c', 'f') -- => {a = 1, b = 2, d = 3, e = 4, g = 5, c = {d = 3, e = 4, f = {g = 5}}} assert.equal(obj.a, 1) assert.equal(obj.b, 2) assert.equal(obj.d, 3) assert.equal(obj.e, 4) assert.equal(obj.g, 5) assert.equal(M.size(obj.c), 3) assert.equal(obj.c.d, 3) assert.equal(obj.c.e, 4) assert.equal(M.size(obj.c.f), 1) assert.equal(obj.c.f.g, 5) end) end) describe('kvpairs', function() it('converts key-values pairs in object to array-list of k,v pairs',function() local obj = M.kvpairs({x = 1, y = 2, z = 3}) table.sort(obj, function(a,b) return a[1] < b[1] end) assert.is_true(M.isEqual(obj[1],{'x',1})) assert.is_true(M.isEqual(obj[2],{'y',2})) assert.is_true(M.isEqual(obj[3],{'z',3})) end) end) describe('toObj', function() it('converts an array-list of {k,v} pairs to an object',function() local obj = M.toObj({{'x',1},{'y',2},{'z',3}}) assert.equal(obj.x,1) assert.equal(obj.y,2) assert.equal(obj.z,3) end) end) describe('invert',function() it('switches key-values pairs', function() assert.is_true(M.isEqual(M.invert({1,2,3}),{1,2,3})) assert.is_true(M.isEqual(M.invert({'a','b','c'}),{a = 1,b = 2,c = 3})) assert.is_true(M.isEqual(M.invert({x = 4, y = 2}),{[2]='y',[4]='x'})) end) end) describe('property', function() it('Returns a function that will return the key property of any passed-in object.',function() assert.equal(M.property('sin')(math), math.sin) assert.equal(M.property('find')(string), string.find) assert.equal(M.property('insert')(table), table.insert) assert.equal(M.property('yield')(coroutine), coroutine.yield) end) end) describe('propertyOf', function() it('Returns a function which will return the value of an object property.',function() assert.equal(M.propertyOf(math)('cos'), math.cos) assert.equal(M.propertyOf(string)('char'), string.char) assert.equal(M.propertyOf(table)('remove'), table.remove) assert.equal(M.propertyOf(M)('propertyOf'), M.propertyOf) end) end) describe('toBoolean', function() it('converts a value to a boolean',function() assert.is_true(type(M.toBoolean(true)) == 'boolean') assert.is_true(type(M.toBoolean(1)) == 'boolean') assert.is_true(type(M.toBoolean(false)) == 'boolean') assert.is_true(type(M.toBoolean(nil)) == 'boolean') assert.is_true(type(M.toBoolean({})) == 'boolean') assert.is_true(type(M.toBoolean(1/0)) == 'boolean') assert.is_true(M.toBoolean(true)) assert.is_true(M.toBoolean(1)) assert.is_false(M.toBoolean(false)) assert.is_false(M.toBoolean(nil)) assert.is_true(M.toBoolean({})) assert.is_true(M.toBoolean(1/0)) end) end) describe('extend', function() it('extends a destination objects with key-values a source object',function() assert.is_true(M.isEqual(M.extend({},{a = 'b'}),{a = 'b'})) end) it('source properties overrides destination properties',function() assert.is_true(M.isEqual(M.extend({a = 'a'},{a = 'b'}),{a = 'b'})) end) it('leaves source object untouched',function() local source = {i = 'i'} assert.is_true(M.isEqual(M.extend({a = 'a'},source),{a = 'a',i = 'i'})) assert.is_true(M.isEqual(source,{i = 'i'})) end) it('can extend destination from multiple sources',function() local sourceA = {a = 'a'}; local sourceBC = {b = 'b', c = 'c'} assert.is_true(M.isEqual(M.extend({},sourceA, sourceBC),{a = 'a', b = 'b', c = 'c'})) end) it('extending from multiple source, latter properties overrides',function() local sourceA = {a = 'a'}; local sourceBC = {b = 'b', a = 'c'} assert.is_true(M.isEqual(M.extend({},sourceA, sourceBC),{a = 'c', b = 'b'})) end) it('will not copy nil values',function() local sourceA = {a = nil}; local sourceBC = {b = 'b', c = nil} assert.is_true(M.isEqual(M.extend({},sourceA, sourceBC),{b = 'b'})) end) end) describe('functions', function() it('collects function names within an object',function() local x = {} function x.a() return end; function x.b() return end assert.is_true(M.same(M.functions(x),{'a','b'})) end) it('collects metatable functions if "recurseMt" arg is supplied',function() local x = {} ; x.__index = x function x.a() return end; function x.b() return end local xx = setmetatable({},x) function xx.c() return end assert.is_true(M.same(M.functions(xx),{'c'})) assert.is_true(M.same(M.functions(xx,true),{'a','b','c'})) end) it('when given no obj as argument, returns all library functions',function() local functions = M.functions() M.each(functions, function(v) assert.is_true(M.isFunction(M[v])) end) end) end) describe('clone', function() it('clones the attributes of an object',function() local vector = {x = 0, y = 0} assert.is_true(M.isEqual(M.clone(vector),vector)) end) it('By default, cloning is deep (clones nested tables)',function() local particle = {position = {x = 0,y=0},mass = 1} local particle_clone = M.clone (particle) assert.is_true(M.isEqual(particle_clone,particle)) particle_clone.position.x = 3 assert.is_false(M.isEqual(particle_clone,particle)) end) it('Unless "shallow" arg is provided',function() local particle = {position = {x = 0,y=0},mass = 1} local particle_clone = M.clone (particle,true) assert.is_true(M.isEqual(particle_clone,particle)) particle_clone.position.x = 3 assert.is_true(M.isEqual(particle_clone,particle)) end) it('Non objects are simply returned',function() assert.equal(M.clone(1),1) assert.equal(M.clone(false),false) assert.equal(M.clone(true),true) assert.equal(M.clone(nil),nil) assert.equal(M.clone('hello'),'hello') assert.equal(M.clone(print),print) end) end) describe('tap', function() it('tap-into a method chain', function() local t = {} local catchMax = function(k) t[#t+1] = M.max(k) end local catchMin = function(k) t[#t+1] = M.min(k) end M.chain({1,2,3}) :map(function(j) return j*2 end) :tap(catchMax) :map(function(k) return k^2 end) :tap(catchMin) :value() assert.equal(t[1],6) assert.equal(t[2],4) end) end) describe('has', function() it('checks if an object has an attribute',function() assert.is_true(M.has(M,'has')) assert.is_true(M.has(table,'concat')) assert.is_true(M.has(string,'format')) assert.is_true(M.has(os,'time')) assert.is_true(M.has(math,'random')) end) end) describe('pick', function() it('collect specified properties',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.pick(object,'a','c'),{a = 1, c = 3})) end) it('given args can be nested as well',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.pick(object,{{'b','a'}},'c'),{a = 1,b = 2, c = 3})) end) it('will ignore properties the object do not have',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.pick(object,{{'k'}},'c'),{c = 3})) end) it('returns an empty table when given no properties to pick',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.pick(object),{})) end) it('should also pick attributes having falsy values',function() local object = {a = false, b = false, c = true} assert.is_true(M.isEqual(M.pick(object,'a','b'),{a = false,b = false})) end) end) describe('omit', function() it('collect all properties leaving those given as args',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.omit(object,'a','c'),{b=2})) end) it('given args can be nested as well',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.omit(object,{{'b'}},'c'),{a = 1})) end) it('will ignore properties the object do not have',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.omit(object,{{'k'}},'c'),{a = 1, b=2})) end) it('returns the original object clone when given no properties to omit',function() local object = {a = 1, b = 2, c = 3} assert.is_true(M.isEqual(M.omit(object),{a = 1, b = 2, c = 3})) end) end) describe('template', function() it('applies a template on an object',function() assert.is_true(M.isEqual(M.template({},{a = 1, b = 2, c = 3}),{a = 1, b = 2, c = 3})) end) it('does not override existing properies',function() assert.is_true(M.isEqual(M.template({a = 10, b = 10},{a = 1, b = 2, c = 3}),{a = 10, b = 10, c = 3})) end) it('returns the object when given no template arg',function() assert.is_true(M.isEqual(M.template({a = 10, b = 10}),{a = 10, b = 10})) end) end) describe('isEqual', function() it('compares values',function() assert.is_true(M.isEqual(1,1)) assert.is_true(M.isEqual(1.0,1)) assert.is_false(M.isEqual(1,2)) assert.is_false(M.isEqual(2,2.0001)) end) it('compares objects by reference and components',function() local oldprint = print assert.is_true(M.isEqual(print,oldprint)) local t = {} local v = t assert.is_true(M.isEqual(t,v)) assert.is_true(M.isEqual({},{})) assert.is_false(M.isEqual('a','b')) assert.is_false(M.isEqual(true, false)) assert.is_false(M.isEqual(nil, false)) assert.is_false(M.isEqual(true, nil)) end) it('compares nested properties',function() assert.is_true(M.isEqual({x = 0,{x1 = 0,{x2 =0}}}, {x = 0,{x1 = 0,{x2 =0}}})) assert.is_false(M.isEqual({x = 0,{x1 = 0,{x2 =0}}}, {x = 0,{x1 = 0,{x2 =1}}})) end) it('can compare tables on the basis of their metatable',function() local a, b = {x = 1, y = 2}, {x = 2, y = 1} setmetatable(a,{__eq = function(a,b) return (a.x and b.x and a.y and b.y)~=nil end}) assert.is_false(M.isEqual(a, b)) assert.is_true(M.isEqual(a, b, true)) end) end) describe('result', function() it('calls an object method, passing it as a first arg the object itself',function() assert.equal(M.result('a','len'),1) assert.equal(M.result('hello','reverse'),'olleh') assert.equal(M.result({'a','b','c'},table.concat),'abc') end) it('returns the property itself if not callable',function() assert.equal(M.result({size = 0},'size'),0) end) end) describe('isTable', function() it('returns "true" if arg is table or array',function() assert.is_true(M.isTable({})) assert.is_true(M.isTable({1,2})) assert.is_true(M.isTable({x = 1, 2})) assert.is_true(M.isTable(string)) assert.is_true(M.isTable(table)) assert.is_true(M.isTable(math)) end) it('returns "false" otherwise',function() assert.is_false(M.isTable(1)) assert.is_false(M.isTable('')) assert.is_false(M.isTable(function() end)) assert.is_false(M.isTable(print)) assert.is_false(M.isTable(false)) assert.is_false(M.isTable(nil)) assert.is_false(M.isTable(true)) end) end) describe('isCallable', function() it('returns "true" if arg is callable',function() assert.is_true(M.isCallable(print)) assert.is_true(M.isCallable(function() end)) assert.is_true(M.isCallable(string.gmatch)) assert.is_true(M.isCallable(setmetatable({},{__index = string}).upper)) assert.is_true(M.isCallable(setmetatable({},{__call = function() return end}))) end) it('returns "false" otherwise',function() assert.is_false(M.isCallable(1)) assert.is_false(M.isCallable('')) assert.is_false(M.isCallable({})) assert.is_false(M.isCallable(false)) assert.is_false(M.isCallable(nil)) assert.is_false(M.isCallable(true)) end) end) describe('isArray', function() it('returns "true" if arg is an array',function() assert.is_true(M.isArray({})) assert.is_true(M.isArray({1,2,3})) assert.is_true(M.isArray({'a','b','c',{}})) assert.is_true(M.isArray({false,true})) assert.is_true(M.isArray({1,nil})) end) it('returns "false" otherwise',function() assert.is_false(M.isArray(1)) assert.is_false(M.isArray('')) assert.is_false(M.isArray(false)) assert.is_false(M.isArray(nil)) assert.is_false(M.isArray(true)) assert.is_false(M.isArray(print)) assert.is_false(M.isArray({a = 1, x = 1})) assert.is_false(M.isArray({a = 1, 1, 2,3})) assert.is_false(M.isArray({1,nil,2})) assert.is_false(M.isArray({1,nil,3,k=4})) assert.is_false(M.isArray({a=1})) end) it('returns false on "sparse arrays"',function() assert.is_false(M.isArray({[1] = true, [10] = false})) end) end) describe('isIterable', function() it('checks if the given object is iterable with pairs',function() assert.is_true(M.isIterable({})) assert.is_true(M.isIterable({1,2,3})) end) end) describe('type', function() it('returns the type of the passed-in object',function() assert.equal(M.type('string'),'string') assert.equal(M.type(table),'table') assert.equal(M.type(1), 'number') assert.equal(M.type(io.open('f','w')),'file') end) end) describe('isEmpty', function() it('returns "true" if arg is an empty array',function() assert.is_true(M.isEmpty({})) end) it('returns "false" otherwise',function() assert.is_false(M.isEmpty({1,2,3})) assert.is_false(M.isEmpty({'a','b','c',{}})) assert.is_false(M.isEmpty({nil,false,true})) end) it('booleans, nil and functions are considered empty',function() assert.is_true(M.isEmpty(print)) assert.is_true(M.isEmpty(nil)) assert.is_true(M.isEmpty(false)) assert.is_true(M.isEmpty(true)) end) it('handles strings',function() assert.is_true(M.isEmpty('')) assert.is_false(M.isEmpty('a')) assert.is_false(M.isEmpty('bcd')) assert.is_false(M.isEmpty(' ')) end) end) describe('isString', function() it('returns "true" if arg is a string',function() assert.is_true(M.isString('')) assert.is_true(M.isString('a')) assert.is_true(M.isString(' ')) assert.is_true(M.isString(type(nil))) end) it('returns "false" otherwise',function() assert.is_false(M.isString(false)) assert.is_false(M.isString(print)) assert.is_false(M.isString(nil)) assert.is_false(M.isString(true)) assert.is_false(M.isString({})) end) end) describe('isFunction', function() it('returns "true" if arg is a function',function() assert.is_true(M.isFunction(print)) assert.is_true(M.isFunction(string.match)) assert.is_true(M.isFunction(function() end)) end) it('returns "false" otherwise',function() assert.is_false(M.isFunction({})) assert.is_false(M.isFunction(nil)) assert.is_false(M.isFunction(false)) assert.is_false(M.isFunction(true)) assert.is_false(M.isFunction('a')) end) end) describe('isNil', function() it('returns "true" if arg is nil',function() assert.is_true(M.isNil(nil)) assert.is_true(M.isNil()) assert.is_true(M.isNil(a)) end) it('returns "false" otherwise',function() assert.is_false(M.isNil(false)) assert.is_false(M.isNil(true)) assert.is_false(M.isNil(table)) assert.is_false(M.isNil(function() end)) assert.is_false(M.isNil('a')) end) end) describe('isNumber', function() it('returns "true" if arg is a number',function() assert.is_true(M.isNumber(1)) assert.is_true(M.isNumber(0.5)) assert.is_true(M.isNumber(math.pi)) assert.is_true(M.isNumber(1/0)) assert.is_true(M.isNumber(math.huge)) assert.is_true(M.isNumber(0/0)) end) it('returns "false" otherwise',function() assert.is_false(M.isNumber(print)) assert.is_false(M.isNumber(nil)) assert.is_false(M.isNumber(true)) assert.is_false(M.isNumber(false)) assert.is_false(M.isNumber({1})) assert.is_false(M.isNumber('1')) end) end) describe('isNaN', function() it('returns "true" if arg is NaN',function() assert.is_true(M.isNaN(0/0)) end) it('returns "false" for not NaN values',function() assert.is_false(M.isNaN(1/0)) assert.is_false(M.isNaN(math.huge)) assert.is_false(M.isNaN(math.pi)) assert.is_false(M.isNaN(1)) assert.is_false(M.isNaN('')) assert.is_false(M.isNaN('0')) assert.is_false(M.isNaN({})) assert.is_false(M.isNaN(nil)) assert.is_false(M.isNaN(false)) assert.is_false(M.isNaN(true)) end) end) describe('isFinite', function() it('returns "true" if arg is a finite number',function() assert.is_true(M.isFinite(1)) assert.is_true(M.isFinite(0)) assert.is_true(M.isFinite(math.pi)) assert.is_true(M.isFinite(99e99)) end) it('returns "false" otherwise',function() assert.is_false(M.isFinite(math.huge)) assert.is_false(M.isFinite(1/0)) assert.is_false(M.isFinite(0/0)) end) it('returns "false" for non-numbers',function() assert.is_false(M.isFinite('')) assert.is_false(M.isFinite(function() end)) assert.is_false(M.isFinite({})) end) end) describe('isBoolean', function() it('returns "true" if arg is a boolean or a thruthy statement',function() assert.is_true(M.isBoolean(true)) assert.is_true(M.isBoolean(false)) assert.is_true(M.isBoolean(1==1)) assert.is_true(M.isBoolean(print==tostring)) end) it('returns "false" otherwise',function() assert.is_false(M.isBoolean('')) assert.is_false(M.isBoolean(nil)) assert.is_false(M.isBoolean({})) assert.is_false(M.isBoolean(function() end)) assert.is_false(M.isBoolean(0)) assert.is_false(M.isBoolean('1')) end) end) describe('isInteger', function() it('returns "true" if arg is a integer, "false" otherwise',function() assert.is_true(M.isInteger(1)) assert.is_true(M.isInteger(0)) assert.is_false(M.isInteger(math.pi)) assert.is_true(M.isInteger(1/0)) assert.is_true(M.isInteger(math.huge)) assert.is_false(M.isInteger(0/0)) end) end) end)Moses-Moses-2.1.0-1/spec/op_spec.lua000066400000000000000000000107721334620647700171320ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Operators specs', function() describe('Arithmetic operators', function() it('add returns a + b', function() assert.equal(M.operator.add(1,2), 3) assert.equal(M.operator.add(0,0), 0) assert.equal(M.operator.add(0,-5), -5) end) it('sub returns a - b', function() assert.equal(M.operator.sub(1,2), -1) assert.equal(M.operator.sub(0,0), 0) assert.equal(M.operator.sub(0,-5), 5) end) it('mul returns a * b', function() assert.equal(M.operator.mul(1,2), 2) assert.equal(M.operator.mul(0,0), 0) assert.equal(M.operator.mul(0,-5), 0) end) it('div returns a / b', function() assert.equal(M.operator.div(1,2), 0.5) assert.equal(M.operator.div(5,5), 1) assert.equal(M.operator.div(8,-2), -4) end) it('mod returns a % b', function() assert.equal(M.operator.mod(6,3), 0) assert.equal(M.operator.mod(5,2), 1) end) it('exp returns a ^ b', function() assert.equal(M.operator.exp(3,3), 27) assert.equal(M.operator.exp(5,2), 25) end) it('unm returns -a', function() assert.equal(M.operator.unm(3), -3) assert.equal(M.operator.unm(-5), 5) end) it('floordiv returns a//b', function() assert.equal(M.operator.floordiv(5,2), 2) end) it('intdiv performs integer division', function() assert.equal(M.operator.intdiv(5,2), 2) assert.equal(M.operator.intdiv(-5,2), -2) end) end) describe('Relational operators', function() it('eq returns a == b', function() assert.equal(M.operator.eq(5,5), true) assert.equal(M.operator.eq(5,4.99), false) end) it('neq returns a ~= b', function() assert.equal(M.operator.neq(5,5), false) assert.equal(M.operator.neq(5,4.99), true) end) it('lt returns a < b', function() assert.equal(M.operator.lt(5,5), false) assert.equal(M.operator.lt(4.99,5), true) end) it('gt returns a > b', function() assert.equal(M.operator.gt(5,5), false) assert.equal(M.operator.gt(5,4.99), true) end) it('le returns a <= b', function() assert.equal(M.operator.le(5,5), true) assert.equal(M.operator.le(4.99,5), true) assert.equal(M.operator.le(5,4.99), false) end) it('ge returns a >= b', function() assert.equal(M.operator.ge(5,5), true) assert.equal(M.operator.ge(4.99,5), false) assert.equal(M.operator.ge(5,4.99), true) end) end) describe('Logical operators', function() it('land returns a and b', function() assert.equal(M.operator.land(true, true),true) assert.equal(M.operator.land(true, false),false) assert.equal(M.operator.land(false, true),false) assert.equal(M.operator.land(false, false),false) assert.equal(M.operator.land(true, nil),nil) assert.equal(M.operator.land(false, nil),false) end) it('lor returns a or b', function() assert.equal(M.operator.lor(true, true),true) assert.equal(M.operator.lor(true, false),true) assert.equal(M.operator.lor(false, true),true) assert.equal(M.operator.lor(false, false),false) assert.equal(M.operator.lor(true, nil),true) assert.equal(M.operator.lor(false, nil),nil) end) it('lnot returns not a', function() assert.equal(M.operator.lnot(true),false) assert.equal(M.operator.lnot(false),true) assert.equal(M.operator.lnot(nil),true) end) end) describe('Length operator', function() it('length returns #a', function() assert.equal(M.operator.length({}),0) assert.equal(M.operator.length({2}),1) assert.equal(M.operator.length({3,5,3}),3) assert.equal(M.operator.length('hello'),5) end) end) describe('Concatenation operator', function() it('concat returns a..b', function() assert.equal(M.operator.concat('a','b'),'ab') assert.equal(M.operator.concat('1','2'),'12') end) end) describe('Aliases', function() it('op is an alias to operator', function() assert.equal(M.operator, M.op) end) it('pow is an alias to exp', function() assert.equal(M.operator.exp, M.operator.pow) end) it('neg is an alias to unm', function() assert.equal(M.operator.neg, M.operator.unm) end) it('len is alias to length', function() assert.equal(M.operator.length,M.operator.len) end) end) end)Moses-Moses-2.1.0-1/spec/table_spec.lua000066400000000000000000000555471334620647700176140ustar00rootroot00000000000000require 'luacov' local M = require 'moses' describe('Table functions specs', function() describe('clear', function() it('', function() local t = M.clear({'a', true, 'hello'}) assert.is_true(M.isEqual(t,{})) assert.is_nil(next(t)) end) end) describe('each', function() it('provides values and iteration count ', function() local t = {4,2,1} local inc = 0 M.each(t,function(v, i) inc = inc+1 assert.equal(i,inc) assert.equal(t[i],v) end) end) it('can reference the given table', function() local t = {1,2,3} local mul = 5 M.each(t,function(v,i) t[i] = v*mul end) assert.is_true(M.isEqual(t,{5,10,15})) end) it('iterates over non-numeric keys and objects', function() local t = {one = 1, two = 2, three = 3} local copy = {} M.each(t,function(v,i) copy[i] = v end) assert.is_true(M.isEqual(t,copy)) end) end) describe('eachi', function() it('provides values and iteration count for integer keys only, in a sorted way', function() local t = {4,2,1} local inc = 0 M.eachi(t,function(v,i) inc = inc+1 assert.equal(i,inc) assert.equal(t[i],v) end) end) it('ignores non-integer keys', function() local t = {a = 1, b = 2, [0] = 1, [-1] = 6, 3, x = 4, 5} local rk = {-1, 0, 1, 2} local rv = {6, 1, 3, 5} local inc = 0 M.eachi(t,function(v,i) inc = inc+1 assert.equal(i,rk[inc]) assert.equal(v,rv[inc]) end) end) end) describe('at', function() it('returns an array of values at numeric keys', function() local t = {4,5,6} local values = M.at(t,1,2,3) assert.is_true(M.isEqual(values, t)) local t = {a = 4, bb = true, ccc = false} local values = M.at(t,'a', 'ccc') assert.is_true(M.isEqual(values, {4, false})) end) end) describe('adjust', function() it('adjusts a given value in a table using a function', function() local double = function(v) return v * 2 end local t = {1,2,3} assert.is_true(M.isEqual(M.adjust(t,1,double),{2,2,3})) assert.is_true(M.isEqual(M.adjust(t,2,double),{1,4,3})) assert.is_true(M.isEqual(M.adjust(t,3,double),{1,2,6})) end) it('adjusts a given value in a table using a value', function() local t = {1,2,3} assert.is_true(M.isEqual(M.adjust(t,1,5),{5,2,3})) assert.is_true(M.isEqual(M.adjust(t,2,-2),{1,-2,3})) end) it('throws an error if key is not found in table', function() local double = function(v) return v * 2 end local t = {x = 1} assert.error(function() M.adjust(t,'y', 2) end) end) end) describe('count', function() it('count the occurences of value in a list', function() assert.equal(M.count({1,1,2,3,3,3,2,4,3,2},1),2) assert.equal(M.count({1,1,2,3,3,3,2,4,3,2},2),3) assert.equal(M.count({1,1,2,3,3,3,2,4,3,2},3),4) assert.equal(M.count({1,1,2,3,3,3,2,4,3,2},4),1) assert.equal(M.count({1,1,2,3,3,3,2,4,3,2},5),0) assert.equal(M.count({false, false, true},false),2) assert.equal(M.count({false, false, true},true),1) assert.equal(M.count({{1,1},{1,1},{1,1},{2,2}},{1,1}),3) assert.equal(M.count({{1,1},{1,1},{1,1},{2,2}},{2,2}),1) end) it('defaults to size when value is not given', function() assert.equal(M.count({1,1,2,3,3,3,2,4,3,2}),M.size({1,1,2,3,3,3,2,4,3,2})) assert.equal(M.count({false, false, true}),M.size({false, false, true})) end) end) describe('countf', function() it('count the occurences of values passing an iterator test in a list', function() assert.equal(M.countf({1,2,3,4,5,6}, function(v) return v%2==0 end),3) assert.equal(M.countf({print, pairs, ipairs}, function(v) return type(v)=='function' end),3) end) end) describe('allEq', function() it('checks if all values are equal', function() assert.is_true(M.allEqual({1,1,1,1,1}, comp)) assert.is_false(M.allEqual({1,1,2,1,1}, comp)) local t1 = {1, 2, {3}} local t2 = {1, 2, {3}} assert.is_true(M.allEqual({t1, t2})) end) it('can use a custom comp function to compare values', function() local t1 = {x = 1, y = 0} local t2 = {x = 1, y = 0} local t3 = {x = 1, y = 2} local t4 = {x = 1, y = 2} local function compx(a, b) return a.x == b.x end local function compy(a, b) return a.y == b.y end assert.is_true(M.allEqual({t1, t2}, compx)) assert.is_true(M.allEqual({t1, t2}, compy)) assert.is_true(M.allEqual({t3, t4}, compx)) assert.is_true(M.allEqual({t3, t4}, compy)) assert.is_true(M.allEqual({t1, t2, t3, t4}, compx)) assert.is_false(M.allEqual({t1, t2, t3, t4}, compy)) end) end) describe('cycle', function() it('loops n times on a list', function() local times = 3 local t = {1,2,3,4,5} local kv = {} for v,k in M.cycle(t,times) do assert.equal(t[k],v) kv[#kv+1] = v end for k,v in ipairs(kv) do assert.equal(M.count(kv,v),times) end end) it('support array-like and map-like tables', function() local times = 10 local t = {x = 1, z = 2} local keys = {} local values = {} for v,k in M.cycle(t,times) do assert.equal(t[k],v) keys[#keys+1] = k values[#values+1] = v end for k,v in ipairs(keys) do assert.equal(M.count(keys,v),times) end for k,v in ipairs(values) do assert.equal(M.count(values,v),times) end end) it('n defaults to 1, if not supplied', function() local t = {1,2,3,4,5} for v,k in M.cycle(t) do t[k] = v + 1 end M.each(t, function(v, k) assert.equal(v, k + 1) end) end) it('if n is negative or equal to 0, it does nothing', function() local t = {1,2,3,4,5} for v,k in M.cycle(t, 0) do t[k] = v + 1 end for v,k in M.cycle(t, -2) do t[k] = v + 1 end M.each(t, function(v, k) assert.equal(v, k) end) end) end) describe('map', function() it('applies an iterator function over each key-value pair ', function() assert.is_true(M.isEqual(M.map({1,2,3},function(v) return v+10 end),{11,12,13})) end) it('iterates over non-numeric keys and objects', function() assert.is_true(M.isEqual(M.map({a = 1, b = 2},function(v,k) return k..v end),{a = 'a1',b = 'b2'})) end) it('maps key-value pairs to key-value pairs', function() assert.is_true(M.isEqual(M.map({a = 1, b = 2}, function(v, k) return k .. k, v + 10 end), {aa = 11, bb = 12})) end) end) describe('reduce', function() it('folds a collection (left to right) from an initial state', function() assert.equal(M.reduce({1,2,3,4},function(memo,v) return memo+v end,0),10) end) it('initial state defaults to the first value when not given', function() assert.equal(M.reduce({'a','b','c'},function(memo,v) return memo..v end),'abc') end) it('supports arrays of booleans', function() assert.equal(M.reduce({true, false, true, true},function(memo,v) return memo and v end), false) assert.equal(M.reduce({true, true, true},function(memo,v) return memo and v end), true) assert.equal(M.reduce({false, false, false},function(memo,v) return memo and v end), false) assert.equal(M.reduce({false, false, true},function(memo,v) return memo or v end), true) end) end) describe('best', function() it('select the best candidate in a table', function() local words = {'Lua', 'Programming', 'Language'} assert.equal(M.best(words, function(a,b) return #a > #b end), 'Programming') assert.equal(M.best(words, function(a,b) return #a < #b end), 'Lua') end) end) describe('reduceBy', function() it('folds a collection (left to right) for specific values', function() local function even(v) return v%2==0 end local function odd(v) return v%2~=0 end assert.equal(M.reduceBy({1,2,3,4},function(memo,v) return memo+v end,even,0), 6) assert.equal(M.reduceBy({1,2,3,4},function(memo,v) return memo+v end,odd,0), 4) end) end) describe('reduceRight', function() it('folds a collection (right to left) from an initial state', function() assert.equal(M.reduceRight({1,2,4,16},function(memo,v) return memo/v end,256),2) end) it('initial state defaults to the first value when not given', function() assert.equal(M.reduceRight({'a','b','c'},function(memo,v) return memo..v end),'cba') end) end) describe('mapReduce', function() it('folds a collection (left to right) saving intermediate states', function() assert.is_true(M.isEqual(M.mapReduce({1,2,4,16},function(memo,v) return memo*v end,0),{0,0,0,0})) end) it('initial state defaults to the first value when not given', function() assert.is_true(M.isEqual(M.mapReduce({'a','b','c'},function(memo,v) return memo..v end),{'a','ab','abc'})) end) end) describe('mapReduceRight', function() it('folds a collection (right to left) saving intermediate states', function() assert.is_true(M.isEqual(M.mapReduceRight({1,2,4,16},function(memo,v) return memo/v end,256),{16,4,2,2})) end) it('initial state defaults to the first value when not given', function() assert.is_true(M.isEqual(M.mapReduceRight({'a','b','c'},function(memo,v) return memo..v end),{'c','cb','cba'})) end) end) describe('include', function() it('looks for a value in a collection, returns true when found', function() assert.is_true(M.include({6,8,10,16,29},16)) end) it('returns false when value was not found', function() assert.is_false(M.include({6,8,10,16,29},1)) end) it('can lookup for a object', function() assert.is_true(M.include({6,{18,{2,6}},10,{18,{2,{3}}},29},{18,{2,{3}}})) end) it('given an iterator, return the first value passing a truth test', function() assert.is_true(M.include({'a','B','c'}, function(array_value) return (array_value:upper() == array_value) end)) end) end) describe('detect', function() it('looks for the first occurence of value, returns the key where it was found', function() assert.equal(M.detect({6,8,10,16},8),2) end) it('returns nil when value was not found', function() assert.is_nil(M.detect({nil,true,0,true,true},false)) end) it('can lookup for a object', function() assert.equal(M.detect({6,{18,{2,6}},10,{18,{2,{3}}},29},{18,{2,6}}),2) end) it('given an iterator, return the key of the first value passing a truth test', function() assert.equal(M.detect({'a','B','c'}, function(array_value) return (array_value:upper() == array_value) end),2) end) end) describe('where', function() it('Returns all values in a list having all of a given set of properties', function() local set = { {a = 1, b = 2}, {a = 2, b = 2}, {a = 2, b = 4}, {a = 3, b = 4} } assert.is_true(M.isEqual(M.where(set, {a = 2}), {set[2],set[3]})) assert.is_true(M.isEqual(M.where(set, {b = 4}), {set[3],set[4]})) assert.is_true(M.isEqual(M.where(set, {a = 2, b = 2}), {set[2]})) end) it('returns nil when value was not found', function() local set = { {a = 1, b = 2}, {a = 2, b = 2}, } assert.is_nil(M.where(set, {a = 3})) assert.is_nil(M.where(set, {b = 1})) end) end) describe('findWhere', function() it('Returns the first value in a list having all of a given set of properties', function() local a = {a = 1, b = 2} local b = {a = 2, b = 3} local c = {a = 3, b = 4} assert.equal(M.findWhere({a, b, c}, {a = 3, b = 4}), c) end) it('returns nil when value was not found', function() local a = {a = 1, b = 2} local b = {a = 2, b = 3} local c = {a = 3, b = 4} assert.is_nil(M.findWhere({a, b, c}, {a = 3, b = 0})) end) end) describe('select', function() it('collects all values passing a truth test with an iterator', function() assert.is_true(M.isEqual(M.select({7,6,5,4,3,2,1}, function(value) return (value%2==0) end),{6,4,2})) assert.is_true(M.isEqual(M.select({7,6,5,4,3,2,1}, function(value) return (value%2~=0) end),{7,5,3,1})) end) end) describe('reject', function() it('collects all values failing a truth test with an iterator', function() assert.is_true(M.isEqual(M.reject({7,6,5,4,3,2,1}, function(value) return (value%2==0) end),{7,5,3,1})) assert.is_true(M.isEqual(M.reject({7,6,5,4,3,2,1}, function(value) return (value%2~=0) end),{6,4,2})) end) end) describe('all', function() it('returns whether all elements matches a truth test', function() assert.is_true(M.all({2,4,6}, function(value) return (value%2==0) end)) assert.is_false(M.all({false,true,false}, function(value) return value == false end)) end) end) describe('invoke', function() it('calls an iterator over each object, passing it as a first arg', function() assert.is_true(M.isEqual(M.invoke({'a','bea','cdhza'},string.len), {1,3,5})) assert.is_true(M.isEqual(M.invoke({{2,3,2},{13,8,10},{0,-5}},M.ary(M.sort,1)), {{2,2,3},{8,10,13},{-5,0}})) assert.is_true(M.isEqual(M.invoke({{x = 1, y = 2},{x = 3, y=4}},'x'), {1,3})) end) it('given a string, calls the matching object property the same way', function() local a = {}; function a:call() return self end local b, c, d = {}, {}, {} b.call, c.call, d.call = a.call, a.call, a.call assert.is_true(M.isEqual(M.invoke({a,b,c,d},'call'), {a,b,c,d})) end) end) describe('pluck', function() it('fetches a property value in a collection of objects', function() local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} assert.is_true(M.isEqual(M.pluck(peoples,'age'), {23,17,15,33})) assert.is_true(M.isEqual(M.pluck(peoples,'name'), {'John','Peter','Steve'})) end) end) describe('max', function() it('returns the maximum targetted property value in a collection of objects', function() local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} assert.equal(M.max(M.pluck(peoples,'age')),33) assert.equal(M.max(peoples,function(people) return people.age end),33) end) it('directly compares items when given no iterator', function() assert.equal(M.max({'a','b','c'}),'c') end) end) describe('min', function() it('returns the maximum targetted property value in a collection of objects', function() local peoples = { {name = 'John', age = 23},{name = 'Peter', age = 17}, {name = 'Steve', age = 15},{age = 33}} assert.equal(M.min(M.pluck(peoples,'age')),15) assert.equal(M.min(peoples,function(people) return people.age end),15) end) it('directly compares items when given no iterator', function() assert.equal(M.min({'a','b','c'}),'a') end) end) describe('same', function() it('returns whether all objects from both given tables exists in each other', function() local a = {'a','b','c','d'} local b = {'b','a','d','c'} assert.is_true(M.same(a,b)) b[#b+1] = 'e' assert.is_false(M.same(a,b)) end) end) describe('sort', function() it('sorts a collection with respect to a given comparison function', function() assert.is_true(M.isEqual(M.sort({'b','a','d','c'}, function(a,b) return a:byte() < b:byte() end),{'a','b','c','d'})) end) it('uses "<" operator when no comparison function is given', function() assert.is_true(M.isEqual(M.sort({'b','a','d','c'}),{'a','b','c','d'})) end) end) describe('sortedk', function() it('iterates on sorted keys', function() local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 local ok_tbl = {12, 6, 5, 10, 8} local sorted = {} for k, v in M.sortedk(tbl) do sorted[k] = v end for k in ipairs(sorted) do assert.equal(sorted[k], ok_tbl[k]) end end) it('can take a comparison function', function() local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 local ok_tbl = {8, 10, 5, 6, 12} local sorted = {} for k, v in M.sortedk(tbl, function(a, b) return a > b end) do sorted[#sorted +1] = {k, v} end for k, pr in ipairs(sorted) do assert.equal(pr[2], ok_tbl[k]) end end) end) describe('sortedv', function() it('iterates on sorted values', function() local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 local ok_tbl = {5, 6, 8, 10, 12} local sorted = {} for k, v in M.sortedv(tbl) do sorted[#sorted + 1] = {k, v} end for k, pr in ipairs(sorted) do assert.equal(pr[2], ok_tbl[k]) end end) it('can take a comparison function', function() local tbl = {}; tbl[3] = 5 ; tbl[2] = 6; tbl[5] = 8; tbl[4] = 10; tbl[1] = 12 local ok_tbl = {12, 10, 8, 6, 5} local sorted = {} for k, v in M.sortedv(tbl, function(a, b) return a > b end) do sorted[#sorted +1] = {k, v} end for k, pr in ipairs(sorted) do assert.equal(pr[2], ok_tbl[k]) end end) end) describe('sortBy', function() it('sort values on the result of a transform function', function() assert.is_true(M.isEqual(M.sortBy({1,2,3,4,5}, math.sin), {5,4,3,1,2})) end) it('the transform function defaults to M.identity', function() assert.is_true(M.isEqual(M.sortBy({1,2,3,4,5}), {1,2,3,4,5})) end) it('transform function can be a string name property', function() local unsorted = {{item = 1, value = 10},{item = 2, value = 5},{item = 3, value = 8}} local sorted = {{item = 2, value = 5},{item = 3, value = 8},{item = 1, value = 10}} assert.is_true(M.isEqual(M.sortBy(unsorted, 'value'), sorted)) end) it('can use a custom comparison function', function() local unsorted = {{item = 1, value = 10},{item = 2, value = 5},{item = 3, value = 8}} local sorted = {{item = 1, value = 10},{item = 3, value = 8},{item = 2, value = 5}} local function comp(a,b) return a > b end assert.is_true(M.isEqual(M.sortBy(unsorted, 'value', comp), sorted)) end) end) describe('groupBy', function() it('splits a collection into subsets of items behaving the same', function() assert.is_true(M.isEqual(M.groupBy({0,1,2,3,4,5,6},function(value) return value%2==0 and 'even' or 'odd' end),{even = {0,2,4,6},odd = {1,3,5}})) assert.is_true(M.isEqual(M.groupBy({0,'a',true, false,nil,b,0.5},type),{number = {0,0.5},string = {'a'},boolean = {true,false}})) assert.is_true(M.isEqual(M.groupBy({'one','two','three','four','five'},string.len),{[3] = {'one','two'},[4] = {'four','five'},[5] = {'three'}})) end) end) describe('countBy', function() it('splits a collection in subsets and counts items inside', function() assert.is_true(M.isEqual(M.countBy({0,1,2,3,4,5,6},function(value) return value%2==0 and 'even' or 'odd' end),{even = 4,odd = 3})) assert.is_true(M.isEqual(M.countBy({0,'a',true, false,nil,b,0.5},type),{number = 2,string = 1,boolean = 2})) assert.is_true(M.isEqual(M.countBy({'one','two','three','four','five'},string.len),{[3] = 2,[4] = 2,[5] = 1})) end) end) describe('size', function() it('counts the very number of objects in a collection', function() assert.equal(M.size {1,2,3},3) end) it('counts nested tables elements as an unique value', function() assert.equal(M.size {1,2,3,{4,5}},4) end) it('leaves nil values', function() assert.equal(M.size {1,2,3,nil,8},4) end) it('counts objects', function() assert.equal(M.size {one = 1,2,b = 3, [{}] = 'nil', 'c', [function() end] = 'foo'},6) end) it('returns the size of the first arg when it is a table', function() assert.equal(M.size ({1,2},3,4,5),2) end) it('counts the number of non-nil args when the first one is not a table', function() assert.equal(M.size (1,3,4,5),4) assert.equal(M.size (nil,1,3,4,5),4) assert.equal(M.size (nil,1,3,4,nil,5),4) end) it('handles nil', function() assert.equal(M.size(),0) assert.equal(M.size(nil),0) end) end) describe('containsKeys', function() it('returns whether a table has all the keys from a given list', function() assert.is_true(M.containsKeys({1,2,3},{1,2,3})) assert.is_true(M.containsKeys({x = 1, y = 2},{x = 1,y =2})) end) it('does not compare values', function() assert.is_true(M.containsKeys({1,2,3},{4,5,6})) assert.is_true(M.containsKeys({x = 1, y = 2},{x = 4,y = -1})) end) it('is not commutative', function() assert.is_true(M.containsKeys({1,2,3,4},{4,5,6})) assert.is_true(M.containsKeys({x = 1, y = 2,z = 5},{x = 4,y = -1})) assert.is_false(M.containsKeys({1,2,3},{4,5,6,7})) assert.is_false(M.containsKeys({x = 1, y = 2},{x = 4,y = -1,z = 0})) end) end) describe('sameKeys', function() it('returns whether both tables features the same keys', function() assert.is_true(M.sameKeys({1,2,3},{1,2,3})) assert.is_true(M.sameKeys({x = 1, y = 2},{x = 1,y =2})) end) it('does not compare values', function() assert.is_true(M.sameKeys({1,2,3},{4,5,6})) assert.is_true(M.sameKeys({x = 1, y = 2},{x = 4,y = -1})) end) it('is commutative', function() assert.is_false(M.sameKeys({1,2,3,4},{4,5,6})) assert.is_false(M.sameKeys({x = 1, y = 2,z = 5},{x = 4,y = -1})) assert.is_false(M.sameKeys({1,2,3},{4,5,6,7})) assert.is_false(M.sameKeys({x = 1, y = 2},{x = 4,y = -1,z = 0})) end) end) end)