177 Commits

Author SHA1 Message Date
Rose Liverman
e2a9e009af Merge branch 'rxi:master' into master 2025-07-20 17:53:40 -06:00
rxi
98847e7812 Updated copyright year; 2018 => 2020 2020-02-12 21:11:41 +00:00
rxi
6389f859c6 Made lume.reduce check initial value for nil instead of non-truthy
Fixes #32
2020-02-12 21:09:33 +00:00
rxi
d8c2eddc10 Merge pull request #30 from jaythomas/cleanup
Remove unnecessary expression; Add test
2019-03-14 23:10:46 +00:00
Jay Thomas
9e0f56e3e9 Remove unnecessary expression; Add test
First half of the expression returns a boolean already so the second
half is redundant
2019-03-08 09:58:40 -05:00
Paul Liverman III
c3089b0eb0 upd readme 2018-04-23 02:43:11 -07:00
Paul Liverman III
fb7b826942 added seed() fn, corrected err with local math_random 2018-04-23 02:41:29 -07:00
Paul Liverman III
0eccde530a upd version / ReadMe 2018-04-23 02:35:20 -07:00
Paul Liverman III
cea8f76bb3 lume uses love.math.random if available 2018-04-23 02:33:27 -07:00
Paul Liverman III
78805a5e42 using a local for math.random calls 2018-04-23 02:31:26 -07:00
rxi
0980d07eaa Fixed lume.ripairs() for falsey values; added test 2018-04-08 15:22:13 +01:00
rxi
09035882f1 Updated copyright year, moved full license to lume.lua 2018-03-10 15:30:04 +00:00
rxi
2b10ce1f98 Fixed README punctuation for lume.reduce 2018-03-10 14:57:56 +00:00
rxi
64aae8d473 Renamed lume.set -> lume.unique 2018-03-10 14:54:27 +00:00
rxi
758067dd33 Removed lume.rgba (superseded by lume.color) 2018-03-10 14:52:02 +00:00
rxi
b539dc74c7 Version 2.3.0 2017-05-06 08:20:35 +01:00
rxi
c517bd7c12 Changed header type used on function names in README 2017-05-06 08:11:21 +01:00
rxi
4fc4520a4c Added clearer example for lume.array() in README 2017-05-06 08:09:19 +01:00
rxi
1942218390 Updated copyright year: 2016 -> 2017 2017-05-06 08:06:14 +01:00
rxi
da0d1bbae7 Updated copyright year: 2015 -> 2016 2016-12-04 14:13:39 +00:00
rxi
03dcf81394 Removed local reference to math.random() 2016-12-04 14:09:58 +00:00
rxi
b569915d3e Added lume.vector(), updated README and tests 2016-09-19 21:56:24 +01:00
rxi
59f90934aa Added lume.isarray() to README 2016-02-21 16:43:18 +00:00
rxi
f226cf2e64 Exposed internal isarray() function as lume.isarray() 2016-02-21 16:33:21 +00:00
rxi
a20a39c8ee Version 2.2.3 2015-11-28 10:40:50 +00:00
rxi
faa5d8252f Removed some unused iterator vars 2015-10-21 19:10:53 +01:00
rxi
bf32432dac Merge pull request #8 from technomancy/luacheck
Pacify Luacheck.
2015-10-21 19:05:56 +01:00
Phil Hagelberg
b861303333 Pacify Luacheck.
Mostly just renaming unused args.
2015-10-19 07:21:47 +07:00
rxi
27278fb887 Version 2.2.2 2015-09-28 21:45:14 +01:00
rxi
8627638db0 Added support for NaN, inf and -inf to lume.serialize; updated tests 2015-09-23 19:32:25 +01:00
rxi
1559803c70 Updated README for lume.serialize changes 2015-09-04 18:59:59 +01:00
rxi
258e523219 Version 2.2.1 2015-08-30 19:47:53 +01:00
rxi
16848d83a5 Fixed number printing in lume.trace for Lua5.3 2015-08-15 11:37:32 +01:00
rxi
ca338b8833 Removed .gitignore file 2015-08-15 11:32:37 +01:00
rxi
ca36473904 Renaming of internal serialize func map 2015-08-15 11:31:50 +01:00
rxi
717745fe79 Updated README example for lume.trace() 2015-08-14 20:56:41 +01:00
rxi
688de3368e Lots of tweaks to lume.serialize(); circular reference detection 2015-08-14 20:50:42 +01:00
rxi
7412706277 Moved some stuff around in "test" directory 2015-08-14 20:32:00 +01:00
rxi
78144dbdb8 Changed lume.trace() to output in a nicer format, updated test 2015-08-14 20:29:29 +01:00
rxi
d8027db54d Version 2.2.0 2015-07-31 18:58:24 +01:00
rxi
6bff74e856 Changed lume.round() such that 0 results in 0 rather than -0 2015-05-12 20:30:05 +01:00
rxi
037f5e3325 Missing '.' in README 2015-05-09 15:44:52 +01:00
rxi
6dec4a8f56 Added lume.pick() to README 2015-05-09 15:42:38 +01:00
rxi
044141fefa Added lume.pick() and tests 2015-05-09 15:40:53 +01:00
rxi
e0d55c8446 Fixed lume.color example in README 2015-05-09 15:21:08 +01:00
rxi
84e23cb82c Added README section for lume.color() 2015-05-09 15:19:38 +01:00
rxi
a753f6e9a2 Added function lume.color() and tests 2015-05-09 15:12:52 +01:00
rxi
9b48d704d2 Removed unused function iternil() 2015-05-09 14:30:32 +01:00
rxi
6c350d81d9 Removed support of nil in lume.ripairs(), updated tests 2015-05-09 14:29:56 +01:00
rxi
300f47456f Improved description of lume.extend() in README 2015-05-09 14:27:38 +01:00
rxi
cb95fea004 Missing language hint on lume.extend's README example 2015-05-05 19:37:52 +01:00
rxi
2e00c753d8 Added function lume.extend(), updated README and tests 2015-05-05 19:32:46 +01:00
rxi
fce4a5e5df Updated test for lume.wordwrap() 2015-05-05 19:13:38 +01:00
rxi
b25fee071f Changed lume.wordwrap() to better retain existing whitespace 2015-05-05 19:12:41 +01:00
rxi
a6744d4ab3 Version 2.1.0 2015-02-28 21:03:42 +00:00
rxi
c3c2d31d37 Changed lume.reduce() to support non-array tables, updated tests 2015-02-24 21:02:04 +00:00
rxi
886bd43bce Changed getiter() to disallow nil values 2015-02-24 20:42:44 +00:00
rxi
976f813de9 Fixed example mistake in reject()'s README section 2015-02-20 19:52:10 +00:00
rxi
7911d62c53 Updated Iteratee functions part of README for lume.reject() 2015-02-20 19:27:34 +00:00
rxi
b1c9e3ec2e Changed lume.filter()'s implementation to mimic lume.reject() 2015-02-20 19:24:48 +00:00
rxi
48a4b43640 Added lume.reject(), updated tests and README.md 2015-02-20 19:22:42 +00:00
rxi
63e6d1daed Small fix to iteratee functions README section 2015-02-14 16:09:43 +00:00
rxi
685b7dc9c4 Added iteratee functions section to README 2015-02-14 16:02:40 +00:00
rxi
d2b26fa681 Changed lume.clear() to return the table, updated doc & tests 2015-02-08 15:13:05 +00:00
rxi
0a84bcd0d6 Fixed internal func isarray() 2015-02-08 15:01:17 +00:00
rxi
8e0b2d2ef8 Updated lume.push()'s README section 2015-02-07 23:04:23 +00:00
rxi
f27b15f9a2 Added tests for lume.remove()/lume.push() return values 2015-02-07 22:59:38 +00:00
rxi
abecb5b718 Updated README.md with new functions 2015-02-07 22:57:49 +00:00
rxi
fa85f83d70 Added lume.clear() and tests 2015-02-07 22:51:28 +00:00
rxi
14b9ee0ca2 Added lume.remove() and tests 2015-02-07 22:48:58 +00:00
rxi
3bec7b356d Added lume.push(), updated tests 2015-02-07 22:38:08 +00:00
rxi
9cdbc27b66 Minor optimisations to lume.combine(), updated tests 2015-02-05 21:32:21 +00:00
rxi
c6ab30cf7d Version 2.0.0 2015-01-24 15:21:35 +00:00
rxi
c07194490b Updated license copyright year 2015-01-24 15:20:58 +00:00
rxi
5305cb34c8 Lua 5.3 compatibility fixes 2015-01-12 19:51:24 +00:00
rxi
f7b3eb64bb Fixed typo in lume.sort()'s README section 2015-01-11 15:27:06 +00:00
rxi
edd7c99382 Added lume.ripairs() function, updated README and tests 2015-01-11 14:58:57 +00:00
rxi
c773acdcf4 Removed retainkeys argument from lume.set() 2015-01-11 14:33:56 +00:00
rxi
756d30416d Added lume.wordwrap(); updated README.md and tests 2015-01-10 21:53:52 +00:00
rxi
9b5abf3d58 Changed lume.merge() functionality, updated README and doc
- The old functionality of lume.merge() is now spread across
  lume.merge() (for tables) and lume.concat() (for arrays). Both these
  functions create new tables rather than operating in-place
