1466 lines
28 KiB
Markdown
1466 lines
28 KiB
Markdown
*Moses: a utility-belt library for 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.<br/>
|
|
__Moses__ was deeply inspired by [Underscore.js](http://documentcloud.github.com/underscore/).
|
|
|
|
# <a name='TOC'>Table of Contents</a>
|
|
|
|
* [Adding *Moses* to your project](#adding)
|
|
* [*Moses*' API](#API)
|
|
* [Table functions](#table)
|
|
* [Array functions](#array)
|
|
* [Utility functions](#utility)
|
|
* [Object functions](#object)
|
|
* [Chaining](#chaining)
|
|
* [Import](#import)
|
|
|
|
# <a name='adding'>Adding *Moses* to your project</a>
|
|
|
|
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 _ = require ("moses")
|
|
````
|
|
|
|
*Note: Lua purists tend to use "\_" to design a "dummy variable". Here, the usage of this underscore is quite idiomatic and refers to the name [Underscore](http://documentcloud.github.com/underscore/), the JS library from which *Moses* takes inspiration*.
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
# <a name='API'>*Moses*' API</a>
|
|
|
|
*Moses*' consists of a large set of functions that can be classified into four categories:
|
|
|
|
* __Table functions__, which are mostly meant for tables, i.e Lua tables which contains both an array-part and/or a map-part,
|
|
* __Array functions__, meant for array lists (or sequences),
|
|
* __Utility functions__,
|
|
* __Object functions__, meant for instances/classes.
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
## <a name='table'>Table functions</a>
|
|
|
|
|
|
### each (t, f, ...)
|
|
*Aliases: `_.forEach`*.
|
|
|
|
Iterates over each key-value pair in table.
|
|
|
|
```lua
|
|
_.each({1,2,3},print)
|
|
|
|
-- => 1 1
|
|
-- => 2 2
|
|
-- => 3 3
|
|
````
|
|
|
|
The table can be map-like (array part and hash-part).
|
|
|
|
```lua
|
|
_.each({one = 1, two = 2, three = 3},print)
|
|
|
|
-- => one 1
|
|
-- => two 2
|
|
-- => three 3
|
|
````
|
|
|
|
Can index and assign in an outer table or in the passed-in table:
|
|
|
|
```lua
|
|
t = {'a','b','c'}
|
|
_.each(t,function(i,v)
|
|
t[i] = v:rep(2)
|
|
print(t[i])
|
|
end)
|
|
|
|
-- => 1 aa
|
|
-- => 2 bb
|
|
-- => 3 cc
|
|
````
|
|
|
|
### eachi (t, f, ...)
|
|
*Aliases: `_.forEachi`*.
|
|
|
|
Iterates only on integer keys in a sparse array table.
|
|
|
|
```lua
|
|
_.eachi({1,2,3},print)
|
|
|
|
-- => 1 1
|
|
-- => 2 2
|
|
-- => 3 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}
|
|
_.eachi(t,function(i,v)
|
|
print(i,v)
|
|
end)
|
|
|
|
-- => -1 6
|
|
-- => 0 1
|
|
-- => 1 3
|
|
-- => 2 5
|
|
````
|
|
|
|
### at (t, ...)
|
|
|
|
Collects all values at some specific keys and returns them in an array.
|
|
|
|
```lua
|
|
local t = {4,5,6}
|
|
_.at(t,1,3) -- => "{4,6}"
|
|
|
|
local t = {a = 4, bb = true, ccc = false}
|
|
_.at(t,'a', 'ccc') -- => "{4, false}"
|
|
````
|
|
|
|
### count (t, value)
|
|
|
|
Counts the number of occurences of a given value in a table.
|
|
|
|
```lua
|
|
_.count({1,1,2,3,3,3,2,4,3,2},1) -- => 2
|
|
_.count({1,1,2,3,3,3,2,4,3,2},2) -- => 2
|
|
_.count({1,1,2,3,3,3,2,4,3,2},3) -- => 4
|
|
_.count({false, false, true},false) -- => 2
|
|
_.count({false, false, true},true) -- => 1
|
|
````
|
|
|
|
Returns the size of the list in case no value was provided.
|
|
|
|
```lua
|
|
_.count({1,1,2,3,3}) -- => 5
|
|
````
|
|
|
|
### countf (t, f, ...)
|
|
|
|
Count the number of occurences of all values passing an iterator test.
|
|
|
|
```lua
|
|
_.countf({1,2,3,4,5,6}, function(i,v)
|
|
return v%2==0
|
|
end) -- => 3
|
|
|
|
_.countf({print, pairs, os, assert, ipairs}, function(i,v)
|
|
return type(v)=='function'
|
|
end) -- => 4
|
|
````
|
|
|
|
### cycle (t, n)
|
|
*Aliases: `_.loop`*.
|
|
|
|
Returns a function which iterates on each key-value pair in a given table (similarly to `_.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 k,v in _.cycle(t, 2) do
|
|
print(k,v)
|
|
end
|
|
|
|
-- => 1 'a'
|
|
-- => 2 'b'
|
|
-- => 3 'c'
|
|
-- => 1 'a'
|
|
-- => 2 'b'
|
|
-- => 3 'c'
|
|
````
|
|
|
|
Supports array-like tables and map-like tables.
|
|
|
|
```lua
|
|
local t = {x = 1, y = 2, z = 3}
|
|
for k,v in _.cycle(t) do
|
|
print(k,v)
|
|
end
|
|
|
|
-- => y 2
|
|
-- => x 1
|
|
-- => z 3
|
|
````
|
|
|
|
### map (t, f, ...)
|
|
*Aliases: `_.collect`*.
|
|
|
|
Executes a function on each key-value pairs.
|
|
|
|
```lua
|
|
_.map({1,2,3},function(i,v)
|
|
return v+10
|
|
end)) -- => "{11,12,13}"
|
|
````
|
|
|
|
```lua
|
|
_.map({a = 1, b = 2},function(k,v)
|
|
return k..v
|
|
end) -- => "{a = 'a1', b = 'b2'}"
|
|
````
|
|
|
|
### reduce (t, f, state)
|
|
*Aliases: `_.inject`, `_.foldl`*.
|
|
|
|
Can sums all values in a table.
|
|
|
|
```lua
|
|
_.reduce({1,2,3,4},function(memo,v)
|
|
return memo+v
|
|
end) -- => 10
|
|
````
|
|
|
|
Or concatenates all values.
|
|
|
|
```lua
|
|
_.reduce({'a','b','c','d'},function(memo,v)
|
|
return memo..v
|
|
end) -- => abcd
|
|
````
|
|
|
|
### reduceRight (t, f, state)
|
|
*Aliases: `_.injectr`, `_.foldr`*.
|
|
|
|
Similar to `_.reduce`, but performs from right to left.
|
|
|
|
```lua
|
|
local initial_state = 256
|
|
_.reduceRight({1,2,4,16},function(memo,v)
|
|
return memo/v
|
|
end,initial_state) -- => 2
|
|
````
|
|
|
|
### mapReduce (t, f, state)
|
|
*Aliases: `_.mapr`*.
|
|
|
|
Reduces while saving intermediate states.
|
|
|
|
```lua
|
|
_.mapReduce({'a','b','c'},function(memo,v)
|
|
return memo..v
|
|
end) -- => "{'a', 'ab', 'abc'}"
|
|
````
|
|
|
|
### mapReduceRight (t, f, state)
|
|
*Aliases: `_.maprr`*.
|
|
|
|
Reduces from right to left, while saving intermediate states.
|
|
|
|
```lua
|
|
_.mapReduceRight({'a','b','c'},function(memo,v)
|
|
return memo..v
|
|
end) -- => "{'c', 'cb', 'cba'}"
|
|
````
|
|
|
|
### include (t, value)
|
|
*Aliases: `_.any`, `_.some`*.
|
|
|
|
Looks for a value in a table.
|
|
|
|
```lua
|
|
_.include({6,8,10,16,29},16) -- => true
|
|
_.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}
|
|
_.include(collection, complex_table) -- => true
|
|
````
|
|
|
|
Handles iterator functions.
|
|
|
|
```lua
|
|
local function isUpper(v) return v:upper()== v end
|
|
_.include({'a','B','c'},isUpper) -- => true
|
|
````
|
|
|
|
### detect (t, value)
|
|
|
|
Returns the index of a value in a table.
|
|
|
|
```lua
|
|
_.detect({6,8,10,16},8) -- => 2
|
|
_.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}
|
|
_.detect(collection, complex_table) -- => 2
|
|
````
|
|
|
|
Handles iterator functions.
|
|
|
|
```lua
|
|
local function isUpper(v)
|
|
return v:upper()==v
|
|
end
|
|
_.detect({'a','B','c'},isUpper) -- => 2
|
|
````
|
|
|
|
### contains (t, value)
|
|
|
|
Returns true if the passed-in value was found in a given table.
|
|
|
|
```lua
|
|
_.contains({6,8,10,16},8) -- => true
|
|
_.contains({nil,true,0,true,true},false) -- => false
|
|
````
|
|
|
|
It can lookup for objects, and accepts iterator functions aswell:
|
|
|
|
```lua
|
|
_.contains({6,{18,{2,6}},10,{18,{2,{3}}},29},{18,{2,6}}) -- => true
|
|
|
|
_.contains({'a','B','c'}, function(array_value)
|
|
return (array_value:upper() == array_value)
|
|
end) -- => true
|
|
````
|
|
|
|
### findWhere (t, props)
|
|
|
|
Looks through a table and returns the first value that matches all of the key-value pairs listed in properties.
|
|
|
|
```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}
|
|
_.findWhere({a, b, c}, {a = 3, b = 4}) == c -- => true
|
|
````
|
|
|
|
### select (t, f, ...)
|
|
*Aliases: `_.filte`*.
|
|
|
|
Collects values passing a validation test.
|
|
|
|
```lua
|
|
-- Even values
|
|
_.select({1,2,3,4,5,6,7}, function(key,value)
|
|
return (value%2==0)
|
|
end) -- => "{2,4,6}"
|
|
|
|
-- Odd values
|
|
_.select({1,2,3,4,5,6,7}, function(key,value)
|
|
return (value%2~=0)
|
|
end) -- => "{1,3,5,7}"
|
|
````
|
|
|
|
### reject (t, f, ...)
|
|
*Aliases: `_.reject`*.
|
|
|
|
Removes all values failing a validation test:
|
|
|
|
```lua
|
|
_.reject({1,2,3,4,5,6,7}, function(key,value)
|
|
return (value%2==0)
|
|
end) -- => "{1,3,5,7}"
|
|
|
|
_.reject({1,2,3,4,5,6,7}, function(key,value)
|
|
return (value%2~=0)
|
|
end) -- => "{2,4,6}"
|
|
````
|
|
|
|
### all (t, f, ...)
|
|
*Aliases: `_.every`*.
|
|
|
|
Checks whether or not all elements pass a validation test.
|
|
|
|
```lua
|
|
_.all({2,4,6}, function(key,value)
|
|
return (value%2==0)
|
|
end) -- => true
|
|
````
|
|
|
|
### invoke (t, method, ...)
|
|
|
|
Invokes a given function on each value in a table
|
|
|
|
```lua
|
|
_.invoke({'a','bea','cdhza'},string.len) -- => "{1,3,5}"
|
|
````
|
|
|
|
Can reference the method of the same name in each value.
|
|
|
|
```lua
|
|
local a = {}
|
|
function a:call() return 'a' end
|
|
local b, c, d = {}, {}, {}
|
|
b.call, c.call, d.call = a.call, a.call, a.call
|
|
|
|
_.invoke({a,b,c,d},'call') -- => "{'a','a','a','a'}"
|
|
````
|
|
|
|
### pluck (t, property)
|
|
|
|
Fetches all values indxed 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}}
|
|
|
|
_.pluck(peoples,'age') -- => "{23,17,15,33}"
|
|
_.pluck(peoples,'name') -- => "{'John', 'Peter', 'Steve'}"
|
|
````
|
|
|
|
### max (t, transform, ...)
|
|
|
|
Returns the maximum value in a collection.
|
|
|
|
```lua
|
|
_.max {1,2,3} -- => 3
|
|
_.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}}
|
|
_.max(peoples,function(people) return people.age end) -- => 33
|
|
````
|
|
|
|
### min (t, transform, ...)
|
|
|
|
Returns the minimum value in a collection.
|
|
|
|
```lua
|
|
_.min {1,2,3} -- => 1
|
|
_.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}}
|
|
_.min(peoples,function(people) return people.age end) -- => 15
|
|
````
|
|
|
|
### shuffle (t, seed)
|
|
|
|
Shuffles a collection.
|
|
|
|
```lua
|
|
local list = _.shuffle {1,2,3,4,5,6} -- => "{3,2,6,4,1,5}"
|
|
_.each(list,print)
|
|
````
|
|
|
|
### 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'}
|
|
_.same(a,b) -- => true
|
|
|
|
b[#b+1] = 'e'
|
|
_.same(a,b) -- => false
|
|
````
|
|
|
|
### sort (t, comp)
|
|
|
|
Sorts a collection.
|
|
|
|
```lua
|
|
_.sort({'b','a','d','c'}) -- => "{'a','b','c','d'}"
|
|
````
|
|
|
|
Handles custom comparison functions.
|
|
|
|
```lua
|
|
_.sort({'b','a','d','c'}, function(a,b)
|
|
return a:byte() > b:byte()
|
|
end) -- => "{'d','c','b','a'}"
|
|
````
|
|
|
|
### groupBy (t, iter, ...)
|
|
|
|
Groups values in a collection depending on their return value when passed to a predicate test.
|
|
|
|
```lua
|
|
_.groupBy({0,1,2,3,4,5,6},function(i,value)
|
|
return value%2==0 and 'even' or 'odd'
|
|
end) -- => "{odd = {1,3,5}, even = {0,2,4,6}}"
|
|
|
|
_.groupBy({0,'a',true, false,nil,b,0.5},function(i,value)
|
|
return type(value)
|
|
end) -- => "{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
|
|
_.countBy({0,1,2,3,4,5,6},function(i,value)
|
|
return value%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
|
|
_.size {1,2,3} -- => 3
|
|
_.size {one = 1, two = 2} -- => 2
|
|
````
|
|
|
|
When given a vararg list of argument, returns the count of these arguments.
|
|
|
|
```lua
|
|
_.size(1,2,3) -- => 3
|
|
_.size('a','b',{}, function() end) -- => 4
|
|
````
|
|
|
|
### containsKeys (t, other)
|
|
|
|
Checks whether a table has all the keys existing in another table.
|
|
|
|
```lua
|
|
_.contains({1,2,3,4},{1,2,3}) -- => true
|
|
_.contains({1,2,'d','b'},{1,2,3,5}) -- => true
|
|
_.contains({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => true
|
|
````
|
|
|
|
### sameKeys (tA, tB)
|
|
|
|
Checks whether both tables features the same keys:
|
|
|
|
```lua
|
|
_.sameKeys({1,2,3,4},{1,2,3}) -- => false
|
|
_.sameKeys({1,2,'d','b'},{1,2,3,5}) -- => true
|
|
_.sameKeys({x = 1, y = 2, z = 3},{x = 1, y = 2}) -- => false
|
|
````
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
## <a name='array'>Array functions</a>
|
|
|
|
### toArray (...)
|
|
|
|
Converts a vararg list of arguments to an array.
|
|
|
|
```lua
|
|
_.toArray(1,2,8,'d','a',0) -- => "{1,2,8,'d','a',0}"
|
|
````
|
|
|
|
### find (array, value, from)
|
|
|
|
Looks for a value in a given array and returns the position of the first occurence.
|
|
|
|
```lua
|
|
_.find({{4},{3},{2},{1}},{3}) -- => 2
|
|
````
|
|
|
|
It can also start the search at a specific position in the array:
|
|
|
|
```lua
|
|
-- search value 4 starting from index 3
|
|
_.find({1,4,2,3,4,5},4,3) -- => 5
|
|
````
|
|
|
|
### reverse (array)
|
|
|
|
Reverses an array.
|
|
|
|
```lua
|
|
_.reverse({1,2,3,'d'}) -- => "{'d',3,2,1}"
|
|
````
|
|
|
|
### selectWhile (array, f, ...
|
|
*Aliases: `_.takeWhile`*.
|
|
|
|
Collects values as long as they pass a given test. Stops on the first non-passing test.
|
|
|
|
```lua
|
|
_.selectWhile({2,4,5,8}, function(i,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
|
|
_.dropWhile({2,4,5,8}, function(i,v)
|
|
return v%2==0
|
|
end) -- => "{5,8}"
|
|
````
|
|
|
|
### sortedIndex (array, value, comp, sort)
|
|
|
|
Returns the index at which a value should be inserted to preserve order.
|
|
|
|
```lua
|
|
_.sortedIndex({1,2,3},4) -- => 4
|
|
````
|
|
|
|
Can take a custom comparison functions.
|
|
|
|
```lua
|
|
local comp = function(a,b) return a<b end
|
|
_.sortedIndex({-5,0,4,4},3,comp) -- => 3
|
|
````
|
|
|
|
### indexOf (array, value)
|
|
|
|
Returns the index of a value in an array.
|
|
|
|
```lua
|
|
_.indexOf({1,2,3},2) -- => 2
|
|
````
|
|
|
|
### lastIndexOf (array, value)
|
|
|
|
Returns the index of the last occurence of a given value in an array.
|
|
|
|
```lua
|
|
_.lastIndexOf({1,2,2,3},2) -- => 3
|
|
````
|
|
|
|
### addTop (array, ...)
|
|
|
|
Adds given values at the top of an array. The latter values bubbles at the top.
|
|
|
|
```lua
|
|
local array = {1}
|
|
_.addTop(array,1,2,3,4) -- => "{4,3,2,1,1}"
|
|
````
|
|
|
|
### push (array, ...)
|
|
|
|
Adds given values at the end of an array.
|
|
|
|
```lua
|
|
local array = {1}
|
|
_.push(array,1,2,3,4) -- => "{1,1,2,3,4}"
|
|
````
|
|
|
|
### pop (array, n)
|
|
*Aliases: `_.shift`*.
|
|
|
|
Removes and returns the first value in an array.
|
|
|
|
```lua
|
|
local array = {1,2,3}
|
|
local pop = _.pop(array) -- => "pop = 1", "array = {2,3}"
|
|
````
|
|
|
|
### unshift (array, n)
|
|
|
|
Removes and returns the last value in an array.
|
|
|
|
```lua
|
|
local array = {1,2,3}
|
|
local value = _.unshift(array) -- => "value = 3", "array = {1,2}"
|
|
````
|
|
|
|
### pull (array, ...)
|
|
*Aliases: `_.remove`*.
|
|
|
|
Removes all provided values from a given array.
|
|
|
|
```lua
|
|
_.pull({1,2,1,2,3,4,3},1,2,3) -- => "{4}"
|
|
````
|
|
|
|
### removeRange (array, start, finish)
|
|
*Aliases: `_.rmRange`, `_.chop`*.
|
|
|
|
Trims out all values index within a range.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.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(key,value,...)`. Consecutive elements which return the same value are aggregated together.
|
|
|
|
```lua
|
|
local t = {1,1,2,3,3,4}
|
|
_.chunk(t, function(k,v) return v%2==0 end) -- => "{{1,1},{2},{3,3},{4}}"
|
|
````
|
|
|
|
### slice (array, start, finish)
|
|
*Aliases: `_.sub`*.
|
|
|
|
Slices and returns a part of an array.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.slice(array, 3,6) -- => "{3,4,5,6}"
|
|
````
|
|
|
|
### first (array, n)
|
|
*Aliases: `_.head`, `_.take`*.
|
|
|
|
Returns the first N elements in an array.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.first(array,3) -- => "{1,2,3}"
|
|
````
|
|
|
|
### initial (array, n)
|
|
|
|
Excludes the last N elements in an array.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.initial(array,5) -- => "{1,2,3,4}"
|
|
````
|
|
|
|
### last (array, n)
|
|
*Aliases: `_.skip`*.
|
|
|
|
Returns the last N elements in an array.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.last(array,3) -- => "{7,8,9}"
|
|
````
|
|
|
|
### rest (array, index)
|
|
*Aliases: `_.tail`*.
|
|
|
|
Trims out all values indexed before *index*.
|
|
|
|
```lua
|
|
local array = {1,2,3,4,5,6,7,8,9}
|
|
_.rest(array,6) -- => "{6,7,8,9}"
|
|
````
|
|
|
|
### compact (array)
|
|
|
|
Trims out all falsy values.
|
|
|
|
```lua
|
|
_.compact {a,'aa',false,'bb',true} -- => "{'aa','bb',true}"
|
|
````
|
|
|
|
### flatten (array, shallow)
|
|
|
|
Flattens a nested array.
|
|
|
|
```lua
|
|
_.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
|
|
_.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}
|
|
_.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}
|
|
_.union(A,B,C) -- => "{'a',1,2,3,10}"
|
|
````
|
|
|
|
### intersection (array, ...)
|
|
|
|
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'}
|
|
_.intersection(A,B,C) -- => "{'a',2,1}"
|
|
````
|
|
|
|
### 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}
|
|
_.symmetricDifference(array, array2) -- => "{2,3,4,5}"
|
|
````
|
|
|
|
### unique (array)
|
|
*Aliases: `_.uniq`*.
|
|
|
|
Makes an array duplicate-free.
|
|
|
|
```lua
|
|
_.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
|
|
_.isunique({1,2,3,4,5}) -- => true
|
|
_.isunique({1,2,3,4,4}) -- => false
|
|
````
|
|
|
|
### zip (...)
|
|
|
|
Zips values from different arrays, on the basis on their common keys.
|
|
|
|
```lua
|
|
local names = {'Bob','Alice','James'}
|
|
local ages = {22, 23}
|
|
_.zip(names,ages) -- => "{{'Bob',22},{'Alice',23},{'James'}}"
|
|
````
|
|
|
|
### append (array, other)
|
|
|
|
Appends two arrays.
|
|
|
|
```lua
|
|
_.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'}
|
|
_.interleave(t1, t2) -- => "{1,'a',2,'b',3,'c'}"
|
|
````
|
|
|
|
### interpose (value, array)
|
|
|
|
Interposes a value between consecutive values in an arrays.
|
|
|
|
```lua
|
|
_.interleave('a', {1,2,3}) -- => "{1,'a',2,'a',3}"
|
|
````
|
|
|
|
### range (...)
|
|
|
|
Generates an arithmetic sequence.
|
|
|
|
```lua
|
|
_.range(1,4) -- => "{1,2,3,4}"
|
|
````
|
|
|
|
In case a single value is provided, it generates a sequence from 0 to that value.
|
|
|
|
````
|
|
_.range(3) -- => "{0,1,2,3}"
|
|
````
|
|
|
|
The incremental step can also be provided as third argument.
|
|
|
|
```lua
|
|
_.range(0,2,0.7) -- => "{0,0.7,1.4}"
|
|
````
|
|
|
|
### rep (value, n)
|
|
|
|
Generates a list of n repetitions of a value.
|
|
|
|
```lua
|
|
_.rep(4,3) -- => "{4,4,4}"
|
|
````
|
|
|
|
### partition (array, n)
|
|
*Aliases: `_.part`*.
|
|
|
|
Returns an iterator function for partitions of a given array.
|
|
|
|
```lua
|
|
local t = {1,2,3,4,5,6}
|
|
for p in _.partition(t,2) do
|
|
print(table.concat(p, ','))
|
|
end
|
|
|
|
-- => 1,2
|
|
-- => 3,4
|
|
-- => 5,6
|
|
````
|
|
|
|
### permutation (array)
|
|
*Aliases: `_.perm`*.
|
|
|
|
Returns an iterator function for permutations of a given array.
|
|
|
|
```lua
|
|
t = {'a','b','c'}
|
|
for p in _.permutation(t) do
|
|
print(table.concat(p))
|
|
end
|
|
|
|
-- => 'bca'
|
|
-- => 'cba'
|
|
-- => 'cab'
|
|
-- => 'acb'
|
|
-- => 'bac'
|
|
-- => 'abc'
|
|
````
|
|
|
|
### invert (array)
|
|
*Aliases: `_.mirror`*.
|
|
|
|
Switches <tt>key-value</tt> pairs:
|
|
|
|
```lua
|
|
_.invert {'a','b','c'} -- => "{a=1, b=2, c=3}"
|
|
````
|
|
|
|
### concat (array, sep, i, j)
|
|
*Aliases: `_.join`*.
|
|
|
|
Concatenates a given array values:
|
|
|
|
```lua
|
|
_.concat({'a',1,0,1,'b'}) -- => 'a101b'
|
|
````
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
## <a name='utility'>Utility functions</a>
|
|
|
|
### identity (value)
|
|
|
|
Returns the passed-in value. <br/>
|
|
This function is internally used as a default transformation function.
|
|
|
|
```lua
|
|
_.identity(1)-- => 1
|
|
_.identity(false) -- => false
|
|
_.identity('hello!') -- => 'hello!'
|
|
````
|
|
|
|
### once (f)
|
|
|
|
Produces a function that runs only once. Successive calls to this function will still yield the same input.
|
|
|
|
```lua
|
|
local sq = _.once(function(a) return a*a end)
|
|
sq(1) -- => 1
|
|
sq(2) -- => 1
|
|
sq(3) -- => 1
|
|
sq(4) -- => 1
|
|
sq(5) -- => 1
|
|
````
|
|
|
|
### memoize (f, hash)
|
|
*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 = _.memoize(fibonacci)
|
|
fibonacci(20) -- => 6765 (but takes some time)
|
|
mem_fibonacci(20) -- => 6765 (takes less time)
|
|
````
|
|
|
|
### after (f, count)
|
|
|
|
Produces a function that will respond only after a given number of calls.
|
|
|
|
```lua
|
|
local f = _.after(_.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 = _.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
|
|
_.pipe(10,f,g,h) -- => 36
|
|
_.pipe(20,f,g,h) -- => 121
|
|
````
|
|
|
|
### complement (f)
|
|
|
|
Returns a function which returns the logical complement of a given function.
|
|
|
|
```lua
|
|
_.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
|
|
_.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 = _.wrap(greet, function(f,arg)
|
|
return f(arg) ..'\nhi: ' .. arg:reverse()
|
|
end)
|
|
greet_backwards('John')
|
|
|
|
-- => hi: John
|
|
-- => hi: nhoJ
|
|
````
|
|
|
|
### times (n, iter, ...)
|
|
|
|
Calls a given function `n` times.
|
|
|
|
```lua
|
|
local f = ('Lua programming'):gmatch('.')
|
|
_.times(3,f) -- => {'L','u','a'}
|
|
````
|
|
|
|
### bind (f, v)
|
|
|
|
Binds a value to be the first argument to a function.
|
|
|
|
```lua
|
|
local sqrt2 = _.bind(math.sqrt,2)
|
|
sqrt2() -- => 1.4142135623731
|
|
````
|
|
|
|
### 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 = _.bindn(out,'OutPut',':',' ')
|
|
out(1,2,3) -- => OutPut: 123
|
|
out('a','b','c','d') -- => OutPut: abcd
|
|
````
|
|
|
|
### uniqueId (template, ...)
|
|
*Aliases: `_.uid`*.
|
|
|
|
Returns an unique integer ID.
|
|
|
|
```lua
|
|
_.uniqueId() -- => 1
|
|
````
|
|
|
|
Can handle string templates for formatted output.
|
|
|
|
```lua
|
|
_.uniqueId('ID%s') -- => 'ID2'
|
|
````
|
|
|
|
Or a function, for the same purpose.
|
|
|
|
```lua
|
|
local formatter = function(ID) return '$'..ID..'$' end
|
|
_.uniqueId(formatter) -- => '$ID1$'
|
|
````
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
## <a name='object'>Object functions</a>
|
|
|
|
### keys (obj)
|
|
|
|
Collects the names of an object attributes.
|
|
|
|
```lua
|
|
_.keys({1,2,3}) -- => "{1,2,3}"
|
|
_.keys({x = 0, y = 1}) -- => "{'y','x'}"
|
|
````
|
|
|
|
### values (obj)
|
|
|
|
Collects the values of an object attributes.
|
|
|
|
```lua
|
|
_.values({1,2,3}) -- => "{1,2,3}"
|
|
_.values({x = 0, y = 1}) -- => "{1,0}"
|
|
````
|
|
|
|
### toBoolean (value)
|
|
|
|
Converts a given value to a boolean.
|
|
|
|
```lua
|
|
_.toBoolean(true) -- => true
|
|
_.toBoolean(false) -- => false
|
|
_.toBoolean(nil) -- => false
|
|
_.toBoolean({}) -- => true
|
|
_.toBoolean(1) -- => true
|
|
````
|
|
|
|
### extend (destObj, ...)
|
|
|
|
Extends a destination object with the properties of some source objects.
|
|
|
|
```lua
|
|
_.extend({},{a = 'b', c = 'd'}) -- => "{a = 'b', c = 'd'}"
|
|
````
|
|
|
|
### functions (obj, recurseMt)
|
|
*Aliases: `_.methods`*.
|
|
|
|
Returns all functions names within an object.
|
|
|
|
```lua
|
|
_.functions(coroutine) -- => "{'create','resume','running','status','wrap','yield'}"
|
|
````
|
|
|
|
### clone (obj, shallow)
|
|
|
|
Clones a given object.
|
|
|
|
```lua
|
|
local obj = {1,2,3}
|
|
local obj2 = _.clone(obj)
|
|
print(obj2 == obj) -- => false
|
|
print(_.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 pased-interceptor is prototyped as `f(obj,...)`.
|
|
|
|
```lua
|
|
local v = _.chain({1,2,3,4,5,6,7,8,9,10)
|
|
:filter(function(k,v) return v%2~=0 end) -- filters even values
|
|
:tap(function(v) print('Max is', _.max(v) end) -- Tap max values
|
|
:map(function(k,v) return k^2)
|
|
:value() -- => Max is 9
|
|
````
|
|
|
|
### has (obj, key)
|
|
|
|
Checks if an object has a given attribute.
|
|
|
|
```lua
|
|
_.has(_,'has') -- => true
|
|
_.has(coroutine,'resume') -- => true
|
|
_.has(math,'random') -- => true
|
|
````
|
|
|
|
### pick (obj, ...)
|
|
*Aliases: `_.choose`*.
|
|
|
|
Collects whilelisted properties of a given object.
|
|
|
|
```lua
|
|
local object = {a = 1, b = 2, c = 3}
|
|
_.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}
|
|
_.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}
|
|
_.template(obj,{a = 1, b = 2, c = 3}) -- => "{a=0, c=3, b=2}"
|
|
````
|
|
|
|
### isEqual (objA, objB, useMt)
|
|
*Aliases: `_.compare`*.
|
|
|
|
Compares objects:
|
|
|
|
```lua
|
|
_.isEqual(1,1) -- => true
|
|
_.isEqual(true,false) -- => false
|
|
_.isEqual(3.14,math.pi) -- => false
|
|
_.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
|
|
_.result('abc','len') -- => 3
|
|
_.result({'a','b','c'},table.concat) -- => 'abc'
|
|
````
|
|
|
|
### isTable (t)
|
|
|
|
Is the given argument an object (i.e a table) ?
|
|
|
|
```lua
|
|
_.isTable({}) -- => true
|
|
_.isTable(math) -- => true
|
|
_.isTable(string) -- => true
|
|
````
|
|
|
|
### isCallable (obj)
|
|
|
|
Is the given argument callable ?
|
|
|
|
```lua
|
|
_.isCallable(print) -- => true
|
|
_.isCallable(function() end) -- => true
|
|
_.isCallable(setmetatable({},{__index = string}).upper) -- => true
|
|
_.isCallable(setmetatable({},{__call = function() return end})) -- => true
|
|
````
|
|
|
|
### isArray (obj)
|
|
|
|
Is the given argument an array (i.e. a sequence) ?
|
|
|
|
```lua
|
|
_.isArray({}) -- => true
|
|
_.isArray({1,2,3}) -- => true
|
|
_.isArray({'a','b','c'}) -- => true
|
|
````
|
|
|
|
### isIterable (obj)
|
|
|
|
Checks if the given object is iterable with `pairs`.
|
|
|
|
```lua
|
|
_.isIterable({}) -- => true
|
|
_.isIterable(function() end) -- => false
|
|
_.isIterable(false) -- => false
|
|
_.isIterable(1) -- => false
|
|
````
|
|
|
|
### isEmpty (obj)
|
|
|
|
Is the given argument empty ?
|
|
|
|
```lua
|
|
_.isEmpty('') -- => true
|
|
_.isEmpty({}) -- => true
|
|
_.isEmpty({'a','b','c'}) -- => false
|
|
````
|
|
|
|
### isString (obj)
|
|
|
|
Is the given argument a string ?
|
|
|
|
```lua
|
|
_.isString('') -- => true
|
|
_.isString('Hello') -- => false
|
|
_.isString({}) -- => false
|
|
````
|
|
|
|
### isFunction (obj)
|
|
|
|
Is the given argument a function ?
|
|
|
|
```lua
|
|
_.isFunction(print) -- => true
|
|
_.isFunction(function() end) -- => true
|
|
_.isFunction({}) -- => false
|
|
````
|
|
|
|
### isNil (obj)
|
|
|
|
Is the given argument nil ?
|
|
|
|
```lua
|
|
_.isNil(nil) -- => true
|
|
_.isNil() -- => true
|
|
_.isNil({}) -- => false
|
|
````
|
|
|
|
### isNumber (obj)
|
|
|
|
Is the given argument a number ?
|
|
|
|
```lua
|
|
_.isNumber(math.pi) -- => true
|
|
_.isNumber(math.huge) -- => true
|
|
_.isNumber(0/0) -- => true
|
|
_.isNumber() -- => false
|
|
````
|
|
|
|
### isNaN (obj)
|
|
|
|
Is the given argument NaN ?
|
|
|
|
```lua
|
|
_.isNaN(1) -- => false
|
|
_.isNaN(0/0) -- => true
|
|
````
|
|
|
|
### isFinite (obj)
|
|
|
|
Is the given argument a finite number ?
|
|
|
|
```lua
|
|
_.isFinite(99e99) -- => true
|
|
_.isFinite(math.pi) -- => true
|
|
_.isFinite(math.huge) -- => false
|
|
_.isFinite(1/0) -- => false
|
|
_.isFinite(0/0) -- => false
|
|
````
|
|
|
|
### isBoolean (obj)
|
|
|
|
Is the given argument a boolean ?
|
|
|
|
```lua
|
|
_.isBoolean(true) -- => true
|
|
_.isBoolean(false) -- => true
|
|
_.isBoolean(1==1) -- => true
|
|
_.isBoolean(print) -- => false
|
|
````
|
|
|
|
### isInteger (obj)
|
|
|
|
Is the given argument an integer ?
|
|
|
|
```lua
|
|
_.isInteger(math.pi) -- => false
|
|
_.isInteger(1) -- => true
|
|
_.isInteger(-1) -- => true
|
|
````
|
|
|
|
**[[⬆]](#TOC)**
|
|
|
|
## <a name='chaining'>Chaining</a>
|
|
|
|
*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 methods calls are chained together.
|
|
Moses offers chaining for your perusal. <br/>
|
|
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"
|
|
}
|
|
|
|
local stats = _.chain(lyrics)
|
|
:map(function(k,line)
|
|
local t = {}
|
|
for w in line:gmatch('(%w+)') do
|
|
t[#t+1] = w
|
|
end
|
|
return t
|
|
end)
|
|
:flatten()
|
|
:countBy(function(i,v) return v:lower() end)
|
|
: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 `_(value)` to start chaining methods, instead of `_.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)**
|
|
|
|
## <a name='import'>Import</a>
|
|
|
|
All library functions can be imported in a context using `import` into a specified context.
|
|
|
|
```lua
|
|
local context = {}
|
|
_.import(context)
|
|
|
|
context.each({1,2,3},print)
|
|
|
|
-- => 1 1
|
|
-- => 2 2
|
|
-- => 3 3
|
|
````
|
|
|
|
When no `context` was provided, it defaults to the global environment `_G`.
|
|
|
|
```lua
|
|
_.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}
|
|
_.import(context, true)
|
|
|
|
print(context.each) -- => 1
|
|
context.eachi({1,2,3},print)
|
|
|
|
-- => 1 1
|
|
-- => 2 2
|
|
-- => 3 3
|
|
````
|
|
|
|
**[[⬆]](#TOC)** |