From 31ccc7b52e427ebb95d62bfc13ebc562138763d5 Mon Sep 17 00:00:00 2001 From: haithium <128622475+haithium@users.noreply.github.com> Date: Mon, 2 Mar 2026 06:19:24 +0000 Subject: [PATCH] chore(docs): auto-generate docs --- docs/src/modules/is.md | 387 ++++++++++-- docs/src/modules/keyword.md | 83 ++- docs/src/modules/list.md | 1037 ++++++++++++++++++++++++++++---- docs/src/modules/operator.md | 398 ++++++++++-- docs/src/modules/repr.md | 40 +- docs/src/modules/runtime.md | 103 ++++ docs/src/modules/set.md | 614 ++++++++++++++++--- docs/src/modules/str.md | 918 +++++++++++++++++++++------- docs/src/modules/stringcase.md | 273 +++++++-- docs/src/modules/tbl.md | 327 ++++++++-- docs/src/modules/template.md | 116 ++-- docs/src/modules/utils.md | 28 +- docs/src/modules/validate.md | 773 +++++++++++++----------- 13 files changed, 4092 insertions(+), 1005 deletions(-) create mode 100644 docs/src/modules/runtime.md diff --git a/docs/src/modules/is.md b/docs/src/modules/is.md index 5e5f8ea..2ce5488 100644 --- a/docs/src/modules/is.md +++ b/docs/src/modules/is.md @@ -18,178 +18,344 @@ ok = is.table({}) --> true > [!NOTE] > -> Function names exist in both lowercase and capitalized forms, and `is` is also -> callable as `is(v, tp)`. +> Function names are case-insensitive. > > ```lua -> is.table({}) --> true -> is.Table({}) --> true -> is("hello", "string") --> true -> is("hello", "String") --> true +> is.table({}) --> true +> is.Table({}) --> true +> is.tAbLe({}) --> true > ``` -## Dependencies +## `is()` -Dependencies below are lazy-loaded 💤 on first access. +`is` is also callable as `is(value, type)` to check if a value is of a given +type. -- [`lfs`](https://github.com/lunarmodules/luafilesystem) (optional; required - only for filesystem/path checks) +```lua +is("hello", "string") --> true +is("hello", "String") --> true +is("hello", "STRING") --> true +``` ## Functions **Type Checks**: -| Function | Description | -| ----------------------- | -------------------------------------- | -| [`boolean`](#boolean) | Returns `true` when `v` is a boolean. | -| [`Function`](#function) | Returns `true` when `v` is a function. | -| [`Nil`](#nil) | Returns `true` when `v` is `nil`. | -| [`number`](#number) | Returns `true` when `v` is a number. | -| [`string`](#string) | Returns `true` when `v` is a string. | -| [`table`](#table) | Returns `true` when `v` is a table. | -| [`thread`](#thread) | Returns `true` when `v` is a thread. | -| [`userdata`](#userdata) | Returns `true` when `v` is userdata. | +| Function | Description | +| ----------------------------- | -------------------------------------- | +| [`boolean(v)`](#fn-boolean) | Returns `true` when `v` is a boolean. | +| [`function(v)`](#fn-function) | Returns `true` when `v` is a function. | +| [`nil(v)`](#fn-nil) | Returns `true` when `v` is `nil`. | +| [`number(v)`](#fn-number) | Returns `true` when `v` is a number. | +| [`string(v)`](#fn-string) | Returns `true` when `v` is a string. | +| [`table(v)`](#fn-table) | Returns `true` when `v` is a table. | +| [`thread(v)`](#fn-thread) | Returns `true` when `v` is a thread. | +| [`userdata(v)`](#fn-userdata) | Returns `true` when `v` is userdata. | **Value Checks**: -| Function | Description | -| ----------------------- | ------------------------------------------- | -| [`False`](#false) | Returns `true` when `v` is exactly `false`. | -| [`True`](#true) | Returns `true` when `v` is exactly `true`. | -| [`falsy`](#falsy) | Returns `true` when `v` is falsy. | -| [`callable`](#callable) | Returns `true` when `v` is callable. | -| [`integer`](#integer) | Returns `true` when `v` is an integer. | -| [`truthy`](#truthy) | Returns `true` when `v` is truthy. | +| Function | Description | +| ----------------------------- | ------------------------------------------- | +| [`false(v)`](#fn-false) | Returns `true` when `v` is exactly `false`. | +| [`true(v)`](#fn-true) | Returns `true` when `v` is exactly `true`. | +| [`falsy(v)`](#fn-falsy) | Returns `true` when `v` is falsy. | +| [`callable(v)`](#fn-callable) | Returns `true` when `v` is callable. | +| [`integer(v)`](#fn-integer) | Returns `true` when `v` is an integer. | +| [`truthy(v)`](#fn-truthy) | Returns `true` when `v` is truthy. | **Path Checks**: -| Function | Description | -| ------------------- | ------------------------------------------------------- | -| [`block`](#block) | Returns `true` when `v` is a block device path. | -| [`char`](#char) | Returns `true` when `v` is a char device path. | -| [`device`](#device) | Returns `true` when `v` is a block or char device path. | -| [`dir`](#dir) | Returns `true` when `v` is a directory path. | -| [`fifo`](#fifo) | Returns `true` when `v` is a FIFO path. | -| [`file`](#file) | Returns `true` when `v` is a file path. | -| [`link`](#link) | Returns `true` when `v` is a symlink path. | -| [`socket`](#socket) | Returns `true` when `v` is a socket path. | +| Function | Description | +| ------------------------- | ------------------------------------------------------- | +| [`block(v)`](#fn-block) | Returns `true` when `v` is a block device path. | +| [`char(v)`](#fn-char) | Returns `true` when `v` is a char device path. | +| [`device(v)`](#fn-device) | Returns `true` when `v` is a block or char device path. | +| [`dir(v)`](#fn-dir) | Returns `true` when `v` is a directory path. | +| [`fifo(v)`](#fn-fifo) | Returns `true` when `v` is a FIFO path. | +| [`file(v)`](#fn-file) | Returns `true` when `v` is a file path. | +| [`link(v)`](#fn-link) | Returns `true` when `v` is a symlink path. | +| [`socket(v)`](#fn-socket) | Returns `true` when `v` is a socket path. | ### Type Checks -Core Lua type checks (`type(v)` family). +Core Lua type checks (`type(v)` family). -#### `boolean` +#### `boolean(v)` Returns `true` when `v` is a boolean. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.boolean(true) ``` -#### `Function` + + +#### `function(v)` Returns `true` when `v` is a function. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.Function(function() end) ``` -#### `Nil` + + +#### `nil(v)` Returns `true` when `v` is `nil`. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.Nil(nil) ``` -#### `number` + + +#### `number(v)` Returns `true` when `v` is a number. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.number(3.14) ``` -#### `string` + + +#### `string(v)` Returns `true` when `v` is a string. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.string("hello") ``` -#### `table` + + +#### `table(v)` Returns `true` when `v` is a table. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.table({}) ``` -#### `thread` + + +#### `thread(v)` Returns `true` when `v` is a thread. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.thread(coroutine.create(function() end)) ``` -#### `userdata` + + +#### `userdata(v)` Returns `true` when `v` is userdata. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.userdata(io.stdout) ``` ### Value Checks -Truthiness, exact-value, and callable checks. +Truthiness, exact-value, and callable checks. -#### `False` +#### `false(v)` Returns `true` when `v` is exactly `false`. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.False(false) ``` -#### `True` + + +#### `true(v)` Returns `true` when `v` is exactly `true`. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.True(true) ``` -#### `falsy` + + +#### `falsy(v)` Returns `true` when `v` is falsy. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.falsy(false) ``` -#### `callable` + + +#### `callable(v)` Returns `true` when `v` is callable. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.callable(function() end) ``` -#### `integer` + + +#### `integer(v)` Returns `true` when `v` is an integer. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.integer(42) ``` -#### `truthy` + + +#### `truthy(v)` Returns `true` when `v` is truthy. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.truthy("non-empty") ``` @@ -202,71 +368,162 @@ Filesystem path kind checks. > > Path checks require **LuaFileSystem** > ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error it -> is not installed. +> is not installed. -#### `block` +#### `block(v)` Returns `true` when `v` is a block device path. -Raises an error if [`lfs`](https://github.com/lunarmodules/luafilesystem) is not -installed. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: ```lua is.block("/dev/sda") ``` -#### `char` + + +#### `char(v)` Returns `true` when `v` is a char device path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.char("/dev/null") ``` -#### `device` + + +#### `device(v)` Returns `true` when `v` is a block or char device path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.device("/dev/null") ``` -#### `dir` + + +#### `dir(v)` Returns `true` when `v` is a directory path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.dir("/tmp") ``` -#### `fifo` + + +#### `fifo(v)` Returns `true` when `v` is a FIFO path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.fifo("/path/to/fifo") ``` -#### `file` + + +#### `file(v)` Returns `true` when `v` is a file path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.file("README.md") ``` -#### `link` + + +#### `link(v)` Returns `true` when `v` is a symlink path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.link("/path/to/link") ``` -#### `socket` + + +#### `socket(v)` Returns `true` when `v` is a socket path. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: + ```lua is.socket("/path/to/socket") ``` diff --git a/docs/src/modules/keyword.md b/docs/src/modules/keyword.md index 5131e5c..600eab1 100644 --- a/docs/src/modules/keyword.md +++ b/docs/src/modules/keyword.md @@ -15,63 +15,108 @@ kw.iskeyword("local")) --> true kw.isidentifier("hello_world") --> true ``` -## Dependencies +## Functions -Dependencies below are lazy-loaded 💤 on first access. +| Function | Description | +| ----------------------------------------------------- | ----------------------------------------------------------------------------------- | +| [`iskeyword(v)`](#fn-iskeyword) | Return `true` when `v` is a reserved Lua keyword. | +| [`isidentifier(v)`](#fn-isidentifier) | Return `true` when `v` is a valid non-keyword Lua identifier. | +| [`kwlist()`](#fn-kwlist) | Return Lua keywords as a [`mods.List`](https://luamod.github.io/mods/modules/list). | +| [`kwset()`](#fn-kwset) | Return Lua keywords as a [`mods.Set`](https://luamod.github.io/mods/modules/set). | +| [`normalize_identifier(s)`](#fn-normalize-identifier) | Normalize an input into a safe Lua identifier. | -- [`mods.Set`](https://luamod.github.io/mods/modules/set) -- [`mods.List`](https://luamod.github.io/mods/modules/list) + -## Functions +### `iskeyword(v)` + +Return `true` when `v` is a reserved Lua keyword. + +**Parameters**: -| Function | Description | -| ----------------------------------------------- | ----------------------------------------------------------------------------------- | -| [`iskeyword`](#iskeyword) | Return `true` when `s` is a reserved Lua keyword. | -| [`isidentifier`](#isidentifier) | Return `true` when `s` is a valid non-keyword Lua identifier. | -| [`kwlist`](#kwlist) | Return Lua keywords as a [`mods.List`](https://luamod.github.io/mods/modules/list). | -| [`kwset`](#kwset) | Return Lua keywords as a [`mods.Set`](https://luamod.github.io/mods/modules/set). | -| [`normalize_identifier`](#normalize-identifier) | Normalize an input into a safe Lua identifier. | +- `v` (`any`): Value to validate. -### `iskeyword` +**Return**: -Return `true` when `s` is a reserved Lua keyword. +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: ```lua kw.iskeyword("function") --> true kw.iskeyword("hello") --> false ``` -### `isidentifier` + + +### `isidentifier(v)` + +Return `true` when `v` is a valid non-keyword Lua identifier. -Return `true` when `s` is a valid non-keyword Lua identifier. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. + +**Example**: ```lua kw.isidentifier("hello_world") --> true kw.isidentifier("local") --> false ``` -### `kwlist` + + +### `kwlist()` Return Lua keywords as a [`mods.List`](https://luamod.github.io/mods/modules/list). +**Return**: + +- `words` (`mods.List`): List of Lua keywords. + +**Example**: + ```lua kw.kwlist():contains("and") --> true ``` -### `kwset` + + +### `kwset()` Return Lua keywords as a [`mods.Set`](https://luamod.github.io/mods/modules/set). +**Return**: + +- `words` (`mods.Set`): Set of Lua keywords. + +**Example**: + ```lua kw.kwlset():contains("and") --> true ``` -### `normalize_identifier` + + +### `normalize_identifier(s)` Normalize an input into a safe Lua identifier. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ident` (`string`): Normalized Lua identifier. + +**Example**: + ```lua kw.normalize_identifier(" 2 bad-name ") --> "_2_bad_name" ``` diff --git a/docs/src/modules/list.md b/docs/src/modules/list.md index 54c68dc..0071d9c 100644 --- a/docs/src/modules/list.md +++ b/docs/src/modules/list.md @@ -1,13 +1,13 @@ --- desc: - "A Python-style list class providing common operations to create, modify, and - query sequences of values." + "A list class providing common operations to create, modify, and query + sequences of values." --- # `List` -A Python-style list class providing common operations to create, modify, and -query sequences of values. +A list class providing common operations to create, modify, and query sequences +of values. ## Usage @@ -16,93 +16,122 @@ List = require "mods.List" ls = List({ "a" }):append("b") print(ls:contains("b")) --> true -print(ls:index("b")) --> 2 +print(ls:index("b")) --> 2 ``` -## Dependencies - -Dependencies below are lazy-loaded 💤 on first access. - -- [`mods.Set`](https://luamod.github.io/mods/modules/set) +> [!NOTE] +> +> `List(t)` wraps `t` with the `List` metatable in place. It does not copy or +> filter table values. `List(t):copy()` or `List.copy(t)` both copy only `1..#t` +> and wrap `t` as a List. ## Functions **Predicates**: -| Function | Description | -| ------------- | ----------------------------------------------- | -| [`all`](#all) | Return true if all values match the predicate. | -| [`any`](#any) | Return true if any value matches the predicate. | +| Function | Description | +| -------------------------- | ------------------------------------------------- | +| [`all(pred)`](#fn-all) | Return true if all values match the predicate. | +| [`any(pred)`](#fn-any) | Return true if any value matches the predicate. | +| [`equals(ls)`](#fn-equals) | Compare two lists using shallow element equality. | +| [`lt(ls)`](#fn-lt) | Compare two lists lexicographically. | +| [`le(ls)`](#fn-le) | Compare two lists lexicographically. | **Mutation**: -| Function | Description | -| --------------------- | -------------------------------------------------------------------- | -| [`append`](#append) | Append a value to the end of the list. | -| [`clear`](#clear) | Remove all elements from the list. | -| [`extend`](#extend) | Extend the list with another list. | -| [`extract`](#extract) | Extract values matching the predicate and remove them from the list. | -| [`insert`](#insert) | Insert a value at the given position. | -| [`insert`](#insert) | Append a value to the end of the list. | -| [`pop`](#pop) | Remove and return the last element. | -| [`pop`](#pop) | Remove and return the element at the given position. | -| [`prepend`](#prepend) | Insert a value at the start of the list. | -| [`remove`](#remove) | Remove the first matching value. | -| [`sort`](#sort) | Sort the list in place. | +| Function | Description | +| ------------------------------ | -------------------------------------------------------------------- | +| [`append()`](#fn-append) | Append a value to the end of the list. | +| [`clear()`](#fn-clear) | Remove all elements from the list. | +| [`extend(ls)`](#fn-extend) | Extend the list with another list. | +| [`extract(pred)`](#fn-extract) | Extract values matching the predicate and remove them from the list. | +| [`insert(pos, v)`](#fn-insert) | Insert a value at the given position. | +| [`insert(v)`](#fn-insert) | Append a value to the end of the list. | +| [`pop()`](#fn-pop) | Remove and return the last element. | +| [`pop(pos)`](#fn-pop) | Remove and return the element at the given position. | +| [`prepend(v)`](#fn-prepend) | Insert a value at the start of the list. | +| [`remove(v)`](#fn-remove) | Remove the first matching value. | +| [`sort(comp?)`](#fn-sort) | Sort the list in place. | **Copying**: -| Function | Description | -| --------------- | ---------------------------------- | -| [`copy`](#copy) | Return a shallow copy of the list. | +| Function | Description | +| -------------------- | ---------------------------------- | +| [`copy()`](#fn-copy) | Return a shallow copy of the list. | **Query**: -| Function | Description | -| ----------------------- | ----------------------------------------------------------- | -| [`contains`](#contains) | Return true if the list contains the value. | -| [`count`](#count) | Count how many times a value appears. | -| [`index`](#index) | Return the index of the first matching value. | -| [`index_if`](#index-if) | Return the index of the first value matching the predicate. | -| [`len`](#len) | Return the number of elements in the list. | +| Function | Description | +| -------------------------------- | ----------------------------------------------------------- | +| [`contains(v)`](#fn-contains) | Return true if the list contains the value. | +| [`count(v)`](#fn-count) | Count how many times a value appears. | +| [`index(v)`](#fn-index) | Return the index of the first matching value. | +| [`index_if(pred)`](#fn-index-if) | Return the index of the first value matching the predicate. | +| [`len()`](#fn-len) | Return the number of elements in the list. | **Access**: -| Function | Description | -| ----------------- | ------------------------------------------- | -| [`first`](#first) | Return the first element or `nil` if empty. | -| [`last`](#last) | Return the last element or `nil` if empty. | +| Function | Description | +| ---------------------- | ------------------------------------------- | +| [`first()`](#fn-first) | Return the first element or `nil` if empty. | +| [`last()`](#fn-last) | Return the last element or `nil` if empty. | **Transform**: -| Function | Description | -| ------------------------------- | ------------------------------------------------------------------ | -| [`difference`](#difference) | Return a new list with values not in the given list. | -| [`drop`](#drop) | Return a new list without the first n elements. | -| [`filter`](#filter) | Return a new list with values matching the predicate. | -| [`flatten`](#flatten) | Flatten one level of nested lists. | -| [`foreach`](#foreach) | Apply a function to each element (for side effects). | -| [`group_by`](#group-by) | Group list values by a computed key. | -| [`intersection`](#intersection) | Return values that are also present in the given list. | -| [`invert`](#invert) | Invert values to indices in a new table. | -| [`join`](#join) | Join list values into a string. | -| [`map`](#map) | Return a new list by mapping each value. | -| [`reduce`](#reduce) | Reduce the list to a single value using an accumulator. | -| [`reverse`](#reverse) | Return a new list with items reversed. | -| [`toset`](#toset) | Convert the list to a set. | -| [`slice`](#slice) | Return a new list containing items from i to j (inclusive). | -| [`take`](#take) | Return the first n elements as a new list. | -| [`uniq`](#uniq) | Return a new list with duplicates removed (first occurrence kept). | -| [`zip`](#zip) | Zip two lists into a list of 2-element tables. | +| Function | Description | +| -------------------------------------- | -------------------------------------------------------------------- | +| [`difference(ls)`](#fn-difference) | Return a new list with values not in the given list. | +| [`drop(n)`](#fn-drop) | Return a new list without the first n elements. | +| [`filter(pred)`](#fn-filter) | Return a new list with values matching the predicate. | +| [`flatten()`](#fn-flatten) | Flatten one level of nested lists. | +| [`foreach(fn)`](#fn-foreach) | Apply a function to each element (for side effects). | +| [`group_by(fn)`](#fn-group-by) | Group list values by a computed key. | +| [`intersection(ls)`](#fn-intersection) | Return values that are also present in the given list. | +| [`invert()`](#fn-invert) | Invert values to indices in a new table. | +| [`concat(sep?, i?, j?)`](#fn-concat) | Concatenate list values using Lua's native `table.concat` behavior. | +| [`join(sep?, quoted?)`](#fn-join) | Join list values into a string. | +| [`tostring()`](#fn-tostring) | Render the list to a string via the regular method form. | +| [`keypath()`](#fn-keypath) | Render list items as a table-access key path. | +| [`map(fn)`](#fn-map) | Return a new list by mapping each value. | +| [`mul(n)`](#fn-mul) | Return a new list repeated `n` times (list multiplication behavior). | +| [`reduce(fn, init?)`](#fn-reduce) | Reduce the list to a single value using an accumulator. | +| [`reverse()`](#fn-reverse) | Return a new list with items reversed. | +| [`toset()`](#fn-toset) | Convert the list to a set. | +| [`slice(i?, j?)`](#fn-slice) | Return a new list containing items from i to j (inclusive). | +| [`take(n)`](#fn-take) | Return the first n elements as a new list. | +| [`uniq()`](#fn-uniq) | Return a new list with duplicates removed (first occurrence kept). | +| [`zip(ls)`](#fn-zip) | Zip two lists into a list of 2-element tables. | + +**Metamethods**: + +| Function | Description | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------- | +| [`__eq(ls)`](#fn-eq) | Compare two lists using shallow element equality (`==`). | +| [`__lt(ls)`](#fn-lt) | Compare two lists lexicographically (`<`). | +| [`__le(ls)`](#fn-le) | Compare two lists lexicographically (`<=`). | +| [`__mul(n)`](#fn-mul) | Repeat a list `n` times (`*`). | +| [`__add(ls)`](#fn-add) | Extend the left-hand list in place with right-hand values, then return the same left-hand list reference (`+`). | +| [`__sub(ls)`](#fn-sub) | Return values from the left list that are not present in the right list (`-`). | +| [`__tostring()`](#fn-tostring) | Render the list to a string like `{ "a", "b", 1 }`. | ### Predicates -Boolean checks for list-wide conditions. +Boolean checks for list-wide conditions. -#### `all` +#### `all(pred)` Return true if all values match the predicate. +**Parameters**: + +- `pred` (`fun(v:any):boolean`): Predicate function. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + ```lua is_even = function(v) return v % 2 == 0 end ok = List({ 2, 4 }):all(is_even) --> true @@ -112,109 +141,346 @@ ok = List({ 2, 4 }):all(is_even) --> true > > Empty lists return `true`. -#### `any` + + +#### `any(pred)` Return true if any value matches the predicate. +**Parameters**: + +- `pred` (`fun(v:any):boolean`): Predicate function. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + ```lua has_len_2 = function(v) return #v == 2 end ok = List({ "a", "bb" }):any(has_len_2) --> true ``` + + +#### `equals(ls)` + +Compare two lists using shallow element equality. + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +a = List({ "x", "y" }) +b = List({ "x", "y" }) +ok = a:equals(b) --> true +``` + +> [!NOTE] +> +> - `equals` is also available through the `==` operator when both operands are +> `List`. +> +> ```lua +> a = List({ "a", 1 }) +> b = List({ "a", 1 }) +> ok = (a == b) --> true +> ``` +> +> - Unlike `==`, this method also works when `ls` is a plain array table. +> +> ```lua +> a = List({ "a", 1 }) +> b = { "a", 1 } +> ok = a:equals(b) --> true +> ``` +> +> - `equals` checks only array positions (`1..#list`), so extra non-array keys +> are ignored: +> +> ```lua +> t = {} +> a = List({ "a", t }) +> b = { "a", t, a = 1 } +> ok = a:equals(b) --> true +> ``` + + + +#### `lt(ls)` + +Compare two lists lexicographically. + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +ok = List({ 1, 2 }):lt({ 1, 3 }) --> true +ok = List({ 1, 2 }):lt({ 1, 2, 0 }) --> true +``` + +> [!NOTE] +> +> `lt` is also available through the `<` operator. + + + +#### `le(ls)` + +Compare two lists lexicographically. + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +ok = List({ 1, 2 }):le({ 1, 2 }) --> true +ok = List({ 1, 2 }):le({ 1, 1 }) --> false +``` + +> [!NOTE] +> +> `le` is also available through the `<=` operator. + ### Mutation -In-place operations that modify the current list. +In-place operations that modify the current list. -#### `append` +#### `append()` Append a value to the end of the list. +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "a" }):append("b") --> { "a", "b" } ``` -#### `clear` + + +#### `clear()` Remove all elements from the list. +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "a", "b" }):clear() --> { } ``` -#### `extend` + + +#### `extend(ls)` Extend the list with another list. +**Parameters**: + +- `ls` (`any[]`): List values. + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "a" }):extend({ "b", "c" }) --> { "a", "b", "c" } ``` -#### `extract` +> [!NOTE] +> +> `extend` is also available through the `+` operator. + + + +#### `extract(pred)` Extract values matching the predicate and remove them from the list. +**Parameters**: + +- `pred` (`fun(v:any):boolean`): Predicate function. + +**Return**: + +- `ls` (`mods.List`): Extracted values. + +**Example**: + ```lua ls = List({ "a", "bb", "c" }) is_len_1 = function(v) return #v == 1 end ex = ls:extract(is_len_1) --> ex = { "a", "c" }, ls = { "bb" } ``` -#### `insert` + + +#### `insert(pos, v)` Insert a value at the given position. +**Parameters**: + +- `pos` (`integer`): Insert position. +- `v` (`any`): Value to insert. + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "a", "c" }):insert(2, "b") --> { "a", "b", "c" } ``` -#### `insert` + + +#### `insert(v)` Append a value to the end of the list. +**Parameters**: + +- `v` (`any`): Value to append. + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua -ls = List({ "a", "b" }):insert("b") --> { "a", "b", "c" } +ls = List({ "a", "b" }):insert("c") --> { "a", "b", "c" } ``` -#### `pop` + + +#### `pop()` Remove and return the last element. +**Return**: + +- `value` (`any`): Removed value. + +**Example**: + ```lua ls = List({ "a", "b" }) v = ls:pop() --> v == "b"; ls is { "a" } ``` -#### `pop` + + +#### `pop(pos)` Remove and return the element at the given position. +**Parameters**: + +- `pos` (`integer`): Numeric value. + +**Return**: + +- `value` (`any`): Removed value. + +**Example**: + ```lua ls = List({ "a", "b", "c" }) v = ls:pop(2) --> v == "b"; ls is { "a", "c" } ``` -#### `prepend` + + +#### `prepend(v)` Insert a value at the start of the list. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "b", "c" }) ls:prepend("a") --> { "a", "b", "c" } ``` -#### `remove` + + +#### `remove(v)` Remove the first matching value. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ "a", "b", "b" }) ls:remove("b") --> { "a", "b" } ``` -#### `sort` + + +#### `sort(comp?)` Sort the list in place. +**Parameters**: + +- `comp?` (`fun(a,b):boolean`): Optional comparison function (defaults to + `nil`). + +**Return**: + +- `self` (`T`): Current list instance. + +**Example**: + ```lua ls = List({ 3, 1, 2 }) ls:sort() --> { 1, 2, 3 } @@ -222,82 +488,155 @@ ls:sort() --> { 1, 2, 3 } ### Copying -Operations that return copied list data. +Operations that return copied list data. -#### `copy` +#### `copy()` Return a shallow copy of the list. +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua c = List({ "a", "b" }):copy() --> { "a", "b" } ``` ### Query -Read-only queries for membership, counts, and indices. +Read-only queries for membership, counts, and indices. -#### `contains` +#### `contains(v)` Return true if the list contains the value. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + ```lua ok = List({ "a", "b" }):contains("b") --> true ``` -#### `count` + + +#### `count(v)` Count how many times a value appears. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `res` (`integer`): Result count. + +**Example**: + ```lua n = List({ "a", "b", "b" }):count("b") --> 2 ``` -#### `index` + + +#### `index(v)` Return the index of the first matching value. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `index` (`integer?`): Result index, or nil when not found. + +**Example**: + ```lua i = List({ "a", "b", "c", "b" }):index("b") --> 2 ``` -#### `index_if` + + +#### `index_if(pred)` Return the index of the first value matching the predicate. +**Parameters**: + +- `pred` (`fun(v:any):boolean`): Predicate function. + +**Return**: + +- `index` (`integer?`): Result index, or nil when no value matches. + +**Example**: + ```lua gt_1 = function(x) return x > 1 end i = List({ 1, 2, 3 }):index_if(gt_1) --> 2 ``` -#### `len` + + +#### `len()` Return the number of elements in the list. +**Return**: + +- `count` (`integer`): Element count. + +**Example**: + ```lua n = List({ "a", "b", "c" }):len() --> 3 ``` > [!NOTE] > -> Uses Lua's `#` operator, so length is reliable for contiguous array-like -> lists. +> Uses Lua's `#` operator. ### Access -Direct element access helpers. +Direct element access helpers. -#### `first` +#### `first()` Return the first element or `nil` if empty. +**Return**: + +- `value` (`any`): First value, or `nil` if empty. + +**Example**: + ```lua v = List({ "a", "b" }):first() --> "a" ``` -#### `last` + + +#### `last()` Return the last element or `nil` if empty. +**Return**: + +- `value` (`any`): Last value, or `nil` if empty. + +**Example**: + ```lua v = List({ "a", "b" }):last() --> "b" ``` @@ -305,63 +644,146 @@ v = List({ "a", "b" }):last() --> "b" ### Transform Non-mutating transformations and derived-list operations. + -#### `difference` +#### `difference(ls)` Return a new list with values not in the given list. +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ls` (`T`): New list. + +**Example**: + ```lua d = List({ "a", "b", "c" }):difference({ "b" }) --> { "a", "c" } ``` -#### `drop` +> [!NOTE] +> +> `difference` is also available through the `-` operator. + + + +#### `drop(n)` Return a new list without the first n elements. +**Parameters**: + +- `n` (`integer`): Numeric value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua t = List({ "a", "b", "c" }):drop(1) --> { "b", "c" } ``` -#### `filter` + + +#### `filter(pred)` Return a new list with values matching the predicate. +**Parameters**: + +- `pred` (`fun(v:any):boolean`): Predicate function. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua is_len_1 = function(v) return #v == 1 end f = List({ "a", "bb", "c" }):filter(is_len_1) --> { "a", "c" } ``` -#### `flatten` + + +#### `flatten()` Flatten one level of nested lists. +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua f = List({ { "a", "b" }, { "c" } }):flatten() --> { "a", "b", "c" } ``` -#### `foreach` + + +#### `foreach(fn)` Apply a function to each element (for side effects). +**Parameters**: + +- `fn` (`fun(v:any)`): Callback function. + +**Return**: + +- `none` (`nil`) + +**Example**: + ```lua List({ "a", "b" }):foreach(print) --> prints -> a --> prints -> b ``` -#### `group_by` + + +#### `group_by(fn)` Group list values by a computed key. +**Parameters**: + +- `fn` (`fun(v:any):any`): Callback function. + +**Return**: + +- `groups` (`table`): Groups keyed by the callback result. + +**Example**: + ```lua words = { "aa", "b", "ccc", "dd" } g = List(words):group_by(string.len) --> { {"b"}, { "aa", "dd" }, { "ccc" } } ``` -#### `intersection` + + +#### `intersection(ls)` Return values that are also present in the given list. +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua i = List({ "a", "b", "a", "c" }):intersection({ "a", "c" }) --> { "a", "a", "c" } @@ -371,35 +793,175 @@ i = List({ "a", "b", "a", "c" }):intersection({ "a", "c" }) > > Order is preserved from the original list. -#### `invert` + + +#### `invert()` Invert values to indices in a new table. +**Return**: + +- `idxByValue` (`table`): Table mapping each value to its last index. + +**Example**: + ```lua t = List({ "a", "b", "c" }):invert() --> { a = 1, b = 2, c = 3 } ``` -#### `join` + + +#### `concat(sep?, i?, j?)` + +Concatenate list values using Lua's native `table.concat` behavior. + +**Parameters**: + +- `sep?` (`string`): Optional separator value (defaults to `""`). +- `i?` (`integer`): Optional start index (defaults to `1`). +- `j?` (`integer`): Optional end index (defaults to `#self`). + +**Return**: + +- `s` (`string`): Concatenated string. + +**Example**: + +```lua +s = List({ "a", "b", "c" }):concat(",") --> "a,b,c" +``` + +> [!NOTE] +> +> This method forwards to `table.concat` directly and keeps its strict element +> rules. + + + +#### `join(sep?, quoted?)` Join list values into a string. +**Parameters**: + +- `sep?` (`string`): Optional separator value (defaults to `""`). +- `quoted?` (`boolean`): Optional boolean flag (defaults to `false`). + +**Return**: + +- `s` (`string`): Joined string. + +**Example**: + ```lua -s = List({ "a", "b", "c" }):join(",") --> "a,b,c" +s = List({ "a", "b", "c" }):join(",") --> "a,b,c" +s = List({ "a", "b", "c" }):join(", ", true) --> '"a", "b", "c"' ``` -#### `map` +> [!NOTE] +> +> Values are converted with `tostring` before joining. Set `quoted = true` to +> quote string values. + + + +#### `tostring()` + +Render the list to a string via the regular method form. + +**Return**: + +- `s` (`string`): Rendered list string. + +**Example**: + +```lua +s = List({ "a", "b", 1 }):tostring() --> '{ "a", "b", 1 }' +``` + +> [!NOTE] +> +> `tostring(list)` calls `list:tostring()`. + + + +#### `keypath()` + +Render list items as a table-access key path. + +**Return**: + +- `s` (`string`): Key-path string. + +**Example**: + +```lua +p = List({ "ctx", "users", 1, "name" }):keypath() --> "ctx.users[1].name" +``` + + + +#### `map(fn)` Return a new list by mapping each value. +**Parameters**: + +- `fn` (`fun(v):any`): Callback function. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua to_upper = function(v) return v:upper() end m = List({ "a", "b" }):map(to_upper) --> { "A", "B" } ``` -#### `reduce` + + +#### `mul(n)` + +Return a new list repeated `n` times (list multiplication behavior). + +**Parameters**: + +- `n` (`integer`): Numeric value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + +```lua +ls = List({ "a", "b" }):mul(3) --> { "a", "b", "a", "b", "a", "b" } +``` + +> [!NOTE] +> +> `mul` is also available through the `*` operator. + + + +#### `reduce(fn, init?)` Reduce the list to a single value using an accumulator. +**Parameters**: + +- `fn` (`fun(acc:any,`): v:any):any Reducer function. +- `init?` (`any`): Optional initial accumulator; for non-empty lists, `nil` or + omitted uses the first item. + +**Return**: + +- `res` (`any`): Reduced value. + +**Example**: + ```lua add = function(acc, v) return acc + v end sum = List({ 1, 2, 3 }):reduce(add, 0) --> 6 @@ -408,21 +970,36 @@ sum = List({ 1, 2, 3 }):reduce(add, 10) --> 16 > [!NOTE] > -> If init is `nil`, the first element is used as the initial value. Empty lists -> return init (or `nil` if init is `nil`). +> For empty lists, returns `init` unchanged (or `nil` when omitted). + + -#### `reverse` +#### `reverse()` Return a new list with items reversed. +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua r = List({ "a", "b", "c" }):reverse() --> { "c", "b", "a" } ``` -#### `toset` + + +#### `toset()` Convert the list to a set. +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua s = List({ "a", "b", "a" }):toset() --> { a = true, b = true } ``` @@ -431,10 +1008,23 @@ s = List({ "a", "b", "a" }):toset() --> { a = true, b = true } > > Order is preserved from the original list. -#### `slice` + + +#### `slice(i?, j?)` Return a new list containing items from i to j (inclusive). +**Parameters**: + +- `i?` (`integer`): Optional start index (defaults to `1`). +- `j?` (`integer`): Optional end index (defaults to `#self`). + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua t = List({ "a", "b", "c", "d" }):slice(2, 3) --> { "b", "c" } ``` @@ -443,26 +1033,58 @@ t = List({ "a", "b", "c", "d" }):slice(2, 3) --> { "b", "c" } > > Supports negative indices (-1 is last element). -#### `take` + + +#### `take(n)` Return the first n elements as a new list. +**Parameters**: + +- `n` (`integer`): Numeric value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua t = List({ "a", "b", "c" }):take(2) --> { "a", "b" } ``` -#### `uniq` + + +#### `uniq()` Return a new list with duplicates removed (first occurrence kept). +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua u = List({ "a", "b", "a", "c" }):uniq() --> { "a", "b", "c" } ``` -#### `zip` + + +#### `zip(ls)` Zip two lists into a list of 2-element tables. +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + ```lua z = List({ "a", "b" }):zip({ 1, 2 }) --> { {"a",1}, {"b",2} } ``` @@ -470,3 +1092,200 @@ z = List({ "a", "b" }):zip({ 1, 2 }) --> { {"a",1}, {"b",2} } > [!NOTE] > > Length is the minimum of both lists. + +### Metamethods + + + +#### `__eq(ls)` + +Compare two lists using shallow element equality (`==`). + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +a = List({ "a", { 1 } }) +b = List({ "a", { 1 } }) +ok = a == b --> false (different nested table references) + +t = { 1 } +a = List({ "a", t }) +b = List({ "a", t }) +ok = a == b --> true (same nested table reference) +``` + +> [!NOTE] +> +> - `==` returns `false` for `List` vs plain-table comparisons. Use +> `:equals(ls)` for `List` vs plain-table comparisons. +> +> ```lua +> t = { "a", 1 } +> a = List(t) +> b = { "a", 1 } +> ok = (a == b) --> false +> ok = a:equals(b) --> true +> ``` +> +> - Like `:equals(ls)`, `==` compares only array positions (`1..#list`), so +> extra non-array keys are ignored when both operands are `List`. +> +> ```lua +> a = List({ "a", t }) +> b = List({ "a", t, extra = 1 }) +> ok = (a == b) --> true +> ``` + + + +#### `__lt(ls)` + +Compare two lists lexicographically (`<`). + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +ok = List({ 1, 2 }) < List({ 1, 3 }) --> true +``` + +> [!NOTE] +> +> `<` is equivalent to `:lt(ls)`. + + + +#### `__le(ls)` + +Compare two lists lexicographically (`<=`). + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ok` (`boolean`): Whether the condition is met. + +**Example**: + +```lua +ok = List({ 1, 2 }) <= List({ 1, 2 }) --> true +``` + +> [!NOTE] +> +> `<=` is equivalent to `:le(ls)`. + + + +#### `__mul(n)` + +Repeat a list `n` times (`*`). + +**Parameters**: + +- `n` (`integer|mods.List`): Right operand. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + +```lua +l1 = List({ "a", "b" }) * 3 --> { "a", "b", "a", "b", "a", "b" } +l2 = 3 * List({ "a", "b" }) --> { "a", "b", "a", "b", "a", "b" } +``` + +> [!NOTE] +> +> `*` is equivalent to `:mul(n)`. + + + +#### `__add(ls)` + +Extend the left-hand list in place with right-hand values, then return the same +left-hand list reference (`+`). + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `self` (`mods.List|any[]`): Current list instance. + +**Example**: + +```lua +a = List({ "a", "b" }) +b = { "c", "d" } +c = a + b --> c and a are the same reference: { "a", "b", "c", "d" } +``` + +> [!NOTE] +> +> `+` operator is equivalent to `:extend(ls)`. + + + +#### `__sub(ls)` + +Return values from the left list that are not present in the right list (`-`). + +**Parameters**: + +- `ls` (`mods.List|any[]`): Other list value. + +**Return**: + +- `ls` (`mods.List`): New list. + +**Example**: + +```lua +a = List({ "a", "b", "c" }) +b = { "b" } +d = a - b --> { "a", "c" } +``` + +> [!NOTE] +> +> `-` operator is equivalent to `:difference(ls)`. + + + +#### `__tostring()` + +Render the list to a string like `{ "a", "b", 1 }`. + +**Return**: + +- `s` (`string`): Rendered list string. + +**Example**: + +```lua +s = tostring(List({ "a", "b", 1 })) --> '{ "a", "b", 1 }' +``` + +> [!NOTE] +> +> `tostring(ls)` is equivalent to `:tostring()`. diff --git a/docs/src/modules/operator.md b/docs/src/modules/operator.md index 0b07355..a836ca8 100644 --- a/docs/src/modules/operator.md +++ b/docs/src/modules/operator.md @@ -18,243 +18,517 @@ print(operator.add(1, 2)) --> 3 **Arithmetic**: -| Function | Description | -| --------------- | ------------------------------------------------------------------ | -| [`add`](#add) | Add two numbers. | -| [`sub`](#sub) | Subtract `b` from `a`. | -| [`mul`](#mul) | Multiply two numbers. | -| [`div`](#div) | Divide `a` by `b` using Lua's floating-point division. | -| [`idiv`](#idiv) | Divide `a` by `b` and return the integer quotient (`//` behavior). | -| [`mod`](#mod) | Return the modulo remainder of `a` divided by `b`. | -| [`pow`](#pow) | Raise `a` to the power of `b`. | -| [`unm`](#unm) | Negate a number. | +| Function | Description | +| ------------------------ | --------------------------------------------------------- | +| [`add(a, b)`](#fn-add) | Add two numbers. | +| [`sub(a, b)`](#fn-sub) | Subtract `b` from `a`. | +| [`mul(a, b)`](#fn-mul) | Multiply two numbers. | +| [`div(a, b)`](#fn-div) | Divide `a` by `b` using Lua's floating-point division. | +| [`idiv(a, b)`](#fn-idiv) | Divide `a` by `b` and return the floor-division quotient. | +| [`mod(a, b)`](#fn-mod) | Return the modulo remainder of `a` divided by `b`. | +| [`pow(a, b)`](#fn-pow) | Raise `a` to the power of `b`. | +| [`unm(a)`](#fn-unm) | Negate a number. | **Comparison**: -| Function | Description | -| ------------- | -------------------------------------------------- | -| [`eq`](#eq) | Check whether two values are equal. | -| [`neq`](#neq) | Check whether two values are not equal. | -| [`lt`](#lt) | Check whether `a` is strictly less than `b`. | -| [`le`](#le) | Check whether `a` is less than or equal to `b`. | -| [`gt`](#gt) | Check whether `a` is strictly greater than `b`. | -| [`ge`](#ge) | Check whether `a` is greater than or equal to `b`. | +| Function | Description | +| ---------------------- | -------------------------------------------------- | +| [`eq(a, b)`](#fn-eq) | Check whether two values are equal. | +| [`neq(a, b)`](#fn-neq) | Check whether two values are not equal. | +| [`lt(a, b)`](#fn-lt) | Check whether `a` is strictly less than `b`. | +| [`le(a, b)`](#fn-le) | Check whether `a` is less than or equal to `b`. | +| [`gt(a, b)`](#fn-gt) | Check whether `a` is strictly greater than `b`. | +| [`ge(a, b)`](#fn-ge) | Check whether `a` is greater than or equal to `b`. | **Logical**: -| Function | Description | -| --------------- | ---------------------------------------------------- | -| [`land`](#land) | Evaluate `a and b` with Lua short-circuit semantics. | -| [`lor`](#lor) | Evaluate `a or b` with Lua short-circuit semantics. | -| [`lnot`](#lnot) | Return the boolean negation of `a`. | +| Function | Description | +| ------------------------ | ---------------------------------------------------- | +| [`land(a, b)`](#fn-land) | Evaluate `a and b` with Lua short-circuit semantics. | +| [`lor(a, b)`](#fn-lor) | Evaluate `a or b` with Lua short-circuit semantics. | +| [`lnot(a)`](#fn-lnot) | Return the boolean negation of `a`. | **String & Length**: -| Function | Description | -| ------------------- | ---------------------------------------------------------------- | -| [`concat`](#concat) | Concatenate two strings. | -| [`len`](#len) | Return the length of a string or table using Lua's `#` operator. | +| Function | Description | +| ---------------------------- | ---------------------------------------------------------------- | +| [`concat(a, b)`](#fn-concat) | Concatenate two strings. | +| [`len(a)`](#fn-len) | Return the length of a string or table using Lua's `#` operator. | **Tables & Calls**: -| Function | Description | -| ----------------------- | -------------------------------------------------------------- | -| [`index`](#index) | Return the value at key/index `k` in table `t`. | -| [`setindex`](#setindex) | Set `t[k] = v` and return the assigned value. | -| [`call`](#call) | Call a function with variadic arguments and return its result. | +| Function | Description | +| ----------------------------------- | -------------------------------------------------------------- | +| [`index(t, k)`](#fn-index) | Return the value at key/index `k` in table `t`. | +| [`setindex(t, k, v)`](#fn-setindex) | Set `t[k] = v` and return the assigned value. | +| [`call(f, ...)`](#fn-call) | Call a function with variadic arguments and return its result. | ### Arithmetic -Numeric arithmetic operators as functions. +Numeric arithmetic operators as functions. -#### `add` +#### `add(a, b)` Add two numbers. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `sum` (`number`): Sum of `a` and `b`. + +**Example**: + ```lua add(1, 2) --> 3 ``` -#### `sub` + + +#### `sub(a, b)` Subtract `b` from `a`. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `difference` (`number`): Difference `a - b`. + +**Example**: + ```lua sub(5, 3) --> 2 ``` -#### `mul` + + +#### `mul(a, b)` Multiply two numbers. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `product` (`number`): Product `a * b`. + +**Example**: + ```lua mul(3, 4) --> 12 ``` -#### `div` + + +#### `div(a, b)` Divide `a` by `b` using Lua's floating-point division. +**Parameters**: + +- `a` (`number`): Dividend value. +- `b` (`number`): Divisor value. + +**Return**: + +- `quotient` (`number`): Quotient `a / b`. + +**Example**: + ```lua div(10, 4) --> 2.5 ``` -#### `idiv` + + +#### `idiv(a, b)` -Divide `a` by `b` and return the integer quotient (`//` behavior). +Divide `a` by `b` and return the floor-division quotient. + +**Parameters**: + +- `a` (`number`): Dividend value. +- `b` (`number`): Divisor value. + +**Return**: + +- `quotient` (`integer`): Floor-division result. + +**Example**: ```lua idiv(5, 2) --> 2 ``` -#### `mod` + + +#### `mod(a, b)` Return the modulo remainder of `a` divided by `b`. +**Parameters**: + +- `a` (`number`): Dividend value. +- `b` (`number`): Divisor value. + +**Return**: + +- `remainder` (`number`): Remainder of `a % b`. + +**Example**: + ```lua mod(5, 2) --> 1 ``` -#### `pow` + + +#### `pow(a, b)` Raise `a` to the power of `b`. +**Parameters**: + +- `a` (`number`): Base value. +- `b` (`number`): Exponent value. + +**Return**: + +- `power` (`number`): Result of `a ^ b`. + +**Example**: + ```lua pow(2, 4) --> 16 ``` -#### `unm` + + +#### `unm(a)` Negate a number. +**Parameters**: + +- `a` (`number`): Input numeric value. + +**Return**: + +- `negated` (`number`): Result of `-a`. + +**Example**: + ```lua unm(3) --> -3 ``` ### Comparison -Equality and ordering comparison operators. +Equality and ordering comparison operators. -#### `eq` +#### `eq(a, b)` Check whether two values are equal. +**Parameters**: + +- `a` (`any`): Left value. +- `b` (`any`): Right value. + +**Return**: + +- `isEqual` (`boolean`): True when `a == b`. + +**Example**: + ```lua eq(1, 1) --> true ``` -#### `neq` + + +#### `neq(a, b)` Check whether two values are not equal. +**Parameters**: + +- `a` (`any`): Left value. +- `b` (`any`): Right value. + +**Return**: + +- `isNotEqual` (`boolean`): True when `a ~= b`. + +**Example**: + ```lua neq(1, 2) --> true ``` -#### `lt` + + +#### `lt(a, b)` Check whether `a` is strictly less than `b`. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `isLess` (`boolean`): True when `a < b`. + +**Example**: + ```lua lt(1, 2) --> true ``` -#### `le` + + +#### `le(a, b)` Check whether `a` is less than or equal to `b`. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `isLessOrEqual` (`boolean`): True when `a <= b`. + +**Example**: + ```lua -lte(2, 2) --> true +le(2, 2) --> true ``` -#### `gt` + + +#### `gt(a, b)` Check whether `a` is strictly greater than `b`. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `isGreater` (`boolean`): True when `a > b`. + +**Example**: + ```lua gt(3, 2) --> true ``` -#### `ge` + + +#### `ge(a, b)` Check whether `a` is greater than or equal to `b`. +**Parameters**: + +- `a` (`number`): Left numeric value. +- `b` (`number`): Right numeric value. + +**Return**: + +- `isGreaterOrEqual` (`boolean`): True when `a >= b`. + +**Example**: + ```lua -gte(2, 2) --> true +ge(2, 2) --> true ``` ### Logical -Boolean logic operators with Lua truthiness semantics. +Boolean logic operators with Lua truthiness semantics. -#### `land` +#### `land(a, b)` Evaluate `a and b` with Lua short-circuit semantics. +**Parameters**: + +- `a` (`T1`): First operand. +- `b` (`T2`): Second operand. + +**Return**: + +- `andValue` (`T1|T2`): Result of `a and b`. + +**Example**: + ```lua land(true, false) --> false ``` -#### `lor` + + +#### `lor(a, b)` Evaluate `a or b` with Lua short-circuit semantics. +**Parameters**: + +- `a` (`T1`): First operand. +- `b` (`T2`): Second operand. + +**Return**: + +- `orValue` (`T1|T2`): Result of `a or b`. + +**Example**: + ```lua lor(false, true) --> true ``` -#### `lnot` + + +#### `lnot(a)` Return the boolean negation of `a`. +**Parameters**: + +- `a` (`any`): Input value. + +**Return**: + +- `isNot` (`boolean`): Result of `not a`. + +**Example**: + ```lua lnot(true) --> false ``` ### String & Length -String concatenation and length operators. +String concatenation and length operators. -#### `concat` +#### `concat(a, b)` Concatenate two strings. +**Parameters**: + +- `a` (`string`): Left string. +- `b` (`string`): Right string. + +**Return**: + +- `concatenated` (`string`): Concatenated result `a .. b`. + +**Example**: + ```lua concat("a", "b") --> "ab" ``` -#### `len` + + +#### `len(a)` Return the length of a string or table using Lua's `#` operator. +**Parameters**: + +- `a` (`string|table`): Value supporting Lua's `#` operator. + +**Return**: + +- `length` (`integer`): Length computed by `#a`. + +**Example**: + ```lua len("abc") --> 3 ``` ### Tables & Calls -Table indexing helpers and function invocation. +Table indexing helpers and function invocation. -#### `index` +#### `index(t, k)` Return the value at key/index `k` in table `t`. +**Parameters**: + +- `t` (`table`): Source table. +- `k` (`T`): Key/index value. + +**Return**: + +- `value` (`T`): Value stored at `t[k]`. + +**Example**: + ```lua index({ a = 1 }, "a") --> 1 ``` -#### `setindex` + + +#### `setindex(t, k, v)` Set `t[k] = v` and return the assigned value. +**Parameters**: + +- `t` (`table`): Target table. +- `k` (`any`): Key/index value. +- `v` (`T`): Value to set. + +**Return**: + +- `value` (`T`): Assigned value `v`. + +**Example**: + ```lua setindex({}, "a", 1) --> 1 ``` -#### `call` + + +#### `call(f, ...)` Call a function with variadic arguments and return its result. +**Parameters**: + +- `f` (`fun(...:T1):T2`): Function to call. +- `...` (`T1`): Additional arguments. + +**Return**: + +- `result` (`T2`): Return value(s) from `f(...)`. + +**Example**: + ```lua call(math.max, 1, 2) --> 2 ``` diff --git a/docs/src/modules/repr.md b/docs/src/modules/repr.md index 2970fe5..2590049 100644 --- a/docs/src/modules/repr.md +++ b/docs/src/modules/repr.md @@ -14,14 +14,36 @@ repr = require "mods.repr" print(repr("Hello world!")) --> "Hello world!" view = { user = { name = "Ada", tags = { "lua", "docs" } } } -print(repr(view)) --> { --- user = { --- name = "Ada", --- tags = { --- [1] = "lua", --- [2] = "docs" --- } --- } --- } +print(repr(view)) +--> { +-- user = { +-- name = "Ada", +-- tags = { +-- [1] = "lua", +-- [2] = "docs" +-- } +-- } +-- } +``` + + + +## `repr(v)` + +Convert a Lua value to a readable string representation. + +**Parameters**: +- `v` (`any`): Value to render. + +**Return**: + +- `out` (`string`): Readable string representation. + +**Example**: + +```lua +repr("Hello") --> '"Hello"' +repr({ "a", "b" }) --> '{ "a", "b" }' +repr() --> "nil" ``` diff --git a/docs/src/modules/runtime.md b/docs/src/modules/runtime.md new file mode 100644 index 0000000..adfe43c --- /dev/null +++ b/docs/src/modules/runtime.md @@ -0,0 +1,103 @@ +--- +desc: "Exposes Lua runtime metadata and version compatibility flags." +--- + +# `runtime` + +Exposes Lua runtime metadata and version compatibility flags. + +## Usage + +```lua +runtime = require "mods.runtime" + +print(runtime.version) --> "Lua 5.x" +print(runtime.version_num) --> 501 | 502 | 503 | 504 +print(runtime.is_lua54) --> true | false +``` + +## Fields + +| Field | Description | +| ----------------------------- | ------------------------------------------------- | +| [`version`](#version) | Version string reported by the runtime. | +| [`major`](#major) | Major version number parsed from `version`. | +| [`minor`](#minor) | Minor version number parsed from `version`. | +| [`version_num`](#version-num) | Numeric version encoded as `major * 100 + minor`. | +| [`is_luajit`](#is-luajit) | True when running under LuaJIT. | +| [`is_lua51`](#is-lua51) | True only on Lua 5.1 runtimes. | +| [`is_lua52`](#is-lua52) | True only on Lua 5.2 runtimes. | +| [`is_lua53`](#is-lua53) | True only on Lua 5.3 runtimes. | +| [`is_lua54`](#is-lua54) | True only on Lua 5.4 runtimes. | + +### `version` + +Version string reported by the runtime. + +```lua +print(runtime.version) --> "Lua 5.x" +``` + +### `major` + +Major version number parsed from `version`. + +```lua +print(runtime.major) --> 5 +``` + +### `minor` + +Minor version number parsed from `version`. + +```lua +print(runtime.minor) --> 1 | 2 | 3 | 4 +``` + +### `version_num` + +Numeric version encoded as `major * 100 + minor`. + +```lua +print(runtime.version_num) --> 501 | 502 | 503 | 504 +``` + +### `is_luajit` + +True when running under LuaJIT. + +```lua +print(runtime.is_luajit) --> true | false +``` + +### `is_lua51` + +True only on Lua 5.1 runtimes. + +```lua +print(runtime.is_lua51) --> true | false +``` + +### `is_lua52` + +True only on Lua 5.2 runtimes. + +```lua +print(runtime.is_lua52) --> true | false +``` + +### `is_lua53` + +True only on Lua 5.3 runtimes. + +```lua +print(runtime.is_lua53) --> true | false +``` + +### `is_lua54` + +True only on Lua 5.4 runtimes. + +```lua +print(runtime.is_lua54) --> true | false +``` diff --git a/docs/src/modules/set.md b/docs/src/modules/set.md index b2595b7..1c6768d 100644 --- a/docs/src/modules/set.md +++ b/docs/src/modules/set.md @@ -1,13 +1,13 @@ --- desc: - "A Python-style set class providing common operations to create, modify, and - query collections of unique values." + "A set class providing common operations to create, modify, and query + collections of unique values." --- # `Set` -A Python-style set class providing common operations to create, modify, and -query collections of unique values. +A set class providing common operations to create, modify, and query collections +of unique values. ## Usage @@ -18,248 +18,728 @@ s = Set({ "a" }) print(s:contains("a")) --> true ``` -## Dependencies - -Dependencies below are lazy-loaded 💤 on first access. - -- [`mods.tbl`](https://luamod.github.io/mods/modules/tbl) - ## Functions **Mutation**: -| Function | Description | -| ------------------------------------------------------------- | ----------------------------------------------------------- | -| [`add`](#add) | Add an element to the set. | -| [`clear`](#clear) | Remove all elements from the set. | -| [`difference_update`](#difference-update) | Remove elements found in another set (in place). | -| [`intersection_update`](#intersection-update) | Keep only elements common to both sets (in place). | -| [`pop`](#pop) | Remove and return an arbitrary element. | -| [`symmetric_difference_update`](#symmetric-difference-update) | Update the set with elements not shared by both (in place). | -| [`update`](#update) | Add all elements from another set (in place). | +| Function | Description | +| --------------------------------------------------------------------- | ----------------------------------------------------------- | +| [`add(v)`](#fn-add) | Add an element to the set. | +| [`clear()`](#fn-clear) | Remove all elements from the set. | +| [`difference_update(set)`](#fn-difference-update) | Remove elements found in another set (in place). | +| [`intersection_update(set)`](#fn-intersection-update) | Keep only elements common to both sets (in place). | +| [`pop()`](#fn-pop) | Remove and return an arbitrary element. | +| [`symmetric_difference_update(set)`](#fn-symmetric-difference-update) | Update the set with elements not shared by both (in place). | +| [`update(set)`](#fn-update) | Add all elements from another set (in place). | **Copying**: -| Function | Description | -| ----------------------------------------------- | --------------------------------------------------- | -| [`copy`](#copy) | Return a shallow copy of the set. | -| [`difference`](#difference) | Return elements in this set but not in another. | -| [`intersection`](#intersection) | Return elements common to both sets. | -| [`remove`](#remove) | Remove an element if present, do nothing otherwise. | -| [`symmetric_difference`](#symmetric-difference) | Return elements not shared by both sets. | -| [`union`](#union) | Return a new set with all elements from both. | +| Function | Description | +| ------------------------------------------------------- | --------------------------------------------------- | +| [`copy()`](#fn-copy) | Return a shallow copy of the set. | +| [`difference(set)`](#fn-difference) | Return elements in this set but not in another. | +| [`intersection(set)`](#fn-intersection) | Return elements common to both sets. | +| [`remove(v)`](#fn-remove) | Remove an element if present, do nothing otherwise. | +| [`symmetric_difference(set)`](#fn-symmetric-difference) | Return elements not shared by both sets. | +| [`union(set)`](#fn-union) | Return a new set with all elements from both. | **Predicates**: -| Function | Description | -| --------------------------- | ---------------------------------------------------------------- | -| [`isdisjoint`](#isdisjoint) | Return true if sets have no elements in common. | -| [`isempty`](#isempty) | Return true if the set has no elements. | -| [`issubset`](#issubset) | Return true if all elements of this set are also in another set. | -| [`issuperset`](#issuperset) | Return true if this set contains all elements of another set. | +| Function | Description | +| ----------------------------------- | ---------------------------------------------------------------- | +| [`isdisjoint(set)`](#fn-isdisjoint) | Return true if sets have no elements in common. | +| [`equals(set)`](#fn-equals) | Return true when both sets contain exactly the same members. | +| [`isempty()`](#fn-isempty) | Return true if the set has no elements. | +| [`issubset(set)`](#fn-issubset) | Return true if all elements of this set are also in another set. | +| [`issuperset(set)`](#fn-issuperset) | Return true if this set contains all elements of another set. | **Query**: -| Function | Description | -| ----------------------- | ----------------------------------------- | -| [`contains`](#contains) | Return true if the set contains `v`. | -| [`len`](#len) | Return the number of elements in the set. | +| Function | Description | +| ----------------------------- | ----------------------------------------- | +| [`contains(v)`](#fn-contains) | Return true if the set contains `v`. | +| [`len()`](#fn-len) | Return the number of elements in the set. | **Transform**: -| Function | Description | -| ------------------- | --------------------------------------- | -| [`map`](#map) | Return a new set by mapping each value. | -| [`values`](#values) | Return a list of all values in the set. | +| Function | Description | +| ------------------------ | --------------------------------------- | +| [`map(fn)`](#fn-map) | Return a new set by mapping each value. | +| [`values()`](#fn-values) | Return a list of all values in the set. | + +**Metamethods**: + +| Function | Description | +| ------------------------- | -------------------------------------------------------------------------- | +| [`__add(set)`](#fn-add) | Return the union of two sets using `+`. | +| [`__bor(set)`](#fn-bor) | Return the union of two sets using `\|`. | +| [`__band(set)`](#fn-band) | Return the intersection of two sets using `&`. | +| [`__bxor(set)`](#fn-bxor) | Return elements present in exactly one set using `^`. | +| [`__eq(set)`](#fn-eq) | Return true if both sets contain exactly the same members using `==`. | +| [`__le(set)`](#fn-le) | Return true if the left set is a subset of the right set using `<=`. | +| [`__lt(set)`](#fn-lt) | Return true if the left set is a proper subset of the right set using `<`. | +| [`__sub(set)`](#fn-sub) | Return the difference of two sets using `-`. | ### Mutation -In-place operations that mutate the current set. +In-place operations that mutate the current set. -#### `add` +#### `add(v)` Add an element to the set. +**Parameters**: + +- `v` (`any`): Value to add. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a" }):add("b") --> s contains "a", "b" ``` -#### `clear` + + +#### `clear()` Remove all elements from the set. +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a", "b" }):clear() --> s is empty ``` -#### `difference_update` + + +#### `difference_update(set)` Remove elements found in another set (in place). +**Parameters**: + +- `set` (`T`): Other set value. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a", "b" }):difference_update(Set({ "b" })) --> s contains "a" ``` -#### `intersection_update` + + +#### `intersection_update(set)` Keep only elements common to both sets (in place). +**Parameters**: + +- `set` (`T`): Other set value. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a", "b" }):intersection_update(Set({ "b", "c" })) --> s contains "b" ``` -#### `pop` + + +#### `pop()` Remove and return an arbitrary element. +**Return**: + +- `value` (`any`): Removed value, or `nil` when the set is empty. + +**Example**: + ```lua v = Set({ "a", "b" }):pop() --> v is either "a" or "b" ``` -#### `symmetric_difference_update` + + +#### `symmetric_difference_update(set)` Update the set with elements not shared by both (in place). +**Parameters**: + +- `set` (`T`): Other set value. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a", "b" }):symmetric_difference_update(Set({ "b", "c" })) --> s contains "a", "c" ``` -#### `update` + + +#### `update(set)` Add all elements from another set (in place). +**Parameters**: + +- `set` (`T`): Other set value. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a" }):update(Set({ "b" })) --> s contains "a", "b" ``` ### Copying -Non-mutating set operations that return new set instances. +Non-mutating set operations that return new set instances. -#### `copy` +#### `copy()` Return a shallow copy of the set. +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua c = Set({ "a" }):copy() --> c is a new set with "a" ``` -#### `difference` + + +#### `difference(set)` Return elements in this set but not in another. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua d = Set({ "a", "b" }):difference(Set({ "b" })) --> d contains "a" ``` -#### `intersection` +> [!NOTE] +> +> `difference` is also available as the `__sub` (`-`) operator. +> `a:difference(b)` is equivalent to `a - b`. + + + +#### `intersection(set)` Return elements common to both sets. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua i = Set({ "a", "b" }):intersection(Set({ "b", "c" })) --> i contains "b" ``` -#### `remove` +> [!NOTE] +> +> `intersection` is also available as `__band` (`&`) on Lua 5.3+. + + + +#### `remove(v)` Remove an element if present, do nothing otherwise. +**Parameters**: + +- `v` (`any`): Value to remove. + +**Return**: + +- `self` (`T`): Current set instance. + +**Example**: + ```lua s = Set({ "a", "b" }):remove("b") --> s contains "a" ``` -#### `symmetric_difference` + + +#### `symmetric_difference(set)` Return elements not shared by both sets. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua d = Set({ "a", "b" }):symmetric_difference(Set({ "b", "c" })) --> d contains "a", "c" ``` -#### `union` +> [!NOTE] +> +> `symmetric_difference` is also available as `__bxor` (`^`) on Lua 5.3+. + + + +#### `union(set)` Return a new set with all elements from both. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua s = Set({ "a" }):union(Set({ "b" })) --> s contains "a", "b" ``` +> [!NOTE] +> +> `union` is available as `__add` (`+`) and `__bor` (`|`) on Lua 5.3+. +> `a:union(b)` is equivalent to `a + b` and `a | b`. + ### Predicates -Boolean checks about set relationships and emptiness. +Boolean checks about set relationships and emptiness. -#### `isdisjoint` +#### `isdisjoint(set)` Return true if sets have no elements in common. +**Parameters**: + +- `set` (`T`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when sets have no elements in common. + +**Example**: + ```lua ok = Set({ "a" }):isdisjoint(Set({ "b" })) --> true ``` -#### `isempty` + + +#### `equals(set)` + +Return true when both sets contain exactly the same members. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when both sets contain the same members. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "a" }) +ok = a:equals(b) --> true +``` + +> [!NOTE] +> +> `equals` is also available as the `__eq` (`==`) operator. `a:equals(b)` is +> equivalent to `a == b`. + + + +#### `isempty()` Return true if the set has no elements. +**Return**: + +- `ok` (`boolean`): True when the set has no elements. + +**Example**: + ```lua empty = Set({}):isempty() --> true ``` -#### `issubset` + + +#### `issubset(set)` Return true if all elements of this set are also in another set. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when every element of `self` exists in `set`. + +**Example**: + ```lua ok = Set({ "a" }):issubset(Set({ "a", "b" })) --> true ``` -#### `issuperset` +> [!NOTE] +> +> `issubset` is also available as the `__le` (`<=`) operator. `a:issubset(b)` is +> equivalent to `a <= b`. + + + +#### `issuperset(set)` Return true if this set contains all elements of another set. +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when `self` contains every element of `set`. + +**Example**: + ```lua ok = Set({ "a", "b" }):issuperset(Set({ "a" })) --> true ``` ### Query -Read-only queries for membership and size. +Read-only queries for membership and size. -#### `contains` +#### `contains(v)` Return true if the set contains `v`. +**Parameters**: + +- `v` (`any`): Value to check. + +**Return**: + +- `ok` (`boolean`): True when `v` is present in the set. + +**Example**: + ```lua ok = Set({ "a", "b" }):contains("a") --> true ok = Set({ "a", "b" }):contains("z") --> false ``` -#### `len` + + +#### `len()` Return the number of elements in the set. +**Return**: + +- `count` (`integer`): Element count. + +**Example**: + ```lua n = Set({ "a", "b" }):len() --> 2 ``` ### Transform -Value-to-value transformations and projection helpers. +Value-to-value transformations and projection helpers. -#### `map` +#### `map(fn)` Return a new set by mapping each value. +**Parameters**: + +- `fn` (`fun(v:any):any`): Mapping function. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + ```lua s = Set({ 1, 2 }):map(function(v) return v * 10 end) --> s contains 10, 20 ``` -#### `values` + + +#### `values()` Return a list of all values in the set. +**Return**: + +- `values` (`mods.List`): List of set values. + +**Example**: + ```lua values = Set({ "a", "b" }):values() --> { "a", "b" } ``` + +### Metamethods + + + +#### `__add(set)` + +Return the union of two sets using `+`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "c" }) +u = a + b --> { a = true, b = true, c = true } +``` + +> [!NOTE] +> +> `__add` is the operator form of `:union(set)`. + + + +#### `__bor(set)` + +Return the union of two sets using `|`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "c" }) +u = a | b --> { a = true, b = true, c = true } +``` + +> [!NOTE] +> +> `__bor` is the operator form of `:union(set)` on Lua 5.3+. + + + +#### `__band(set)` + +Return the intersection of two sets using `&`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "c" }) +i = a & b --> { b = true } +``` + +> [!NOTE] +> +> `__band` is the operator form of `:intersection(set)` on Lua 5.3+. + + + +#### `__bxor(set)` + +Return elements present in exactly one set using `^`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "c" }) +d = a ^ b --> { a = true, c = true } +``` + +> [!NOTE] +> +> `__bxor` is the operator form of `:symmetric_difference(set)` on Lua 5.3+. + + + +#### `__eq(set)` + +Return true if both sets contain exactly the same members using `==`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when both sets contain the same members. + +**Example**: + +```lua +ok = Set({ "a", "b" }) == Set({ "b", "a" }) --> true +``` + +> [!NOTE] +> +> `__eq` is the operator form of `:equals(set)`. + + + +#### `__le(set)` + +Return true if the left set is a subset of the right set using `<=`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when `self` is a subset of `set`. + +**Example**: + +```lua +a = Set({ "a" }) +b = Set({ "a", "b" }) +ok = a <= b --> true +``` + +> [!NOTE] +> +> `__le` is the operator form of `:issubset(set)`. + + + +#### `__lt(set)` + +Return true if the left set is a proper subset of the right set using `<`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `ok` (`boolean`): True when `self` is a proper subset of `set`. + +**Example**: + +```lua +a = Set({ "a" }) +b = Set({ "a", "b" }) +ok = a < b --> true +``` + + + +#### `__sub(set)` + +Return the difference of two sets using `-`. + +**Parameters**: + +- `set` (`mods.Set|table`): Other set value. + +**Return**: + +- `set` (`mods.Set`): New set. + +**Example**: + +```lua +a = Set({ "a", "b" }) +b = Set({ "b", "c" }) +d = a - b --> { a = true } +``` + +> [!NOTE] +> +> `__sub` is the operator form of `:difference(set)`. diff --git a/docs/src/modules/str.md b/docs/src/modules/str.md index 987bbbc..391a811 100644 --- a/docs/src/modules/str.md +++ b/docs/src/modules/str.md @@ -14,167 +14,263 @@ str = require "mods.str" print(str.capitalize("hello world")) --> "Hello world" ``` -## Dependencies - -Dependencies below are lazy-loaded 💤 on first access. - -- [`mods.keyword`](https://luamod.github.io/mods/modules/keyword) -- [`mods.List`](https://luamod.github.io/mods/modules/list) -- [`mods.stringcase`](https://luamod.github.io/mods/modules/stringcase) - ## Functions **Formatting**: -| Function | Description | -| --------------------------- | --------------------------------------------------------------------- | -| [`capitalize`](#capitalize) | Return copy with first character capitalized and the rest lowercased. | -| [`center`](#center) | Center string within width, padded with fill characters. | -| [`count`](#count) | Count non-overlapping occurrences of a substring. | -| [`endswith`](#endswith) | Return true if string ends with suffix. | -| [`expandtabs`](#expandtabs) | Expand tabs to spaces using given tabsize. | -| [`find`](#find) | Return lowest index of substring or nil if not found. | -| [`format_map`](#format-map) | Format string with mapping (key-based) replacement. | +| Function | Description | +| ---------------------------------------------------- | --------------------------------------------------------------------- | +| [`capitalize(s)`](#fn-capitalize) | Return copy with first character capitalized and the rest lowercased. | +| [`center(s, width, fillchar?)`](#fn-center) | Center string within width, padded with fill characters. | +| [`count(s, sub, start?, stop?)`](#fn-count) | Count non-overlapping occurrences of a substring. | +| [`endswith(s, suffix, start?, stop?)`](#fn-endswith) | Return true if string ends with suffix. | +| [`expandtabs(s, tabsize?)`](#fn-expandtabs) | Expand tabs to spaces using given tabsize. | +| [`find(s, sub, start?, stop?)`](#fn-find) | Return lowest index of substring or nil if not found. | +| [`format_map(s, mapping)`](#fn-format-map) | Format string with mapping (key-based) replacement. | **Predicates**: -| Function | Description | -| ------------------------------- | -------------------------------------------------------------------------------------------- | -| [`isalnum`](#isalnum) | Return true if all characters are alphanumeric and string is non-empty. | -| [`isalpha`](#isalpha) | Return true if all characters are alphabetic and string is non-empty. | -| [`isascii`](#isascii) | Return true if all characters are ASCII and string is non-empty. | -| [`isdecimal`](#isdecimal) | Return true if all characters are decimal characters and string is non-empty. | -| [`isdigit`](#isdigit) | Return true if all characters are digits and string is non-empty. | -| [`isidentifier`](#isidentifier) | Return true if string is a valid identifier and not a reserved keyword. | -| [`islower`](#islower) | Return true if all cased characters are lowercase and there is at least one cased character. | -| [`isnumeric`](#isnumeric) | Return true if all characters are numeric and string is non-empty. | -| [`isprintable`](#isprintable) | Return true if all characters are printable and string is non-empty. | -| [`isspace`](#isspace) | Return true if all characters are whitespace and string is non-empty. | -| [`istitle`](#istitle) | Return true if string is titlecased. | -| [`isupper`](#isupper) | Return true if all cased characters are uppercase and there is at least one cased character. | +| Function | Description | +| ------------------------------------- | -------------------------------------------------------------------------------------------- | +| [`isalnum(s)`](#fn-isalnum) | Return true if all characters are alphanumeric and string is non-empty. | +| [`isalpha(s)`](#fn-isalpha) | Return true if all characters are alphabetic and string is non-empty. | +| [`isascii(s)`](#fn-isascii) | Return true if all characters are ASCII. | +| [`isdecimal(s)`](#fn-isdecimal) | Return true if all characters are decimal characters and string is non-empty. | +| [`isdigit(s)`](#fn-isdigit) | Return true if all characters are digits and string is non-empty. | +| [`isidentifier(s)`](#fn-isidentifier) | Return true if string is a valid identifier and not a reserved keyword. | +| [`islower(s)`](#fn-islower) | Return true if all cased characters are lowercase and there is at least one cased character. | +| [`isnumeric(s)`](#fn-isnumeric) | Return true if all characters are numeric and string is non-empty. | +| [`isprintable(s)`](#fn-isprintable) | Return true if all characters are printable. | +| [`isspace(s)`](#fn-isspace) | Return true if all characters are whitespace and string is non-empty. | +| [`istitle(s)`](#fn-istitle) | Return true if string is titlecased. | +| [`isupper(s)`](#fn-isupper) | Return true if all cased characters are uppercase and there is at least one cased character. | **Layout**: -| Function | Description | -| ------------------- | ------------------------------------------------------------- | -| [`join`](#join) | Join an iterable of strings using this string as separator. | -| [`ljust`](#ljust) | Left-justify string in a field of given width. | -| [`lower`](#lower) | Return lowercased copy. | -| [`lstrip`](#lstrip) | Remove leading characters (default: whitespace). | -| [`rstrip`](#rstrip) | Remove trailing characters (default: whitespace). | -| [`strip`](#strip) | Remove leading and trailing characters (default: whitespace). | +| Function | Description | +| ----------------------------------------- | ------------------------------------------------------------------- | +| [`join(sep, ls)`](#fn-join) | Join an array-like table of strings using this string as separator. | +| [`ljust(s, width, fillchar?)`](#fn-ljust) | Left-justify string in a field of given width. | +| [`lower(s)`](#fn-lower) | Return lowercased copy. | +| [`lstrip(s, chars?)`](#fn-lstrip) | Remove leading characters (default: whitespace). | +| [`rstrip(s, chars?)`](#fn-rstrip) | Remove trailing characters (default: whitespace). | +| [`strip(s, chars?)`](#fn-strip) | Remove leading and trailing characters (default: whitespace). | **Split & Replace**: -| Function | Description | -| ------------------------------- | ------------------------------------------------------------------------- | -| [`partition`](#partition) | Partition string into head, sep, tail from left. | -| [`removeprefix`](#removeprefix) | Remove prefix if present. | -| [`removesuffix`](#removesuffix) | Remove suffix if present. | -| [`replace`](#replace) | Return a copy of the string with all occurrences of a substring replaced. | -| [`rfind`](#rfind) | Return highest index of substring or nil if not found. | -| [`rindex`](#rindex) | Like rfind but raises on failure (placeholder). | -| [`rjust`](#rjust) | Right-justify string in a field of given width. | -| [`rpartition`](#rpartition) | Partition string into head, sep, tail from right. | -| [`rsplit`](#rsplit) | Split from the right by separator, up to maxsplit. | -| [`split`](#split) | Split by separator (or whitespace) up to maxsplit. | -| [`splitlines`](#splitlines) | Split on line boundaries. | +| Function | Description | +| --------------------------------------------- | ------------------------------------------------------------------------- | +| [`partition(s, sep)`](#fn-partition) | Partition string into head, sep, tail from left. | +| [`removeprefix(s, prefix)`](#fn-removeprefix) | Remove prefix if present. | +| [`removesuffix(s, suffix)`](#fn-removesuffix) | Remove suffix if present. | +| [`replace(s, old, new, count?)`](#fn-replace) | Return a copy of the string with all occurrences of a substring replaced. | +| [`rfind(s, sub, start?, stop?)`](#fn-rfind) | Return highest index of substring or nil if not found. | +| [`rindex(s, sub, start?, stop?)`](#fn-rindex) | Like `rfind` but raises an error when the substring is not found. | +| [`rjust(s, width, fillchar?)`](#fn-rjust) | Right-justify string in a field of given width. | +| [`rpartition(s, sep)`](#fn-rpartition) | Partition string into head, sep, tail from right. | +| [`rsplit(s, sep?, maxsplit?)`](#fn-rsplit) | Split from the right by separator, up to maxsplit. | +| [`split(s, sep?, maxsplit?)`](#fn-split) | Split by separator (or whitespace) up to maxsplit. | +| [`splitlines(s, keepends?)`](#fn-splitlines) | Split on line boundaries. | **Casing & Transform**: -| Function | Description | -| --------------------------- | --------------------------------------------------------- | -| [`swapcase`](#swapcase) | Return a copy with case of alphabetic characters swapped. | -| [`startswith`](#startswith) | Return true if string starts with prefix. | -| [`title`](#title) | Return titlecased copy. | -| [`translate`](#translate) | Translate characters using a mapping table. | -| [`upper`](#upper) | Return uppercased copy. | -| [`zfill`](#zfill) | Pad numeric string on the left with zeros. | +| Function | Description | +| -------------------------------------------------------- | --------------------------------------------------------- | +| [`swapcase(s)`](#fn-swapcase) | Return a copy with case of alphabetic characters swapped. | +| [`startswith(s, prefix, start?, stop?)`](#fn-startswith) | Return true if string starts with prefix. | +| [`title(s)`](#fn-title) | Return titlecased copy. | +| [`translate(s, table_map)`](#fn-translate) | Translate characters using a mapping table. | +| [`upper(s)`](#fn-upper) | Return uppercased copy. | +| [`zfill(s, width)`](#fn-zfill) | Pad numeric string on the left with zeros. | ### Formatting -#### `capitalize` + + +#### `capitalize(s)` Return copy with first character capitalized and the rest lowercased. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = capitalize("hello WORLD") ---result: "Hello world" +s = capitalize("hello WORLD") --> "Hello world" ``` -#### `center` + + +#### `center(s, width, fillchar?)` Center string within width, padded with fill characters. +**Parameters**: + +- `s` (`string`): Input string. +- `width` (`integer`): Target width. +- `fillchar?` (`string`): Optional fill character. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = center("hi", 6, "-") ---result: "--hi--" +s = center("hi", 6, "-") --> "--hi--" ``` -#### `count` + + +#### `count(s, sub, start?, stop?)` Count non-overlapping occurrences of a substring. -```lua -n = count("aaaa", "aa") ---result: 2 +**Parameters**: -n = count("aaaa", "a", 2, -1) ---result: 2 +- `s` (`string`): Input string. +- `sub` (`string`): Substring to search. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional exclusive end index (defaults to `#s + 1`). -n = count("abcd", "") ---result: 5 +**Return**: + +- `n` (`integer`): Computed numeric value. + +**Example**: + +```lua +n = count("aaaa", "aa") --> 2 +n = count("aaaa", "a", 2, -1) --> 2 +n = count("abcd", "") --> 5 ``` -#### `endswith` + + +#### `endswith(s, suffix, start?, stop?)` Return true if string ends with suffix. +**Parameters**: + +- `s` (`string`): Input string. +- `suffix` (`string|string[]`): Suffix string. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional exclusive end index (defaults to `#s + 1`). + +**Return**: + +- `ok` (`boolean`): True when `s` ends with `suffix`. + +**Example**: + +```lua +ok = endswith("hello.lua", ".lua") --> true +``` + > [!NOTE] > > If suffix is a list, returns `true` when any suffix matches. -```lua -ok = endswith("hello.lua", ".lua") ---result: true -``` + -#### `expandtabs` +#### `expandtabs(s, tabsize?)` Expand tabs to spaces using given tabsize. +**Parameters**: + +- `s` (`string`): Input string. +- `tabsize?` (`integer`): Optional tab width (defaults to `8`). + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = expandtabs("a\tb", 4) ---result: "a b" +s = expandtabs("a\tb", 4) --> "a b" ``` -#### `find` + + +#### `find(s, sub, start?, stop?)` Return lowest index of substring or nil if not found. +**Parameters**: + +- `s` (`string`): Input string. +- `sub` (`string`): Substring to search. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional exclusive end index (defaults to `#s + 1`). + +**Return**: + +- `index` (`integer?`): First match index, or `nil` when not found. + +**Example**: + ```lua -i = find("hello", "ll") ---result: 3 +i = find("hello", "ll") --> 3 ``` -#### `format_map` + + +#### `format_map(s, mapping)` Format string with mapping (key-based) replacement. +**Parameters**: + +- `s` (`string`): Template string with `{key}` placeholders. +- `mapping` (`table`): Values used to replace placeholder keys. + +**Return**: + +- `s` (`string`): Formatted string with placeholders replaced. + +**Example**: + ```lua -s = format_map("hi {name}", { name = "bob" }) ---result: "hi bob" +s = format_map("hi {name}", { name = "bob" }) --> "hi bob" ``` +> [!NOTE] +> +> `format_map` is a lightweight `{key}` replacement helper. For richer +> templating, use +> [`mods.template`](https://luamod.github.io/mods/modules/template). + ### Predicates -#### `isalnum` + + +#### `isalnum(s)` Return true if all characters are alphanumeric and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are + alphanumeric. + +**Example**: + ```lua -ok = isalnum("abc123") ---result: true +ok = isalnum("abc123") --> true ``` > [!NOTE] @@ -182,16 +278,28 @@ ok = isalnum("abc123") > Lua letters are ASCII by default, so non-ASCII letters are not alphanumeric. > > ```lua -> isalnum("á1")` --> `false` +> isalnum("á1") --> false > ``` -#### `isalpha` + + +#### `isalpha(s)` Return true if all characters are alphabetic and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are + alphabetic. + +**Example**: + ```lua -ok = isalpha("abc") ---result: true +ok = isalpha("abc") --> true ``` > [!NOTE] @@ -199,329 +307,727 @@ ok = isalpha("abc") > Lua letters are ASCII by default, so non-ASCII letters are not alphabetic. > > ```lua -> isalpha("á")` --> `false` +> isalpha("á") --> false > ``` -#### `isascii` + + +#### `isascii(s)` + +Return true if all characters are ASCII. + +**Parameters**: -Return true if all characters are ASCII and string is non-empty. +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when all bytes in `s` are ASCII. + +**Example**: ```lua -ok = isascii("hello") ---result: true +ok = isascii("hello") --> true ``` > [!NOTE] > > The empty string returns `true`. -#### `isdecimal` + + +#### `isdecimal(s)` Return true if all characters are decimal characters and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are decimal + digits. + +**Example**: + ```lua -ok = isdecimal("123") ---result: true +ok = isdecimal("123") --> true ``` -#### `isdigit` + + +#### `isdigit(s)` Return true if all characters are digits and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are digits. + +**Example**: + ```lua -ok = isdigit("123") ---result: true +ok = isdigit("123") --> true ``` -#### `isidentifier` + + +#### `isidentifier(s)` Return true if string is a valid identifier and not a reserved keyword. -```lua -ok = isidentifier("foo_bar") ---result: true +**Parameters**: -ok = isidentifier("2var") ---result: false +- `s` (`string`): Input string. -ok = isidentifier("end") ---result: false (keyword) +**Return**: + +- `ok` (`boolean`): True when `s` is a valid identifier and not a keyword. + +**Example**: + +```lua +ok = isidentifier("foo_bar") --> true +ok = isidentifier("2var") --> false +ok = isidentifier("end") --> false (keyword) ``` -#### `islower` + + +#### `islower(s)` Return true if all cased characters are lowercase and there is at least one cased character. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` has at least one cased character and all are + lowercase. + +**Example**: + ```lua -ok = islower("hello") ---result: true +ok = islower("hello") --> true ``` -#### `isnumeric` + + +#### `isnumeric(s)` Return true if all characters are numeric and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are numeric. + +**Example**: + ```lua -ok = isnumeric("123") ---result: true +ok = isnumeric("123") --> true ``` -#### `isprintable` + -Return true if all characters are printable and string is non-empty. +#### `isprintable(s)` + +Return true if all characters are printable. + +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when all bytes in `s` are printable ASCII. + +**Example**: ```lua -ok = isprintable("abc!") ---result: true +ok = isprintable("abc!") --> true ``` > [!NOTE] > > The empty string returns `true`. -#### `isspace` + + +#### `isspace(s)` Return true if all characters are whitespace and string is non-empty. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is non-empty and all characters are + whitespace. + +**Example**: + ```lua -ok = isspace(" \t") ---result: true +ok = isspace(" \t") --> true ``` -#### `istitle` + + +#### `istitle(s)` Return true if string is titlecased. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` is titlecased. + +**Example**: + ```lua -ok = istitle("Hello World") ---result: true +ok = istitle("Hello World") --> true ``` -#### `isupper` + + +#### `isupper(s)` Return true if all cased characters are uppercase and there is at least one cased character. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `ok` (`boolean`): True when `s` has at least one cased character and all are + uppercase. + +**Example**: + ```lua -ok = isupper("HELLO") ---result: true +ok = isupper("HELLO") --> true ``` ### Layout -#### `join` + + +#### `join(sep, ls)` -Join an iterable of strings using this string as separator. +Join an array-like table of strings using this string as separator. + +**Parameters**: + +- `sep` (`string`): Separator value. +- `ls` (`string[]`): Table value. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: ```lua -s = join(",", { "a", "b", "c" }) ---result: "a,b,c" +s = join(",", { "a", "b", "c" }) --> "a,b,c" ``` -#### `ljust` + + +#### `ljust(s, width, fillchar?)` Left-justify string in a field of given width. +**Parameters**: + +- `s` (`string`): Input string. +- `width` (`integer`): Target width. +- `fillchar?` (`string`): Optional fill character. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = ljust("hi", 5, ".") ---result: "hi..." +s = ljust("hi", 5, ".") --> "hi..." ``` -#### `lower` + + +#### `lower(s)` Return lowercased copy. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = lower("HeLLo") ---result: "hello" +s = lower("HeLLo") --> "hello" ``` -#### `lstrip` + + +#### `lstrip(s, chars?)` Remove leading characters (default: whitespace). +**Parameters**: + +- `s` (`string`): Input string. +- `chars?` (`string`): Optional character set. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = lstrip(" hello") ---result: "hello" +s = lstrip(" hello") --> "hello" ``` -#### `rstrip` + + +#### `rstrip(s, chars?)` Remove trailing characters (default: whitespace). +**Parameters**: + +- `s` (`string`): Input string. +- `chars?` (`string`): Optional character set. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = rstrip("hello ") ---result: "hello" +s = rstrip("hello ") --> "hello" ``` -#### `strip` + + +#### `strip(s, chars?)` Remove leading and trailing characters (default: whitespace). +**Parameters**: + +- `s` (`string`): Input string. +- `chars?` (`string`): Optional character set. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = strip(" hello ") ---result: "hello" +s = strip(" hello ") --> "hello" ``` ### Split & Replace -#### `partition` + + +#### `partition(s, sep)` Partition string into head, sep, tail from left. +**Parameters**: + +- `s` (`string`): Input string. +- `sep` (`string`): Separator value. + +**Return**: + +- `head` (`string`): Part before the separator. +- `sep_found` (`string`): Matched separator, or empty string when not found. +- `tail` (`string`): Part after the separator. + +**Example**: + ```lua -a, b, c = partition("a-b-c", "-") ---result: "a", "-", "b-c" +a, b, c = partition("a-b-c", "-") --> "a", "-", "b-c" ``` -#### `removeprefix` + + +#### `removeprefix(s, prefix)` Remove prefix if present. +**Parameters**: + +- `s` (`string`): Input string. +- `prefix` (`string`): Prefix string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = removeprefix("foobar", "foo") ---result: "bar" +s = removeprefix("foobar", "foo") --> "bar" ``` -#### `removesuffix` + + +#### `removesuffix(s, suffix)` Remove suffix if present. +**Parameters**: + +- `s` (`string`): Input string. +- `suffix` (`string`): Suffix string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = removesuffix("foobar", "bar") ---result: "foo" +s = removesuffix("foobar", "bar") --> "foo" ``` -#### `replace` + + +#### `replace(s, old, new, count?)` Return a copy of the string with all occurrences of a substring replaced. +**Parameters**: + +- `s` (`string`): Input string. +- `old` (`string`): Substring to replace. +- `new` (`string`): Replacement string. +- `count?` (`integer`): Optional maximum replacement count. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = replace("a-b-c", "-", "_", 1) ---result: "a_b-c" +s = replace("a-b-c", "-", "_", 1) --> "a_b-c" ``` -#### `rfind` + + +#### `rfind(s, sub, start?, stop?)` Return highest index of substring or nil if not found. +**Parameters**: + +- `s` (`string`): Input string. +- `sub` (`string`): Substring to search. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional inclusive end index (defaults to `#s`). + +**Return**: + +- `index` (`integer?`): Last match index, or `nil` when not found. + +**Example**: + ```lua -i = rfind("ababa", "ba") ---result: 4 +i = rfind("ababa", "ba") --> 4 ``` -#### `rindex` + + +#### `rindex(s, sub, start?, stop?)` + +Like `rfind` but raises an error when the substring is not found. -Like rfind but raises on failure (placeholder). +**Parameters**: + +- `s` (`string`): Input string. +- `sub` (`string`): Substring to search. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional inclusive end index (defaults to `#s`). + +**Return**: + +- `index` (`integer`): Computed numeric value. + +**Example**: ```lua -i = rindex("ababa", "ba") ---result: 4 +i = rindex("ababa", "ba") --> 4 ``` -#### `rjust` + + +#### `rjust(s, width, fillchar?)` Right-justify string in a field of given width. +**Parameters**: + +- `s` (`string`): Input string. +- `width` (`integer`): Target width. +- `fillchar?` (`string`): Optional fill character. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = rjust("hi", 5, ".") ---result: "...hi" +s = rjust("hi", 5, ".") --> "...hi" ``` -#### `rpartition` + + +#### `rpartition(s, sep)` Partition string into head, sep, tail from right. +**Parameters**: + +- `s` (`string`): Input string. +- `sep` (`string`): Separator value. + +**Return**: + +- `head` (`string`): Part before the separator. +- `sep_found` (`string`): Matched separator, or empty string when not found. +- `tail` (`string`): Part after the separator. + +**Example**: + ```lua -a, b, c = rpartition("a-b-c", "-") ---result: "a-b", "-", "c" +a, b, c = rpartition("a-b-c", "-") --> "a-b", "-", "c" ``` -#### `rsplit` + + +#### `rsplit(s, sep?, maxsplit?)` Split from the right by separator, up to maxsplit. +**Parameters**: + +- `s` (`string`): Input string. +- `sep?` (`string`): Optional separator value. +- `maxsplit?` (`integer`): Optional maximum number of splits. + +**Return**: + +- `parts` (`mods.List`): Split parts. + +**Example**: + ```lua -parts = rsplit("a,b,c", ",", 1) ---result: { "a,b", "c" } +parts = rsplit("a,b,c", ",", 1) --> { "a,b", "c" } ``` -#### `split` + + +#### `split(s, sep?, maxsplit?)` Split by separator (or whitespace) up to maxsplit. +**Parameters**: + +- `s` (`string`): Input string. +- `sep?` (`string`): Optional separator value. +- `maxsplit?` (`integer`): Optional maximum number of splits. + +**Return**: + +- `parts` (`mods.List`): Split parts. + +**Example**: + ```lua -parts = split("a,b,c", ",") ---result: { "a", "b", "c" } +parts = split("a,b,c", ",") --> { "a", "b", "c" } ``` -#### `splitlines` + + +#### `splitlines(s, keepends?)` Split on line boundaries. +**Parameters**: + +- `s` (`string`): Input string. +- `keepends?` (`boolean`): Optional whether to keep line endings. + +**Return**: + +- `lines` (`mods.List`): Split lines. + +**Example**: + ```lua -lines = splitlines("a\nb\r\nc") ---result: { "a", "b", "c" } +lines = splitlines("a\nb\r\nc") --> { "a", "b", "c" } ``` ### Casing & Transform -#### `swapcase` + + +#### `swapcase(s)` Return a copy with case of alphabetic characters swapped. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = swapcase("AbC") ---result: "aBc" +s = swapcase("AbC") --> "aBc" ``` -#### `startswith` + + +#### `startswith(s, prefix, start?, stop?)` Return true if string starts with prefix. +**Parameters**: + +- `s` (`string`): Input string. +- `prefix` (`string|string[]`): Prefix string. +- `start?` (`integer`): Optional start index (defaults to `1`). +- `stop?` (`integer`): Optional exclusive end index (defaults to `#s + 1`). + +**Return**: + +- `ok` (`boolean`): True when `s` starts with `prefix`. + +**Example**: + +```lua +ok = startswith("hello.lua", "he") --> true +``` + > [!NOTE] > > If prefix is a list, returns `true` when any prefix matches. -```lua -ok = startswith("hello.lua", "he") ---result: true -``` + -#### `title` +#### `title(s)` Return titlecased copy. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = title("hello world") ---result: "Hello World" +s = title("hello world") --> "Hello World" ``` -#### `translate` + + +#### `translate(s, table_map)` Translate characters using a mapping table. +**Parameters**: + +- `s` (`string`): Input string. +- `table_map` (`table`): Character translation map. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua map = { [string.byte("a")] = "b", ["c"] = false } -s = translate("abc", map) ---result: "bb" +s = translate("abc", map) --> "bb" ``` -#### `upper` + + +#### `upper(s)` Return uppercased copy. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = upper("Hello") ---result: "HELLO" +s = upper("Hello") --> "HELLO" ``` -#### `zfill` + + +#### `zfill(s, width)` Pad numeric string on the left with zeros. +**Parameters**: + +- `s` (`string`): Input string. +- `width` (`integer`): Target width. + +**Return**: + +- `s` (`string`): Computed string value. + +**Example**: + ```lua -s = zfill("42", 5) ---result: "00042" +s = zfill("42", 5) --> "00042" ``` diff --git a/docs/src/modules/stringcase.md b/docs/src/modules/stringcase.md index aabbfe5..69c02ed 100644 --- a/docs/src/modules/stringcase.md +++ b/docs/src/modules/stringcase.md @@ -9,7 +9,7 @@ String case conversion helpers. ## Usage ```lua -sc = require "mods.stringcase" +stringcase = require "mods.stringcase" print(stringcase.snake("FooBar")) --> "foo_bar" ``` @@ -18,50 +18,74 @@ print(stringcase.snake("FooBar")) --> "foo_bar" **Basic**: -| Function | Description | -| ----------------- | -------------------------------- | -| [`lower`](#lower) | Convert string to all lowercase. | -| [`upper`](#upper) | Convert string to all uppercase. | +| Function | Description | +| ----------------------- | -------------------------------- | +| [`lower(s)`](#fn-lower) | Convert string to all lowercase. | +| [`upper(s)`](#fn-upper) | Convert string to all uppercase. | **Word Case**: -| Function | Description | -| ----------------------- | --------------------------------------------------------------------- | -| [`snake`](#snake) | Convert string to snake_case. | -| [`camel`](#camel) | Convert string to camelCase. | -| [`replace`](#replace) | Normalize to snake_case, then replace underscores with a separator. | -| [`acronym`](#acronym) | Get acronym of words in string (first letters only). | -| [`title`](#title) | Convert string to Title Case (first letter of each word capitalized). | -| [`constant`](#constant) | Convert string to CONSTANT_CASE (uppercase snake_case). | -| [`pascal`](#pascal) | Convert string to PascalCase. | -| [`kebab`](#kebab) | Convert string to kebab-case. | -| [`dot`](#dot) | Convert string to dot.case. | -| [`space`](#space) | Convert string to space case (spaces between words). | -| [`path`](#path) | Convert string to path/case (slashes between words). | +| Function | Description | +| --------------------------------- | --------------------------------------------------------------------- | +| [`snake(s)`](#fn-snake) | Convert string to snake_case. | +| [`camel(s)`](#fn-camel) | Convert string to camelCase. | +| [`replace(s, sep?)`](#fn-replace) | Normalize to snake_case, then replace underscores with a separator. | +| [`acronym(s)`](#fn-acronym) | Get acronym of words in string (first letters only). | +| [`title(s)`](#fn-title) | Convert string to Title Case (first letter of each word capitalized). | +| [`constant(s)`](#fn-constant) | Convert string to CONSTANT_CASE (uppercase snake_case). | +| [`pascal(s)`](#fn-pascal) | Convert string to PascalCase. | +| [`kebab(s)`](#fn-kebab) | Convert string to kebab-case. | +| [`dot(s)`](#fn-dot) | Convert string to dot.case. | +| [`space(s)`](#fn-space) | Convert string to space case (spaces between words). | +| [`path(s)`](#fn-path) | Convert string to path/case (slashes between words). | **Letter Case**: -| Function | Description | -| ----------------------- | ------------------------------------------------------------------------- | -| [`swap`](#swap) | Swap case of each letter. | -| [`capital`](#capital) | Capitalize the first letter and lowercase the rest. | -| [`sentence`](#sentence) | Convert string to sentence case (first letter uppercase, rest lowercase). | +| Function | Description | +| ----------------------------- | ------------------------------------------------------------------------- | +| [`swap(s)`](#fn-swap) | Swap case of each letter. | +| [`capital(s)`](#fn-capital) | Capitalize the first letter and lowercase the rest. | +| [`sentence(s)`](#fn-sentence) | Convert string to sentence case (first letter uppercase, rest unchanged). | ### Basic -#### `lower` + + +#### `lower(s)` Convert string to all lowercase. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Lowercased string. + +**Example**: + ```lua lower("foo_bar-baz") --> "foo_bar-baz" lower("FooBar baz") --> "foobar baz" ``` -#### `upper` + + +#### `upper(s)` Convert string to all uppercase. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Uppercased string. + +**Example**: + ```lua upper("foo_bar-baz") --> "FOO_BAR-BAZ" upper("FooBar baz") --> "FOOBAR BAZ" @@ -69,100 +93,233 @@ upper("FooBar baz") --> "FOOBAR BAZ" ### Word Case -#### `snake` + + +#### `snake(s)` Convert string to snake_case. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Snake-cased string. + +**Example**: + ```lua snake("foo_bar-baz") --> "foo_bar_baz" snake("FooBar baz") --> "foo_bar_baz" ``` -#### `camel` + + +#### `camel(s)` Convert string to camelCase. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Camel-cased string. + +**Example**: + ```lua camel("foo_bar-baz") --> "fooBarBaz" camel("FooBar baz") --> "fooBarBaz" ``` -#### `replace` + + +#### `replace(s, sep?)` Normalize to snake_case, then replace underscores with a separator. +**Parameters**: + +- `s` (`string`): Input string. +- `sep?` (`string`): Optional separator value (defaults to `""`). + +**Return**: + +- `s` (`string`): String with underscores replaced by `sep`. + +**Example**: + ```lua replace("foo_bar-baz", "-") --> "foo-bar-baz" replace("FooBar baz", "-") --> "foo-bar-baz" ``` -#### `acronym` + + +#### `acronym(s)` Get acronym of words in string (first letters only). +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Acronym string. + +**Example**: + ```lua acronym("foo_bar-baz") --> "FBB" acronym("FooBar baz") --> "FBB" ``` -#### `title` + + +#### `title(s)` Convert string to Title Case (first letter of each word capitalized). +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Title-cased string. + +**Example**: + ```lua title("foo_bar-baz") --> "Foo Bar Baz" title("FooBar baz") --> "Foo Bar Baz" ``` -#### `constant` + + +#### `constant(s)` Convert string to CONSTANT_CASE (uppercase snake_case). +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Constant-cased string. + +**Example**: + ```lua constant("foo_bar-baz") --> "FOO_BAR_BAZ" constant("FooBar baz") --> "FOO_BAR_BAZ" ``` -#### `pascal` + + +#### `pascal(s)` Convert string to PascalCase. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Pascal-cased string. + +**Example**: + ```lua pascal("foo_bar-baz") --> "FooBarBaz" pascal("FooBar baz") --> "FooBarBaz" ``` -#### `kebab` + + +#### `kebab(s)` Convert string to kebab-case. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Kebab-cased string. + +**Example**: + ```lua kebab("foo_bar-baz") --> "foo-bar-baz" kebab("FooBar baz") --> "foo-bar-baz" ``` -#### `dot` + + +#### `dot(s)` Convert string to dot.case. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Dot-cased string. + +**Example**: + ```lua dot("foo_bar-baz") --> "foo.bar.baz" dot("FooBar baz") --> "foo.bar.baz" ``` -#### `space` + + +#### `space(s)` Convert string to space case (spaces between words). +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Space-cased string. + +**Example**: + ```lua space("foo_bar-baz") --> "foo bar baz" space("FooBar baz") --> "foo bar baz" ``` -#### `path` + + +#### `path(s)` Convert string to path/case (slashes between words). +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Path-cased string. + +**Example**: + ```lua path("foo_bar-baz") --> "foo/bar/baz" path("FooBar baz") --> "foo/bar/baz" @@ -170,27 +327,63 @@ path("FooBar baz") --> "foo/bar/baz" ### Letter Case -#### `swap` + + +#### `swap(s)` Swap case of each letter. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Swap-cased string. + +**Example**: + ```lua swap("foo_bar-baz") --> "FOO_BAR-BAZ" swap("FooBar baz") --> "fOObAR BAZ" ``` -#### `capital` + + +#### `capital(s)` Capitalize the first letter and lowercase the rest. +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Capitalized string. + +**Example**: + ```lua capital("foo_bar-baz") --> "Foo_bar-baz" capital("FooBar baz") --> "Foobar baz" ``` -#### `sentence` + + +#### `sentence(s)` + +Convert string to sentence case (first letter uppercase, rest unchanged). + +**Parameters**: + +- `s` (`string`): Input string. + +**Return**: + +- `s` (`string`): Sentence-cased string. -Convert string to sentence case (first letter uppercase, rest lowercase). +**Example**: ```lua sentence("foo_bar-baz") --> "Foo_bar-baz" diff --git a/docs/src/modules/tbl.md b/docs/src/modules/tbl.md index fb53980..1e8128d 100644 --- a/docs/src/modules/tbl.md +++ b/docs/src/modules/tbl.md @@ -18,177 +18,375 @@ print(tbl.count({ a = 1, b = 2 })) --> 2 **Basics**: -| Function | Description | -| ----------------- | --------------------------------------- | -| [`clear`](#clear) | Remove all entries from the table. | -| [`count`](#count) | Return the number of keys in the table. | +| Function | Description | +| ----------------------- | --------------------------------------- | +| [`clear(t)`](#fn-clear) | Remove all entries from the table. | +| [`count(t)`](#fn-count) | Return the number of keys in the table. | **Copying**: -| Function | Description | -| ----------------------- | ----------------------------------- | -| [`copy`](#copy) | Create a shallow copy of the table. | -| [`deepcopy`](#deepcopy) | Create a deep copy of a value. | +| Function | Description | +| ----------------------------- | ----------------------------------- | +| [`copy(t)`](#fn-copy) | Create a shallow copy of the table. | +| [`deepcopy(v)`](#fn-deepcopy) | Create a deep copy of a value. | **Query**: -| Function | Description | -| --------------------- | ------------------------------------------------------ | -| [`filter`](#filter) | Filter entries by a value predicate. | -| [`find`](#find) | Find the first key whose value equals the given value. | -| [`find_if`](#find-if) | Find first value and key matching predicate. | -| [`get`](#get) | Safely get nested value by keys. | +| Function | Description | +| --------------------------------- | ---------------------------------------------------------------- | +| [`filter(t, pred)`](#fn-filter) | Filter entries by a value predicate. | +| [`find(t, v)`](#fn-find) | Find the first key whose value equals the given value. | +| [`same(a, b)`](#fn-same) | Return `true` if two tables have the same keys and equal values. | +| [`find_if(t, pred)`](#fn-find-if) | Find first value and key matching predicate. | +| [`get(t, ...)`](#fn-get) | Safely get nested value by keys. | +| [`keypath(...)`](#fn-keypath) | Format a key chain as a Lua-like table access path. | **Transforms**: -| Function | Description | -| --------------------- | ---------------------------------------------------------- | -| [`invert`](#invert) | Invert keys/values into new table. | -| [`isempty`](#isempty) | Return true if table has no entries. | -| [`keys`](#keys) | Return a list of all keys in the table. | -| [`map`](#map) | Return a new table by mapping each value (keys preserved). | -| [`pairmap`](#pairmap) | Return a new table by mapping each key-value pair. | -| [`update`](#update) | Merge entries from `t2` into `t1` and return `t1`. | -| [`values`](#values) | Return a list of all values in the table. | +| Function | Description | +| ------------------------------- | ---------------------------------------------------------- | +| [`invert(t)`](#fn-invert) | Invert keys/values into new table. | +| [`isempty(t)`](#fn-isempty) | Return true if table has no entries. | +| [`keys(t)`](#fn-keys) | Return a list of all keys in the table. | +| [`map(t, fn)`](#fn-map) | Return a new table by mapping each value (keys preserved). | +| [`pairmap(t, fn)`](#fn-pairmap) | Return a new table by mapping each key-value pair. | +| [`update(t1, t2)`](#fn-update) | Merge entries from `t2` into `t1` and return `t1`. | +| [`values(t)`](#fn-values) | Return a list of all values in the table. | ### Basics -Core table utilities for clearing and counting. +Core table utilities for clearing and counting. -#### `clear` +#### `clear(t)` Remove all entries from the table. +**Parameters**: + +- `t` (`table`): Target table. + +**Return**: + +- `none` (`nil`) + +**Example**: + ```lua t = { a = 1, b = 2 } clear(t) --> t = {} ``` -#### `count` + + +#### `count(t)` Return the number of keys in the table. +**Parameters**: + +- `t` (`table`): Input table. + +**Return**: + +- `count` (`integer`): Number of keys in `t`. + +**Example**: + ```lua n = count({ a = 1, b = 2 }) --> 2 ``` ### Copying -Shallow and deep copy helpers. +Shallow and deep copy helpers. -#### `copy` +#### `copy(t)` Create a shallow copy of the table. +**Parameters**: + +- `t` (`T`): Source table. + +**Return**: + +- `copy` (`T`): Shallow-copied table. + +**Example**: + ```lua t = copy({ a = 1, b = 2 }) --> { a = 1, b = 2 } ``` -#### `deepcopy` + + +#### `deepcopy(v)` Create a deep copy of a value. -> [!NOTE] -> -> If `v` is a table, all nested tables are copied recursively; other types are -> returned as-is. +**Parameters**: + +- `v` (`T`): Input value. + +**Return**: + +- `copy` (`T`): Deep-copied value. + +**Example**: ```lua t = deepcopy({ a = { b = 1 } }) --> { a = { b = 1 } } n = deepcopy(42) --> 42 ``` +> [!NOTE] +> +> If `v` is a table, all nested tables are copied recursively; other types are +> returned as-is. + ### Query -Read-only lookup and selection helpers. +Read-only lookup and selection helpers. -#### `filter` +#### `filter(t, pred)` Filter entries by a value predicate. +**Parameters**: + +- `t` (`table`): Input table. +- `pred` (`fun(v:any):boolean`): Value predicate. + +**Return**: + +- `filtered` (`table`): Table containing entries where `pred(v)` is true. + +**Example**: + ```lua even = filter({ a = 1, b = 2, c = 3 }, function(v) return v % 2 == 0 end) --> { b = 2 } ``` -#### `find` + + +#### `find(t, v)` Find the first key whose value equals the given value. +**Parameters**: + +- `t` (`{[T1]:T2}`): Input table. +- `v` (`T2`): Value to find. + +**Return**: + +- `key` (`T1?`): First matching key, or `nil` when not found. + +**Example**: + ```lua key = find({ a = 1, b = 2, c = 2 }, 2) --> "b" or "c" ``` -#### `find_if` + + +#### `same(a, b)` + +Return `true` if two tables have the same keys and equal values. + +**Parameters**: + +- `a` (`table`): Left table. +- `b` (`table`): Right table. + +**Return**: + +- `ok` (`boolean`): True when both tables have the same keys and values. + +**Example**: + +```lua +ok = same({ a = 1, b = 2 }, { b = 2, a = 1 }) --> true +ok = same({ a = {} }, { a = {} }) --> false +``` + + + +#### `find_if(t, pred)` Find first value and key matching predicate. +**Parameters**: + +- `t` (`table`): Input table. +- `pred` (`fun(v:T1,k:T2):boolean`): Predicate function. + +**Return**: + +- `v` (`T1?`): First matching value, or `nil` when not found. +- `k` (`T2?`): Key for the first matching value, or `nil` when not found. + +**Example**: + ```lua v, k = find_if({ a = 1, b = 2 }, function(v, k) return k == "b" and v == 2 end) --> 2, "b" ``` -#### `get` + + +#### `get(t, ...)` Safely get nested value by keys. +**Parameters**: + +- `t` (`table`): Root table. +- `...` (`any`): Additional arguments. + +**Return**: + +- `value` (`any`): Nested value, or `nil` when any key is missing. + +**Example**: + ```lua t = { a = { b = { c = 1 } } } v1 = get(t, "a", "b", "c") --> 1 -v2 = get(t) --> { a = { b = { c = 1 } } } +v2 = get(t) --> { a = { b = { c = 1 } } } ``` > [!NOTE] > > If no keys are provided, returns the input table. + + +#### `keypath(...)` + +Format a key chain as a Lua-like table access path. + +**Parameters**: + +- `...` (`any`): Additional arguments. + +**Return**: + +- `path` (`string`): Rendered key path. + +**Example**: + +```lua +p1 = keypath("t", "a", "b", "c") --> "t.a.b.c" +p2 = keypath("ctx", "users", 1, "name") --> "ctx.users[1].name" +p3 = keypath("ctx", "invalid-key") --> 'ctx["invalid-key"]' +p4 = keypath() --> "" +``` + ### Transforms -Table transformation and conversion utilities. +Table transformation and conversion utilities. -#### `invert` +#### `invert(t)` Invert keys/values into new table. +**Parameters**: + +- `t` (`{[T1]:T2}`): Input table. + +**Return**: + +- `inverted` (`{[T2]:T1}`): Inverted table (`value -> key`). + +**Example**: + ```lua t = invert({ a = 1, b = 2 }) --> { [1] = "a", [2] = "b" } ``` -#### `isempty` + + +#### `isempty(t)` Return true if table has no entries. +**Parameters**: + +- `t` (`table`): Input table. + +**Return**: + +- `ok` (`boolean`): True when `t` has no entries. + +**Example**: + ```lua empty = isempty({}) --> true ``` -#### `keys` + + +#### `keys(t)` Return a list of all keys in the table. +**Parameters**: + +- `t` (`{[T]:any}`): Input table. + +**Return**: + +- `keys` (`mods.List`): List of keys in `t`. + +**Example**: + ```lua keys = keys({ a = 1, b = 2 }) --> { "a", "b" } ``` -#### `map` + + +#### `map(t, fn)` Return a new table by mapping each value (keys preserved). +**Parameters**: + +- `t` (`{[T1]:T2}`): Input table. +- `fn` (`fun(v:T2):T3`): Mapping function. + +**Return**: + +- `mapped` (`{[T1]:T3}`): New table with mapped values. + +**Example**: + ```lua t = map({ a = 1, b = 2 }, function(v) return v * 10 end) --> { a = 10, b = 20 } ``` -#### `pairmap` + + +#### `pairmap(t, fn)` Return a new table by mapping each key-value pair. -> [!NOTE] -> -> Output keeps original keys; only values are transformed by `fn`. +**Parameters**: + +- `t` (`{[T1]:T2}`): Input table. +- `fn` (`fun(k:T1,`): v:T2):T3 Key-value mapping function. + +**Return**: + +- `mapped` (`{[T1]:T3}`): New table with mapped values. + +**Example**: ```lua t = pairmap({ a = 1, b = 2 }, function(k, v) @@ -196,19 +394,48 @@ t = pairmap({ a = 1, b = 2 }, function(k, v) end) --> { a = "a1", b = "b2" } ``` -#### `update` +> [!NOTE] +> +> Output keeps original keys; only values are transformed by `fn`. + + + +#### `update(t1, t2)` Merge entries from `t2` into `t1` and return `t1`. +**Parameters**: + +- `t1` (`T`): Target table. +- `t2` (`table`): Source table. + +**Return**: + +- `t1` (`T`): Updated `t1` table. + +**Example**: + ```lua t1 = { a = 1, b = 2 } update(t1, { b = 3, c = 4 }) --> t1 is { a = 1, b = 3, c = 4 } ``` -#### `values` + + +#### `values(t)` Return a list of all values in the table. +**Parameters**: + +- `t` (`{[any]:T}`): Input table. + +**Return**: + +- `values` (`mods.List`): List of values in `t`. + +**Example**: + ```lua vals = values({ a = 1, b = 2 }) --> { 1, 2 } ``` diff --git a/docs/src/modules/template.md b/docs/src/modules/template.md index a95234f..407ffb3 100644 --- a/docs/src/modules/template.md +++ b/docs/src/modules/template.md @@ -1,13 +1,10 @@ --- -desc: - "Render lightweight templates with dot-path placeholders and function-aware - values." +desc: "Interpolate string placeholders of the form {{." --- # `template` -Render lightweight templates with dot-path placeholders and function-aware -values. +Interpolate string placeholders of the form {{...}}. ## Usage @@ -15,76 +12,113 @@ values. template = require "mods.template" view = { - user = { name = "World" }, + user = { name = "Ada" }, } -out = template("Hello {{user.name}}!", view) --> "Hello World!" +out = template("Hello {{user.name}}!", view) --> "Hello Ada!" ``` -## Rules + -- Placeholders use {{name}}. +## `template(tmpl, view)` -```lua -template("Hi {{name}}", { name = "Ada" }) --> "Hi Ada" -``` +Render string templates with {{...}} placeholders. -- Whitespace inside placeholders is ignored. +**Parameters**: -```lua -template("Hi {{ name }}", { name = "Ada" }) --> "Hi Ada" -``` +- `tmpl` (`string`): Template string with placeholders. +- `view` (`table`): Input data used to resolve placeholders. + +**Return**: -- Dot paths are supported. +- `out` (`string`): Rendered output string. + +**Example**: ```lua -template("Role: {{user.meta.role}}", { - user = { meta = { role = "Engineer" } }, -}) --> "Role: Engineer" +view = { subject = "World" } +template("Hello {{subject}}", view) --> "Hello World" ``` -- {{.}} resolves to the whole `view`. +> [!NOTE] +> +> Whitespace inside placeholders is ignored. +> +> ```lua +> template("Hi {{ name }}", { name = "Ada" }) --> "Hi Ada" +> ``` + +## Dot Paths + +Use dot notation to access nested values in `view`. ```lua -template("Value: {{.}}", 123) --> "Value: 123" +view = { user = { meta = { role = "Engineer" } } } +template("Role: {{user.meta.role}}", view) --> "Role: Engineer" ``` -- Function values are called and their return value is rendered. +> [!NOTE] +> +> {{.}} renders the entire root `view` table, not a nested +> field. +> +> ```lua +> template("View: {{.}}", { value = 123 }) +> --> View: { +> -- value = 123 +> -- } +> ``` + +## Function Values + +If a placeholder resolves to a function, that function is called and its result +is rendered. ```lua -template("Hi {{name_func}}", { name_func = function() return "Ada" end }) ---> "Hi Ada" +view = { name_func = function() return "Ada" end } +template("Hi {{name_func}}", view) --> "Hi Ada" ``` -- Table values render as first-depth key/value pairs. String values are quoted; - nested tables/functions are summarized. +> [!NOTE] +> +> If the function returns `nil`, the placeholder renders as an empty string. + +## Table Values + +Table placeholders are rendered using +[`mods.repr`](https://luamod.github.io/mods/modules/repr). ```lua -template("Data: {{data}}", { data = { a = 1, b = true } }) ---> { --- a = 1, --- b = true +view = { data = { a = 1, b = true } } +template("Data: {{data}}", view) +--> Data: { +-- a = 1, +-- b = true -- } ``` -- Missing keys render as an empty string. +## Missing and Invalid Placeholders + +Missing keys render as an empty string. ```lua -template("Missing: {{unknown}}", {}) --> "Missing: " +view = {} +template("Missing: {{unknown}}", view) --> "Missing: " ``` -- If a tag is not closed ({{name), it is emitted as-is. +Invalid placeholder names render as an empty string (for example: +{{..}}, {{.name}}, +{{user.}}, {{user..name}}). ```lua -template("Hi {{name", { name = "Ada" }) --> "Hi {{name" +view = { user = { name = "Ada" } } +template("Bad: {{user..name}}", view) --> "Bad: " ``` -- `template(view)` is shorthand for template("{{.}}", view). +If a placeholder is not closed ({{unclosed), it is emitted +as-is. ```lua -template({ a = 1, b = true }) ---> { --- a = 1, --- b = true --- } +view = { name = "Ada" } +template("Hi {{name", view) --> "Hi {{name" ``` diff --git a/docs/src/modules/utils.md b/docs/src/modules/utils.md index 8ff5de7..4fa475d 100644 --- a/docs/src/modules/utils.md +++ b/docs/src/modules/utils.md @@ -16,16 +16,30 @@ print(utils.quote('hello "world"')) --> 'hello "world"' ## Functions -### `quote` + + +### `quote(v)` Smart-quote a string for readable Lua-like output. +**Parameters**: + +- `v` (`string`) + +**Return**: + +- `out` (`string`) + +**Example**: + ```lua print(utils.quote('He said "hi"')) -- 'He said "hi"' print(utils.quote('say "hi" and \\'bye\\'')) -- "say \"hi\" and 'bye'" ``` -### `repr` + + +### `repr(v)` Render any Lua value as a string. @@ -35,6 +49,16 @@ Render any Lua value as a string. > otherwise falls back to > [`mods.repr`](https://luamod.github.io/mods/modules/repr). +**Parameters**: + +- `v` (`any`) + +**Return**: + +- `out` (`string`) + +**Example**: + ```lua print(utils.repr({ a = 1 })) --> { -- a = 1 diff --git a/docs/src/modules/validate.md b/docs/src/modules/validate.md index 33d7f18..d6dbf4a 100644 --- a/docs/src/modules/validate.md +++ b/docs/src/modules/validate.md @@ -8,565 +8,668 @@ Validation checks for values and filesystem path types. ## Usage -```lua [.lua] -validate= require "mods.validate" - -ok, err = validate.is.number("nope") ---> false, "expected number, got string" +```lua +local validate = require "mods.validate" -ok, err = validate.is_not.number(3.14) ---> false, "expected not number" +ok, err = validate.number("nope") --> false, "expected number, got string" +ok, err = validate(123, "number") --> true, nil ``` -> [!IMPORTANT] -> -> Behavior without `tp`: -> -> - `validate()` is equivalent to `validate(nil, "nil")` (passes) -> - `validate(1)` is equivalent to `validate(1, "nil")` (fails with -> `expected nil, got number`) -> -> Validator access is case-insensitive: -> -> - `validate.is.number` and `validate.IS.Number` are equivalent. -> - Top-level aliases are underscore-insensitive: `validate.is_number`, -> `validate.IS_NUMBER`, and `validate.isnumber`. -> - Negated validators are available via `is_not`, `isnot`, `isNot`, `not`, and -> `Not`, including underscore-insensitive top-level aliases (for example, -> `validate.is_not_number` and `validate.isnotnumber`). - -## Dependencies +## `validate()` -Dependencies below are lazy-loaded 💤 on first access. - -- [`lfs`](https://github.com/lunarmodules/luafilesystem) (optional; required - only for filesystem/path checks) -- [`mods.is`](https://luamod.github.io/mods/modules/is) - -## Callable Forms - -`validate`, `validate.is`, and `validate.is_not` are all callable. +`validate(v, tp)` dispatches to the registered validator `tp`. If `tp` is +omitted, it defaults to `"truthy"`. ```lua -ok, err = validate(1, "number") --> true, nil -ok, err = validate.is("x", "string") --> true, nil -ok, err = validate.is_not(1, "number") --> false, "expected not number" +validate() --> false, "expected truthy value, got no value" +validate(1) --> true, nil +validate(1, "nil") --> false, "expected nil, got number" ``` -> [!IMPORTANT] -> -> When `tp` is omitted, the default check is `"nil"`: -> -> - `validate()` is equivalent to `validate(nil, "nil")` (passes) -> - `validate(1)` is equivalent to `validate(1, "nil")` (fails) -> -> Callable namespace aliases are case-insensitive, and negated aliases are -> underscore-insensitive: -> -> - `validate.is`, `validate.IS` -> - `validate.is_not`, `validate.isnot`, `validate.isNot`, `validate["not"]`, -> `validate.Not` -> -> ```lua -> validate.is(1, "number") --> true -> validate.IS(1, "number") --> true -> validate.is_not(1, "number") --> false, "expected not number" -> validate.Not(1, "number") --> false, "expected not number" -> ``` - -## Custom Messages - -Customize validator error messages through `validate.messages`. - -- `validate.messages.positive.` customizes positive checks -- `validate.messages.negative.` customizes negated checks - -`` is the validator key (for example: `number`, `string`, `truthy`, -`integer`, `callable`, `file`, `dir`, etc.). - -Available placeholders: - -- {{expected}}: The check target (for example `number`, - `string`, `truthy`). -- {{got}}: The detected failure kind (usually a Lua type; - path validators use `invalid path`). -- {{value}}: The passed value, formatted for display (strings - are quoted). +## Validator Names -### Example +Validator names are case-insensitive for field access. ```lua -validate.messages.positive.number = "need {{expected}}, got {{got}} (value={{value}})" -validate.messages.negative.number = "must not be {{expected}} (value={{value}})" - -ok, err = validate.is.number("x") ---> false, 'need number, got string (value="x")' - -ok, err = validate.is_not.number(42) ---> false, "must not be number (value=42)" +validate.number(1) --> true, nil +validate.NumBer(1) --> true, nil ``` -## Default Messages - -By default, validate uses built-in templates unless -`validate.messages.positive.` or `validate.messages.negative.` is -overridden: - -- Positive type/value checks (`validate.is.*`): - `expected {{expected}}, got {{got}}` -- Positive path checks (`validate.is.block`, `char`, `device`, `dir`, `fifo`, - `file`, `link`, `socket`): `{{value}} is not a valid {{expected}} path` -- Negative checks (`validate.is_not.*`): `expected not {{expected}}` - -`integer` uses a more specific default that includes the passed value: - -- Positive `integer`: `expected integer, got {{value}}` -- Negative `integer`: `expected non-integer, got {{value}}` - -## On Fail Hook - -Set `validate.on_fail` to handle failed validations globally. - -- If `on_fail` is set, it is called with the rendered error message. -- If `on_fail` returns a truthy value, that value is used as the returned error. -- If `on_fail` returns a falsy value, the default rendered error is returned. -- If `on_fail` is `nil`, validators return `false, err` as usual. +`tp` in `validate(v, tp)` is matched as-is (case-sensitive): ```lua -validate.on_fail = function(errmsg) - print("validation failed:", errmsg) - return "custom failure" -end - -ok, err = validate.number("x") ---> prints -> validation failed: expected number, got string ---> false, "custom failure" +validate(1, "number") --> true, nil +validate(1, "NuMbEr") --> false, "expected NuMbEr, got number" ``` ## Functions **Type Checks**: -| Function | Description | -| ------------------------------- | ---------------------------------------------------------------------------------------------- | -| [`boolean`](#boolean) | Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. | -| [`function`](#function) | Returns `true` when `v` is a function. Otherwise returns `false` and an error message. | -| [`nil`](#nil) | Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. | -| [`number`](#number) | Returns `true` when `v` is a number. Otherwise returns `false` and an error message. | -| [`string`](#string) | Returns `true` when `v` is a string. Otherwise returns `false` and an error message. | -| [`table`](#table) | Returns `true` when `v` is a table. Otherwise returns `false` and an error message. | -| [`thread`](#thread) | Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. | -| [`userdata`](#userdata) | Returns `true` when `v` is userdata. Otherwise returns `false` and an error message. | -| [`not_boolean`](#not-boolean) | Returns `true` when `v` is **not** a boolean. Otherwise returns `false` and an error message. | -| [`not_function`](#not-function) | Returns `true` when `v` is **not** a function. Otherwise returns `false` and an error message. | -| [`not_nil`](#not-nil) | Returns `true` when `v` is **not** `nil`. Otherwise returns `false` and an error message. | -| [`not_number`](#not-number) | Returns `true` when `v` is **not** a number. Otherwise returns `false` and an error message. | -| [`not_string`](#not-string) | Returns `true` when `v` is **not** a string. Otherwise returns `false` and an error message. | -| [`not_table`](#not-table) | Returns `true` when `v` is **not** a table. Otherwise returns `false` and an error message. | -| [`not_thread`](#not-thread) | Returns `true` when `v` is **not** a thread. Otherwise returns `false` and an error message. | -| [`not_userdata`](#not-userdata) | Returns `true` when `v` is **not** userdata. Otherwise returns `false` and an error message. | +| Function | Description | +| ----------------------------- | -------------------------------------------------------------------------------------------- | +| [`boolean(v)`](#fn-boolean) | Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. | +| [`function(v)`](#fn-function) | Returns `true` when `v` is a function. Otherwise returns `false` and an error message. | +| [`nil(v)`](#fn-nil) | Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. | +| [`number(v)`](#fn-number) | Returns `true` when `v` is a number. Otherwise returns `false` and an error message. | +| [`string(v)`](#fn-string) | Returns `true` when `v` is a string. Otherwise returns `false` and an error message. | +| [`table(v)`](#fn-table) | Returns `true` when `v` is a table. Otherwise returns `false` and an error message. | +| [`thread(v)`](#fn-thread) | Returns `true` when `v` is a thread. Otherwise returns `false` and an error message. | +| [`userdata(v)`](#fn-userdata) | Returns `true` when `v` is a userdata value. Otherwise returns `false` and an error message. | **Value Checks**: -| Function | Description | -| ------------------------------- | --------------------------------------------------------------------------------------------------- | -| [`false`](#false) | Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. | -| [`true`](#true) | Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. | -| [`falsy`](#falsy) | Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. | -| [`callable`](#callable) | Returns `true` when `v` is callable. Otherwise returns `false` and an error message. | -| [`integer`](#integer) | Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. | -| [`truthy`](#truthy) | Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. | -| [`not_false`](#not-false) | Returns `true` when `v` is **not** exactly `false`. Otherwise returns `false` and an error message. | -| [`not_true`](#not-true) | Returns `true` when `v` is **not** exactly `true`. Otherwise returns `false` and an error message. | -| [`not_falsy`](#not-falsy) | Returns `true` when `v` is **not** falsy. Otherwise returns `false` and an error message. | -| [`not_callable`](#not-callable) | Returns `true` when `v` is **not** callable. Otherwise returns `false` and an error message. | -| [`not_integer`](#not-integer) | Returns `true` when `v` is **not** an integer. Otherwise returns `false` and an error message. | -| [`not_truthy`](#not-truthy) | Returns `true` when `v` is **not** truthy. Otherwise returns `false` and an error message. | +| Function | Description | +| ----------------------------- | ------------------------------------------------------------------------------------------- | +| [`false(v)`](#fn-false) | Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. | +| [`true(v)`](#fn-true) | Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. | +| [`falsy(v)`](#fn-falsy) | Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. | +| [`callable(v)`](#fn-callable) | Returns `true` when `v` is callable. Otherwise returns `false` and an error message. | +| [`integer(v)`](#fn-integer) | Returns `true` when `v` is an integer. Otherwise returns `false` and an error message. | +| [`truthy(v)`](#fn-truthy) | Returns `true` when `v` is truthy. Otherwise returns `false` and an error message. | **Path Checks**: -| Function | Description | -| ------------------- | ------------------------------------------------------------------------------------------------------- | -| [`block`](#block) | Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. | -| [`char`](#char) | Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. | -| [`device`](#device) | Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. | -| [`dir`](#dir) | Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. | -| [`fifo`](#fifo) | Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. | -| [`file`](#file) | Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. | -| [`link`](#link) | Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. | -| [`socket`](#socket) | Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. | +| Function | Description | +| ------------------------- | ------------------------------------------------------------------------------------------------------- | +| [`block(v)`](#fn-block) | Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. | +| [`char(v)`](#fn-char) | Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. | +| [`device(v)`](#fn-device) | Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. | +| [`dir(v)`](#fn-dir) | Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. | +| [`fifo(v)`](#fn-fifo) | Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. | +| [`file(v)`](#fn-file) | Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. | +| [`link(v)`](#fn-link) | Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. | +| [`socket(v)`](#fn-socket) | Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. | + +**Validator API**: + +| Function | Description | +| --------------------------------------------- | -------------------------------------------------- | +| [`register(name, check, msg?)`](#fn-register) | Register or override a validator function by name. | ### Type Checks -Basic Lua type validators (and their negated variants). +Basic Lua type validators (and their negated variants). -#### `boolean` +#### `boolean(v)` Returns `true` when `v` is a boolean. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.boolean(true) --> true, nil -ok, err = validate.is.boolean(1) --> false, "expected boolean, got number" +ok, err = validate.boolean(true) --> true, nil +ok, err = validate.boolean(1) --> false, "expected boolean, got number" ``` -#### `function` + + +#### `function(v)` Returns `true` when `v` is a function. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.Function(function() end) --> true, nil -ok, err = validate.is.Function(1) +ok, err = validate.Function(function() end) --> true, nil +ok, err = validate.Function(1) --> false, "expected function, got number" ``` -#### `nil` + + +#### `nil(v)` Returns `true` when `v` is `nil`. Otherwise returns `false` and an error message. -```lua -ok, err = validate.is.Nil(nil) --> true, nil -ok, err = validate.is.Nil(0) --> false, "expected nil, got number" -``` - -#### `number` +**Parameters**: -Returns `true` when `v` is a number. Otherwise returns `false` and an error -message. +- `v` (`any`): Value to validate. -```lua -ok, err = validate.is.number(42) --> true, nil -ok, err = validate.is.number("x") --> false, "expected number, got string" -``` +**Return**: -#### `string` +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. -Returns `true` when `v` is a string. Otherwise returns `false` and an error -message. +**Example**: ```lua -ok, err = validate.is.string("hello") --> true, nil -ok, err = validate.is.string(1) --> false, "expected string, got number" +ok, err = validate.Nil(nil) --> true, nil +ok, err = validate.Nil(0) --> false, "expected nil, got number" ``` -#### `table` + -Returns `true` when `v` is a table. Otherwise returns `false` and an error +#### `number(v)` + +Returns `true` when `v` is a number. Otherwise returns `false` and an error message. -```lua -ok, err = validate.is.table({}) --> true, nil -ok, err = validate.is.table(1) --> false, "expected table, got number" -``` +**Parameters**: -#### `thread` +- `v` (`any`): Value to validate. -Returns `true` when `v` is a thread. Otherwise returns `false` and an error -message. +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: ```lua -co = coroutine.create(function() end) -ok, err = validate.is.thread(co) --> true, nil -ok, err = validate.is.thread(1) --> false, "expected thread, got number" +ok, err = validate.number(42) --> true, nil +ok, err = validate.number("x") --> false, "expected number, got string" ``` -#### `userdata` + -Returns `true` when `v` is userdata. Otherwise returns `false` and an error -message. +#### `string(v)` -```lua -ok, err = validate.is.userdata(io.stdout) --> true, nil -ok, err = validate.is.userdata(1) --> false, "expected userdata, got number" -``` +Returns `true` when `v` is a string. Otherwise returns `false` and an error +message. -#### `not_boolean` +**Parameters**: -Returns `true` when `v` is **not** a boolean. Otherwise returns `false` and an -error message. +- `v` (`any`): Value to validate. -```lua -ok, err = validate.is_not.boolean(1) --> true, nil -ok, err = validate.is_not.boolean(true) --> false, "expected not boolean" -``` +**Return**: -#### `not_function` +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. -Returns `true` when `v` is **not** a function. Otherwise returns `false` and an -error message. +**Example**: ```lua -ok, err = validate.is_not.Function(1) --> true, nil -ok, err = validate.is_not.Function(function() end) --> false, "expected not function" +ok, err = validate.string("hello") --> true, nil +ok, err = validate.string(1) --> false, "expected string, got number" ``` -#### `not_nil` + -Returns `true` when `v` is **not** `nil`. Otherwise returns `false` and an error +#### `table(v)` + +Returns `true` when `v` is a table. Otherwise returns `false` and an error message. -```lua -ok, err = validate.is_not.Nil(0) --> true, nil -ok, err = validate.is_not.Nil(nil) --> false, "expected not nil" -``` +**Parameters**: -#### `not_number` +- `v` (`any`): Value to validate. -Returns `true` when `v` is **not** a number. Otherwise returns `false` and an -error message. +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: ```lua -ok, err = validate.is_not.number("x") --> true, nil -ok, err = validate.is_not.number(42) --> false, "expected not number" +ok, err = validate.table({}) --> true, nil +ok, err = validate.table(1) --> false, "expected table, got number" ``` -#### `not_string` + -Returns `true` when `v` is **not** a string. Otherwise returns `false` and an -error message. +#### `thread(v)` -```lua -ok, err = validate.is_not.string(1) --> true, nil -ok, err = validate.is_not.string("hello") --> false, "expected not string" -``` +Returns `true` when `v` is a thread. Otherwise returns `false` and an error +message. -#### `not_table` +**Parameters**: -Returns `true` when `v` is **not** a table. Otherwise returns `false` and an -error message. +- `v` (`any`): Value to validate. -```lua -ok, err = validate.is_not.table(1) --> true, nil -ok, err = validate.is_not.table({}) --> false, "expected not table" -``` +**Return**: -#### `not_thread` +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. -Returns `true` when `v` is **not** a thread. Otherwise returns `false` and an -error message. +**Example**: ```lua co = coroutine.create(function() end) -ok, err = validate.is_not.thread(1) --> true, nil -ok, err = validate.is_not.thread(co) --> false, "expected not thread" +ok, err = validate.thread(co) --> true, nil +ok, err = validate.thread(1) --> false, "expected thread, got number" ``` -#### `not_userdata` + + +#### `userdata(v)` -Returns `true` when `v` is **not** userdata. Otherwise returns `false` and an +Returns `true` when `v` is a userdata value. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is_not.userdata(1) --> true, nil -ok, err = validate.is_not.userdata(io.stdout) --> false, "expected not userdata" +ok, err = validate.userdata(io.stdout) --> true, nil +ok, err = validate.userdata(1) --> false, "expected userdata, got number" ``` ### Value Checks Value-state validators (exact true/false, truthy/falsy, callable, integer). + -#### `false` +#### `false(v)` Returns `true` when `v` is exactly `false`. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.False(false) --> true, nil -ok, err = validate.is.False(true) --> false, "expected false, got true" +ok, err = validate.False(false) --> true, nil +ok, err = validate.False(true) --> false, "expected false, got true" ``` -#### `true` + + +#### `true(v)` Returns `true` when `v` is exactly `true`. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.True(true) --> true, nil -ok, err = validate.is.True(false) --> false, "expected true, got false" +ok, err = validate.True(true) --> true, nil +ok, err = validate.True(false) --> false, "expected true, got false" ``` -#### `falsy` + + +#### `falsy(v)` Returns `true` when `v` is falsy. Otherwise returns `false` and an error message. -```lua -ok, err = validate.is.falsy(false) --> true, nil -ok, err = validate.is.falsy(1) --> false, "expected falsy, got number" -``` +**Parameters**: -#### `callable` +- `v` (`any`): Value to validate. -Returns `true` when `v` is callable. Otherwise returns `false` and an error -message. +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: ```lua -ok, err = validate.is.callable(type) --> true, nil -ok, err = validate.is.callable(1) --> false, "expected callable, got number" +ok, err = validate.falsy(false) --> true, nil +ok, err = validate.falsy(1) --> false, "expected falsy, got number" ``` -#### `integer` + -Returns `true` when `v` is an integer. Otherwise returns `false` and an error +#### `callable(v)` + +Returns `true` when `v` is callable. Otherwise returns `false` and an error message. -```lua -ok, err = validate.is.integer(1) --> true, nil -ok, err = validate.is.integer(1.5) --> false, "expected integer, got 1.5" -``` +**Parameters**: -#### `truthy` +- `v` (`any`): Value to validate. -Returns `true` when `v` is truthy. Otherwise returns `false` and an error -message. +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: ```lua -ok, err = validate.is.truthy(1) --> true, nil -ok, err = validate.is.truthy(false) --> false, "expected truthy, got boolean" +ok, err = validate.callable(type) --> true, nil +ok, err = validate.callable(1) --> false, "expected callable, got number" ``` -#### `not_false` + -Returns `true` when `v` is **not** exactly `false`. Otherwise returns `false` -and an error message. +#### `integer(v)` -```lua -ok, err = validate.is_not.False(true) --> true, nil -ok, err = validate.is_not.False(false) --> false, "expected not false" -``` +Returns `true` when `v` is an integer. Otherwise returns `false` and an error +message. -#### `not_true` +**Parameters**: -Returns `true` when `v` is **not** exactly `true`. Otherwise returns `false` and -an error message. +- `v` (`any`): Value to validate. -```lua -ok, err = validate.is_not.True(false) --> true, nil -ok, err = validate.is_not.True(true) --> false, "expected not true" -``` +**Return**: -#### `not_falsy` +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. -Returns `true` when `v` is **not** falsy. Otherwise returns `false` and an error -message. +**Example**: ```lua -ok, err = validate.is_not.falsy(1) --> true, nil -ok, err = validate.is_not.falsy(false) --> false, "expected not falsy" +ok, err = validate.integer(1) --> true, nil +ok, err = validate.integer(1.5) --> false, "expected integer, got 1.5" ``` -#### `not_callable` + -Returns `true` when `v` is **not** callable. Otherwise returns `false` and an -error message. +#### `truthy(v)` -```lua -ok, err = validate.is_not.callable(1) --> true, nil -ok, err = validate.is_not.callable(function() end) --> false, "expected not callable" -``` +Returns `true` when `v` is truthy. Otherwise returns `false` and an error +message. -#### `not_integer` +**Parameters**: -Returns `true` when `v` is **not** an integer. Otherwise returns `false` and an -error message. +- `v` (`any`): Value to validate. -```lua -ok, err = validate.is_not.integer(1.5) --> true, nil -ok, err = validate.is_not.integer(1) --> false, "expected non-integer, got 1" -``` +**Return**: -#### `not_truthy` +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. -Returns `true` when `v` is **not** truthy. Otherwise returns `false` and an -error message. +**Example**: ```lua -ok, err = validate.is_not.truthy(false) --> true, nil -ok, err = validate.is_not.truthy(1) --> false, "expected not truthy" +ok, err = validate.truthy(1) --> true, nil +ok, err = validate.truthy(false) --> false, "expected truthy, got boolean" ``` ### Path Checks Filesystem path-kind validators backed by LuaFileSystem (`lfs`). -Filesystem path kind checks. - > [!IMPORTANT] > > Path checks require **LuaFileSystem** -> ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error it -> is not installed. +> ([`lfs`](https://github.com/lunarmodules/luafilesystem)) and raise an error if +> it is not installed. -#### `block` +#### `block(v)` Returns `true` when `v` is a block device path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.block(".") +ok, err = validate.block(".") ``` -#### `char` + + +#### `char(v)` Returns `true` when `v` is a char device path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.char(".") +ok, err = validate.char(".") ``` -#### `device` + + +#### `device(v)` Returns `true` when `v` is a block or char device path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.device(".") +ok, err = validate.device(".") ``` -#### `dir` + + +#### `dir(v)` Returns `true` when `v` is a directory path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.dir(".") +ok, err = validate.dir(".") ``` -#### `fifo` + + +#### `fifo(v)` Returns `true` when `v` is a FIFO path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.fifo(".") +ok, err = validate.fifo(".") ``` -#### `file` + + +#### `file(v)` Returns `true` when `v` is a file path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.file(".") +ok, err = validate.file(".") ``` -#### `link` + + +#### `link(v)` Returns `true` when `v` is a symlink path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.link(".") +ok, err = validate.link(".") ``` -#### `socket` + + +#### `socket(v)` Returns `true` when `v` is a socket path. Otherwise returns `false` and an error message. +**Parameters**: + +- `v` (`any`): Value to validate. + +**Return**: + +- `ok` (`boolean`): Whether the check succeeds. +- `err` (`string?`): Error message when the check fails. + +**Example**: + ```lua -ok, err = validate.is.socket(".") +ok, err = validate.socket(".") ``` + +### Validator API + + + +#### `register(name, check, msg?)` + +Register or override a validator function by name. + +**Parameters**: + +- `name` (`string`): Validator name. +- `check` (`fun(v:any):(ok:boolean)`): Validator function. +- `msg?` (`string`): Optional default message template. + +**Return**: + +- `none` (`nil`) + +**Example**: + +```lua +validate.register("odd", function(v) + return type(v) == "number" and v % 2 == 1 +end, "{{value}} does not satisfy {{expected}}") + +ok, err = validate.odd(3) --> true, nil +ok, err = validate.odd("x") --> false, '"x" does not satisfy odd' +ok, err = validate(2, "odd") --> false, "2 does not satisfy odd" +``` + +> [!NOTE] +> +> - If `msg` is provided, it becomes the default message template for that +> validator. +> - If `msg` is omitted, failures use: `expected {{expected}}, got {{got}}`. + +## Fields + +### `messages` + +Custom error-message templates for validator failures. Set +`validate.messages.`, where `` is a validator name (for example: +`number`, `truthy`, `file`). The template is used only when validation fails and +an error message is returned. + +```lua +validate.messages.number = "need {{expected}}, got {{got}}" +ok, err = validate.number("x") --> false, "need number, got string" +``` + +**Placeholders**: + +- {{expected}}: The check target (for example `number`, + `string`, `truthy`). +- {{got}}: The detected failure kind (usually a Lua type; + path validators use `invalid path`). +- {{value}}: The passed value, formatted for display (strings + are quoted). + +> [!NOTE] +> +> When the passed value is `nil`, rendered value text uses `no value`. +> +> ```lua +> validate.messages.truthy = "expected {{expected}} value, got {{value}}" +> validate.truthy(nil) --> false, "expected truthy value, got no value" +> ``` +> +> **Default Messages**: + +- Type checks: expected {{expected}}, got {{got}} +- Value checks: expected {{expected}} value, got {{value}} +- Path checks: {{value}} is not a valid {{expected}} path