- Changed lume.fn() to use lume.concat() internally
2015-01-10 17:31:35 +00:00
rxi
397dce4c5e Added lume.concat(), updated README and tests 2015-01-10 17:13:15 +00:00
rxi
ce86f4b0ea Fixed nil iterator in internal getiter() 2015-01-10 17:08:14 +00:00
rxi
c565f0739b Fixed lume.call() section of README.md 2015-01-10 16:56:32 +00:00
rxi
7a0f5a0831 Added lume.sort(), updated tests & README 2015-01-10 16:54:23 +00:00
rxi
b873c043c5 Added lume.call(), updated tests and README 2015-01-10 16:29:13 +00:00
rxi
4373a202dc Changed lume.shuffle() to not operate in-place, updated doc + tests 2015-01-10 16:24:31 +00:00
rxi
ac10d54b47 Changed internal func isarray() to handle nil 2015-01-10 14:32:58 +00:00
rxi
067e58b30f Changed lume.count() to return length if table is array 2015-01-10 14:31:55 +00:00
rxi
a42cbb12f0 Changed all applicable functions to use iter func based on table 2015-01-10 14:23:25 +00:00
rxi
0c21cfcf5b Updated lume.each() to use iter func based on table type 2015-01-10 14:13:07 +00:00
rxi
0e4256ef0d Version 1.5.0 2014-12-21 12:25:38 +00:00
rxi
bcad07fc5f Added explanation of calling lume() to the README 2014-12-13 01:00:47 +00:00
rxi
8f1267f967 Added lume.first() and .last(), updated README.md and tests 2014-12-12 21:33:41 +00:00
rxi
de37bd6d65 Added lume.keys() and tests, updated docs 2014-12-12 20:40:25 +00:00
rxi
ac920c8f5e Fixed lume.invert test name 2014-12-12 20:28:48 +00:00
rxi
5d258d4fd0 Made calling lume table an alias to calling lume.chain()
Updated tests
2014-12-12 20:25:54 +00:00
rxi
df26e7939d Added tests for funcitons which now use iteratee() 2014-12-12 20:22:29 +00:00
rxi
16e370cdf0 Changed all applicable functions to use iteratee() internally 2014-12-12 19:45:22 +00:00
rxi
0b991d7ea5 Added identity() and iteratee() local funcs 2014-12-12 18:56:13 +00:00
rxi
f6174a4b68 Version 1.4.1 2014-07-17 22:02:39 +01:00
rxi
d99bf9549a Removed unnecessary pack & unpack from lume.array() 2014-06-16 21:07:40 +01:00
rxi
0cc52cd24e Version 1.4.0 2014-05-18 08:46:28 +01:00
rxi
0a8258d608 Made some minor formatting changes 2014-05-07 08:21:36 +01:00
rxi
95c3f8960d Merge pull request #3 from icrawler/Dev2
Stripped all trailing whitespace, changed ease function, and pre-computed po2
2014-05-07 08:18:22 +01:00
Phoenix Enero
6b73aaa8ad Pre-computed powers of two in lume.rgba 2014-05-07 12:11:29 +08:00
Phoenix Enero
1a82d308af Changed ease function from cosine to cubic 2014-05-07 12:11:26 +08:00
Phoenix Enero
17b58ec63d Stripped all trailing whitespace 2014-05-07 12:11:15 +08:00
rxi
5ab25046a2 Renamed local memoize_nilkey -> memoize_nil 2014-05-01 21:27:57 +01:00
rxi
3f61d823ae Changed position of lume.time() function 2014-05-01 19:23:44 +01:00
rxi
0716caf6a1 Added lume.memoize(), updated README.md and tests 2014-05-01 18:58:29 +01:00
rxi
6a160a3afe Fixed iscallable() to handle the lack of metatable properly 2014-04-28 12:52:29 +01:00
rxi
fff0d780bb Updated README.md and tests for lume.combine() 2014-04-28 12:48:44 +01:00
rxi
283f7ee787 Changed lume.combine() to ignore nil args 2014-04-28 12:46:58 +01:00
rxi
076ca7972c Version 1.3.1 2014-04-23 20:11:00 +01:00
rxi
c2311f9821 Added missing tostring() call on args in lume.trace() 2014-04-19 09:06:33 +01:00
rxi
beced85d6b Updated test for lume.trace() 2014-04-18 19:16:33 +01:00
rxi
8a2765a41b Fixed lume.trace() to handle and print nil argument 2014-04-18 19:15:13 +01:00
rxi
09847bd266 Version 1.3.0 2014-04-17 20:52:54 +01:00
rxi
841cee30e1 Added another test for lume.slice() 2014-04-17 12:30:19 +01:00
rxi
cd3c0a1eea Made callable tables be accepted as functions 2014-04-17 12:13:50 +01:00
rxi
3190d65130 Removed use of math.min and math.max in lume.slice() 2014-04-17 12:07:59 +01:00
rxi
c7471b32fb Changed lume.uuid() to use local math_random() 2014-04-05 23:08:03 +01:00
rxi
bb56f1ce3a Added missing comment for lume.uuid func in test_lua.lua 2014-04-05 16:37:05 +01:00
rxi
098754056a Added tests for lume.chain() 2014-04-05 16:35:53 +01:00
rxi
330779fb0f Added lume.chain(), added section to README.md 2014-04-05 16:30:10 +01:00
rxi
acdb58a447 Added lume.uuid(), tests and README.md section 2014-04-05 14:41:31 +01:00
rxi
88b428cb4d Added lume.count() to README.md 2014-04-05 12:21:36 +01:00
rxi
fdf01937e2 Added lume.count() function and tests 2014-04-05 12:11:41 +01:00
rxi
3a4ce4fe3b Added type check in lume.fn() and additional tests 2014-04-04 18:38:36 +01:00
rxi
1a087efe99 Added lume.match() to README.md 2014-04-04 18:21:21 +01:00
rxi
9a82d6318e Added tests for lume.match() 2014-04-04 18:09:23 +01:00
rxi
30991649f8 Added lume.match() 2014-04-04 18:08:39 +01:00
rxi
dbd93b3861 Moved position of lume.combine() in readme and other files 2014-04-03 20:17:31 +01:00
rxi
8311519e3f Added test for lume.combine() to test_lume.lua 2014-04-03 20:10:08 +01:00
rxi
82c697b08e Added lume.combine() to README.md 2014-04-03 20:09:56 +01:00
rxi
5db6be936a Added lume.combine() function 2014-04-03 20:09:40 +01:00
rxi
335b928cae Removed function in lume.slice()
Moved the function index() from lume.slice()'s body to local var
absindex, this improves the performance of lume.slice() on luajit
significantly and improves it to a lesser extent on non-jit lua.
2014-04-01 20:16:39 +01:00
rxi
94977b4f7e Updated test for lume.trace() 2014-03-30 18:38:45 +01:00
rxi
e6246834b7 Changed lume.trace() to round numbers to 2 decimal places 2014-03-30 18:31:14 +01:00
rxi
9bf2d24ee2 table.unpack() is now used if unpack() is not available. 2014-03-29 10:02:48 +00:00
rxi
89931c1ad8 Version 1.2.1 2014-03-27 17:57:19 +00:00
rxi
9ff4637201 Moved shared code of lume.split/trim() to local func 2014-03-19 21:05:34 +00:00
rxi
617729e261 Added more tests for lume.trim() 2014-03-19 20:18:32 +00:00
rxi
ad64d7af05 Fixed use of pattern special chars in lume.trim()
Using lua pattern special chars in the `chars` argument of lume.trim()
are now handled correctly and treated like any other character.
2014-03-19 20:14:48 +00:00
rxi
d69f419f5a Improved lume.split()'s README.md section for clarity 2014-03-19 19:49:50 +00:00
rxi
ad34f6ce33 Updated lume.split() in README.md 2014-03-19 13:02:55 +00:00
rxi
5882ca1303 Fixed minor error in lume.set()'s README.md example 2014-03-19 12:54:14 +00:00
rxi
828d23e6f6 Added new tests and updated some others for lume.split() 2014-03-19 12:53:01 +00:00
rxi
13a8edb2e7 Changed lume.split() to mimic python's str.split()
The lume.split() function now mimics python's str.split() function,
though it does not support the third argument (maxsplit)
2014-03-19 12:51:35 +00:00
rxi
425a52b99f Fixed spelling mistake in README.md 2014-03-18 18:01:12 +00:00
rxi
a234e36975 Version 1.2.0 2014-03-18 12:12:38 +00:00
rxi
4ba373c2d1 Localised global funcs/variables
Set most of the global funcs / variables which are used to local
variables. This offers better performance in lua 5.1 and 5.2, and seems
to make no difference in luaJIT.
2014-03-18 12:07:53 +00:00
rxi
c537d00a47 Added type tests for lume.random() 2014-03-18 12:04:36 +00:00
rxi
2c3be23a2b Added test for lume.lambda() caching 2014-03-15 21:58:35 +00:00
rxi
be40cd6276 Added caching to lume.lambda() 2014-03-15 21:58:26 +00:00
rxi
c971cee753 Added more tests for lume.slice() 2014-03-13 21:53:07 +00:00
rxi
151b57adc6 Fixed behaviour for negative i argument on lume.slice()
A negative value for the `i` argument of lume.slice() is now handled
properly (used as an index from the end of the string) to mimicing the
behaviour of lua's string.sub()
2014-03-13 21:32:22 +00:00
rxi
cbafc49e8a Added "unsupported type" error to lume.serialize()
The unsupported type error is raised if an unsupported type is
encountered in the table we are trying to serialize.
2014-03-12 21:16:32 +00:00
rxi
fcb1fa90d4 Reworded description of lume.weightedchoice() in README 2014-03-12 13:16:36 +00:00
rxi
2a6d1ea9a8 Added some tests for lume.weightedchoice() 2014-03-12 13:12:55 +00:00
rxi
2d7fa98155 Added lume.weightedchoice() 2014-03-12 13:12:45 +00:00
rxi
af4c919be4 Added tests for lume.lambda() 2014-03-09 00:11:06 +00:00
rxi
abdfd78354 Added tester.test.error() to tester.lua script 2014-03-08 23:00:47 +00:00
rxi
fbb5cbac1a Replaced table concat with str concat in lume.lambda()
This offers an improvement in performance for the function on Lua5.1,
5.2 and JIT 2.0.2
2014-03-08 22:19:55 +00:00
rxi
f8cbfc0bb0 Added lume.lambda() to README.md 2014-03-08 21:18:05 +00:00
rxi
cf031025fd Added lume.lambda() 2014-03-08 21:08:56 +00:00
rxi
4db5a6b683 Added another test for lume.reduce() 2014-03-08 16:19:31 +00:00
rxi
a4fe134985 Version 1.1.2 2014-03-08 16:10:16 +00:00
rxi
cbff46bdfb Fixed empty-table test for lume.invert() 2014-03-08 16:08:58 +00:00
rxi
5e15a57f37 Moved lume.invert()'s test func to match order in lume.lua 2014-03-08 15:47:28 +00:00
rxi
2f388bc2c7 Moved lume.invert() to be near lume.clone()
This makes the series of python-like functions (map, all, any, reduce,
set, filter) consecutive in the source and readme, which seems like a
more logical order.
2014-03-08 15:23:13 +00:00
rxi
8f4d1b158f Added empty-table test for lume.set() 2014-03-08 14:48:04 +00:00
rxi
1bbb795a89 Changed lume.set() to make use of lume.invert() 2014-03-08 14:47:27 +00:00
rxi
2c71079ef3 Added tests for lume.invert() 2014-03-08 14:45:18 +00:00
rxi
8a76fd7595 Added lume.invert() 2014-03-08 14:45:08 +00:00
rxi
b4bea5f4e0 Added new tests for lume.reduce() 2014-03-06 19:41:14 +00:00
rxi
51189d190d Made first argument in lume.reduce() optional 2014-03-06 19:33:13 +00:00
7 changed files with 1495 additions and 438 deletions

3
.gitignore vendored
View File

@@ -1,3 +0,0 @@
__*
*.tmp
*.swp

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014, rxi Copyright (c) 2020 rxi
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of

362
README.md
View File

@@ -2,6 +2,10 @@
A collection of functions for Lua, geared towards game development. A collection of functions for Lua, geared towards game development.
This fork incorporates randomization from the LOVE engine's math library if
available, uses a local for random calls, and adds a function for setting the
seed for its randomizer.
## Installation ## Installation
@@ -15,10 +19,10 @@ lume = require "lume"
## Function Reference ## Function Reference
### lume.clamp(x, min, max) #### lume.clamp(x, min, max)
Returns the number `x` clamped between the numbers `min` and `max` Returns the number `x` clamped between the numbers `min` and `max`
### lume.round(x [, increment]) #### lume.round(x [, increment])
Rounds `x` to the nearest integer; rounds away from zero if we're midway Rounds `x` to the nearest integer; rounds away from zero if we're midway
between two integers. If `increment` is set then the number is rounded to the between two integers. If `increment` is set then the number is rounded to the
nearest increment. nearest increment.
@@ -27,53 +31,123 @@ lume.round(2.3) -- Returns 2
lume.round(123.4567, .1) -- Returns 123.5 lume.round(123.4567, .1) -- Returns 123.5
``` ```
### lume.sign(x) #### lume.sign(x)
Returns `1` if `x` is 0 or above, returns `-1` when `x` is negative. Returns `1` if `x` is 0 or above, returns `-1` when `x` is negative.
### lume.lerp(a, b, amount) #### lume.lerp(a, b, amount)
Returns the linearly interpolated number between `a` and `b`, `amount` should Returns the linearly interpolated number between `a` and `b`, `amount` should
be in the range of 0 - 1; if `amount` is outside of this range it is clamped. be in the range of 0 - 1; if `amount` is outside of this range it is clamped.
```lua ```lua
lume.lerp(100, 200, .5) -- Returns 150 lume.lerp(100, 200, .5) -- Returns 150
``` ```
### lume.smooth(a, b, amount) #### lume.smooth(a, b, amount)
Similar to `lume.lerp()` but uses cosine interpolation instead of linear Similar to `lume.lerp()` but uses cubic interpolation instead of linear
interpolation. interpolation.
### lume.pingpong(x) #### lume.pingpong(x)
Ping-pongs the number `x` between 0 and 1. Ping-pongs the number `x` between 0 and 1.
### lume.distance(x1, y1, x2, y2 [, squared]) #### lume.distance(x1, y1, x2, y2 [, squared])
Returns the distance between the two points. If `squared` is true then the Returns the distance between the two points. If `squared` is true then the
squared distance is returned -- this is faster to calculate and can still be squared distance is returned -- this is faster to calculate and can still be
used when comparing distances. used when comparing distances.
### lume.angle(x1, y1, x2, y2) #### lume.angle(x1, y1, x2, y2)
Returns the angle between the two points. Returns the angle between the two points.
### lume.random([a [, b]]) #### lume.vector(angle, magnitude)
Given an `angle` and `magnitude`, returns a vector.
```lua
local x, y = lume.vector(0, 10) -- Returns 10, 0
```
#### lume.seed([low [, high]])
Sets random seed. If using LOVE engine's math library, both `low` and `high`
arguments are used, else, only one argument is accepted.
#### lume.random([a [, b]])
Returns a random number between `a` and `b`. If only `a` is supplied a number Returns a random number between `a` and `b`. If only `a` is supplied a number
between `0` and `a` is returned. If no arguments are supplied a random number between `0` and `a` is returned. If no arguments are supplied a random number
between `0` and `1` is returned. between `0` and `1` is returned.
### lume.randomchoice(t) #### lume.randomchoice(t)
Returns a random value from array `t`. If the array is empty an error is Returns a random value from array `t`. If the array is empty an error is
raised. raised.
```lua ```lua
lume.randomchoice({true, false}) -- Returns either true or false lume.randomchoice({true, false}) -- Returns either true or false
``` ```
### lume.shuffle(t) #### lume.weightedchoice(t)
Shuffles the values of array `t` in place, returns the array. Takes the argument table `t` where the keys are the possible choices and the
value is the choice's weight. A weight should be 0 or above, the larger the
### lume.array(...) number the higher the probability of that choice being picked. If the table is
Iterates the supplied iterator and returns an array filled with the values. empty, a weight is below zero or all the weights are 0 then an error is raised.
```lua ```lua
lume.array(pairs({a = 1, b = 2})) -- Returns {"a", "b"} lume.weightedchoice({ ["cat"] = 10, ["dog"] = 5, ["frog"] = 0 })
-- Returns either "cat" or "dog" with "cat" being twice as likely to be chosen.
``` ```
### lume.each(t, fn, ...) #### lume.isarray(x)
Returns `true` if `x` is an array -- the value is assumed to be an array if it
is a table which contains a value at the index `1`. This function is used
internally and can be overridden if you wish to use a different method to detect
arrays.
#### lume.push(t, ...)
Pushes all the given values to the end of the table `t` and returns the pushed
values. Nil values are ignored.
```lua
local t = { 1, 2, 3 }
lume.push(t, 4, 5) -- `t` becomes { 1, 2, 3, 4, 5 }
```
#### lume.remove(t, x)
Removes the first instance of the value `x` if it exists in the table `t`.
Returns `x`.
```lua
local t = { 1, 2, 3 }
lume.remove(t, 2) -- `t` becomes { 1, 3 }
```
#### lume.clear(t)
Nils all the values in the table `t`, this renders the table empty. Returns
`t`.
```lua
local t = { 1, 2, 3 }
lume.clear(t) -- `t` becomes {}
```
#### lume.extend(t, ...)
Copies all the fields from the source tables to the table `t` and returns `t`.
If a key exists in multiple tables the right-most table's value is used.
```lua
local t = { a = 1, b = 2 }
lume.extend(t, { b = 4, c = 6 }) -- `t` becomes { a = 1, b = 4, c = 6 }
```
#### lume.shuffle(t)
Returns a shuffled copy of the array `t`.
#### lume.sort(t [, comp])
Returns a copy of the array `t` with all its items sorted. If `comp` is a
function it will be used to compare the items when sorting. If `comp` is a
string it will be used as the key to sort the items by.
```lua
lume.sort({ 1, 4, 3, 2, 5 }) -- Returns { 1, 2, 3, 4, 5 }
lume.sort({ {z=2}, {z=3}, {z=1} }, "z") -- Returns { {z=1}, {z=2}, {z=3} }
lume.sort({ 1, 3, 2 }, function(a, b) return a > b end) -- Returns { 3, 2, 1 }
```
#### lume.array(...)
Iterates the supplied iterator and returns an array filled with the values.
```lua
lume.array(string.gmatch("Hello world", "%a+")) -- Returns {"Hello", "world"}
```
#### lume.each(t, fn, ...)
Iterates the table `t` and calls the function `fn` on each value followed by Iterates the table `t` and calls the function `fn` on each value followed by
the supplied additional arguments; if `fn` is a string the method of that name the supplied additional arguments; if `fn` is a string the method of that name
is called for each value. The function returns `t` unmodified. is called for each value. The function returns `t` unmodified.
@@ -82,14 +156,14 @@ lume.each({1, 2, 3}, print) -- Prints "1", "2", "3" on separate lines
lume.each({a, b, c}, "move", 10, 20) -- Does x:move(10, 20) on each value lume.each({a, b, c}, "move", 10, 20) -- Does x:move(10, 20) on each value
``` ```
### lume.map(t, fn) #### lume.map(t, fn)
Applies the function `fn` to each value in table `t` and returns a new table Applies the function `fn` to each value in table `t` and returns a new table
with the resulting values. with the resulting values.
```lua ```lua
lume.map({1, 2, 3}, function(x) return x * 2 end) -- Returns {2, 4, 6} lume.map({1, 2, 3}, function(x) return x * 2 end) -- Returns {2, 4, 6}
``` ```
### lume.all(t [, fn]) #### lume.all(t [, fn])
Returns true if all the values in `t` table are true. If a `fn` function is Returns true if all the values in `t` table are true. If a `fn` function is
supplied it is called on each value, true is returned if all of the calls to supplied it is called on each value, true is returned if all of the calls to
`fn` return true. `fn` return true.
@@ -97,7 +171,7 @@ supplied it is called on each value, true is returned if all of the calls to
lume.all({1, 2, 1}, function(x) return x == 1 end) -- Returns false lume.all({1, 2, 1}, function(x) return x == 1 end) -- Returns false
``` ```
### lume.any(t [, fn]) #### lume.any(t [, fn])
Returns true if any of the values in `t` table are true. If a `fn` function is Returns true if any of the values in `t` table are true. If a `fn` function is
supplied it is called on each value, true is returned if any of the calls to supplied it is called on each value, true is returned if any of the calls to
`fn` return true. `fn` return true.
@@ -105,23 +179,23 @@ supplied it is called on each value, true is returned if any of the calls to
lume.any({1, 2, 1}, function(x) return x == 1 end) -- Returns true lume.any({1, 2, 1}, function(x) return x == 1 end) -- Returns true
``` ```
### lume.reduce(t, fn, first) #### lume.reduce(t, fn [, first])
Applies `fn` on two arguments cumulative to the items of the array `t`, from Applies `fn` on two arguments cumulative to the items of the array `t`, from
left to right, so as to reduce the array to a single value. The accumulator is left to right, so as to reduce the array to a single value. If a `first` value
intialised to the `first` value. is specified the accumulator is initialised to this, otherwise the first value
in the array is used. If the array is empty and no `first` value is specified
an error is raised.
```lua ```lua
lume.reduce({1, 2, 3}, function(a, b) return a + b end, 0) -- Returns 6 lume.reduce({1, 2, 3}, function(a, b) return a + b end) -- Returns 6
``` ```
### lume.set(t [, retainkeys]) #### lume.unique(t)
Returns a copy of the `t` table with all the duplicate values removed. If Returns a copy of the `t` array with all the duplicate values removed.
`retainkeys` is true the table is not treated as an array and retains its
original keys.
```lua ```lua
lume.set({2, 1, 2, "cat", "cat"}) -- Returns {1, 2, cat} lume.unique({2, 1, 2, "cat", "cat"}) -- Returns {1, 2, "cat"}
``` ```
### lume.filter(t, fn [, retainkeys]) #### lume.filter(t, fn [, retainkeys])
Calls `fn` on each value of `t` table. Returns a new table with only the values Calls `fn` on each value of `t` table. Returns a new table with only the values
where `fn` returned true. If `retainkeys` is true the table is not treated as where `fn` returned true. If `retainkeys` is true the table is not treated as
an array and retains its original keys. an array and retains its original keys.
@@ -129,32 +203,90 @@ an array and retains its original keys.
lume.filter({1, 2, 3, 4}, function(x) return x % 2 == 0 end) -- Returns {2, 4} lume.filter({1, 2, 3, 4}, function(x) return x % 2 == 0 end) -- Returns {2, 4}
``` ```
### lume.merge(t, t2 [, retainkeys]) #### lume.reject(t, fn [, retainkeys])
Merges all the values from the table `t2` into `t` in place. If `retainkeys` is The opposite of `lume.filter()`: Calls `fn` on each value of `t` table; returns
true the table is not treated as an array and retains its original keys; if `t` a new table with only the values where `fn` returned false. If `retainkeys` is
and `t2` have a conflicting key, the value from `t2` is used. true the table is not treated as an array and retains its original keys.
```lua ```lua
lume.merge({2, 3}, {4, 5}) -- Returns {2, 3, 4, 5} lume.reject({1, 2, 3, 4}, function(x) return x % 2 == 0 end) -- Returns {1, 3}
``` ```
### lume.find(t, value) #### lume.merge(...)
Returns a new table with all the given tables merged together. If a key exists
in multiple tables the right-most table's value is used.
```lua
lume.merge({a=1, b=2, c=3}, {c=8, d=9}) -- Returns {a=1, b=2, c=8, d=9}
```
#### lume.concat(...)
Returns a new array consisting of all the given arrays concatenated into one.
```lua
lume.concat({1, 2}, {3, 4}, {5, 6}) -- Returns {1, 2, 3, 4, 5, 6}
```
#### lume.find(t, value)
Returns the index/key of `value` in `t`. Returns `nil` if that value does not Returns the index/key of `value` in `t`. Returns `nil` if that value does not
exist in the table. exist in the table.
```lua ```lua
lume.find({"a", "b", "c"}, "b") -- Returns 2 lume.find({"a", "b", "c"}, "b") -- Returns 2
``` ```
### lume.slice(t [, i [, j]]) #### lume.match(t, fn)
Returns the value and key of the value in table `t` which returns true when
`fn` is called on it. Returns `nil` if no such value exists.
```lua
lume.match({1, 5, 8, 7}, function(x) return x % 2 == 0 end) -- Returns 8, 3
```
#### lume.count(t [, fn])
Counts the number of values in the table `t`. If a `fn` function is supplied it
is called on each value, the number of times it returns true is counted.
```lua
lume.count({a = 2, b = 3, c = 4, d = 5}) -- Returns 4
lume.count({1, 2, 4, 6}, function(x) return x % 2 == 0 end) -- Returns 3
```
#### lume.slice(t [, i [, j]])
Mimics the behaviour of Lua's `string.sub`, but operates on an array rather Mimics the behaviour of Lua's `string.sub`, but operates on an array rather
than a string. Creates and returns a new array of the given slice. than a string. Creates and returns a new array of the given slice.
```lua ```lua
lume.slice({"a", "b", "c", "d", "e"}, 2, 4) -- Returns {"b", "c", "d"} lume.slice({"a", "b", "c", "d", "e"}, 2, 4) -- Returns {"b", "c", "d"}
``` ```
### lume.clone(t) #### lume.first(t [, n])
Returns the first element of an array or nil if the array is empty. If `n` is
specificed an array of the first `n` elements is returned.
```lua
lume.first({"a", "b", "c"}) -- Returns "a"
```
#### lume.last(t [, n])
Returns the last element of an array or nil if the array is empty. If `n` is
specificed an array of the last `n` elements is returned.
```lua
lume.last({"a", "b", "c"}) -- Returns "c"
```
#### lume.invert(t)
Returns a copy of the table where the keys have become the values and the
values the keys.
```lua
lume.invert({a = "x", b = "y"}) -- returns {x = "a", y = "b"}
```
#### lume.pick(t, ...)
Returns a copy of the table filtered to only contain values for the given keys.
```lua
lume.pick({ a = 1, b = 2, c = 3 }, "a", "c") -- Returns { a = 1, c = 3 }
```
#### lume.keys(t)
Returns an array containing each key of the table.
#### lume.clone(t)
Returns a shallow copy of the table `t`. Returns a shallow copy of the table `t`.
### lume.fn(fn, ...) #### lume.fn(fn, ...)
Creates a wrapper function around function `fn`, automatically inserting the Creates a wrapper function around function `fn`, automatically inserting the
arguments into `fn` which will persist every time the wrapper is called. Any arguments into `fn` which will persist every time the wrapper is called. Any
arguments which are passed to the returned function will be inserted after the arguments which are passed to the returned function will be inserted after the
@@ -164,7 +296,7 @@ local f = lume.fn(print, "Hello")
f("world") -- Prints "Hello world" f("world") -- Prints "Hello world"
``` ```
### lume.once(fn, ...) #### lume.once(fn, ...)
Returns a wrapper function to `fn` which takes the supplied arguments. The Returns a wrapper function to `fn` which takes the supplied arguments. The
wrapper function will call `fn` on the first call and do nothing on any wrapper function will call `fn` on the first call and do nothing on any
subsequent calls. subsequent calls.
@@ -174,39 +306,75 @@ f() -- Prints "Hello"
f() -- Does nothing f() -- Does nothing
``` ```
### lume.time(fn, ...) #### lume.memoize(fn)
Returns a wrapper function to `fn` where the results for any given set of
arguments are cached. `lume.memoize()` is useful when used on functions with
slow-running computations.
```lua
fib = lume.memoize(function(n) return n < 2 and n or fib(n-1) + fib(n-2) end)
```
#### lume.combine(...)
Creates a wrapper function which calls each supplied argument in the order they
were passed to `lume.combine()`; nil arguments are ignored. The wrapper
function passes its own arguments to each of its wrapped functions when it is
called.
```lua
local f = lume.combine(function(a, b) print(a + b) end,
function(a, b) print(a * b) end)
f(3, 4) -- Prints "7" then "12" on a new line
```
#### lume.call(fn, ...)
Calls the given function with the provided arguments and returns its values. If
`fn` is `nil` then no action is performed and the function returns `nil`.
```lua
lume.call(print, "Hello world") -- Prints "Hello world"
```
#### lume.time(fn, ...)
Inserts the arguments into function `fn` and calls it. Returns the time in Inserts the arguments into function `fn` and calls it. Returns the time in
seconds the function `fn` took to execute followed by `fn`'s returned values. seconds the function `fn` took to execute followed by `fn`'s returned values.
```lua ```lua
lume.time(function(x) return x end, "hello") -- Returns 0, "hello" lume.time(function(x) return x end, "hello") -- Returns 0, "hello"
``` ```
### lume.serialize(x) #### lume.lambda(str)
Takes a string lambda and returns a function. `str` should be a list of
comma-separated parameters, followed by `->`, followed by the expression which
will be evaluated and returned.
```lua
local f = lume.lambda "x,y -> 2*x+y"
f(10, 5) -- Returns 25
```
#### lume.serialize(x)
Serializes the argument `x` into a string which can be loaded again using Serializes the argument `x` into a string which can be loaded again using
`lume.deserialize()`. Only booleans, numbers, tables and strings can be `lume.deserialize()`. Only booleans, numbers, tables and strings can be
serialized. Circular references are not handled; all nested tables are serialized. Circular references will result in an error; all nested tables are
serialized as unique tables. serialized as unique tables.
```lua ```lua
lume.serialize({a = "test", b = {1, 2, 3}, false}) lume.serialize({a = "test", b = {1, 2, 3}, false})
-- Returns "{[1]=false,["a"]="test",["b"]={[1]=1,[2]=2,[3]=3,},}" -- Returns "{[1]=false,["a"]="test",["b"]={[1]=1,[2]=2,[3]=3,},}"
``` ```
### lume.deserialize(str) #### lume.deserialize(str)
Deserializes a string created by `lume.serialize()` and returns the resulting Deserializes a string created by `lume.serialize()` and returns the resulting
value. This function should not be run on an untrusted string. value. This function should not be run on an untrusted string.
```lua ```lua
lume.deserialize("{1, 2, 3}") -- Returns {1, 2, 3} lume.deserialize("{1, 2, 3}") -- Returns {1, 2, 3}
``` ```
### lume.split(str [, sep]) #### lume.split(str [, sep])
Splits the string `str` into words and returns a table of the sub strings. If Returns an array of the words in the string `str`. If `sep` is provided it is
`sep` is provided the string will be split at any of the characters in `sep` used as the delimiter, consecutive delimiters are not grouped together and will
instead of on whitespace. delimit empty strings.
```lua ```lua
lume.split("One two three") -- Returns {"One", "two", "three"} lume.split("One two three") -- Returns {"One", "two", "three"}
lume.split("a,b,,c", ",") -- Returns {"a", "b", "", "c"}
``` ```
### lume.trim(str [, chars]) #### lume.trim(str [, chars])
Trims the whitespace from the start and end of the string `str` and returns the Trims the whitespace from the start and end of the string `str` and returns the
new string. If a `chars` value is set the characters in `chars` are trimmed new string. If a `chars` value is set the characters in `chars` are trimmed
instead of whitespace. instead of whitespace.
@@ -214,7 +382,16 @@ instead of whitespace.
lume.trim(" Hello ") -- Returns "Hello" lume.trim(" Hello ") -- Returns "Hello"
``` ```
### lume.format(str [, vars]) #### lume.wordwrap(str [, limit])
Returns `str` wrapped to `limit` number of characters per line, by default
`limit` is `72`. `limit` can also be a function which when passed a string,
returns `true` if it is too long for a single line.
```lua
-- Returns "Hello world\nThis is a\nshort string"
lume.wordwrap("Hello world. This is a short string", 14)
```
#### lume.format(str [, vars])
Returns a formatted string. The values of keys in the table `vars` can be Returns a formatted string. The values of keys in the table `vars` can be
inserted into the string by using the form `"{key}"` in `str`; numerical keys inserted into the string by using the form `"{key}"` in `str`; numerical keys
can also be used. can also be used.
@@ -223,21 +400,25 @@ lume.format("{b} hi {a}", {a = "mark", b = "Oh"}) -- Returns "Oh hi mark"
lume.format("Hello {1}!", {"world"}) -- Returns "Hello world!" lume.format("Hello {1}!", {"world"}) -- Returns "Hello world!"
``` ```
### lume.trace(...) #### lume.trace(...)
Prints the current filename and line number followed by each argument separated Prints the current filename and line number followed by each argument separated
by a space. by a space.
```lua ```lua
-- Assuming the file is called "example.lua" and the next line is 12: -- Assuming the file is called "example.lua" and the next line is 12:
lume.trace("hello", 1234) -- Prints "[example.lua:12] hello 1234" lume.trace("hello", 1234) -- Prints "example.lua:12: hello 1234"
``` ```
### lume.dostring(str) #### lume.dostring(str)
Executes the lua code inside `str`. Executes the lua code inside `str`.
```lua ```lua
lume.dostring("print('Hello!')") -- Prints "Hello!" lume.dostring("print('Hello!')") -- Prints "Hello!"
``` ```
### lume.hotswap(modname) #### lume.uuid()
Generates a random UUID string; version 4 as specified in
[RFC 4122](http://www.ietf.org/rfc/rfc4122.txt).
#### lume.hotswap(modname)
Reloads an already loaded module in place, allowing you to immediately see the Reloads an already loaded module in place, allowing you to immediately see the
effects of code changes without having to restart the program. `modname` should effects of code changes without having to restart the program. `modname` should
be the same string used when loading the module with require(). In the case of be the same string used when loading the module with require(). In the case of
@@ -248,12 +429,72 @@ lume.hotswap("lume") -- Reloads the lume module
assert(lume.hotswap("inexistant_module")) -- Raises an error assert(lume.hotswap("inexistant_module")) -- Raises an error
``` ```
### lume.rgba(color) #### lume.ripairs(t)
Takes the 32bit integer `color` argument and returns 4 numbers, one for each Performs the same function as `ipairs()` but iterates in reverse; this allows
channel, with a range of 0 - 255. The returned values can be used as the the removal of items from the table during iteration without any items being
arguments to [LÖVE](http://love2d.org)'s setColor() function. skipped.
```lua ```lua
lume.rgba(0xFF304050) -- Returns 48, 64, 80, 255 -- Prints "3->c", "2->b" and "1->a" on separate lines
for i, v in lume.ripairs({ "a", "b", "c" }) do
print(i .. "->" .. v)
end
```
#### lume.color(str [, mul])
Takes color string `str` and returns 4 values, one for each color channel (`r`,
`g`, `b` and `a`). By default the returned values are between 0 and 1; the
values are multiplied by the number `mul` if it is provided.
```lua
lume.color("#ff0000") -- Returns 1, 0, 0, 1
lume.color("rgba(255, 0, 255, .5)") -- Returns 1, 0, 1, .5
lume.color("#00ffff", 256) -- Returns 0, 256, 256, 256
lume.color("rgb(255, 0, 0)", 256) -- Returns 256, 0, 0, 256
```
#### lume.chain(value)
Returns a wrapped object which allows chaining of lume functions. The function
result() should be called at the end of the chain to return the resulting
value.
```lua
lume.chain({1, 2, 3, 4})
:filter(function(x) return x % 2 == 0 end)
:map(function(x) return -x end)
:result() -- Returns { -2, -4 }
```
The table returned by the `lume` module, when called, acts in the same manner
as calling `lume.chain()`.
```lua
lume({1, 2, 3}):each(print) -- Prints 1, 2 then 3 on separate lines
```
## Iteratee functions
Several lume functions allow a `table`, `string` or `nil` to be used in place
of their iteratee function argument. The functions that provide this behaviour
are: `map()`, `all()`, `any()`, `filter()`, `reject()`, `match()` and
`count()`.
If the argument is `nil` then each value will return itself.
```lua
lume.filter({ true, true, false, true }, nil) -- { true, true, true }
```
If the argument is a `string` then each value will be assumed to be a table,
and will return the value of the key which matches the string.
``` lua
local t = {{ z = "cat" }, { z = "dog" }, { z = "owl" }}
lume.map(t, "z") -- Returns { "cat", "dog", "owl" }
```
If the argument is a `table` then each value will return `true` or `false`,
depending on whether the values at each of the table's keys match the
collection's value's values.
```lua
local t = {
{ age = 10, type = "cat" },
{ age = 8, type = "dog" },
{ age = 10, type = "owl" },
}
lume.count(t, { age = 10 }) -- returns 2
``` ```
@@ -261,4 +502,3 @@ lume.rgba(0xFF304050) -- Returns 48, 64, 80, 255
This library is free software; you can redistribute it and/or modify it under This library is free software; you can redistribute it and/or modify it under
the terms of the MIT license. See [LICENSE](LICENSE) for details. the terms of the MIT license. See [LICENSE](LICENSE) for details.

630
lume.lua
View File

@@ -1,13 +1,84 @@
-- --
-- lume -- lume
-- --
-- Copyright (c) 2014, rxi -- Copyright (c) 2020 rxi
-- --
-- This library is free software; you can redistribute it and/or modify it -- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- under the terms of the MIT license. See LICENSE for details. -- 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.
-- --
local lume = { _version = "1.1.1" } local lume = { _version = "2.4.0-Guard13007-fork" }
local pairs, ipairs = pairs, ipairs
local type, assert, unpack = type, assert, unpack or table.unpack
local tostring, tonumber = tostring, tonumber
local math_floor = math.floor
local math_ceil = math.ceil
local math_atan2 = math.atan2 or math.atan
local math_sqrt = math.sqrt
local math_abs = math.abs
local math_random = love and love.math and love.math.random or math.random
local math_randomseed = love and love.math and love.math.setRandomSeed or math.randomseed
local noop = function()
end
local identity = function(x)
return x
end
local patternescape = function(str)
return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")
end
local absindex = function(len, i)
return i < 0 and (len + i + 1) or i
end
local iscallable = function(x)
if type(x) == "function" then return true end
local mt = getmetatable(x)
return mt and mt.__call ~= nil
end
local getiter = function(x)
if lume.isarray(x) then
return ipairs
elseif type(x) == "table" then
return pairs
end
error("expected table", 3)
end
local iteratee = function(x)
if x == nil then return identity end
if iscallable(x) then return x end
if type(x) == "table" then
return function(z)
for k, v in pairs(x) do
if z[k] ~= v then return false end
end
return true
end
end
return function(z) return z[x] end
end
function lume.clamp(x, min, max) function lume.clamp(x, min, max)
@@ -17,7 +88,7 @@ end
function lume.round(x, increment) function lume.round(x, increment)
if increment then return lume.round(x / increment) * increment end if increment then return lume.round(x / increment) * increment end
return x > 0 and math.floor(x + .5) or math.ceil(x - .5) return x >= 0 and math_floor(x + .5) or math_ceil(x - .5)
end end
@@ -32,13 +103,14 @@ end
function lume.smooth(a, b, amount) function lume.smooth(a, b, amount)
local m = (1 - math.cos(lume.clamp(amount, 0, 1) * math.pi)) / 2 local t = lume.clamp(amount, 0, 1)
local m = t * t * (3 - 2 * t)
return a + (b - a) * m return a + (b - a) * m
end end
function lume.pingpong(x) function lume.pingpong(x)
return 1 - math.abs(1 - x % 2) return 1 - math_abs(1 - x % 2)
end end
@@ -46,63 +118,164 @@ function lume.distance(x1, y1, x2, y2, squared)
local dx = x1 - x2 local dx = x1 - x2
local dy = y1 - y2 local dy = y1 - y2
local s = dx * dx + dy * dy local s = dx * dx + dy * dy
return squared and s or math.sqrt(s) return squared and s or math_sqrt(s)
end end
function lume.angle(x1, y1, x2, y2) function lume.angle(x1, y1, x2, y2)
return math.atan2(y2 - y1, x2 - x1) return math_atan2(y2 - y1, x2 - x1)
end
function lume.vector(angle, magnitude)
return math.cos(angle) * magnitude, math.sin(angle) * magnitude
end
function lume.seed(low, high)
return math_randomseed(low, high)
end end
function lume.random(a, b) function lume.random(a, b)
if not a then a, b = 0, 1 end if not a then a, b = 0, 1 end
if not b then b = 0 end if not b then b = 0 end
return a + math.random() * (b - a) return a + math_random() * (b - a)
end end
function lume.randomchoice(t) function lume.randomchoice(t)
return t[math.random(#t)] return t[math_random(#t)]
end end
function lume.shuffle(t) function lume.weightedchoice(t)
for i = 1, #t do local sum = 0
local r = math.random(#t) for _, v in pairs(t) do
t[i], t[r] = t[r], t[i] assert(v >= 0, "weight value less than zero")
sum = sum + v
end
assert(sum ~= 0, "all weights are zero")
local rnd = lume.random(sum)
for k, v in pairs(t) do
if rnd < v then return k end
rnd = rnd - v
end
end
function lume.isarray(x)
return type(x) == "table" and x[1] ~= nil
end
function lume.push(t, ...)
local n = select("#", ...)
for i = 1, n do
t[#t + 1] = select(i, ...)
end
return ...
end
function lume.remove(t, x)
local iter = getiter(t)
for i, v in iter(t) do
if v == x then
if lume.isarray(t) then
table.remove(t, i)
break
else
t[i] = nil
break
end
end
end
return x
end
function lume.clear(t)
local iter = getiter(t)
for k in iter(t) do
t[k] = nil
end end
return t return t
end end
function lume.extend(t, ...)
for i = 1, select("#", ...) do
local x = select(i, ...)
if x then
for k, v in pairs(x) do
t[k] = v
end
end
end
return t
end
function lume.shuffle(t)
local rtn = {}
for i = 1, #t do
local r = math_random(i)
if r ~= i then
rtn[i] = rtn[r]
end
rtn[r] = t[i]
end
return rtn
end
function lume.sort(t, comp)
local rtn = lume.clone(t)
if comp then
if type(comp) == "string" then
table.sort(rtn, function(a, b) return a[comp] < b[comp] end)
else
table.sort(rtn, comp)
end
else
table.sort(rtn)
end
return rtn
end
function lume.array(...) function lume.array(...)
local t = {} local t = {}
for x in unpack({...}) do t[#t + 1] = x end for x in ... do t[#t + 1] = x end
return t return t
end end
function lume.each(t, fn, ...) function lume.each(t, fn, ...)
local iter = getiter(t)
if type(fn) == "string" then if type(fn) == "string" then
for _, v in pairs(t) do v[fn](v, ...) end for _, v in iter(t) do v[fn](v, ...) end
else else
for _, v in pairs(t) do fn(v, ...) end for _, v in iter(t) do fn(v, ...) end
end end
return t return t
end end
function lume.map(t, fn) function lume.map(t, fn)
local rtn = {} fn = iteratee(fn)
for k, v in pairs(t) do rtn[k] = fn(v) end local iter = getiter(t)
local rtn = {}
for k, v in iter(t) do rtn[k] = fn(v) end
return rtn return rtn
end end
function lume.all(t, fn) function lume.all(t, fn)
fn = fn or function(x) return x end fn = iteratee(fn)
for k, v in pairs(t) do local iter = getiter(t)
for _, v in iter(t) do
if not fn(v) then return false end if not fn(v) then return false end
end end
return true return true
@@ -110,8 +283,9 @@ end
function lume.any(t, fn) function lume.any(t, fn)
fn = fn or function(x) return x end fn = iteratee(fn)
for k, v in pairs(t) do local iter = getiter(t)
for _, v in iter(t) do
if fn(v) then return true end if fn(v) then return true end
end end
return false return false
@@ -119,52 +293,174 @@ end
function lume.reduce(t, fn, first) function lume.reduce(t, fn, first)
for i = 1, #t do first = fn(first, t[i]) end local started = first ~= nil
return first local acc = first
local iter = getiter(t)
for _, v in iter(t) do
if started then
acc = fn(acc, v)
else
acc = v
started = true
end
end
assert(started, "reduce of an empty table with no first value")
return acc
end end
function lume.set(t, retainkeys) function lume.unique(t)
local tmp = {}
for k, v in pairs(t) do tmp[v] = k end
local rtn = {} local rtn = {}
for k, v in pairs(tmp) do rtn[retainkeys and v or (#rtn + 1)] = k end for k in pairs(lume.invert(t)) do
rtn[#rtn + 1] = k
end
return rtn return rtn
end end
function lume.filter(t, fn, retainkeys) function lume.filter(t, fn, retainkeys)
fn = iteratee(fn)
local iter = getiter(t)
local rtn = {} local rtn = {}
for k, v in pairs(t) do if retainkeys then
if fn(v) then rtn[retainkeys and k or (#rtn + 1)] = v end for k, v in iter(t) do
if fn(v) then rtn[k] = v end
end
else
for _, v in iter(t) do
if fn(v) then rtn[#rtn + 1] = v end
end
end end
return rtn return rtn
end end
function lume.merge(t, t2, retainkeys) function lume.reject(t, fn, retainkeys)
for k, v in pairs(t2) do fn = iteratee(fn)
t[retainkeys and k or (#t + 1)] = v local iter = getiter(t)
local rtn = {}
if retainkeys then
for k, v in iter(t) do
if not fn(v) then rtn[k] = v end
end
else
for _, v in iter(t) do
if not fn(v) then rtn[#rtn + 1] = v end
end
end end
return t return rtn
end
function lume.merge(...)
local rtn = {}
for i = 1, select("#", ...) do
local t = select(i, ...)
local iter = getiter(t)
for k, v in iter(t) do
rtn[k] = v
end
end
return rtn
end
function lume.concat(...)
local rtn = {}
for i = 1, select("#", ...) do
local t = select(i, ...)
if t ~= nil then
local iter = getiter(t)
for _, v in iter(t) do
rtn[#rtn + 1] = v
end
end
end
return rtn
end end
function lume.find(t, value) function lume.find(t, value)
for k, v in pairs(t) do local iter = getiter(t)
for k, v in iter(t) do
if v == value then return k end if v == value then return k end
end end
return nil return nil
end end
function lume.slice(t, i, j) function lume.match(t, fn)
i = i or 1 fn = iteratee(fn)
j = j and (j < 0 and (#t + j + 1) or j) or #t local iter = getiter(t)
local rtn = {} for k, v in iter(t) do
for i = math.max(i, 1), math.min(j, #t) do if fn(v) then return v, k end
rtn[#rtn + 1] = t[i]
end end
return nil
end
function lume.count(t, fn)
local count = 0
local iter = getiter(t)
if fn then
fn = iteratee(fn)
for _, v in iter(t) do
if fn(v) then count = count + 1 end
end
else
if lume.isarray(t) then
return #t
end
for _ in iter(t) do count = count + 1 end
end
return count
end
function lume.slice(t, i, j)
i = i and absindex(#t, i) or 1
j = j and absindex(#t, j) or #t
local rtn = {}
for x = i < 1 and 1 or i, j > #t and #t or j do
rtn[#rtn + 1] = t[x]
end
return rtn
end
function lume.first(t, n)
if not n then return t[1] end
return lume.slice(t, 1, n)
end
function lume.last(t, n)
if not n then return t[#t] end
return lume.slice(t, -n, -1)
end
function lume.invert(t)
local rtn = {}
for k, v in pairs(t) do rtn[v] = k end
return rtn
end
function lume.pick(t, ...)
local rtn = {}
for i = 1, select("#", ...) do
local k = select(i, ...)
rtn[k] = t[k]
end
return rtn
end
function lume.keys(t)
local rtn = {}
local iter = getiter(t)
for k in iter(t) do rtn[#rtn + 1] = k end
return rtn return rtn
end end
@@ -177,20 +473,69 @@ end
function lume.fn(fn, ...) function lume.fn(fn, ...)
local args = {...} assert(iscallable(fn), "expected a function as the first argument")
local args = { ... }
return function(...) return function(...)
local a = lume.merge(lume.clone(args), {...}) local a = lume.concat(args, { ... })
return fn(unpack(a)) return fn(unpack(a))
end end
end end
function lume.once(fn, ...) function lume.once(fn, ...)
local fn = lume.fn(fn, ...) local f = lume.fn(fn, ...)
local done = false local done = false
return function(...) return function(...)
if done then return end if done then return end
done = true done = true
return f(...)
end
end
local memoize_fnkey = {}
local memoize_nil = {}
function lume.memoize(fn)
local cache = {}
return function(...)
local c = cache
for i = 1, select("#", ...) do
local a = select(i, ...) or memoize_nil
c[a] = c[a] or {}
c = c[a]
end
c[memoize_fnkey] = c[memoize_fnkey] or {fn(...)}
return unpack(c[memoize_fnkey])
end
end
function lume.combine(...)
local n = select('#', ...)
if n == 0 then return noop end
if n == 1 then
local fn = select(1, ...)
if not fn then return noop end
assert(iscallable(fn), "expected a function or nil")
return fn
end
local funcs = {}
for i = 1, n do
local fn = select(i, ...)
if fn ~= nil then
assert(iscallable(fn), "expected a function or nil")
funcs[#funcs + 1] = fn
end
end
return function(...)
for _, f in ipairs(funcs) do f(...) end
end
end
function lume.call(fn, ...)
if fn then
return fn(...) return fn(...)
end end
end end
@@ -203,17 +548,54 @@ function lume.time(fn, ...)
end end
function lume.serialize(x) local lambda_cache = {}
local f = { string = function(v) return string.format("%q", v) end,
number = tostring, boolean = tostring } function lume.lambda(str)
f.table = function(t) if not lambda_cache[str] then
local rtn = {} local args, body = str:match([[^([%w,_ ]-)%->(.-)$]])
for k, v in pairs(t) do assert(args and body, "bad string lambda")
rtn[#rtn + 1] = "[" .. f[type(k)](k) .. "]=" .. f[type(v)](v) .. "," local s = "return function(" .. args .. ")\nreturn " .. body .. "\nend"
end lambda_cache[str] = lume.dostring(s)
return "{" .. table.concat(rtn) .. "}"
end end
return f[type(x)](x) return lambda_cache[str]
end
local serialize
local serialize_map = {
[ "boolean" ] = tostring,
[ "nil" ] = tostring,
[ "string" ] = function(v) return string.format("%q", v) end,
[ "number" ] = function(v)
if v ~= v then return "0/0" -- nan
elseif v == 1 / 0 then return "1/0" -- inf
elseif v == -1 / 0 then return "-1/0" end -- -inf
return tostring(v)
end,
[ "table" ] = function(t, stk)
stk = stk or {}
if stk[t] then error("circular reference") end
local rtn = {}
stk[t] = true
for k, v in pairs(t) do
rtn[#rtn + 1] = "[" .. serialize(k, stk) .. "]=" .. serialize(v, stk)
end
stk[t] = nil
return "{" .. table.concat(rtn, ",") .. "}"
end
}
setmetatable(serialize_map, {
__index = function(_, k) error("unsupported serialize type: " .. k) end
})
serialize = function(x, stk)
return serialize_map[type(x)](x, stk)
end
function lume.serialize(x)
return serialize(x)
end end
@@ -223,20 +605,59 @@ end
function lume.split(str, sep) function lume.split(str, sep)
return lume.array(str:gmatch("([^" .. (sep or "%s") .. "]+)")) if not sep then
return lume.array(str:gmatch("([%S]+)"))
else
assert(sep ~= "", "empty separator")
local psep = patternescape(sep)
return lume.array((str..sep):gmatch("(.-)("..psep..")"))
end
end end
function lume.trim(str, chars) function lume.trim(str, chars)
chars = chars or "%s" if not chars then return str:match("^[%s]*(.-)[%s]*$") end
chars = patternescape(chars)
return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$") return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$")
end end
function lume.wordwrap(str, limit)
limit = limit or 72
local check
if type(limit) == "number" then
check = function(s) return #s >= limit end
else
check = limit
end
local rtn = {}
local line = ""
for word, spaces in str:gmatch("(%S+)(%s*)") do
local s = line .. word
if check(s) then
table.insert(rtn, line .. "\n")
line = word
else
line = s
end
for c in spaces:gmatch(".") do
if c == "\n" then
table.insert(rtn, line .. "\n")
line = ""
else
line = line .. c
end
end
end
table.insert(rtn, line)
return table.concat(rtn)
end
function lume.format(str, vars) function lume.format(str, vars)
if not vars then return str end if not vars then return str end
local f = function(x) local f = function(x)
return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}") return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}")
end end
return (str:gsub("{(.-)}", f)) return (str:gsub("{(.-)}", f))
end end
@@ -244,8 +665,15 @@ end
function lume.trace(...) function lume.trace(...)
local info = debug.getinfo(2, "Sl") local info = debug.getinfo(2, "Sl")
local head = "[" .. info.short_src .. ":" .. info.currentline .. "] " local t = { info.short_src .. ":" .. info.currentline .. ":" }
print(head .. table.concat(lume.map({...}, tostring), " ")) for i = 1, select("#", ...) do
local x = select(i, ...)
if type(x) == "number" then
x = string.format("%g", lume.round(x, .01))
end
t[#t + 1] = tostring(x)
end
print(table.concat(t, " "))
end end
@@ -254,11 +682,21 @@ function lume.dostring(str)
end end
function lume.uuid()
local fn = function(x)
local r = math_random(16) - 1
r = (x == "x") and (r + 1) or (r % 4) + 9
return ("0123456789abcdef"):sub(r, r)
end
return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn))
end
function lume.hotswap(modname) function lume.hotswap(modname)
local oldglobal = lume.clone(_G) local oldglobal = lume.clone(_G)
local updated = {} local updated = {}
local function update(old, new) local function update(old, new)
if updated[old] then return end if updated[old] then return end
updated[old] = true updated[old] = true
local oldmt, newmt = getmetatable(old), getmetatable(new) local oldmt, newmt = getmetatable(old), getmetatable(new)
if oldmt and newmt then update(oldmt, newmt) end if oldmt and newmt then update(oldmt, newmt) end
@@ -268,7 +706,7 @@ function lume.hotswap(modname)
end end
local err = nil local err = nil
local function onerror(e) local function onerror(e)
for k, v in pairs(_G) do _G[k] = oldglobal[k] end for k in pairs(_G) do _G[k] = oldglobal[k] end
err = lume.trim(e) err = lume.trim(e)
end end
local ok, oldmod = pcall(require, modname) local ok, oldmod = pcall(require, modname)
@@ -278,7 +716,7 @@ function lume.hotswap(modname)
local newmod = require(modname) local newmod = require(modname)
if type(oldmod) == "table" then update(oldmod, newmod) end if type(oldmod) == "table" then update(oldmod, newmod) end
for k, v in pairs(oldglobal) do for k, v in pairs(oldglobal) do
if v ~= _G[k] and type(v) == "table" then if v ~= _G[k] and type(v) == "table" then
update(v, _G[k]) update(v, _G[k])
_G[k] = v _G[k] = v
end end
@@ -290,14 +728,60 @@ function lume.hotswap(modname)
end end
function lume.rgba(color) local ripairs_iter = function(t, i)
local floor = math.floor i = i - 1
local a = floor((color / 2 ^ 24) % 256) local v = t[i]
local r = floor((color / 2 ^ 16) % 256) if v ~= nil then
local g = floor((color / 2 ^ 08) % 256) return i, v
local b = floor((color) % 256) end
return r, g, b, a end
function lume.ripairs(t)
return ripairs_iter, t, (#t + 1)
end end
function lume.color(str, mul)
mul = mul or 1
local r, g, b, a
r, g, b = str:match("#(%x%x)(%x%x)(%x%x)")
if r then
r = tonumber(r, 16) / 0xff
g = tonumber(g, 16) / 0xff
b = tonumber(b, 16) / 0xff
a = 1
elseif str:match("rgba?%s*%([%d%s%.,]+%)") then
local f = str:gmatch("[%d.]+")
r = (f() or 0) / 0xff
g = (f() or 0) / 0xff
b = (f() or 0) / 0xff
a = f() or 1
else
error(("bad color string '%s'"):format(str))
end
return r * mul, g * mul, b * mul, a * mul
end
local chain_mt = {}
chain_mt.__index = lume.map(lume.filter(lume, iscallable, true),
function(fn)
return function(self, ...)
self._value = fn(self._value, ...)
return self
end
end)
chain_mt.__index.result = function(x) return x._value end
function lume.chain(value)
return setmetatable({ _value = value }, chain_mt)
end
setmetatable(lume, {
__call = function(_, ...)
return lume.chain(...)
end
})
return lume return lume

624
test/test.lua Normal file
View File

@@ -0,0 +1,624 @@
local tester = require "util.tester"
package.path = "../?.lua;" .. package.path
local lume = require "lume"
local tests = {}
local testeq = tester.test.equal
-- lume.clamp
tests["lume.clamp"] = function()
testeq( lume.clamp(8, 5, 10), 8 )
testeq( lume.clamp(12, 5, 10), 10 )
testeq( lume.clamp(-1, 5, 10), 5 )
testeq( lume.clamp(-1, -10, 10), -1 )
testeq( lume.clamp(-100, -10, 10), -10 )
testeq( lume.clamp(13, 8, 8), 8 )
testeq( lume.clamp(3, 8, 8), 8 )
end
-- lume.round
tests["lume.round"] = function()
testeq( lume.round(.5), 1 )
testeq( lume.round(-.5), -1 )
testeq( lume.round(2.4), 2 )
testeq( lume.round(123, 10), 120 )
testeq( lume.round(129, 64), 128 )
testeq( lume.round(-123.45, .1), -123.5 )
testeq( lume.round(0), 0 )
end
-- lume.sign
tests["lume.sign"] = function()
testeq( lume.sign(-10), -1 )
testeq( lume.sign(10), 1 )
testeq( lume.sign(0), 1 )
end
-- lume.lerp
tests["lume.lerp"] = function()
testeq( lume.lerp(100, 200, .5), 150 )
testeq( lume.lerp(100, 200, .25), 125 )
testeq( lume.lerp(100, 200, 2), 200 )
testeq( lume.lerp(100, 200, -2), 100 )
end
-- lume.smooth
tests["lume.smooth"] = function()
testeq( lume.smooth(100, 200, .5), 150 )
testeq( lume.smooth(100, 200, 0), 100 )
testeq( lume.smooth(100, 200, 1), 200 )
testeq( lume.smooth(100, 200, 2), 200 )
testeq( lume.smooth(100, 200, -2), 100 )
end
-- lume.pingpong
tests["lume.pingpong"] = function()
testeq( lume.pingpong(0), 0 )
testeq( lume.pingpong(1.5), .5 )
testeq( lume.pingpong(-.2), .2 )
testeq( lume.pingpong(-1.6), .4 )
testeq( lume.pingpong(1.8), .2 )
end
-- lume.distance
tests["lume.distance"] = function()
testeq( lume.distance(15, 20, 15, 20), 0 )
testeq( lume.distance(13, 44, 156, 232), 236.205419074 )
testeq( lume.distance(-23, 66, -232, 123), 216.633330769 )
local x = lume.distance(13, 15, -2, 81)
testeq( lume.distance(13, 15, -2, 81, true), x * x )
end
-- lume.angle
tests["lume.angle"] = function()
testeq( lume.angle(10, 10, 10, 10), math.rad(0) )
testeq( lume.angle(10, 10, 20, 10), math.rad(0) )
testeq( lume.angle(10, 10, 5, 10), math.rad(180) )
testeq( lume.angle(10, 10, 20, 20), math.rad(45) )
testeq( lume.angle(10, 10, 10, 30), math.rad(90) )
end
-- lume.vector
tests["lume.vector"] = function()
local function cmp(a, b) return math.abs(a - b) < 10e-6 end
local x, y
x, y = lume.vector(0, 10)
testeq( cmp(x, 10) and cmp(y, 0), true )
x, y = lume.vector(math.pi, 100)
testeq( cmp(x, -100) and cmp(y, 0), true )
x, y = lume.vector(math.pi * 0.25, 100)
testeq( cmp(x, 70.71067811865476) and cmp(y, 70.71067811865476), true )
end
-- lume.random
tests["lume.random"] = function()
testeq( type(lume.random()), "number" )
testeq( type(lume.random(1)), "number" )
testeq( type(lume.random(1, 2)), "number" )
end
-- lume.randomchoice
tests["lume.randomchoice"] = function()
local t = {}
for i = 0, 1000 do
t[lume.randomchoice({"a", "b", "c", "d"})] = true
end
testeq( t.a and t.b and t.c and t.d, true )
testeq( lume.randomchoice({true}), true )
end
-- lume.weightedchoice
tests["lume.weightedchoice"] = function()
testeq( lume.weightedchoice( {a = 1} ), "a" )
testeq( lume.weightedchoice( {a = 0, b = 1} ), "b" )
tester.test.error( lume.weightedchoice, {} )
tester.test.error( lume.weightedchoice, { a = 0, b = 0 } )
tester.test.error( lume.weightedchoice, { a = 1, b = -1 } )
end
-- lume.push
tests["lume.push"] = function()
local t = { 1, 2 }
lume.push(t, 3, 4)
testeq(t, { 1, 2, 3, 4 })
lume.push(t, 5, nil, 6, nil, 7)
testeq(t, { 1, 2, 3, 4, 5, 6, 7 })
lume.push(t)
testeq(t, { 1, 2, 3, 4, 5, 6, 7 })
local x, y = lume.push(t, 123, 456)
testeq(x, 123)
testeq(y, 456)
end
-- lume.remove
tests["lume.remove"] = function()
local t = { 1, 2, 3, 4, 5 }
lume.remove(t, 3)
testeq(t, { 1, 2, 4, 5 })
lume.remove(t, 1)
testeq(t, { 2, 4, 5 })
lume.remove(t, 5)
testeq(t, { 2, 4 })
local x = lume.remove(t, 123)
testeq(x, 123)
end
-- lume.clear
tests["lume.clear"] = function()
local t = { 1, 2, 3 }
lume.clear(t)
testeq(t, {})
local m = { a = 1, b = 2, c = 3 }
lume.clear(m)
testeq(m, {})
testeq( lume.clear(t) == t, true )
end
-- lume.extend
tests["lume.extend"] = function()
local t = { a = 10, b = 20, c = 30 }
testeq( lume.extend(t) == t, true )
lume.extend(t, { d = 40 }, { e = 50 })
testeq( t, { a = 10, b = 20, c = 30, d = 40, e = 50 } )
lume.extend(t, { a = "cat", b = "dog" }, { b = "owl", c = "fox" })
testeq( t, { a = "cat", b = "owl", c = "fox", d = 40, e = 50 } )
end
-- lume.shuffle
tests["lume.shuffle"] = function()
local t = {1, 2, 3, 4, 5}
t = lume.shuffle(t)
table.sort(t)
testeq( t, {1, 2, 3, 4, 5} )
testeq( lume.shuffle({}), {} )
end
-- lume.sort
tests["lume.sort"] = function()
local t = { 1, 5, 2, 4, 3 }
local fn = function(a, b) return a > b end
testeq( t == lume.sort(t), false )
testeq( lume.sort(t), { 1, 2, 3, 4, 5 } )
testeq( lume.sort(t, fn), { 5, 4, 3, 2, 1 } )
testeq( t, { 1, 5, 2, 4, 3 } )
local t = { { id = 2 }, { id = 3 }, { id = 1 } }
testeq( lume.sort(t, "id"), { { id = 1 }, { id = 2 }, { id = 3 } })
end
-- lume.array
tests["lume.array"] = function()
local t = lume.array(pairs({a=0, b=0, c=0}))
table.sort(t)
testeq( t, {"a", "b", "c"} )
testeq( lume.array(ipairs({0, 0, 0})), {1, 2, 3} )
end
-- lume.each
tests["lume.each"] = function()
local acc = 1
lume.each({1, 2, 3}, function(x) acc = acc + x end)
testeq( acc, 7 )
local acc = 1
local f = function(o, x) acc = acc + x end
local f2 = function() end
local t = {a = {f = f}, b = {f = f}, c = {f = f2}}
lume.each(t, "f", 10)
testeq( acc, 21 )
end
-- lume.map
tests["lume.map"] = function()
testeq( lume.map({1, 2, 3}, function(x) return x * 2 end), {2, 4, 6} )
testeq( lume.map({a=2,b=3}, function(x) return x * 2 end), {a=4,b=6} )
local t = {{ id = 10 }, { id = 20 }, { id = 30 }}
testeq( lume.map(t, "id"), { 10, 20, 30 })
end
-- lume.all
tests["lume.all"] = function()
testeq( lume.all({true, true, false, true}), false )
testeq( lume.all({true, true, true, true}), true )
testeq( lume.all({2, 3, 4, 5}, function(x) return x % 2 == 0 end), false )
testeq( lume.all({2, 4, 6, 8}, function(x) return x % 2 == 0 end), true )
testeq( lume.all({{ x = 1 }, {}, { x = 3 }}, "x"), false )
testeq( lume.all({{ x = 1 }, { x = 2 }, { x = 3 }}, "x"), true )
testeq( lume.all({{ x = 1 }, { x = 2 }, { x = 3 }}, { x = 2 }), false )
testeq( lume.all({{ x = 2 }, { x = 2 }, { x = 2 }}, { x = 2 }), true )
end
-- lume.any
tests["lume.any"] = function()
testeq( lume.any({true, true, false, true}), true )
testeq( lume.any({false, false, false}), false )
testeq( lume.any({2, 3, 4, 5}, function(x) return x % 2 == 0 end), true )
testeq( lume.any({1, 3, 5, 7}, function(x) return x % 2 == 0 end), false )
local t = {{ id = 10 }, { id = 20 }, { id = 30 }}
testeq( lume.any(t, { id = 10 }), true )
testeq( lume.any(t, { id = 40 }), false )
end
-- lume.reduce
tests["lume.reduce"] = function()
local concat = function(a, b) return a .. b end
local add = function(a, b) return a + b end
local any = function(a, b) return a or b end
testeq( lume.reduce({"cat", "dog"}, concat, ""), "catdog" )
testeq( lume.reduce({"cat", "dog"}, concat, "pig"), "pigcatdog" )
testeq( lume.reduce({"me", "ow"}, concat), "meow" )
testeq( lume.reduce({1, 2, 3, 4}, add), 10 )
testeq( lume.reduce({1, 2, 3, 4}, add, 5), 15 )
testeq( lume.reduce({1}, add), 1 )
testeq( lume.reduce({}, concat, "potato"), "potato" )
testeq( lume.reduce({a=1, b=2}, add, 5), 8 )
testeq( lume.reduce({a=1, b=2}, add), 3 )
testeq( lume.reduce({false, false, false}, any), false )
testeq( lume.reduce({false, true, false}, any), true )
tester.test.error(lume.reduce, {}, add)
end
-- lume.unique
tests["lume.unique"] = function()
testeq( lume.unique({}), {} )
local t = lume.unique({1, 2, 3, 2, 5, 6, 6})
table.sort(t)
testeq( t, {1, 2, 3, 5, 6} )
local t = lume.unique({"a", "b", "c", "b", "d"})
table.sort(t)
testeq( t, {"a", "b", "c", "d"} )
end
-- lume.filter
tests["lume.filter"] = function()
local t = lume.filter({1, 2, 3, 4, 5}, function(x) return x % 2 == 0 end )
testeq( t, {2, 4} )
local t = lume.filter({a=1, b=2, c=3}, function(x) return x == 2 end, true)
testeq( t, {b=2} )
local t = lume.filter({{ x=1, y=1 }, { x=2, y=2 }, { x=1, y=3 }}, { x = 1 })
testeq( t, {{ x=1, y=1 }, {x=1, y=3}} )
end
-- lume.reject
tests["lume.reject"] = function()
local t = lume.reject({1, 2, 3, 4, 5}, function(x) return x % 2 == 0 end )
testeq( t, {1, 3, 5} )
local t = lume.reject({a=1, b=2, c=3}, function(x) return x == 2 end, true)
testeq( t, {a=1, c=3} )
local t = lume.reject({{ x=1, y=1 }, { x=2, y=2 }, { x=1, y=3 }}, { x = 1 })
testeq( t, {{ x=2, y=2 }} )
end
-- lume.merge
tests["lume.merge"] = function()
testeq( lume.merge(), {} )
testeq( lume.merge({x=1, y=2}), {x=1, y=2} )
testeq( lume.merge({a=1, b=2}, {b=3, c=4}), {a=1, b=3, c=4} )
end
-- lume.concat
tests["lume.concat"] = function()
testeq( lume.concat(nil), {} )
testeq( lume.concat({1, 2, 3}), {1, 2, 3} )
testeq( lume.concat({1, 2, 3}, {4, 5, 6}), {1, 2, 3, 4, 5, 6} )
testeq( lume.concat({1, 2, 3}, {4, 5, 6}, nil, {7}), {1, 2, 3, 4, 5, 6, 7} )
end
-- lume.find
tests["lume.find"] = function()
testeq( lume.find({"a", "b", "c"}, "b"), 2 )
testeq( lume.find({"a", "b", "c"}, "c"), 3 )
testeq( lume.find({a=1, b=5, c=7}, 5), "b" )
end
-- lume.match
tests["lume.match"] = function()
local t = { "a", "b", "c", "d" }
local t2 = { a = 1, b = 2, c = 3, d = 4 }
local t3 = { {x=1, y=2}, {x=3, y=4}, {x=5, y=6} }
local v, k = lume.match(t, function(x) return x > "c" end)
testeq( v, "d" )
testeq( k, 4 )
local v, k = lume.match(t, function(x) return x < "b" end)
testeq( v, "a" )
testeq( k, 1 )
local v, k = lume.match(t2, function(x) return x < 2 end)
testeq( v, 1 )
testeq( k, "a" )
local v, k = lume.match(t2, function(x) return x > 5 end)
testeq( v, nil )
testeq( k, nil )
local v, k = lume.match(t3, { x = 3, y = 4 })
testeq( k, 2 )
end
-- lume.count
tests["lume.count"] = function()
local t = { a = 1, b = 2, c = 5, [13] = 22, z = 8 }
testeq( lume.count(t), 5 )
testeq( lume.count(t, function(x) return x % 2 == 0 end ), 3 )
local a = { 5, 6, 7, 8, 9 }
testeq( lume.count(a), #a )
local t = { { n = 20 }, { n = 30 }, { n = 40 }, { n = 20 } }
testeq( lume.count(t, { n = 20 }), 2 )
testeq( lume.count(t, { n = 30 }), 1 )
testeq( lume.count(t, { n = 50 }), 0 )
end
-- lume.slice
tests["lume.slice"] = function()
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 4), {"b", "c", "d"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, -2), {"b", "c", "d"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 3, -1), {"c", "d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 3), {"c", "d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 4), {"d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 1, 1), {"a"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 1), {} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, -3, -2), {"c", "d"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, -3, 1), {} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 0, 1), {"a"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 0, 0), {} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, -3), {"c", "d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, -3, 900), {"c", "d", "e"} )
end
-- lume.first
tests["lume.first"] = function()
local t = { "a", "b", "c", "d", "e" }
testeq( lume.first(t), "a" )
testeq( lume.first(t, 1), { "a" } )
testeq( lume.first(t, 2), { "a", "b" } )
end
-- lume.last
tests["lume.last"] = function()
local t = { "a", "b", "c", "d", "e" }
testeq( lume.last(t), "e" )
testeq( lume.last(t, 1), { "e" } )
testeq( lume.last(t, 2), { "d", "e" } )
end
-- lume.invert
tests["lume.invert"] = function()
testeq( lume.invert({}), {} )
testeq( lume.invert{a = "x", b = "y"}, {x = "a", y = "b"} )
testeq( lume.invert{a = 1, b = 2}, {"a", "b"} )
testeq( lume.invert(lume.invert{a = 1, b = 2}), {a = 1, b = 2} )
end
-- lume.pick
tests["lume.pick"] = function()
local t = { cat = 10, dog = 20, fox = 30, owl = 40 }
testeq( lume.pick(t, "cat", "dog"), { cat = 10, dog = 20 } )
testeq( lume.pick(t, "fox", "owl"), { fox = 30, owl = 40 } )
testeq( lume.pick(t, "owl"), { owl = 40 } )
testeq( lume.pick(t), {} )
end
-- lume.keys
tests["lume.keys"] = function()
testeq( lume.keys({}), {} )
local t = lume.keys({ aaa = 1, bbb = 2, ccc = 3 })
table.sort(t)
testeq( t, {"aaa", "bbb", "ccc"} )
local t = lume.keys({ "x", "x", "x" })
testeq( t, {1, 2, 3} )
end
-- lume.clone
tests["lume.clone"] = function()
local t = {6, 7, 4, 5}
testeq( lume.clone(t) ~= t, true )
testeq( lume.clone(t), {6, 7, 4, 5} )
testeq( lume.clone({x=2, y="a"}), {x=2, y="a"} )
end
-- lume.fn
tests["lume.fn"] = function()
local f = lume.fn(function(a, b) return a + b end, 10)
testeq( f(5), 15 )
tester.test.error( lume.fn, 123 )
end
-- lume.once
tests["lume.once"] = function()
local f = lume.once(function(a, b) return a + b end, 10)
testeq( f(5), 15 )
testeq( f(5), nil )
tester.test.error( lume.once, 123 )
end
-- lume.memoize
tests["lume.memoize"] = function()
local f = lume.memoize(
function(a, b, c)
return tostring(a) .. tostring(b) .. tostring(c)
end)
testeq( f("hello", nil, 15), "hellonil15" )
testeq( f("hello", nil, 15), "hellonil15" )
testeq( f(), "nilnilnil" )
testeq( f(), "nilnilnil" )
local f2 = lume.memoize(function() end)
testeq( f2(), nil )
end
-- lume.combine
tests["lume.combine"] = function()
local acc = 0
local a = function(x, y) acc = acc + x + y end
local b = function(x, y) acc = acc + x * y end
local fn = lume.combine(a, b)
fn(10, 20)
testeq( acc, 230 )
acc = 0
fn = lume.combine(nil, a, nil, b, nil)
fn(10, 20)
testeq( acc, 230 )
local x = false
fn = lume.combine(function() x = true end)
fn()
testeq( x, true )
testeq( type(lume.combine(nil)), "function" )
testeq( type(lume.combine()), "function" )
end
-- lume.call
tests["lume.call"] = function()
local add = function(a, b) return a + b end
testeq( lume.call(), nil )
testeq( lume.call(nil, 1, 2, 3), nil )
testeq( lume.call(add, 1, 2), 3 )
end
-- lume.time
tests["lume.time"] = function()
local t, a, b, c = lume.time(function(x) return 50, 60, x end, 70)
testeq( type(t), "number" )
testeq( {a, b, c}, {50, 60, 70} )
end
-- lume.lambda
tests["lume.lambda"] = function()
testeq( lume.lambda "x->x*x"(10), 100 )
testeq( lume.lambda "x->x*x"(20), 400 )
testeq( lume.lambda "x,y -> 2*x+y"(10,5), 25 )
testeq( lume.lambda "a, b -> a / b"(1, 2), .5 )
testeq( lume.lambda "a -> 'hi->' .. a"("doggy"), "hi->doggy" )
testeq( lume.lambda "A1,_->A1.._"("te","st"), "test" )
testeq( lume.lambda "->"(1,2,3), nil )
tester.test.error( lume.lambda, "abc" )
tester.test.error( lume.lambda, "" )
tester.test.error( lume.lambda, "a,b->a->b" )
tester.test.error( lume.lambda, "(a),b->a+b" )
end
-- lume.serialize / lume.deserialize
tests["lume.serialize, lume.deserialize"] = function()
local t = { 1, 2, 3, 4, true, false, "cat", "dog", {1, 2, 3} }
local s = lume.serialize(t)
testeq( lume.deserialize(s), t )
testeq( lume.deserialize(lume.serialize(math.huge)), math.huge )
testeq( lume.deserialize(lume.serialize(-math.huge)), -math.huge )
local x = lume.deserialize(lume.serialize(0 / 0)) -- nan
testeq( x ~= x, true )
end
-- lume.split
tests["lume.split"] = function()
testeq( lume.split("cat dog pig"), {"cat", "dog", "pig"} )
testeq( lume.split("cat,dog,pig", ","), {"cat", "dog", "pig"} )
testeq( lume.split("cat,dog;pig", ";"), {"cat,dog", "pig"} )
testeq( lume.split("cat,dog,,pig", ","), {"cat", "dog", "", "pig"} )
testeq( lume.split(";;;cat;", ";"), {"", "", "", "cat", ""} )
testeq( lume.split("cat.dog", "."), {"cat", "dog"} )
testeq( lume.split("cat%dog", "%"), {"cat", "dog"} )
testeq( lume.split("1<>2<>3", "<>"), {"1", "2", "3"} )
tester.test.error( lume.split, "abc", "" )
end
-- lume.trim
tests["lume.trim"] = function()
testeq( lume.trim(" hello world "), "hello world" )
testeq( lume.trim("-=-hello-world===", "-="), "hello-world" )
testeq( lume.trim("***hello world*-*", "*"), "hello world*-" )
testeq( lume.trim("...hello world.", "."), "hello world" )
testeq( lume.trim("^.hello world]^", "^.]"), "hello world" )
end
-- lume.wordwrap
tests["lume.wordwrap"] = function()
local str = "A small string with some words and then some more words"
local b = "A small string with \nsome words and then \nsome more words"
local fn = function(str) return #str >= 20 end
testeq( lume.wordwrap(str), str )
testeq( lume.wordwrap(str, 20), b )
testeq( lume.wordwrap(str, fn), b )
end
-- lume.format
tests["lume.format"] = function()
local str = lume.format("a {a} in a {b}", {a = "mouse", b = "house"})
testeq( str, "a mouse in a house" )
testeq( lume.format("number {num}", {num = 13}), "number 13" )
testeq( lume.format("{missing} {keys}", {}), "{missing} {keys}" )
testeq( lume.format("A {missing} table"), "A {missing} table" )
testeq( lume.format("{1} idx {2}", {"an", "test"}), "an idx test" )
testeq( lume.format("bad idx {-1}", {"x"}), "bad idx {-1}" )
testeq( lume.format("empty {}", {"idx"}), "empty {}" )
end
-- lume.trace
tests["lume.trace"] = function()
local oldprint = print
local file, line, msg
print = function(x)
file, line, msg = x:match("(.-):(.-): (.*)")
end
lume.trace("Hi world", 123.456, 1, nil)
print = oldprint
testeq( file:match(".lua$"), ".lua" )
testeq( tonumber(line) ~= nil, true )
testeq( msg, "Hi world 123.46 1 nil" )
end
-- lume.dostring
tests["lume.dostring"] = function()
testeq( lume.dostring([[return "hello!"]]), "hello!" )
testeq( lume.dostring([[return 12345]]), 12345 )
end
-- lume.uuid
tests["lume.uuid"] = function()
testeq( type(lume.uuid()), "string" )
testeq( #lume.uuid(), 36 )
end
-- lume.hotswap
tests["lume.hotswap"] = function()
local ok, err = lume.hotswap("bad_module_name")
testeq( ok, nil )
testeq( type(err), "string" )
end
-- lume.ripairs
tests["lume.ripairs"] = function()
local t = { "a", "b", false, "c" }
local r = {}
for i, v in lume.ripairs(t) do
table.insert(r, { i, v })
end
testeq( r, { { 4, "c" }, { 3, false }, { 2, "b" }, { 1, "a" } })
tester.test.error(lume.ripairs, nil)
end
-- lume.color
tests["lume.color"] = function()
testeq({ lume.color("#ff0000") }, { 1, 0, 0, 1 } )
testeq({ lume.color("#00ff00") }, { 0, 1, 0, 1 } )
testeq({ lume.color("#0000ff") }, { 0, 0, 1, 1 } )
testeq({ lume.color("rgb( 255, 255, 255 )") }, { 1, 1, 1, 1 } )
testeq({ lume.color("rgb (0, 0, 0)") }, { 0, 0, 0, 1 } )
testeq({ lume.color("rgba(255, 255, 255, .5)") }, { 1, 1, 1, .5 } )
testeq({ lume.color("#ffffff", 2) }, { 2, 2, 2, 2 } )
testeq({ lume.color("rgba(255, 255, 255, 1)", 3) }, { 3, 3, 3, 3 } )
tester.test.error(lume.color, "#ff00f")
tester.test.error(lume.color, "#xyzxyz")
tester.test.error(lume.color, "rgba(hello)")
tester.test.error(lume.color, "rgba()")
tester.test.error(lume.color, "rgba(1, 1, 1, 1")
end
-- lume.chain
tests["lume.chain"] = function()
local t = lume.chain({1, 2}):map(function(x) return x * 2 end):result()
testeq( t, { 2, 4 } )
testeq( lume.chain(10):result(), 10 )
local t = lume({1, 2}):map(function(x) return x * 2 end):result()
testeq( t, { 2, 4 } )
end
tester.dotests(tests)
tester.test.global()
tester.printresults()

View File

@@ -1,300 +0,0 @@
local tester = require "tester"
package.path = "../?.lua;" .. package.path
local lume = require "lume"
local tests = {}
local testeq = tester.test.equal
-- lume.clamp
tests["lume.clamp"] = function()
testeq( lume.clamp(8, 5, 10), 8 )
testeq( lume.clamp(12, 5, 10), 10 )
testeq( lume.clamp(-1, 5, 10), 5 )
testeq( lume.clamp(-1, -10, 10), -1 )
testeq( lume.clamp(-100, -10, 10), -10 )
testeq( lume.clamp(13, 8, 8), 8 )
testeq( lume.clamp(3, 8, 8), 8 )
end
-- lume.round
tests["lume.round"] = function()
testeq( lume.round(.5), 1 )
testeq( lume.round(-.5), -1 )
testeq( lume.round(2.4), 2 )
testeq( lume.round(123, 10), 120 )
testeq( lume.round(129, 64), 128 )
testeq( lume.round(-123.45, .1), -123.5 )
testeq( lume.round(0), 0 )
end
-- lume.sign
tests["lume.sign"] = function()
testeq( lume.sign(-10), -1 )
testeq( lume.sign(10), 1 )
testeq( lume.sign(0), 1 )
end
-- lume.lerp
tests["lume.lerp"] = function()
testeq( lume.lerp(100, 200, .5), 150 )
testeq( lume.lerp(100, 200, .25), 125 )
testeq( lume.lerp(100, 200, 2), 200 )
testeq( lume.lerp(100, 200, -2), 100 )
end
-- lume.smooth
tests["lume.smooth"] = function()
testeq( lume.smooth(100, 200, .5), 150 )
testeq( lume.smooth(100, 200, 0), 100 )
testeq( lume.smooth(100, 200, 1), 200 )
testeq( lume.smooth(100, 200, 2), 200 )
testeq( lume.smooth(100, 200, -2), 100 )
end
-- lume.pingpong
tests["lume.pingpong"] = function()
testeq( lume.pingpong(0), 0 )
testeq( lume.pingpong(1.5), .5 )
testeq( lume.pingpong(-.2), .2 )
testeq( lume.pingpong(-1.6), .4 )
testeq( lume.pingpong(1.8), .2 )
end
-- lume.distance
tests["lume.distance"] = function()
testeq( lume.distance(15, 20, 15, 20), 0 )
testeq( lume.distance(13, 44, 156, 232), 236.205419074 )
testeq( lume.distance(-23, 66, -232, 123), 216.633330769 )
local x = lume.distance(13, 15, -2, 81)
testeq( lume.distance(13, 15, -2, 81, true), x * x )
end
-- lume.angle
tests["lume.angle"] = function()
testeq( lume.angle(10, 10, 10, 10), math.rad(0) )
testeq( lume.angle(10, 10, 20, 10), math.rad(0) )
testeq( lume.angle(10, 10, 5, 10), math.rad(180) )
testeq( lume.angle(10, 10, 20, 20), math.rad(45) )
testeq( lume.angle(10, 10, 10, 30), math.rad(90) )
end
-- lume.random
tests["lume.random"] = function()
end
-- lume.randomchoice
tests["lume.randomchoice"] = function()
local t = {}
for i = 0, 1000 do
t[lume.randomchoice({"a", "b", "c", "d"})] = true
end
testeq( t.a and t.b and t.c and t.d, true )
testeq( lume.randomchoice({true}), true )
end
-- lume.shuffle
tests["lume.shuffle"] = function()
local t = {1, 2, 3, 4, 5}
lume.shuffle(t)
table.sort(t)
testeq( t, {1, 2, 3, 4, 5} )
testeq( lume.shuffle({}), {} )
end
-- lume.array
tests["lume.array"] = function()
local t = lume.array(pairs({a=0, b=0, c=0}))
table.sort(t)
testeq( t, {"a", "b", "c"} )
testeq( lume.array(ipairs({0, 0, 0})), {1, 2, 3} )
end
-- lume.each
tests["lume.each"] = function()
local acc = 1
lume.each({1, 2, 3}, function(x) acc = acc + x end)
testeq( acc, 7 )
local acc = 1
local f = function(o, x) acc = acc + x end
local f2 = function() end
local t = {a = {f = f}, b = {f = f}, c = {f = f2}}
lume.each(t, "f", 10)
testeq( acc, 21 )
end
-- lume.map
tests["lume.map"] = function()
testeq( lume.map({1, 2, 3}, function(x) return x * 2 end), {2, 4, 6} )
testeq( lume.map({a=2,b=3}, function(x) return x * 2 end), {a=4,b=6} )
end
-- lume.all
tests["lume.all"] = function()
testeq( lume.all({true, true, false, true}), false )
testeq( lume.all({true, true, true, true}), true )
testeq( lume.all({2, 3, 4, 5}, function(x) return x % 2 == 0 end), false )
testeq( lume.all({2, 4, 6, 8}, function(x) return x % 2 == 0 end), true )
end
-- lume.any
tests["lume.any"] = function()
testeq( lume.any({true, true, false, true}), true )
testeq( lume.any({false, false, false}), false )
testeq( lume.any({2, 3, 4, 5}, function(x) return x % 2 == 0 end), true )
testeq( lume.any({1, 3, 5, 7}, function(x) return x % 2 == 0 end), false )
end
-- lume.reduce
tests["lume.reduce"] = function()
local concat = function(a, b) return a .. b end
testeq( lume.reduce({"cat", "dog"}, concat, ""), "catdog" )
testeq( lume.reduce({"cat", "dog"}, concat, "pig"), "pigcatdog" )
end
-- lume.set
tests["lume.set"] = function()
local t = lume.set({1, 2, 3, 2, 5, 6, 6})
table.sort(t)
testeq( t, {1, 2, 3, 5, 6} )
local t = lume.set({"a", "b", "c", "b", "d"})
table.sort(t)
testeq( t, {"a", "b", "c", "d"} )
end
-- lume.filter
tests["lume.filter"] = function()
local t = lume.filter({1, 2, 3, 4, 5}, function(x) return x % 2 == 0 end )
testeq( t, {2, 4} )
local t = lume.filter({a=1, b=2, c=3}, function(x) return x == 2 end, true)
testeq( t, {b=2} )
end
-- lume.merge
tests["lume.merge"] = function()
testeq( lume.merge({1, 2, 3}, {8, 9, 0}), {1, 2, 3, 8, 9, 0} )
testeq( lume.merge({a=1, b=2}, {b=3, c=4}, true), {a=1, b=3, c=4} )
end
-- lume.find
tests["lume.find"] = function()
testeq( lume.find({"a", "b", "c"}, "b"), 2 )
testeq( lume.find({"a", "b", "c"}, "c"), 3 )
testeq( lume.find({a=1, b=5, c=7}, 5), "b" )
end
-- lume.slice
tests["lume.slice"] = function()
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 4), {"b", "c", "d"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, -2), {"b", "c", "d"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 3, -1), {"c", "d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 3), {"c", "d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 4), {"d", "e"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 1, 1), {"a"} )
testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 1), {} )
end
-- lume.clone
tests["lume.clone"] = function()
local t = {6, 7, 4, 5}
testeq( lume.clone(t) ~= t, true )
testeq( lume.clone(t), {6, 7, 4, 5} )
testeq( lume.clone({x=2, y="a"}), {x=2, y="a"} )
end
-- lume.fn
tests["lume.fn"] = function()
local f = lume.fn(function(a, b) return a + b end, 10)
testeq( f(5), 15 )
end
-- lume.once
tests["lume.once"] = function()
local f = lume.once(function(a, b) return a + b end, 10)
testeq( f(5), 15 )
testeq( f(5), nil )
end
-- lume.time
tests["lume.time"] = function()
local t, a, b, c = lume.time(function(x) return 50, 60, x end, 70)
testeq( type(t), "number" )
testeq( {a, b, c}, {50, 60, 70} )
end
-- lume.serialize / lume.deserialize
tests["lume.serialize, lume.deserialize"] = function()
local t = { 1, 2, 3, 4, true, false, "cat", "dog", {1, 2, 3} }
local s = lume.serialize(t)
testeq( lume.deserialize(s), t )
end
-- lume.split
tests["lume.split"] = function()
testeq( lume.split("cat dog pig"), {"cat", "dog", "pig"} )
testeq( lume.split(",cat,dog,pig", ","), {"cat", "dog", "pig"} )
testeq( lume.split(",cat,dog;pig", ",;"), {"cat", "dog", "pig"} )
end
-- lume.trim
tests["lume.trim"] = function()
testeq( lume.trim(" hello world "), "hello world" )
testeq( lume.trim("-=-hello-world===", "-="), "hello-world" )
testeq( lume.trim("***hello world*-*", "*"), "hello world*-" )
end
-- lume.format
tests["lume.format"] = function()
local str = lume.format("a {a} in a {b}", {a = "mouse", b = "house"})
testeq( str, "a mouse in a house" )
testeq( lume.format("number {num}", {num = 13}), "number 13" )
testeq( lume.format("{missing} {keys}", {}), "{missing} {keys}" )
testeq( lume.format("A {missing} table"), "A {missing} table" )
testeq( lume.format("{1} idx {2}", {"an", "test"}), "an idx test" )
testeq( lume.format("bad idx {-1}", {"x"}), "bad idx {-1}" )
testeq( lume.format("empty {}", {"idx"}), "empty {}" )
end
-- lume.trace
tests["lume.trace"] = function()
local oldprint = print
local file, line, msg
print = function(x)
file, line, msg = x:match("%[(.-):(.-)%] (.*)")
end
lume.trace("Hi world")
print = oldprint
testeq( file:match(".lua$"), ".lua" )
testeq( tonumber(line) ~= nil, true )
testeq( msg, "Hi world" )
end
-- lume.dostring
tests["lume.dostring"] = function()
testeq( lume.dostring([[return "hello!"]]), "hello!" )
testeq( lume.dostring([[return 12345]]), 12345 )
end
-- lume.hotswap
tests["lume.hotswap"] = function()
local ok, err = lume.hotswap("bad_module_name")
testeq( ok, nil )
testeq( type(err), "string" )
end
-- lume.rgba
tests["lume.rgba"] = function()
local r, g, b, a = lume.rgba(0x12345678)
testeq( a, 0x12 )
testeq( r, 0x34 )
testeq( g, 0x56 )
testeq( b, 0x78 )
end
tester.dotests(tests)
tester.test.global()
tester.printresults()

View File

@@ -128,6 +128,18 @@ function tester.test.equal(result, expected)
end end
function tester.test.error(fn, ...)
local passed = not pcall(fn, ...)
local info = debug.getinfo(2)
if passed then
dopass(info.short_src, info.currentline)
else
dofail(info.short_src, info.currentline)
printfailmsg("Expected an error to be raised")
end
end
function tester.dotests(t) function tester.dotests(t)
local keys = {} local keys = {}
for k in pairs(t) do table.insert(keys, k) end for k in pairs(t) do table.insert(keys, k) end