diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index dbac14c..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-*~
-.DS_Store
-/*.src.rock
-/Makefile
-/build-aux/config.ld
-/doc
-/lib/std/version.lua
-/luacov.*.out
-/stdlib-*.tar.gz
diff --git a/.luacov b/.luacov
deleted file mode 100644
index 40b9d6a..0000000
--- a/.luacov
+++ /dev/null
@@ -1,52 +0,0 @@
-return {
- -- filename to store stats collected
- ["statsfile"] = "luacov.stats.out",
-
- -- filename to store report
- ["reportfile"] = "luacov.report.out",
-
- -- luacov.stats file updating frequency.
- -- The lower this value - the more frequenty results will be written out to luacov.stats
- -- You may want to reduce this value for short lived scripts (to for example 2) to avoid losing coverage data.
- ["savestepsize"] = 100,
-
- -- Run reporter on completion? (won't work for ticks)
- runreport = true,
-
- -- Delete stats file after reporting?
- deletestats = false,
-
- -- Process Lua code loaded from raw strings
- -- (that is, when the 'source' field in the debug info
- -- does not start with '@')
- codefromstrings = false,
-
- -- Patterns for files to include when reporting
- -- all will be included if nothing is listed
- -- (exclude overrules include, do not include
- -- the .lua extension, path separator is always '/')
- ["include"] = {
- "lib/std/_base$",
- "lib/std/debug$",
- "lib/std/init$",
- "lib/std/io$",
- "lib/std/math$",
- "lib/std/package$",
- "lib/std/string$",
- "lib/std/table$",
- --"lib/std/version$",
- },
-
- -- Patterns for files to exclude when reporting
- -- all will be included if nothing is listed
- -- (exclude overrules include, do not include
- -- the .lua extension, path separator is always '/')
- ["exclude"] = {
- "luacov$",
- "luacov/reporter$",
- "luacov/defaults$",
- "luacov/runner$",
- "luacov/stats$",
- "luacov/tick$",
- },
-}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 92f4f73..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-language: python
-
-sudo: false
-
-env:
- matrix:
- - LUA="lua=5.3"
- - LUA="lua=5.2"
- - LUA="lua=5.1"
- - LUA="luajit=2.1"
- - LUA="luajit=2.0"
-
-before_install:
- - pip install hererocks
- - hererocks here -r^ --$LUA --patch
- - export PATH=$PWD/here/bin:$PATH
-
-install:
- - luarocks install ldoc
- - luarocks install ansicolors
- - luarocks install specl
- - luarocks install luacov
-
-script:
- - make
- - luarocks make
- - make check SPECL_OPTS='-vfreport --coverage'
-
-after_success:
- - tail luacov.report.out
- - bash <(curl -s https://codecov.io/bash) -v
-
-notifications:
- slack: aspirinc:JyWeNrIdS0J5nf2Pn2BS1cih
diff --git a/AUTHORS.md b/AUTHORS.md
deleted file mode 100644
index 6589984..0000000
--- a/AUTHORS.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Stdlib's contributors
-
-This file lists major contributors to _stdlib_. If you think you
-should be on it, please raise a [github][] issue. Thanks also to all
-those who have contributed bug fixes, suggestions and support.
-
-Gary V. Vaughan now maintains _stdlib_, having rewritten and reorganised
-the libraries for hygiene, consistent argument type checking in debug
-mode, and object orientation, in addition to adding a lot of new
-functionality.
-
-Reuben Thomas started the standard libraries project, wrote many of the
-libraries, and integrated code from other authors.
-
-John Belmonte helped set the project up on lua-users, and contributed
-to the early organisation of the libraries.
-
-The call trace debugging code is based on test/trace-calls.lua from
-the Lua 5.0 distribution.
-
-Jamie Webb contributed several miscellaneous functions from his
-private standard library.
-
-Johann Hibschman supplied the code on which math.floor and math.round
-were based.
-
-[github]: https://github.com/lua-stdlib/lua-stdlib/issues
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index c2b4620..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (C) 2002-2018 stdlib authors
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without restriction,
-including without limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of the Software,
-and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGE-
-MENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 7b8dd8c..0000000
--- a/Makefile
+++ /dev/null
@@ -1,49 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-LDOC = ldoc
-LUA = lua
-MKDIR = mkdir -p
-SED = sed
-SPECL = specl
-
-VERSION = git
-
-luadir = lib/std
-SOURCES = \
- $(luadir)/_base.lua \
- $(luadir)/debug.lua \
- $(luadir)/init.lua \
- $(luadir)/io.lua \
- $(luadir)/math.lua \
- $(luadir)/package.lua \
- $(luadir)/string.lua \
- $(luadir)/table.lua \
- $(luadir)/version.lua \
- $(NOTHING_ELSE)
-
-
-all: doc
-
-$(luadir)/version.lua: .FORCE
- @echo 'return "General Lua libraries / $(VERSION)"' > '$@T'; \
- if cmp -s '$@' '$@T'; then \
- rm -f '$@T'; \
- else \
- echo 'echo return "General Lua libraries / $(VERSION)" > $@'; \
- mv '$@T' '$@'; \
- fi
-
-doc: build-aux/config.ld $(SOURCES)
- $(LDOC) -c build-aux/config.ld .
-
-build-aux/config.ld: build-aux/config.ld.in
- $(SED) -e "s,@PACKAGE_VERSION@,$(VERSION)," '$<' > '$@'
-
-
-CHECK_ENV = LUA=$(LUA)
-
-check:
- LUA=$(LUA) $(SPECL) $(SPECL_OPTS) spec/*_spec.yaml
-
-.FORCE:
diff --git a/NEWS.md b/NEWS.md
deleted file mode 100644
index fdbf720..0000000
--- a/NEWS.md
+++ /dev/null
@@ -1,1414 +0,0 @@
-# Stdlib NEWS - User visible changes
-
-## Noteworthy changes in release ?.? (????-??-??) [?]
-
-### New features
-
- - Overhaul of the LDoc documentation, adding more introductory
- material, clearer usage examples and better internal consistency. At
- this point we're pushing the technical limits of what LDoc can do for
- us organization-wise, but improvements and corrections to the content
- are always welcome!
-
- - With this release, stdlib is much more focused, and non-core modules
- `optparse`, `std.functional`, 'std.prototype', `std.strict` and
- `typecheck` have been moved into their own packages and release
- cycle. Also, the shared debug initialization, Lua host normalization
- and API deprecation code have been split out into new 'std._debug',
- 'std.normalize' and 'apimaturity' respectively, and are pulled in
- automatically as dependencies for any of any modules that need them.
- You can still install them all separately from their own projects or
- by using Luarocks:
-
- ```bash
- luarocks install optparse
- luarocks install std.functional
- luarocks install std.prototype
- luarocks install std.strict
- luarocks install typecheck
- ```
-
- - All support for previously deprecated APIs has been removed, reducing
- the install size even further.
-
- - `std.string.prettytostring` continues to use `normalize.string.render`
- for more legible deeply nested table output, identically to previous
- releases.
-
- - `std.npairs` and `std.rnpairs` now respect `__len` metamethod, if any.
-
- - `std.table.okeys` has been removed for lack of utility. If you
- still need it, use this instead:
-
- ```lua
- local okeys = std.functional.compose (std.table.keys, std.table.sort)
- ```
-
-### Bug fixes
-
- - `std.string.wrap` doesn't throw a StrBuf deprecation warning any more.
-
- - `std.getmetamethod` now returns functable valued metamethods
- correctly, rather than `nil` as in previous releases. It's also
- considerably faster now that it doesn't use `pcall` any more.
-
- - `table.pack` now sets `n` field to number of arguments packed, even
- in Lua 5.1.
-
-### Incompatible changes
-
- - `std.container`, `std.functional`, `std.list`, `std.maturity`,
- `std.object`, `std.operator`, `std.optparse`, `std.set`,
- `std.strbuf`, `std.strict` and `std.tuple` have been moved to their
- own packages, and are no longer shipped as part of stdlib.
-
- - Monkey patching calls `std.barrel`, `std.monkey_patch`,
- `std.io.monkey_patch`, `std.math.monkey_patch`,
- `std.string.monkey_patch` and `std.table.monkey_patch` have all
- been removed.
-
- - `std.debug.argerror`, `std.debug.argcheck`, `std.debug.argscheck`,
- `std.debug.extramsg_mismatch`, `std.debug.extramsg_toomany`,
- `std.debug.parsetypes`, `std.debug.resulterror` and `std.debug.typesplit`
- have all been moved to their own package, and are no longer shipped
- as part of stdlib.
-
- - `std.debug.DEPRECATED` and `std.debug.DEPRECATIONMSG` have been
- removed. At some point these will resurface in a new standalone
- package.
-
- - Deprecated functions `string.assert`, `string.require_version`,
- `string.tostring`, `table.clone_rename`, `table.metamethod`,
- `table.ripairs` and `table.totable` have been removed. See previous
- NEWS entries below for what they were replaced by.
-
- - Passing a table with a `__len` metamethod, that returns a value other
- the index of the largest non-nil valued integer key, to `std.npairs`
- now iterates upto whatever `__len` returns rather than `std.table.maxn`.
- If `__len` is not present, or gives the same result as `maxn` then
- `npairs` continues to behave as in the previous release.
-
- - `std.tostring` and `std.string.render` have been superceded by their
- equivalents from 'std.normalize': `str` and `string.render`. Those
- implementations handle skipping initial sequence keys for a more
- compact output, escaping of whitespace and other C escape characters
- for even more compact output and stringification of nested Objects and
- Containers using their `__tostring` metamethods.
-
- - For consistency with std.normalize and other package symbols, we now
- spell `package.path_mark` as `package.pathmark`.
-
-
-## Noteworthy changes in release 41.2.0 (2015-03-08) [stable]
-
-### New features
-
- - New iterators, `std.npairs` and `std.rnpairs` behave like
- `std.ipairs` and `std.ripairs` resp., except that they will visit
- all integer keyed elements, including nil-valued "holes". This is
- useful for iterating over argument lists with nils:
-
- ```lua
- function fn(a, b, c) for _, v in npairs {...} do print(v) end
- fn(nil, nil, 3) --> nil nil 3
- ```
-
- - New `debug.getfenv` and `debug.setfenv` that work with Lua 5.2 and
- 5.3.
-
- - `debug.argscheck` will skip typecheck for `self` parameter if the
- function name specification contains a colon.
-
- - New `debug.resulterror` is much like `debug.argerror`, but uses the
- message format "bad result #n from 'fname'".
-
- - New `debug.extramsg_mismatch` to generate `extramsg` argument for
- `debug.argerror` or `debug.resulterror` on encountering a type
- mismatch.
-
- - New `debug.extramsg_toomany` to generate a too many arguments or
- similar `extramsg` argument.
-
-### Deprecations
-
- - `debug.toomanyargmsg` has been deprecated in favour of the more
- orthogal `debug.extramsg_toomany` api. You can rewrite clients of
- deprecated api like this:
-
- ```lua
- if maxn(argt) > 7 then
- argerror('fname', 8, extramsg_toomany('argument', 7, maxn(argt)), 2)
- end
- ```
-
-### Bug fixes
-
- - `std.getmetamethod` no longer rejects non-table subjects when
- `_DEBUG.argcheck` is set.
-
- - `functional.bind`, `functional.collect`, `functional.compose`,
- `functional.filter` and `functional.map` propagate nil valued
- arguments correctly.
-
- - `functional.callable` no longer raises an argument error when passed
- a nil valued argument.
-
- - `debug.argcheck` and `debug.argscheck` accept "bool" as an alias for
- "boolean" consistently.
-
- - `io.catdir` and `io.dirname` no longer leak extra results from
- implementation details.
-
-### Incompatible changes
-
- - `functional.collect` uses `std.npairs` as a default iterator rather
- than `std.ipairs`.
-
-
-## Noteworthy changes in release 41.1.1 (2015-01-31) [stable]
-
-### Bug fixes
-
- - `std.barrel` no longer gets stuck in an infinite loop when called in
- Lua 5.3.
-
-
-## Noteworthy changes in release 41.1.0 (2015-01-30) [stable]
-
-### New features
-
- - Anything that responds to `tostring` can be appended to a `std.strbuf`:
-
- ```lua
- local a, b = StrBuf {'foo', 'bar'}, StrBuf {'baz', 'quux'}
- a = a .. b --> 'foobarbazquux'
- ```
-
- - `std.strbuf` stringifies lazily, so adding tables to a StrBuf
- object, and then changing the content of them before calling
- `tostring` also changes the contents of the buffer. See LDocs for
- an example.
-
- - `debug.argscheck` accepts square brackets around final optional
- parameters, which is distinct to the old way of appending `?` or
- `|nil` in that no spurious "or nil" is reported for type mismatches
- against a final bracketed argument.
-
- - `debug.argscheck` can also check types of function return values, when
- specified as:
-
- ```lua
- fn = argscheck('fname(?any...) => int, table or nil, string', fname)
- ```
-
- Optional results can be marked with brackets, and an ellipsis following
- the final type denotes any additional results must match that final
- type specification. Alternative result type groups are separated by "or".
-
- - New `table.unpack(t, [i, [j]])` function that defaults j to
- `table.maxn(t)`, even on luajit which stops before the first nil
- valued numeric index otherwise.
-
-### Deprecations
-
- - `std.strbuf.tostring` has been deprecated in favour of `tostring`.
- Why write `std.strbuf.tostring(sb)` or `sb:tostring()` when it is
- more idiomatic to write `tostring(sb)`?
-
-### Bug fixes
-
- - `std.barrel` and the various `monkey_patch` functions now return
- their parent module table as documented.
-
- - stdlib modules are all `std.strict` compliant; require 'std.strict'
- before requiring other modules no longer raises an error.
-
- - `debug.argscheck` can now diagnose when there are too many arguments,
- even in the case where the earlier arguments match parameters by
- skipping bracketed optionals, and the total number of arguments is
- still less than the absolute maximum allowed if optionals are counted
- too.
-
- - `package.normalize` now leaves valid ./../../ path prefixes unmolested.
-
-### Incompatible changes
-
- - `debug.argscheck` requires nil parameter type `?` notation to be
- prepended to match Specl and TypedLua syntax. `?` suffixes are a
- syntax error.
-
- - `debug.argscheck` uses `...` instead of `*` appended to the final element
- if all unmatched argument types should match. The trailing `*` syntax
- was confusing, because it was easy to misread it as "followed by zero-or-
- more of this type".
-
-
-## Noteworthy changes in release 41.0.0 (2015-01-03) [beta]
-
-### New features
-
- - Preliminary Lua 5.3.0 compatibility.
-
- - `object.prototype` now reports "file" for open file handles, and
- "closed file" for closed file handles.
-
- - New `debug.argerror` and `debug.argcheck` functions that provide Lua
- equivalents of `luaL_argerror` and `luaL_argcheck`.
-
- - New `debug.argscheck` function for checking all function parameter
- types with a single function call in the common case.
-
- - New `debug.export` function, which returns a wrapper function for
- checking all arguments of an inner function against a type list.
-
- - New `_DEBUG.argcheck` field that disables `debug.argcheck`, and
- changes `debug.argscheck` to return its function argument unwrapped,
- for production code. Similarly `_DEBUG = false` deactivates these
- functions in the same way.
-
- - New `std.operator` module, with easier to type operator names (`conj`,
- `deref`, `diff`, `disj`, `eq`, `neg`, `neq`, `prod`, `quot`, and `sum`),
- and a functional operator for concatenation `concat`; plus new mathematical
- operators `mod`, and `pow`; and relational operators `lt`, `lte`, `gt` and
- `gte`.
-
- - `functional.case` now accepts non-callable branch values, which are
- simply returned as is, and functable values which are called and
- their return value propagated back to the case caller. Function
- values behave the same as in previous releases.
-
- - `functional.collect`, `functional.filter`, `functional.map` and
- `functional.reduce` now work with standard multi-return iterators,
- such as `std.pairs`.
-
- - `functional.collect` defaults to using `std.ipairs` as an iterator.
-
- - New `functional.cond`, for evaluating multiple distinct expressions
- to determine what following value to be the returned.
-
- - `functional.filter` and `functional.map` default to using `std.pairs`
- as an iterator.
-
- - The init argument to `functional.foldl` and `functional.foldr` is now
- optional; when omitted these functions automatically start with
- the left- or right-most element of the table argument resp.
-
- - New `functional.callable` function for unwrapping objects or
- primitives that can be called as if they were a function.
-
- - New `functional.lambda` function for compiling lambda strings:
-
- ```lua
- table.sort(t, lambda '|a,b| a
- explaining why any deprecation should be reinstated or at least kept
- around for more than 1 year.
-
- - By default, deprecated APIs will issue a warning to stderr on every
- call. However, in production code, you can turn off these warnings
- entirely with any of:
-
- ```lua
- _DEBUG = false
- _DEBUG = {deprecate=false}
- require 'std.debug_init'.deprecate = false
- ```
-
- Or, to confirm you're not trying to call a deprecated function at
- runtime, you can prevent deprecated functions from being defined at
- all with any of:
-
- ```lua
- _DEBUG = true
- _DEBUG = {deprecate=true}
- require 'std.debug_init'.deprecate = true
- ```
-
- The `_DEBUG` global must be set before requiring any stdlib modules,
- but you can adjust the fields in the `std.debug_init` table at any
- time.
-
- - `functional.eval` has been moved to `std.eval`, the old name now
- gives a deprecation warning.
-
- - `functional.fold` has been renamed to `functional.reduce`, the old
- name now gives a deprecation warning.
-
- - `functional.op` has been moved to a new `std.operator` module, the
- old function names now gives deprecation warnings.
-
- - `list.depair` and `list.enpair` have been moved to `table.depair` and
- `table.enpair`, the old names now give deprecation warnings.
-
- - `list.filter` has been moved to `functional.filter`, the old name now
- gives a deprecation warning.
-
- - `list.flatten` has been moved to `table.flatten`, the old name now
- gives a deprecation warning.
-
- - `list.foldl` and `list.foldr` have been replaced by the richer
- `functional.foldl` and `functional.foldr` respectively. The old
- names now give a deprecation warning. Note that List object methods
- `foldl` and `foldr` are not affected.
-
- - `list.index_key` and `list.index_value` have been deprecated. These
- functions are not general enough to belong in lua-stdlib, because
- (among others) they only work correctly with tables that can be
- inverted without loss of key values. They currently give deprecation
- warnings.
-
- - `list.map` and `list.map_with` has been deprecated, in favour of the
- more powerful new `functional.map` and `functional.map_with` which
- handle tables as well as lists.
-
- - `list.project` has been deprecated in favour of `table.project`, the
- old name now gives a deprecation warning.
-
- - `list.relems` has been deprecated, in favour of the more idiomatic
- `functional.compose(std.ireverse, std.ielems)`.
-
- - `list.reverse` has been deprecated in favour of the more general
- and more accurately named `std.ireverse`.
-
- - `list.shape` has been deprecated in favour of `table.shape`, the old
- name now gives a deprecation warning.
-
- - `list.transpose` has been deprecated in favour of `functional.zip`,
- see above for details.
-
- - `list.zip_with` has been deprecated in favour of `functional.zip_with`,
- see above for details.
-
- - `string.assert` has been moved to `std.assert`, the old name now
- gives a deprecation warning.
-
- - `string.require_version` has been moved to `std.require`, the old
- name now gives a deprecation warning.
-
- - `string.tostring` has been moved to `std.tostring`, the old name now
- gives a deprecation warning.
-
- - `table.metamethod` has been moved to `std.getmetamethod`, the old
- name now gives a deprecation warning.
-
- - `table.ripairs` has been moved to `std.ripairs`, the old name now
- gives a deprecation warning.
-
- - `table.totable` has been deprecated and now gives a warning when used.
-
-### Incompatible changes
-
- - `std.monkey_patch` works the same way as the other submodule
- monkey_patch functions now, by injecting its methods into the given
- (or global) namespace. To get the previous effect of running all the
- monkey_patch functions, either run them all manually, or call
- `std.barrel()` as before.
-
- - `functional.bind` sets fixed positional arguments when called as
- before, but when the newly bound function is called, those arguments
- fill remaining unfixed positions rather than being overwritten by
- original fixed arguments. For example, where this would have caused
- an error previously, it now prints "100" as expected.
-
- ```lua
- local function add(a, b) return a + b end
- local incr = functional.bind(add, {1})
- print(incr(99))
- ```
-
- If you have any code that calls functions returned from `bind`, you
- need to remove the previously ignored arguments that correspond to
- the fixed argument positions in the `bind` invocation.
-
- - `functional.collect`, `functional.filter` and `functional.map` still
- make a list from the results from an iterator that returns single
- values, but when an iterator returns multiple values they now make a
- table with key:value pairs taken from the first two returned values of
- each iteration.
-
- - The `functional.op` table has been factored out into its own new
- module `std.operator`. It will also continue to be available from the
- legacy `functional.op` access point for the forseeable future.
-
- - The `functional.op['..']` operator is no longer a list concatenation
- only loaded when `std.list` is required, but a regular string
- concatenation just like Lua's `..` operator.
-
- - `io.catdir` now raises an error when called with no arguments, for
- consistency with `io.catfile`.
-
- - `io.die` no longer calls `io.warn` to write the error message to
- stderr, but passes that error message to the core `error` function.
-
- - `std.set` objects used to be lax about enforcing type correctness in
- function arguments, but now that we have strict type-checking on all
- apis, table arguments are not coerced to Set objects but raise an
- error. Due to an accident of implementation, you can get the old
- inconsistent behaviour back for now by turning off type checking
- before loading any stdlib modules:
-
- ```lua
- _DEBUG = {argcheck=false}
- local set = require 'std.set'
- ```
-
- - `string.pad` will still (by implementation accident) coerce non-
- string initial arguments to a string using `string.tostring` as long
- as argument checking is disabled. Under normal circumstances,
- passing a non-string will now raise an error as specified in the api
- documentation.
-
- - `table.totable` is deprecated, and thus objects no longer provide or
- use a `__totable` metamethod. Instead, using a `__pairs` metamethod
- to return key/value pairs, and that will automatically be used by
- `__tostring`, `object.mapfields` etc. The base object now provides a
- `__pairs` metamethod that returns key/value pairs in order, and
- ignores private fields. If you have objects that relied on the
- previous treatment of `__totable`, please convert them to set a
- custom `__pairs` instead.
-
-
-### Bug fixes
-
- - Removed LDocs for unused `_DEBUG.std` field.
-
- - `debug.trace` works with Lua 5.2.x again.
-
- - `list:foldr` works again instead of raising a "bad argument #1 to
- 'List'" error.
-
- - `list.transpose` works again, and handles empty lists without
- raising an error; but is deprecated and will be removed in a future
- release (see above).
-
- - `list.zip_with` no longer raises an argument error on every call; but,
- like `list.transpose`, is also deprecated (see above).
-
- - `optparse.on` now works with `std.strict` enabled.
-
- - `std.require` (nee `string.require_version`) now extracts the last
- substring made entirely of digits and periods from the required
- module's version string before splitting on period. That means, for
- version strings like luaposix's "posix library for Lua 5.2 / 32" we
- now correctly compare just the numeric part against specified version
- range rather than an ASCII comparison of the whole thing as before!
-
- - The documentation now correcly notes that `std.require` looks
- first in `module.version` and then `module._VERSION` to match the
- long-standing implementation.
-
- - `string.split` now really does split on whitespace when no split
- pattern argument is provided. Also, the documentation now
- correctly cites `%s+` as the default whitespace splitting pattern
- (not `%s*` which splits between every non-whitespace character).
-
-
-## Noteworthy changes in release 40 (2014-05-01) [stable]
-
-### New features
-
- - `functional.memoize` now accepts a user normalization function,
- falling back on `string.tostring` otherwise.
-
- - `table.merge` now supports `map` and `nometa` arguments orthogonally
- to `table.clone`.
-
- - New `table.merge_select` function, orthogonal to
- `table.clone_select`. See LDocs for details.
-
-### Incompatible changes
-
- - Core methods and metamethods are no longer monkey patched by default
- when you `require 'std'` (or `std.io`, `std.math`, `std.string` or
- `std.table`). Instead they provide a new `monkey_patch` method you
- should use when you don't care about interactions with other
- modules:
-
- ```lua
- local io = require 'std.io'.monkey_patch()
- ```
-
- To install all of stdlib's monkey patches, the `std` module itself
- has a `monkey_patch` method that loads all submodules with their own
- `monkey_patch` method and runs them all.
-
- If you want full compatibility with the previous release, in addition
- to the global namespace scribbling snippet above, then you need to
- adjust the first line to:
-
- ```lua
- local std = require 'std'.monkey_patch()
- ```
-
- - The global namespace is no longer clobbered by `require 'std'`. To
- get the old behaviour back:
-
- ```lua
- local std = require 'std'.barrel(_G)
- ```
-
- This will execute all available monkey_patch functions, and then
- scribble all over the `_G` namespace, just like the old days.
-
- - The `metamethod` call is no longer in `std.functional`, but has moved
- to `std.table` where it properly belongs. It is a utility method for
- tables and has nothing to do with functional programming.
-
- - The following deprecated camelCase names have been removed, you
- should update your code to use the snake_case equivalents:
- `std.io.processFiles`, `std.list.indexKey`, `std.list.indexValue`,
- `std.list.mapWith`, `std.list.zipWith`, `std.string.escapePattern`,
- `std.string. escapeShell`, `std.string.ordinalSuffix`.
-
- - The following deprecated function names have been removed:
- `std.list.new` (call `std.list` directly instead),
- `std.list.slice` (use `std.list.sub` instead),
- `std.set.new` (call `std.set` directly instead),
- `std.strbuf.new` (call `std.strbuf` directly instead), and
- `std.tree.new` (call `std.tree` directly instead).
-
-### Bug fixes
-
- - Allow `std.object` derived tables as `std.tree` keys again.
-
-
-## Noteworthy changes in release 39 (2014-04-23) [stable]
-
-### New features
-
- - New `std.functional.case` function for rudimentary case statements.
- The main difference from serial if/elseif/end comparisons is that
- `with` is evaluated only once, and then the match function is looked
- up with an O(1) table reference and function call, as opposed to
- hoisting an expression result into a temporary variable, and O(n)
- comparisons.
-
- The function call overhead is much more significant than several
- comparisons, and so `case` is slower for all but the largest series
- of if/elseif/end comparisons. It can make your code more readable,
- however.
-
- See LDocs for usage.
-
- - New pathstring management functions in `std.package`.
-
- Manage `package.path` with normalization, duplicate removal,
- insertion & removal of elements and automatic folding of '/' and '?'
- onto `package.dirsep` and `package.path_mark`, for easy addition of
- new paths. For example, instead of all this:
-
- ```lua
- lib = std.io.catfile('.', 'lib', package.path_mark .. '.lua')
- paths = std.string.split(package.path, package.pathsep)
- for i, path in ipairs(paths) do
- -- ... lots of normalization code...
- end
- i = 1
- while i <= #paths do
- if paths[i] == lib then
- table.remove(paths, i)
- else
- i = i + 1
- end
- end
- table.insert(paths, 1, lib)
- package.path = table.concat(paths, package.pathsep)
- ```
-
- You can now write just:
-
- ```lua
- package.path = package.normalize('./lib/?.lua', package.path)
- ```
-
- - `std.optparse:parse` accepts a second optional parameter, a table of
- default option values.
-
- - `table.clone` accepts an optional table of key field renames in the
- form of `{oldkey=newkey, ...}` subsuming the functionality of
- `table.clone_rename`. The final `nometa` parameter is supported
- whether or not a rename map is given:
-
- ```lua
- r = table.clone(t, 'nometa')
- r = table.clone(t, {oldkey=newkey}, 'nometa')
- ```
-
-### Deprecations
-
- - `table.clone_rename` now gives a warning on first call, and will be
- removed entirely in a few releases. The functionality has been
- subsumed by the improvements to `table.clone` described above.
-
-### Bug fixes
-
- - `std.optparse` no longer throws an error when it encounters an
- unhandled option in a combined (i.e. `-xyz`) short option string.
-
- - Surplus unmapped fields are now discarded during object cloning, for
- example when a prototype has `_init` set to `{'first', 'second'}`,
- and is cloned using `Proto {'one', 'two', 'three'}`, then the
- unmapped `three` argument is now discarded.
-
- - The path element returned by `std.tree.nodes` can now always be
- used as a key list to dereference the root of the tree, particularly
- `tree[{}]` now returns the root node of `tree`, to match the initial
- `branch` and final `join` results from a full traversal by
- `std.tree.nodes(tree)`.
-
-### Incompatible changes
-
- - `std.string` no longer sets `__append`, `__concat` and `__index` in
- the core strings metatable by default, though `require 'std'` does
- continue to do so. See LDocs for `std.string` for details.
-
- - `std.optparse` no longer normalizes unhandled options. For example,
- `--unhandled-option=argument` is returned unmolested from `parse`,
- rather than as two elements split on the `=`; and if a combined
- short option string contains an unhandled option, then whatever was
- typed at the command line is returned unmolested, rather than first
- stripping off and processing handled options, and returning only the
- unhandled substring.
-
- - Setting `_init` to `{}` in a prototype object will now discard all
- positional parameters passed during cloning, because a table valued
- `_init` is a list of field names, beyond which surplus arguments (in
- this case, all arguments!) are discarded.
-
-
-## Noteworthy changes in release 38 (2014-01-30) [stable]
-
-### New features
-
- - The separator parameter to `std.string.split` is now optional. It
- now splits strings with `%s+` when no separator is specified. The
- new implementation is faster too.
-
- - New `std.object.mapfields` method factors out the table field copying
- and mapping performed when cloning a table `_init` style object. This
- means you can call it from a function `_init` style object after
- collecting a table to serve as `src` to support derived objects with
- normal std.object syntax:
-
- ```lua
- Proto = Object {
- _type = 'proto'
- _init = function(self, arg, ...)
- if type(arg) == 'table' then
- mapfields(self, arg)
- else
- -- non-table instantiation code
- end
- end,
- }
- new = Proto(str, #str)
- Derived = proto {_type='Derived', ...}
- ```
-
- - Much faster object cloning; `mapfields` is in imperative style and
- makes one pass over each table it looks at, where previous releases
- used functional style (stack frame overhead) and multiple passes over
- input tables.
-
- On my 2013 Macbook Air with 1.3GHz Core i5 CPU, I can now create a
- million std.objects with several assorted fields in 3.2s. Prior to
- this release, the same process took 8.15s... and even release 34.1,
- with drastically simpler Objects (19SLOC vs over 120) took 5.45s.
-
- - `std.object.prototype` is now almost an order of magnitude faster
- than previous releases, taking about 20% of the time it previously
- used to return its results.
-
- - `io.warn` and `io.die` now integrate properly with `std.optparse`,
- provided you save the `opts` return from `parser:parse` back to the
- global namespace where they can access it:
-
- ```lua
- local OptionParser = require 'std.optparse'
- local parser = OptionParser 'eg 0\nUsage: eg\n'
- _G.arg, _G.opts = parser:parse(_G.arg)
- if not _G.opts.keep_going then
- require 'std.io'.warn 'oh noes!'
- end
- ```
-
- will, when run, output to stderr: "eg: oh noes!"
-
-### Bug fixes
-
- - Much improved documentation for `optparse`, so you should be able
- to use it without reading the source code now!
-
- - `io.warn` and `io.die` no longer output a line-number when there is
- no file name to append it to.
-
- - `io.warn` and `io.die` no longer crash in the absence of a global
- `prog` table.
-
- - `string.split` no longer goes into an infinite loop when given an
- empty separator string.
-
- - Fix `getmetatable(container._functions) == getmetatable(container)`,
- which made tostring on containers misbehave, among other latent bugs.
-
- - `_functions` is never copied into a metatable now, finally solving
- the conflicted concerns of needing metatables to be shared between
- all objects of the same `_type` (for `__lt` to work correctly for one
- thing) and not leaving a dangling `_functions` list in the metatable
- of cloned objects, which could delete functions with matching names
- from subsequent clones.
-
-
-## Noteworthy changes in release 37 (2014-01-19) [stable]
-
-### New features
-
- - Lazy loading of submodules into `std` on first reference. On initial
- load, `std` has the usual single `version` entry, but the `__index`
- metatable will automatically require submodules on first reference:
-
- ```lua
- local std = require 'std'
- local prototype = std.container.prototype
- ```
-
- - New `std.optparse` module: A civilised option parser.
- (L)Documentation distributed in doc/classes/std.optparse.html.
-
-### Bug fixes
-
- - Modules no longer leak `new' and `proper_subset' into the global
- table.
-
- - Cloned `Object` and `Container` derived types are more aggressive
- about sharing metatables, where previously the metatable was copied
- unnecessarily the base object used `_functions` for module functions
-
- - The retracted release 36 changed the operand order of many `std.list`
- module functions unnecessarily. Now that `_function` support is
- available, there's no need to be so draconian, so the original v35
- and earlier operand order works as before again.
-
- - `std.list.new`, `std.set.new`, `set.strbuf.new` and `std.tree.new`
- are available again for backwards compatibility.
-
- - LuaRocks install doesn't copy config.ld and config.ld to $docdir.
-
-### Incompatible changes
-
- - `std.getopt` is no more. It appears to have no users, though if there
- is a great outcry, it should be easy to make a compatibility api over
- `std.optparse` in the next release.
-
-
-## Noteworthy changes in release 36 (2014-01-16) [stable]
-
-### New features
-
- - Modules have been refactored so that they can be safely
- required individually, and without loading themselves or any
- dependencies on other std modules into the global namespace.
-
- - Objects derived from the `std.object` prototype have a new
- :prototype() method that returns the contents of the
- new internal `_type` field. This can be overridden during cloning
- with, e.g.:
-
- ```lua
- local Object = require 'std.object'
- Prototype = Object {_type='Prototype', }
- ```
-
- - Objects derived from the `std.object` prototype return a new table
- with a shallow copy of all non-private fields (keys that do not
- begin with '_') when passed to `table.totable` - unless overridden
- in the derived object's __totable field.
-
- - list and strbuf are now derived from `std.object`, which means that
- they respond to `object.prototype` with appropriate type names ('List',
- 'StrBuf', etc.) and can be used as prototypes for further derived
- objects or clones; support object:prototype(); respond to totable etc.
-
- - A new Container module at `std.container` makes separation between
- container objects (which are free to use __index as a '[]' access
- metamethod, but) which have no object methods, and regular objects
- (which do have object methods, but) which cannot use the __index
- metamethod for '[]' access to object contents.
-
- - set and tree are now derived from `std.container`, so there are no
- object methods. Instead there are a full complement of equivalent
- module functions. Metamethods continue to work as before.
-
- - `string.prettytostring` always displays table elements in the same
- order, as provided by `table.sort`.
-
- - `table.totable` now accepts a string, and returns a list of the
- characters that comprise the string.
-
- - Can now be installed directly from a release tarball by `luarocks`.
- No need to run `./configure` or `make`, unless you want to install to
- a custom location, or do not use LuaRocks.
-
-### Bug fixes
-
- - string.escape_pattern is now Lua 5.2 compatible.
-
- - all objects now reuse prototype metatables, as required for __le and
- __lt metamethods to work as documented.
-
-### Deprecations
-
- - To avoid confusion between the builtin Lua `type` function and the
- method for finding the object prototype names, `std.object.type` is
- deprecated in favour of `std.object.prototype`. `std.object.type`
- continues to work for now, but might be removed from a future
- release.
-
- ```lua
- local prototype = require 'std.object'.prototype
- ```
-
- ...makes for more readable code, rather than confusion between the
- different flavours of `type`.
-
-### Incompatible changes
-
- - Following on from the Grand Renaming™ change in the last release,
- `std.debug_ext`, `std.io_ext`, `std.math_ext`, `std.package_ext`,
- `std.string_ext` and `std.table_ext` no longer have the spurious
- `_ext` suffix. Instead, you must now use, e.g.:
-
- ```lua
- local string = require 'std.string'
- ```
-
- These names are now stable, and will be available from here for
- future releases.
-
- - The `std.list` module, as a consequence of returning a List object
- prototype rather than a table of functions including a constructor,
- now always has the list operand as the first argument, whether that
- function is called with `.` syntax or `:` syntax. Functions which
- previously had the list operand in a different position when called
- with `.` syntax were: list.filter, list.foldl, list.foldr,
- list.index_key, list.index_value, list.map, list.map_with,
- list.project, list.shape and list.zip_with. Calls made as object
- methods using `:` calling syntax are unchanged.
-
- - The `std.set` module is a `std.container` with no object methods,
- and now uses prototype functions instead:
-
- ```lua
- local union = Set.union(set1, set2)
- ```
-
-
-## Noteworthy changes in release 35 (2013-05-06) [stable]
-
-### New features
-
- - Move to the Slingshot release system.
- - Continuous integration from Travis automatically builds stdilb
- with Lua 5.1, Lua 5.2 and luajit-2.0 with every commit, which
- should help prevent future release breaking compatibility with
- one or another of those interpreters.
-
-### Bug fixes
-
- - `std.package_ext` no longer overwrites the core `package` table,
- leaving the core holding on to memory that Lua code could no
- longer access.
-
-### Incompatible changes
-
- - The Grand Renaming™ - everything now installs to $luaprefix/std/,
- except `std.lua` itself. Importing individual modules now involves:
-
- ```lua
- local list = require 'std.list'
- ```
-
- If you want to have all the symbols previously available from the
- global and core module namespaces, you will need to put them there
- yourself, or import everything with:
-
- ```lua
- require 'std'
- ```
-
- which still behaves per previous releases.
-
- Not all of the modules work correctly when imported individually
- right now, until we figure out how to break some circular dependencies.
-
-
-## Noteworthy changes in release 34.1 (2013-04-01) [stable]
-
- - This is a maintenance release to quickly fix a breakage in getopt
- from release v34. Getopt no longer parses non-options, but stops
- on the first non-option... if a use case for the other method
- comes up, we can always add it back in.
-
-
-## Noteworthy changes in release 34 (2013-03-25) [stable]
-
- - stdlib is moving towards supporting separate requirement of individual
- modules, without scribbling on the global environment; the work is not
- yet complete, but we're collecting tests along the way to ensure that
- once it is all working, it will carry on working;
-
- - there are some requirement loops between modules, so not everything can
- be required independently just now;
-
- - `require 'std'` will continue to inject std symbols into the system
- tables for backwards compatibility;
-
- - stdlib no longer ships a copy of Specl, which you will need to install
- separately if you want to run the bundled tests;
-
- - getopt supports parsing of undefined options; useful for programs that
- wrap other programs;
-
- - getopt.Option constructor is no longer used, pass a plain Lua table of
- options, and getopt will do the rest;
-
-
-## Noteworthy changes in release 33 (2013-07-27) [stable]
-
- - This release improves stability where Specl has helped locate some
- corner cases that are now fixed.
-
- - `string_ext.wrap` and `string_ext.tfind` now diagnose invalid arguments.
-
- - Specl code coverage is improving.
-
- - OrdinalSuffix improvements.
-
- - Use '%' instead of math.mod, as the latter does not exist in Lua 5.2.
-
- - Accept negative arguments.
-
-
-## Noteworthy changes in release 32 (2013-02-22) [stable]
-
- - This release fixes a critical bug preventing getopt from returning
- anything in getopt.opt. Gary V. Vaughan is now a co-maintainer, currently
- reworking the sources to use (Lua 5.1 compatible) Lua 5.2 style module
- packaging, which requires you to assign the return values from your imports:
-
- ```lua
- getopt = require 'getopt'
- ```
-
- - Extension modules, table_ext, package_ext etc. return the unextended module
- table before injecting additional package methods, so you can ignore those
- return values or save them for programatically backing out the changes:
-
- ```lua
- table_unextended = require 'table_ext'
- ```
-
- - Additionally, Specl (see http://github.com/gvvaughan/specl/) specifications
- are being written for stdlib modules to help us stop accidentally breaking
- things between releases.
-
-
-## Noteworthy changes in release 31 (2013-02-20) [stable]
-
- - This release improves the list module: lists now have methods, list.slice
- is renamed to list.sub (the old name is provided as an alias for backwards
- compatibility), and all functions that construct a new list return a proper
- list, not a table. As a result, it is now often possible to write code that
- works on both lists and strings.
-
-
-## Noteworthy changes in release 30 (2013-02-17) [stable]
-
- - This release changes some modules to be written in a Lua 5.2 style (but
- not the way they work with 5.1). Some fixes and improvements were made to
- the build system. Bugs in the die function, the parser module, and a nasty
- bug in the set module introduced in the last release (29) were fixed.
-
-
-## Noteworthy changes in release 29 (2013-02-06) [stable]
-
- - This release overhauls the build system to have LuaRocks install releases
- directly from git rather than from tarballs, and fixes a bug in set (issue
- #8).
-
-
-## Noteworthy changes in release 28 (2012-10-28) [stable]
-
- - This release improves the documentation and build system, and improves
- require_version to work by default with more libraries.
-
-
-## Noteworthy changes in release 27 (2012-10-03) [stable]
-
- - This release changes getopt to return all arguments in a list, rather than
- optionally processing them with a function, fixes an incorrect definition
- of set.elems introduced in release 26, turns on debugging by default,
- removes the not-very-useful string.gsubs, adds constructor functions for
- objects, renames table.rearrange to the more descriptive table.clone_rename
- and table.indices to table.keys, and makes table.merge not clone but modify
- its left-hand argument. A function require_version has been added to allow
- version constraints on a module being required. Gary Vaughan has
- contributed a memoize function, and minor documentation and build system
- improvements have been made. Usage information is now output to stdout, not
- stderr. The build system has been fixed to accept Lua 5.2. The luarock now
- installs documentation, and the build command used is now more robust
- against previous builds in the same tree.
-
-
-## Noteworthy changes in release 26 (2012-02-18) [stable]
-
- - This release improves getopt's output messages and conformance to
- standard practice for default options. io.processFiles now unsets prog.file
- when it finishes, so that a program can tell when itâs no longer
- processing a file. Three new tree iterators, inodes, leaves and ileaves,
- have been added; the set iterator set.elements (renamed to set.elems for
- consistency with list.elems) is now leaves rather than pairs. tree indexing
- has been made to work in more circumstances (thanks, Gary Vaughan).
- io.writeline is renamed io.writelines for consistency with io.readlines and
- its function. A slurping function, io.slurp, has been added. Strings now
- have a __concat metamethod.
-
-
-## Noteworthy changes in release 25 (2011-09-19) [stable]
-
- - This release adds a version string to the std module and fixes a buglet in
- the build system.
-
-
-## Noteworthy changes in release 24 (2011-09-19) [stable]
-
- - This release fixes a rename missing from release 23, and makes a couple of
- fixes to the new build system, also from release 23.
-
-
-## Noteworthy changes in release 23 (2011-09-17) [stable]
-
- - This release removes the posix_ext module, which is now part of luaposix,
- renames string.findl to string.tfind to be the same as lrexlib, and
- autotoolizes the build system, as well as providing a rockspec file.
-
-
-## Noteworthy changes in release 22 (2011-09-02) [stable]
-
- - This release adds two new modules: strbuf, a trivial string buffers
- implementation, which is used to speed up the stdlib tostring method for
- tables, and bin, which contains a couple of routines for converting binary
- data into numbers and strings. Some small documentation and build system
- fixes have been made.
-
-
-## Noteworthy changes in release 21 (2011-06-06) [stable]
-
- - This release converts the documentation of stdlib to LuaDoc, adds an
- experimental Lua 5.2 module "fstable", for storing tables directly on
- disk as files and directories, and fixes a few minor bugs (with help from
- David Favro).
-
- - This release has been tested lightly on Lua 5.2 alpha, but is not
- guaranteed to work fully.
-
-
-## Noteworthy changes in release 20 (2011-04-14) [stable]
-
- - This release fixes a conflict between the global _DEBUG setting and the use
- of strict.lua, changes the argument order of some list functions to favour
- OO-style use, adds posix.euidaccess, and adds OO-style use to set. mk1file
- can now produce a single-file version of a user-supplied list of modules,
- not just the standard set.
-
-
-## Noteworthy changes in release 19 (2011-02-26) [stable]
-
- - This release puts the package.config reflection in a new package_ext
- module, where it belongs. Thanks to David Manura for this point, and for a
- small improvement to the code.
-
-
-## Noteworthy changes in release 18 (2011-02-26) [stable]
-
- - This release provides named access to the contents of package.config, which
- is undocumented in Lua 5.1. See luaconf.h and the Lua 5.2 manual for more
- details.
-
-
-## Noteworthy changes in release 17 (2011-02-07) [stable]
-
- - This release fixes two bugs in string.pad (thanks to Bob Chapman for the
- fixes).
-
-
-## Noteworthy changes in release 16 (2010-12-09) [stable]
-
- - Adds posix module, using luaposix, and makes various other small fixes and
- improvements.
-
-
-## Noteworthy changes in release 15 (2010-06-14) [stable]
-
- - This release fixes list.foldl, list.foldr, the fold iterator combinator and
- io.writeLine. It also simplifies the op table, which now merely sugars the
- built-in operators rather than extending them. It adds a new tree module,
- which subsumes the old table.deepclone and table.lookup functions.
- table.subscript has become op['[]'], and table.subscripts has been removed;
- the old treeIter iterator has been simplified and generalised, and renamed
- to nodes. The mk1file script and std.lua library loader have had the module
- list factored out into modules.lua. strict.lua from the Lua distribution is
- now included in stdlib, which has been fixed to work with it. Some minor
- documentation and other code improvements and fixes have been made.
-
-
-## Noteworthy changes in release 14 (2010-06-07) [stable]
-
- - This release makes stdlib compatible with strict.lua, which required a
- small change to the debug_ext module. Some other minor changes have also
- been made to that module. The table.subscripts function has been removed
- from the table_ext.lua.
-
-
-## Noteworthy changes in release 13 (2010-06-02) [stable]
-
- - This release removes the lcs module from the standard set loaded by
- 'std', removes an unnecessary definition of print, and tidies up the
- implementation of the "op" table of functional versions of the infix
- operators and logical operators.
-
-
-## Noteworthy changes in release 12 (2009-09-07) [stable]
-
- - This release removes io.basename and io.dirname, which are now available in
- lposix, and the little-used functions addSuffix and changeSuffix which
- dependend on them. io.pathConcat is renamed to io.catdir and io.pathSplit
- to io.splitdir, making them behave the same as the corresponding Perl
- functions. The dependency on lrexlib has been removed along with the rex
- wrapper module. Some of the more esoteric and special-purpose modules
- (mbox, xml, parser) are no longer loaded by 'require 'std''.
-
- This leaves stdlib with no external dependencies, and a rather more
- coherent set of basic modules.
-
-
-## Noteworthy changes in release 11 (2009-03-15) [stable]
-
- - This release fixes a bug in string.format, removes the redundant
- string.join (it's the same as table.concat), and adds to table.clone and
- table.deepclone the ability to copy without metatables. Thanks to David
- Kantowitz for pointing out the various deficiencies.
-
-
-## Noteworthy changes in release 10 (2009-03-13) [stable]
-
- - This release fixes table.deepclone to copy metatables, as it should.
- Thanks to David Kantowitz for the fix.
-
-
-## Noteworthy changes in release 9 (2009-02-19) [stable]
-
- - This release updates the object module to be the same as that published
- in "Lua Gems", and fixes a bug in the utility mk1file which makes a
- one-file version of the library, to stop it permanently redefining require.
-
-
-## Noteworthy changes in release 8 (2008-09-04) [stable]
-
- - This release features fixes and improvements to the set module; thanks to
- Jiutian Yanling for a bug report and suggestion which led to this work.
-
-
-## Noteworthy changes in release 7 (2008-09-04) [stable]
-
- - just a bug fix
-
-
-## Noteworthy changes in release 6 (2008-07-28) [stable]
-
- - This release rewrites the iterators in a more Lua-ish 5.1 style.
-
-
-## Noteworthy changes in release 5 (2008-03-04) [stable]
-
- - I'm happy to announce a new release of my standard Lua libraries. It's been
- nearly a year since the last release, and I'm happy to say that since then
- only one bug has been found (thanks Roberto!). Two functions have been
- added in this release, to deal with file paths, and one removed (io.length,
- which is handled by lfs.attributes) along with one constant (INTEGER_BITS,
- handled by bitlib's bit.bits).
-
- - For those not familiar with stdlib, it's a pure-Lua library of mostly
- fundamental data structures and algorithms, in particular support for
- functional and object-oriented programming, string and regex operations and
- extensible pretty printing of data structures. More specific modules
- include a getopt implementation, a generalised least common subsequences
- (i.e. diff algorithm) implementation, a recursive-descent parser generator,
- and an mbox parser.
-
- - It's quite a mixed bag, but almost all written for real projects. It's
- written in a doc-string-ish style with the supplied very simple ldoc tool.
-
- - I am happy with this code base, but there are various things it could use:
-
- 0. Tests. Tests. Tests. The code has no unit tests. It so needs them.
-
- 1. More code. Nothing too specialised (unless it's too small to be released
- on its own, although very little seems "too small" in the Lua
- community). Anything that either has widespread applicability (like
- getopt) or is very general (data structures, algorithms, design
- patterns) is good.
-
- 2. Refactoring. The code is not ideally factored. At the moment it is
- divided into modules that extend existing libraries, and new modules
- constructed along similar lines, but I think that some of the divisions
- are confusing. For example, the functional programming support is spread
- between the list and base modules, and would probably be better in its
- own module, as those who aren't interested in the functional style won't
- want the functional list support or the higher-order functions support,
- and those who want one will probably want the other.
-
- 3. Documentation work. There's not a long wrong with the existing
- documentation, but it would be nice, now that there is a stable LuaDoc,
- to use that instead of the built-in ldoc, which I'm happy to discard now
- that LuaDoc is stable. ldoc was always designed as a minimal LuaDoc
- substitute in any case.
-
- 4. Maintenance and advocacy. For a while I have been reducing my work on
- Lua, and am also now reducing my work in Lua. If anyone would like to
- take on stdlib, please talk to me. It fills a much-needed function: I
- suspect a lot of Lua programmers have invented the wheels with which it
- is filled over and over again. In particular, many programmers could
- benefit from the simplicity of its simple and well-designed functional,
- string and regex capabilities, and others will love its comprehensive
- getopt.
-
-
-## Noteworthy changes in release 4 (2007-04-26) [beta]
-
- - This release removes the dependency on the currently unmaintained lposix
- library, includes pre-built HTML documentation, and fixes some 5.0-style
- uses of variadic arguments.
-
- Thanks to Matt for pointing out all these problems. stdlib is very much
- user-driven at the moment, since it already does everything I need, and I
- don't have much time to work on it, so do please contact me if you find
- bugs or problems or simply don't understand it, as the one thing I *do*
- want to do is make it useful and accessible!
-
-
-## Noteworthy changes in release 3 (2007-02-25) [beta]
-
- - This release fixes the "set" and "lcs" (longest common subsequence, or
- "grep") libraries, which were broken, and adds one or two other bug and
- design fixes. Thanks are due to Enrico Tassi for pointing out some of the
- problems.
-
-
-## Noteworthy changes in release 2 (2007-01-05) [beta]
-
- - This release includes some bug fixes, and compatibility with lrexlib 2.0.
-
-
-## Noteworthy changes in release 1 (2011-09-02) [beta]
-
- - It's just a snapshot of CVS, but it's pretty stable at the moment; stdlib,
- until such time as greater interest or participation enables (or forces!)
- formal releases will be in permanent beta, and tracking CVS is recommended.
-
-
-[optparse]: https://github.com/gvvaughan/optparse
-[strict]: https://github.com/lua-stdlib/strict
diff --git a/README.md b/README.md
deleted file mode 100644
index 49b0328..0000000
--- a/README.md
+++ /dev/null
@@ -1,92 +0,0 @@
-Standard Lua libraries
-======================
-
-Copyright (C) 2000-2018 [stdlib authors][github]
-
-[](http://mit-license.org)
-[](http://travis-ci.org/lua-stdlib/lua-stdlib/builds)
-[](https://codecov.io/gh/lua-stdlib/lua-stdlib)
-[](https://waffle.io/lua-stdlib/lua-stdlib)
-
-
-This is a collection of Lua libraries for Lua 5.1 (including LuaJIT), 5.2
-and 5.3. The libraries are copyright by their authors (see the [AUTHORS][]
-file for details), and released under the [MIT license][mit] (the same
-license as Lua itself). There is no warranty.
-
-_stdlib_ has no run-time prerequisites beyond a standard Lua system,
-though it will take advantage of [strict][] and [typecheck][] if they
-are installed.
-
-[authors]: http://github.com/lua-stdlib/lua-stdlib/blob/master/AUTHORS.md
-[github]: http://github.com/lua-stdlib/lua-stdlib/ "Github repository"
-[lua]: http://www.lua.org "The Lua Project"
-[mit]: http://mit-license.org "MIT License"
-[strict]: https://github.com/lua-stdlib/strict "strict variables"
-[typecheck]: https://github.com/gvvaughan/typecheck "function type checks"
-
-
-Installation
-------------
-
-The simplest and best way to install stdlib is with [LuaRocks][]. To
-install the latest release (recommended):
-
-```bash
- luarocks install stdlib
-```
-
-To install current git master (for testing, before submitting a bug
-report for example):
-
-```bash
- luarocks install http://raw.githubusercontent.com/lua-stdlib/lua-stdlib/master/stdlib-git-1.rockspec
-```
-
-The best way to install without [LuaRocks][] is to copy the `std`
-folder and its contents into a directory on your package search path.
-
-[luarocks]: http://www.luarocks.org "Lua package manager"
-
-
-Documentation
--------------
-
-The latest release of these libraries is [documented in LDoc][github.io].
-Pre-built HTML files are included in the release.
-
-[github.io]: http://lua-stdlib.github.io/lua-stdlib
-
-
-Bug reports and code contributions
-----------------------------------
-
-These libraries are written and maintained by their users.
-
-Please make bug reports and suggestions as [GitHub Issues][issues].
-Pull requests are especially appreciated.
-
-But first, please check that your issue has not already been reported by
-someone else, and that it is not already fixed by [master][github] in
-preparation for the next release (see Installation section above for how
-to temporarily install master with [LuaRocks][]).
-
-There is no strict coding style, but please bear in mind the following
-points when proposing changes:
-
-0. Follow existing code. There are a lot of useful patterns and avoided
- traps there.
-
-1. 3-character indentation using SPACES in Lua sources: It makes rogue
- TABS easier to see, and lines up nicely with 'if' and 'end' keywords.
-
-2. Simple strings are easiest to type using single-quote delimiters,
- saving double-quotes for where a string contains apostrophes.
-
-3. Save horizontal space by only using SPACES where the parser requires
- them.
-
-4. Use vertical space to separate out compound statements to help the
- coverage reports discover untested lines.
-
-[issues]: http://github.com/lua-stdlib/lua-stdlib/issues
diff --git a/STYLE.md b/STYLE.md
deleted file mode 100644
index f01f630..0000000
--- a/STYLE.md
+++ /dev/null
@@ -1,97 +0,0 @@
-## Lua
-
- - Requiring any stdlib module must not leak any symbols into the global
- namespace.
-
- - Any stdlib module may `require "std.base"`, and use any functions from
- there, as well as functions from `std.debug` (and `debug_init`); but,
- all other modules export argument checked functions that should not be
- called from anywhere in stdlib -- this is the client API. If a
- function is needed by more than one module, move it to `std.base`
- without argument checking, and re-export with `argscheck` if necess-
- ary.
-
- Obviously, for objects it's perfectly fine to require the file that
- defines the object being derived from. But to prevent accidentally
- calling argchecked methods, we always immediately create a prototype
- object with, e.g:
-
- local Container = require "std.container" {}
-
- (`std.object` is an exception to this rule because of how tightly
- bound to `std.container` it is, and does directly call some of
- containers methods by design).
-
- - Minimise forward declarations of functions, because having some
- declared as `local` in line, and others not is ugly and can easily
- cause rogue `local` keywords to be introduced that end up shadowing
- the intended declaration. Mutually recursive functions, and
- alternate definitions are acceptable, in which case keep the forward
- declarations and definitions as close together as possible to
- minimise any possible misunderstandings later.
-
- - Try to maintain asciibetical ordering of function definitions in each
- source file, except where doing so would require forward declar-
- ations. In that case use topological ordering to avoid the forward
- declarations.
-
- - Unless a table cannot possibly have a __len metamethod (i.e. it was
- constructed without one in the current scope), always use
- `base.insert` and `base.len` rather than core `table.insert` and the
- `#` operator, which do not honor __len in all implementations.
-
- - Unless a table cannot possibly have __pairs or __len metamethods
- (i.e. it was constructed without them in the current scope), always
- use `base.pairs` or `base.ipairs` rather than core `pairs` and
- `ipairs`, which do not honor __pairs or __len in all implementations.
-
- - Use consistent short names for common parameters:
-
- fh a file handle, usually from io.open or similar
- fmt a format string
- fn a function
- i an index
- k a value, usually from pairs or similar
- l a list-like table
- n a number
- s a string
- t a table
-
- - Do argument check all object methods (functions available from an
- object created by a module function -- usually listed in the
- `__index` subtable of the object metatable), to catch pathological
- calls early, preferably using a `typecheck.argscheck` wrapper around
- the internal implementation: this way, implementation functions can
- call each other without excessive rechecking of argument types.
-
- - Do argument check all module functions (functions available in the
- table returned from requiring that module).
-
- - Do argument check metamethods, to catch pathological calls early.
-
-
-## LDocs
-
- - LDocs should be next to each function's argcheck wrapper (if it has
- one) in the export table, so that it's easy to check the consistency
- between the types declared in the LDocs and the argument types
- enforced by `typecheck.argscheck` or equivalent.
-
- - `backtick_references` is disabled for stdlib, if you want an inline
- cross-reference, use `@{reference}`.
-
- - Be liberal with `@see` references to similar apis.
-
- - Refer to other argument names with italics (`*italic*` in markdown).
-
- - Try to add entries for callback function signatures, and name them
- with the suffix `cb`.
-
- - Rely on the reader to understand how `:` call syntax works in Lua, and
- don't waste effort documenting methods that are already documented as
- functions.
-
- - Do document the prototype chain. Don't document methods inherited
- from the prototype, even they have been overridden to behave consist-
- ently from a UI perspective even though the implementation needs to be
- different to provide that same UI.
diff --git a/build-aux/config.ld.in b/build-aux/config.ld.in
deleted file mode 100644
index 20ee48b..0000000
--- a/build-aux/config.ld.in
+++ /dev/null
@@ -1,53 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
-
-title = 'stdlib @PACKAGE_VERSION@ Reference'
-project = 'stdlib @PACKAGE_VERSION@'
-description = [[
-# Standard Lua Libraries
-
-This is a collection of light-weight libraries for Lua 5.1 (including
-LuaJIT), 5.2 and 5.3 written in pure Lua, comprising:
-
-1. Enhanced and expanded versions of some core Lua functions in the
- @{std} module itself;
-
-2. Enhanced versions of some core Lua libraries: @{std.debug}, @{std.io},
- @{std.math}, @{std.package}, @{std.string} and @{std.table};
-
-## LICENSE
-
-The code is copyright by its respective authors, and released under the
-MIT license (the same license as Lua itself). There is no warranty.
-]]
-
-dir = '../doc'
-
-file = {
- '../lib/std/init.lua',
- '../lib/std/debug.lua',
- '../lib/std/io.lua',
- '../lib/std/math.lua',
- '../lib/std/package.lua',
- '../lib/std/string.lua',
- '../lib/std/table.lua',
-}
-
-new_type ('corefunction', 'Core_Functions', true)
-new_type ('corelibrary', 'Core_Libraries', true)
-
-function postprocess_html(s)
- s = s:gsub('
A container is a std.object with no methods. It's functionality is
+ instead defined by its metamethods.
+
+
Where an Object uses the __index metatable entry to hold object
+ methods, a Container stores its contents using __index, preventing
+ it from having methods in there too.
+
+
Although there are no actual methods, Containers are free to use
+ metamethods (__index, __sub, etc) and, like Objects, can supply
+ module functions by listing them in _functions. Also, since a
+ std.container is a std.object, it can be passed to the
+ std.object module functions, or anywhere else a std.object is
+ expected.
+
+
When making your own prototypes, derive from std.container if you want
+ to access the contents of your objects with the [] operator, or from
+ std.object if you want to access the functionality of your objects with
+ named object methods.
This module creates the root prototype object from which every other
+ object is descended. There are no classes as such, rather new objects
+ are created by cloning an existing object, and then changing or adding
+ to the clone. Further objects can then be made by cloning the changed
+ object, and so on.
+
+
Objects are cloned by simply calling an existing object, which then
+ serves as a prototype from which the new object is copied.
+
+
Note that Object methods are stored in the __index field of their
+ metatable, and so cannot also use __index to lookup references with
+ square brackets. See std.container objects if you want to do that.
+ -- `_init` can be a list of keys; then the unnamed `init_1` through
+-- `init_m` values from the argument table are assigned to the
+-- corresponding keys in `new_object`.
+local Process = Object {
+ _type = "Process",
+ _init = { "status", "out", "err" },
+ }
+ local process = Process {
+ procs[pid].status, procs[pid].out, procs[pid].err, -- auto assigned
+ command = pipeline[pid], -- manual assignment
+ }
+
+ -- Or it can be a function, in which the arguments passed to the
+-- prototype during cloning are simply handed to the `_init` function.
+local Bag = Object {
+ _type = "Bag",
+ _init = function (obj, ...)
+ for e in std.elems {...} do
+ obj[#obj + 1] = e
+ end
+ return obj
+ end,
+ }
+ local bag = Bag ("function", "arguments", "sent", "to", "_init")
+
+
+
+
+
Functions
+ Methods
+
+
+
+ std.object.clone (obj, ...)
+
+
+ Clone an Object.
+
+
Objects are essentially tables of field_n = value_n pairs.
+
+
Normally new_object automatically shares a metatable with
+ proto_object. However, field names beginning with "_" are private,
+ and moved into the object metatable during cloning. So, adding new
+ private fields to an object during cloning will result in a new
+ metatable for new_object that also happens to contain a copy of all
+ the entries from the proto_object metatable.
+
+
While clones of Object inherit all properties of their prototype,
+ it's idiomatic to always keep separate tables for the module table and
+ the root object itself: That way you can't mistakenly engage the slower
+ clone-from-module-table process unnecessarily.
+
+
+
+ local object = require"std.object"-- module table
+local Object = object {} -- root object
+local o = Object {
+ field_1 = "value_1",
+ method_1 = function (self) return self.field_1 end,
+ }
+ print (o.field_1) --> value_1
+ o.field_2 = 2
+ function o:method_2 (n) return self.field_2 + n end
+ print (o:method_2 (2)) --> 4
+os.exit (0)
+
+
+
+
+
+ std.object.mapfields (obj, src[, map={}])
+
+
+ Return obj with references to the fields of src merged in.
+
+
More importantly, split the fields in src between obj and its
+ metatable. If any field names begin with "_", attach a metatable
+ to obj by cloning the metatable from src, and then copy the
+ "private" _ prefixed fields there.
+
+
You might want to use this function to instantiate your derived
+ object clones when the src._init is a function -- when
+ src._init is a table, the default (inherited unless you overwrite
+ it) clone method calls mapfields automatically. When you're
+ using a function _init setting, clone doesn't know what to
+ copy into a new object from the _init function's arguments...
+ so you're on your own. Except that calling mapfields inside
+ _init is safer than manually splitting src into obj and
+ its metatable, because you'll pick up any fixes and changes when
+ you upgrade stdlib.
+
+
+
+
+
+ table
+ obj with non-private fields from src merged,
+ and a metatable with private fields (if any) merged, both sets
+ of keys renamed according to map
+
+
+
+
+
Usage:
+
+
+ myobject.mapfields = function (obj, src, map)
+ object.mapfields (obj, src, map)
+ ...
+ end
+
+
+
+
+
+ std.object.prototype (x)
+
+
+ Type of an object, or primitive.
+
+
It's conventional to organise similar objects according to a
+ string valued _type field, which can then be queried using this
+ function.
+
+
Additionally, this function returns the results of ??? for
+ file objects, or type otherwise.
+
+
+
for k, v in std.pairs (anobject) do process (k, v) end
+
+
+
+
+
+ std.object:__tostring ()
+
+
+ Return a string representation of this object.
+
+
First the object type, and then between { and } a list of the
+ array part of the object table (without numeric keys) followed
+ by the remaining key-value pairs.
+
+
This function doesn't recurse explicity, but relies upon suitable
+ __tostring metamethods in field values.
+
+
+
+
Most often, after instantiating an OptionParser, everything else
+ is handled automatically.
+
+
Then, calling parser:parse as shown below saves unparsed arguments
+ into _G.arg (usually filenames or similar), and _G.opts will be a
+ table of successfully parsed option values. The keys into this table
+ are the long-options with leading hyphens stripped, and non-word
+ characters turned to _. For example if --another-long had been
+ found in the initial _G.arg, then _G.opts will have a key named
+ another_long, with an appropriate value. If there is no long
+ option name, then the short option is used, i.e. _G.opts.b will be
+ set.
+
+
The values saved against those keys are controlled by the option
+ handler, usually just true or the option argument string as
+ appropriate.
+
+
+
program
+ string
+ the first word following "Usage:" from spec
+
+
version
+ string
+ the last white-space delimited word on the first line
+ of text from spec
+
+
versiontext
+ string
+ everything preceding "Usage:" from spec, and
+ which will be displayed by the versionon_handler
+
+
helptext
+ string
+ everything including and following "Usage:" from
+ spec string and which will be displayed by the help
+ on_handler
+
+
+
+
+
+
+
Usage:
+
+
+ local std = require"std"
+
+ local optparser = std.optparse [[
+ any text VERSION
+ Additional lines of text to show when the --version
+ option is passed.
+
+ Several lines or paragraphs are permitted.
+
+ Usage: PROGNAME
+
+ Banner text.
+
+ Optional long description text to show when the --help
+ option is passed.
+
+ Several lines or paragraphs of long description are permitted.
+
+ Options:
+
+ -b a short option with no long option
+ --long a long option with no short option
+ --another-long a long option with internal hypen
+ -v, --verbose a combined short and long option
+ -n, --dryrun, --dry-run several spellings of the same option
+ -u, --name=USER require an argument
+ -o, --output=[FILE] accept an optional argument
+ --version display version information, then exit
+ --help display this help, then exit
+
+ Footer text. Several lines or paragraphs are permitted.
+
+ Please report bugs at bug-list@yourhost.com
+ ]]
+
+ -- Note that std.io.die and std.io.warn will only prefix messages
+-- with `parser.program` if the parser options are assigned back to
+-- `_G.opts`:
+ _G.arg, _G.opts = optparser:parse (_G.arg)
+
+
+
+
+
Functions
+ Methods
+
+
+
+ std.optparse.OptionParser_Init (spec)
+
+
+ Signature for initialising a custom OptionParser.
+
+
Read the documented options from spec and return custom parser that
+ can be used for parsing the options described in spec from a run-time
+ argument list. Options in spec are recognised as lines that begin
+ with at least two spaces, followed by a hyphen.
+
+
+
+
+
+ OptionParser
+ a parser for options described by spec
+
+
+
+
+
Usage:
+
+
customparser = std.optparse (optparse_spec)
+
+
+
+
+
+ std.optparse.boolean (opt[, optarg="1"])
+
+
+ Return a Lua boolean equivalent of various optarg strings.
+ Report an option parse error if optarg is not recognised.
+
+
Pass this as the value function to on when you want various
+ "truthy" or "falsey" option arguments to be coerced to a Lua true
+ or false respectively in the options table.
+
+
+
This is the handler automatically assigned to the option written as
+ -- in the OptionParser spec argument. You can also pass it as
+ the handler argument to on if you want to manually add an end
+ of options marker without writing it in the OptionParser spec.
+
+
This handler tells the parser to stop processing arguments, so that
+ anything after it will be an argument even if it otherwise looks
+ like an option.
+
+
+
i
+ int
+ index of last processed element of arglist
+
+
+
+
Returns:
+
+
+ int
+ index of next element of arglist to process
+
+
+
+
+
Usage:
+
+
parser:on ("--", parser.finished)
+
+
+
+
+
+ std.optparse.flag (arglist, i[, value])
+
+
+ Option at arglist[i] is a boolean switch.
+
+
This is the handler automatically assigned to options that have
+ --long-opt or -x style specifications in the OptionParser spec
+ argument. You can also pass it as the handler argument to on for
+ options you want to add manually without putting them in the
+ OptionParser spec.
+
+
Beware that, unlikerequired, this handler will store multiple
+ occurrences of a command-line option as a table only when given a
+ value function. Automatically assigned handlers do not do this, so
+ the option will simply be true if the option was given one or more
+ times on the command-line.
+
+
+
+ Option at arglist[i] can take an argument.
+ Argument is accepted only if there is a following entry that does not
+ begin with a '-'.
+
+
This is the handler automatically assigned to options that have
+ --opt=[ARG] style specifications in the OptionParser spec
+ argument. You can also pass it as the handler argument to on for
+ options you want to add manually without putting them in the
+ OptionParser spec.
+
+
Like required, this handler will store multiple occurrences of a
+ command-line option.
+
+
+
This is the handler automatically assigned to options that have
+ --opt=ARG style specifications in the OptionParser spec argument.
+ You can also pass it as the handler argument to on for options
+ you want to add manually without putting them in the OptionParser
+ spec.
+
+
Normally the value stored in the opt table by this handler will be
+ the string given as the argument to that option on the command line.
+ However, if the option is given on the command-line multiple times,
+ opt["name"] will end up with all those arguments stored in the
+ array part of a table:
i
+ int
+ index of last processed element of arglist
+
+
value
+ either a function to process the option argument,
+ or a forced value to replace the user's option argument.
+ (optional)
+
+
+
+
Returns:
+
+
+ int
+ index of next element of arglist to process
+
+
+
+
+
Usage:
+
+
parser:on ({"-o", "--output"}, parser.required)
+
+
+
+
+
+ std.optparse.version ()
+
+
+ Option should display version text, then exit.
+
+
This is the handler automatically assigned tooptions that have
+ --version in the specification, e.g. -V, --version.
+
+
+
+
+
+
+
Usage:
+
+
parser:on ("-V", parser.version)
+
+
+
+
+
Tables
+
+
+
+
+ std.optparse.boolvals
+
+
+ Map various option strings to equivalent Lua boolean values.
+
+
+
Fields:
+
+
false
+ false
+
+
0
+ false
+
+
no
+ false
+
+
n
+ false
+
+
true
+ true
+
+
1
+ true
+
+
yes
+ true
+
+
y
+ true
+
+
+
+
+
+
+
+
+
+
+ std.optparse.opts
+
+
+ Parsed options table, with a key for each encountered option, each
+ with value set by that option's on_handler. Where an option
+ has one or more long-options specified, the key will be the first
+ one of those with leading hyphens stripped and non-alphanumeric
+ characters replaced with underscores. For options that can only be
+ specified by a short option, the key will be the letter of the first
+ of the specified short options:
+
+
Generally there will be one key for each previously specified
+ option (either automatically assigned by OptionParser or
+ added manually with on) containing the value(s) assigned by the
+ associated on_handler. For automatically assigned handlers,
+ that means true for straight-forward flags and
+ optional-argument options for which no argument was given; or else
+ the string value of the argument passed with an option given only
+ once; or a table of string values of the same for arguments given
+ multiple times.
If you write your own handlers, or otherwise specify custom
+ handling of options with on, then whatever value those handlers
+ return will be assigned to the respective keys in opts.
+
+
+
+
+
+
+
+
+
+
Methods
+
+
+
+
+ std.optparse:on (name, handler, value)
+
+
+ Add an option handler.
+
+
When the automatically assigned option handlers don't do everything
+ you require, or when you don't want to put an option into the
+ OptionParserspec argument, use this function to specify custom
+ behaviour. If you write the option into the spec argument anyway,
+ calling this function will replace the automatically assigned handler
+ with your own.
+
+
When writing your own handlers for std.optparse:on, you only need
+ to deal with normalised arguments, because combined short arguments
+ (-xyz), equals separators to long options (--long=ARG) are fully
+ expanded before any handler is called.
+
+
+
Parameters:
+
+
name
+ opts
+ of the option, or list of option names
+
+
handler
+ on_handler
+ function to call when any of opts is
+ encountered
+
Note that Functions listed below are only available from the Set
+ prototype returned by requiring this module, because Container
+ objects cannot have object methods.
Buffers are mutable by default, but being based on objects, they can
+ also be used in a functional style:
+
+
+
+local StrBuf = require"std.strbuf" {}
+local a = StrBuf {"a"}
+local b = a:concat "b"-- mutate *a*
+print (a, b) --> ab ab
+local c = a {} .. "c"-- copy and append
+print (a, c) --> ab abc
+
+
+ local std = require"std"
+ local StrBuf = std.strbuf {}
+ local a = {1, 2, 3}
+ local b = {a, "five", "six"}
+ a = a .. 4
+ b = b:concat "seven"
+ print (a, b) --> 1234 1234fivesixseven
+os.exit (0)
+
+
+
+
+
Functions
+ Methods
+
+
+
+ std.strbuf.concat (x)
+
+
+ Add a object to a buffer.
+ Elements are stringified lazily, so if add a table and then change
+ its contents, the contents of the buffer will be affected too.
+
+
+
Note that Functions listed below are only available from the Tree
+ prototype returned by requiring this module, because Container objects
+ cannot have object methods.
The returned iterator function performs a depth-first traversal of
+ tr, and at each node it returns {node-type, tree-path, tree-node}
+ where node-type is branch, join or leaf; tree-path is a
+ list of keys used to reach this node, and tree-node is the current
+ node.
+
+
Note that the tree-path reuses the same table on each iteration, so
+ you must table.clone a copy if you want to take a snap-shot of the
+ current state of the tree-path list before the next iteration
+ changes it.
+
+
+
Parameters:
+
+
tr
+ Tree or table
+ tree or tree-like table to iterate over
+
+generated by LDoc 1.4.3
+Last updated 2018-09-03 17:48:42
+
+
+
+
diff --git a/ldoc.css b/ldoc.css
new file mode 100644
index 0000000..7d74ca2
--- /dev/null
+++ b/ldoc.css
@@ -0,0 +1,307 @@
+/* BEGIN RESET
+
+Copyright (c) 2010, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.8.2r1
+*/
+html {
+ color: #000;
+ background: #FFF;
+}
+body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td {
+ margin: 0;
+ padding: 0;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+fieldset,img {
+ border: 0;
+}
+address,caption,cite,code,dfn,em,strong,th,var,optgroup {
+ font-style: inherit;
+ font-weight: inherit;
+}
+del,ins {
+ text-decoration: none;
+}
+li {
+ list-style: disc;
+ margin-left: 20px;
+}
+caption,th {
+ text-align: left;
+}
+h1,h2,h3,h4,h5,h6 {
+ font-size: 100%;
+ font-weight: bold;
+}
+q:before,q:after {
+ content: '';
+}
+abbr,acronym {
+ border: 0;
+ font-variant: normal;
+}
+sup {
+ vertical-align: baseline;
+}
+sub {
+ vertical-align: baseline;
+}
+legend {
+ color: #000;
+}
+input,button,textarea,select,optgroup,option {
+ font-family: inherit;
+ font-size: inherit;
+ font-style: inherit;
+ font-weight: inherit;
+}
+input,button,textarea,select {*font-size:100%;
+}
+/* END RESET */
+
+body {
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: arial, helvetica, geneva, sans-serif;
+ background-color: #ffffff; margin: 0px;
+}
+
+code, tt { font-family: monospace; font-size: 1.1em; }
+span.parameter { font-family:monospace; }
+span.parameter:after { content:":"; }
+span.types:before { content:"("; }
+span.types:after { content:")"; }
+.type { font-weight: bold; font-style:italic }
+
+body, p, td, th { font-size: .95em; line-height: 1.2em;}
+
+p, ul { margin: 10px 0 0 0px;}
+
+strong { font-weight: bold;}
+
+em { font-style: italic;}
+
+h1 {
+ font-size: 1.5em;
+ margin: 0 0 20px 0;
+}
+h2, h3, h4 { margin: 15px 0 10px 0; }
+h2 { font-size: 1.25em; }
+h3 { font-size: 1.15em; }
+h4 { font-size: 1.06em; }
+
+a:link { font-weight: bold; color: #004080; text-decoration: none; }
+a:visited { font-weight: bold; color: #006699; text-decoration: none; }
+a:link:hover { text-decoration: underline; }
+
+hr {
+ color:#cccccc;
+ background: #00007f;
+ height: 1px;
+}
+
+blockquote { margin-left: 3em; }
+
+ul { list-style-type: disc; }
+
+p.name {
+ font-family: "Andale Mono", monospace;
+ padding-top: 1em;
+}
+
+pre.example {
+ background-color: rgb(245, 245, 245);
+ border: 1px solid silver;
+ padding: 10px;
+ margin: 10px 0 10px 0;
+ font-family: "Andale Mono", monospace;
+ font-size: .85em;
+}
+
+pre {
+ background-color: rgb(245, 245, 245);
+ border: 1px solid silver;
+ padding: 10px;
+ margin: 10px 0 10px 0;
+ overflow: auto;
+ font-family: "Andale Mono", monospace;
+}
+
+
+table.index { border: 1px #00007f; }
+table.index td { text-align: left; vertical-align: top; }
+
+#container {
+ margin-left: 1em;
+ margin-right: 1em;
+ background-color: #f0f0f0;
+}
+
+#product {
+ text-align: center;
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#product big {
+ font-size: 2em;
+}
+
+#main {
+ background-color: #f0f0f0;
+ border-left: 2px solid #cccccc;
+}
+
+#navigation {
+ float: left;
+ width: 14em;
+ vertical-align: top;
+ background-color: #f0f0f0;
+ overflow: visible;
+}
+
+#navigation h2 {
+ background-color:#e7e7e7;
+ font-size:1.1em;
+ color:#000000;
+ text-align: left;
+ padding:0.2em;
+ border-top:1px solid #dddddd;
+ border-bottom:1px solid #dddddd;
+}
+
+#navigation ul
+{
+ font-size:1em;
+ list-style-type: none;
+ margin: 1px 1px 10px 1px;
+}
+
+#navigation li {
+ text-indent: -1em;
+ display: block;
+ margin: 3px 0px 0px 22px;
+}
+
+#navigation li li a {
+ margin: 0px 3px 0px -1em;
+}
+
+#content {
+ margin-left: 14em;
+ padding: 1em;
+ width: 700px;
+ border-left: 2px solid #cccccc;
+ border-right: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#about {
+ clear: both;
+ padding: 5px;
+ border-top: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+@media print {
+ body {
+ font: 12pt "Times New Roman", "TimeNR", Times, serif;
+ }
+ a { font-weight: bold; color: #004080; text-decoration: underline; }
+
+ #main {
+ background-color: #ffffff;
+ border-left: 0px;
+ }
+
+ #container {
+ margin-left: 2%;
+ margin-right: 2%;
+ background-color: #ffffff;
+ }
+
+ #content {
+ padding: 1em;
+ background-color: #ffffff;
+ }
+
+ #navigation {
+ display: none;
+ }
+ pre.example {
+ font-family: "Andale Mono", monospace;
+ font-size: 10pt;
+ page-break-inside: avoid;
+ }
+}
+
+table.module_list {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #cccccc;
+ border-collapse: collapse;
+}
+table.module_list td {
+ border-width: 1px;
+ padding: 3px;
+ border-style: solid;
+ border-color: #cccccc;
+}
+table.module_list td.name { background-color: #f0f0f0; min-width: 200px; }
+table.module_list td.summary { width: 100%; }
+
+
+table.function_list {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #cccccc;
+ border-collapse: collapse;
+}
+table.function_list td {
+ border-width: 1px;
+ padding: 3px;
+ border-style: solid;
+ border-color: #cccccc;
+}
+table.function_list td.name { background-color: #f0f0f0; min-width: 200px; }
+table.function_list td.summary { width: 100%; }
+
+ul.nowrap {
+ overflow:auto;
+ white-space:nowrap;
+}
+
+dl.table dt, dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;}
+dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;}
+dl.table h3, dl.function h3 {font-size: .95em;}
+
+/* stop sublists from having initial vertical space */
+ul ul { margin-top: 0px; }
+ol ul { margin-top: 0px; }
+ol ol { margin-top: 0px; }
+ul ol { margin-top: 0px; }
+
+/* make the target distinct; helps when we're navigating to a function */
+a:target + * {
+ background-color: #FF9;
+}
+
+/* styles for prettification of source */
+pre .comment { color: #558817; }
+pre .constant { color: #a8660d; }
+pre .escape { color: #844631; }
+pre .keyword { color: #aa5050; font-weight: bold; }
+pre .library { color: #0e7c6b; }
+pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
+pre .string { color: #8080ff; }
+pre .number { color: #f8660d; }
+pre .operator { color: #2239a8; font-weight: bold; }
+pre .preprocessor, pre .prepro { color: #a33243; }
+pre .global { color: #800080; }
+pre .prompt { color: #558817; }
+pre .url { color: #272fc2; text-decoration: underline; }
diff --git a/lib/std/_base.lua b/lib/std/_base.lua
deleted file mode 100644
index 0c623d4..0000000
--- a/lib/std/_base.lua
+++ /dev/null
@@ -1,204 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Prevent dependency loops with key function implementations.
-
- A few key functions are used in several stdlib modules; we implement those
- functions in this internal module to prevent dependency loops in the first
- instance, and to minimise coupling between modules where the use of one of
- these functions might otherwise load a whole selection of other supporting
- modules unnecessarily.
-
- Although the implementations are here for logistical reasons, we re-export
- them from their respective logical modules so that the api is not affected
- as far as client code is concerned. The functions in this file do not make
- use of `argcheck` or similar, because we know that they are only called by
- other stdlib functions which have already performed the necessary checking
- and neither do we want to slow everything down by recheckng those argument
- types here.
-
- This implies that when re-exporting from another module when argument type
- checking is in force, we must export a wrapper function that can check the
- user's arguments fully at the API boundary.
-]]
-
-
-local _ENV = require 'std.normalize' {
- concat = 'table.concat',
- dirsep = 'package.dirsep',
- find = 'string.find',
- gsub = 'string.gsub',
- insert = 'table.insert',
- min = 'math.min',
- shallow_copy = 'table.merge',
- sort = 'table.sort',
- sub = 'string.sub',
- table_maxn = table.maxn,
- wrap = 'coroutine.wrap',
- yield = 'coroutine.yield',
-}
-
-
-
---[[ ============================ ]]--
---[[ Enhanced Core Lua functions. ]]--
---[[ ============================ ]]--
-
-
--- These come as early as possible, because we want the rest of the code
--- in this file to use these versions over the core Lua implementation
--- (which have slightly varying semantics between releases).
-
-
-local maxn = table_maxn or function(t)
- local n = 0
- for k in pairs(t) do
- if type(k) == 'number' and k > n then
- n = k
- end
- end
- return n
-end
-
-
-
---[[ ============================ ]]--
---[[ Shared Stdlib API functions. ]]--
---[[ ============================ ]]--
-
-
--- No need to recurse because functables are second class citizens in
--- Lua:
--- func = function() print 'called' end
--- func() --> 'called'
--- functable=setmetatable({}, {__call=func})
--- functable() --> 'called'
--- nested=setmetatable({}, {__call=functable})
--- nested()
--- --> stdin:1: attempt to call a table value(global 'd')
--- --> stack traceback:
--- --> stdin:1: in main chunk
--- --> [C]: in ?
-local function callable(x)
- if type(x) == 'function' then
- return x
- end
- return (getmetatable(x) or {}).__call
-end
-
-
-local function catfile(...)
- return concat({...}, dirsep)
-end
-
-
-local function compare(l, m)
- local lenl, lenm = len(l), len(m)
- for i = 1, min(lenl, lenm) do
- local li, mi = tonumber(l[i]), tonumber(m[i])
- if li == nil or mi == nil then
- li, mi = l[i], m[i]
- end
- if li < mi then
- return -1
- elseif li > mi then
- return 1
- end
- end
- if lenl < lenm then
- return -1
- elseif lenl > lenm then
- return 1
- end
- return 0
-end
-
-
-local function escape_pattern(s)
- return (gsub(s, '[%^%$%(%)%%%.%[%]%*%+%-%?]', '%%%0'))
-end
-
-
-local function invert(t)
- local i = {}
- for k, v in pairs(t) do
- i[v] = k
- end
- return i
-end
-
-
-local function leaves(it, tr)
- local function visit(n)
- if type(n) == 'table' then
- for _, v in it(n) do
- visit(v)
- end
- else
- yield(n)
- end
- end
- return wrap(visit), tr
-end
-
-
-local function split(s, sep)
- local r, patt = {}
- if sep == '' then
- patt = '(.)'
- insert(r, '')
- else
- patt = '(.-)' ..(sep or '%s+')
- end
- local b, slen = 0, len(s)
- while b <= slen do
- local e, n, m = find(s, patt, b + 1)
- insert(r, m or sub(s, b + 1, slen))
- b = n or slen + 1
- end
- return r
-end
-
-
---[[ ============= ]]--
---[[ Internal API. ]]--
---[[ ============= ]]--
-
-
--- For efficient use within stdlib, these functions have no type-checking.
--- In debug mode, type-checking wrappers are re-exported from the public-
--- facing modules as necessary.
---
--- Also, to provide some sanity, we mirror the subtable layout of stdlib
--- public API here too, which means everything looks relatively normal
--- when importing the functions into stdlib implementation modules.
-return {
- io = {
- catfile = catfile,
- },
-
- list = {
- compare = compare,
- },
-
- object = {
- Module = Module,
- mapfields = mapfields,
- },
-
- string = {
- escape_pattern = escape_pattern,
- split = split,
- },
-
- table = {
- invert = invert,
- maxn = maxn,
- },
-
- tree = {
- leaves = leaves,
- },
-}
diff --git a/lib/std/debug.lua b/lib/std/debug.lua
deleted file mode 100644
index cab29ff..0000000
--- a/lib/std/debug.lua
+++ /dev/null
@@ -1,156 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Additions to the core debug module.
-
- The module table returned by `std.debug` also contains all of the entries
- from the core debug table. An hygienic way to import this module, then, is
- simply to override the core `debug` locally:
-
- local debug = require 'std.debug'
-
- @corelibrary std.debug
-]]
-
-
-local _ENV = require 'std.normalize' {
- 'debug',
- _debug = require 'std._debug',
- concat = 'table.concat',
- huge = 'math.huge',
- max = 'math.max',
- merge = 'table.merge',
- stderr = 'io.stderr',
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local function say(n, ...)
- local level, argt = n, {...}
- if type(n) ~= 'number' then
- level, argt = 1, {n, ...}
- end
- if _debug.level ~= huge and
- ((type(_debug.level) == 'number' and _debug.level >= level) or level <= 1)
- then
- local t = {}
- for k, v in pairs(argt) do
- t[k] = str(v)
- end
- stderr:write(concat(t, '\t') .. '\n')
- end
-end
-
-
-local level = 0
-
-local function trace(event)
- local t = debug.getinfo(3)
- local s = ' >>> '
- for i = 1, level do
- s = s .. ' '
- end
- if t ~= nil and t.currentline >= 0 then
- s = s .. t.short_src .. ':' .. t.currentline .. ' '
- end
- t = debug.getinfo(2)
- if event == 'call' then
- level = level + 1
- else
- level = max(level - 1, 0)
- end
- if t.what == 'main' then
- if event == 'call' then
- s = s .. 'begin ' .. t.short_src
- else
- s = s .. 'end ' .. t.short_src
- end
- elseif t.what == 'Lua' then
- s = s .. event .. ' ' ..(t.name or '(Lua)') .. ' <' ..
- t.linedefined .. ':' .. t.short_src .. '>'
- else
- s = s .. event .. ' ' ..(t.name or '(C)') .. ' [' .. t.what .. ']'
- end
- stderr:write(s .. '\n')
-end
-
--- Set hooks according to _debug
-if _debug.call then
- debug.sethook(trace, 'cr')
-end
-
-
-
-local M = {
- --- Function Environments
- -- @section environments
-
- --- Extend `debug.getfenv` to unwrap functables correctly.
- -- @function getfenv
- -- @tparam int|function|functable fn target function, or stack level
- -- @treturn table environment of *fn*
- getfenv = getfenv,
-
- --- Extend `debug.setfenv` to unwrap functables correctly.
- -- @function setfenv
- -- @tparam function|functable fn target function
- -- @tparam table env new function environment
- -- @treturn function *fn*
- setfenv = setfenv,
-
-
- --- Functions
- -- @section functions
-
- --- Print a debugging message to `io.stderr`.
- -- Display arguments passed through `std.tostring` and separated by tab
- -- characters when `std._debug` hinting is `true` and *n* is 1 or less;
- -- or `std._debug.level` is a number greater than or equal to *n*. If
- -- `std._debug` hinting is false or nil, nothing is written.
- -- @function say
- -- @int[opt=1] n debugging level, smaller is higher priority
- -- @param ... objects to print(as for print)
- -- @usage
- -- local _debug = require 'std._debug'
- -- _debug.level = 3
- -- say(2, '_debug status level:', _debug.level)
- say = say,
-
- --- Trace function calls.
- -- Use as debug.sethook(trace, 'cr'), which is done automatically
- -- when `std._debug.call` is set.
- -- Based on test/trace-calls.lua from the Lua distribution.
- -- @function trace
- -- @string event event causing the call
- -- @usage
- -- local _debug = require 'std._debug'
- -- _debug.call = true
- -- local debug = require 'std.debug'
- trace = trace,
-}
-
-
---- Metamethods
--- @section metamethods
-
---- Equivalent to calling `debug.say(1, ...)`
--- @function __call
--- @see say
--- @usage
--- local debug = require 'std.debug'
--- debug 'oh noes!'
-local metatable = {
- __call = function(self, ...)
- M.say(1, ...)
- end,
-}
-
-
-return setmetatable(merge(debug, M), metatable)
diff --git a/lib/std/init.lua b/lib/std/init.lua
deleted file mode 100644
index 732d41f..0000000
--- a/lib/std/init.lua
+++ /dev/null
@@ -1,389 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Enhanced Lua core functions, and others.
-
- After requiring this module, simply referencing symbols in the submodule
- hierarchy will load the necessary modules on demand. There are no
- changes to any global symbols, or monkey patching of core module tables
- and metatables.
-
- @todo Write a style guide(indenting/wrapping, capitalisation,
- function and variable names); library functions should call
- error, not die; OO vs non-OO(a thorny problem).
- @todo pre-compile.
- @corefunction std
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.typecheck.argscheck
-local compare = _.list.compare
-local maxn = _.table.maxn
-local split = _.string.split
-
-_ = nil
-
-
-local _ENV = require 'std.normalize' {
- format = 'string.format',
- match = 'string.match',
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local M
-
-
-local function _assert(expect, fmt, arg1, ...)
- local msg =(arg1 ~= nil) and format(fmt, arg1, ...) or fmt or ''
- return expect or error(msg, 2)
-end
-
-
-local function elems(t)
- -- capture pairs iterator initial state
- local fn, istate, ctrl = pairs(t)
- return function(state, _)
- local v
- ctrl, v = fn(state, ctrl)
- if ctrl then
- return v
- end
- end, istate, true -- wrapped initial state
-end
-
-
-local function eval(s)
- return load('return ' .. s)()
-end
-
-
-local function ielems(t)
- -- capture pairs iterator initial state
- local fn, istate, ctrl = ipairs(t)
- return function(state, _)
- local v
- ctrl, v = fn(state, ctrl)
- if ctrl then
- return v
- end
- end, istate, true -- wrapped initial state
-end
-
-
-local function npairs(t)
- local m = getmetamethod(t, '__len')
- local i, n = 0, m and m(t) or maxn(t)
- return function(t)
- i = i + 1
- if i <= n then
- return i, t[i]
- end
- end,
- t, i
-end
-
-
-local function ripairs(t)
- local oob = 1
- while t[oob] ~= nil do
- oob = oob + 1
- end
-
- return function(t, n)
- n = n - 1
- if n > 0 then
- return n, t[n]
- end
- end, t, oob
-end
-
-
-local function rnpairs(t)
- local m = getmetamethod(t, '__len')
- local oob =(m and m(t) or maxn(t)) + 1
-
- return function(t, n)
- n = n - 1
- if n > 0 then
- return n, t[n]
- end
- end, t, oob
-end
-
-
-local vconvert = setmetatable({
- string = function(x)
- return split(x, '%.')
- end,
- number = function(x)
- return {x}
- end,
- table = function(x)
- return x
- end,
-}, {
- __call = function(self, x)
- local fn = self[type(x)] or function()
- return 0
- end
- return fn(x)
- end,
-})
-
-
-local function vcompare(a, b)
- return compare(vconvert(a), vconvert(b))
-end
-
-
-local function _require(module, min, too_big, pattern)
- pattern = pattern or '([%.%d]+)%D*$'
-
- local s, m = '', require(module)
- if type(m) == 'table' then
- s = tostring(m.version or m._VERSION or '')
- end
- local v = match(s, pattern) or 0
- if min then
- _assert(vcompare(v, min) >= 0, "require '" .. module ..
- "' with at least version " .. min .. ', but found version ' .. v)
- end
- if too_big then
- _assert(vcompare(v, too_big) < 0, "require '" .. module ..
- "' with version less than " .. too_big .. ', but found version ' .. v)
- end
- return m
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.' .. decl, fn) or fn
-end
-
-M = {
- --- Release version string.
- -- @field version
-
-
- --- Core Functions
- -- @section corefuncs
-
- --- Enhance core `assert` to also allow formatted arguments.
- -- @function assert
- -- @param expect expression, expected to be *truthy*
- -- @string[opt=''] f format string
- -- @param[opt] ... arguments to format
- -- @return value of *expect*, if *truthy*
- -- @usage
- -- std.assert(expect == nil, '100% unexpected!')
- -- std.assert(expect == 'expect', '%s the unexpected!', expect)
- assert = X('assert(?any, ?string, [any...])', _assert),
-
- --- Evaluate a string as Lua code.
- -- @function eval
- -- @string s string of Lua code
- -- @return result of evaluating `s`
- -- @usage
- -- --> 2
- -- std.eval 'math.min(2, 10)'
- eval = X('eval(string)', eval),
-
- --- Return named metamethod, if any, otherwise `nil`.
- -- The value found at the given key in the metatable of *x* must be a
- -- function or have its own `__call` metamethod to qualify as a
- -- callable. Any other value found at key *n* will cause this function
- -- to return `nil`.
- -- @function getmetamethod
- -- @param x item to act on
- -- @string n name of metamethod to lookup
- -- @treturn callable|nil callable metamethod, or `nil` if no metamethod
- -- @usage
- -- clone = std.getmetamethod(std.object.prototype, '__call')
- getmetamethod = X('getmetamethod(?any, string)', getmetamethod),
-
-
- --- Module Functions
- -- @section modulefuncs
-
- --- Enhance core `require` to assert version number compatibility.
- -- By default match against the last substring of(dot-delimited)
- -- digits in the module version string.
- -- @function require
- -- @string module module to require
- -- @string[opt] min lowest acceptable version
- -- @string[opt] too_big lowest version that is too big
- -- @string[opt] pattern to match version in `module.version` or
- -- `module._VERSION`(default: `'([%.%d]+)%D*$'`)
- -- @usage
- -- -- posix.version == 'posix library for Lua 5.2 / 32'
- -- posix = require('posix', '29')
- require = X('require(string, ?string, ?string, ?string)', _require),
-
- --- Iterator Functions
- -- @section iteratorfuncs
-
- --- An iterator over all values of a table.
- -- If *t* has a `__pairs` metamethod, use that to iterate.
- -- @function elems
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table *t*, the table being iterated over
- -- @return *key*, the previous iteration key
- -- @see ielems
- -- @see pairs
- -- @usage
- -- --> foo
- -- --> bar
- -- --> baz
- -- --> 5
- -- std.functional.map(print, std.ielems, {'foo', 'bar', [4]='baz', d=5})
- elems = X('elems(table)', elems),
-
- --- An iterator over the integer keyed elements of a table.
- --
- -- If *t* has a `__len` metamethod, iterate up to the index it
- -- returns, otherwise up to the first `nil`.
- --
- -- This function does **not** support the Lua 5.2 `__ipairs` metamethod.
- -- @function ielems
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table *t*, the table being iterated over
- -- @treturn int *index*, the previous iteration index
- -- @see elems
- -- @see ipairs
- -- @usage
- -- --> foo
- -- --> bar
- -- std.functional.map(print, std.ielems, {'foo', 'bar', [4]='baz', d=5})
- ielems = X('ielems(table)', ielems),
-
- --- An iterator over integer keyed pairs of a sequence.
- --
- -- Like Lua 5.1 and 5.3, this iterator returns successive key-value
- -- pairs with integer keys starting at 1, up to the first `nil` valued
- -- pair.
- --
- -- If there is a `_len` metamethod, keep iterating up to and including
- -- that element, regardless of any intervening `nil` values.
- --
- -- This function does **not** support the Lua 5.2 `__ipairs` metamethod.
- -- @function ipairs
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table *t*, the table being iterated over
- -- @treturn int *index*, the previous iteration index
- -- @see ielems
- -- @see npairs
- -- @see pairs
- -- @usage
- -- --> 1 foo
- -- --> 2 bar
- -- std.functional.map(print, std.ipairs, {'foo', 'bar', [4]='baz', d=5})
- ipairs = X('ipairs(table)', ipairs),
-
- --- Ordered iterator for integer keyed values.
- -- Like ipairs, but does not stop until the __len or maxn of *t*.
- -- @function npairs
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table t
- -- @see ipairs
- -- @see rnpairs
- -- @usage
- -- --> 1 foo
- -- --> 2 bar
- -- --> 3 nil
- -- --> 4 baz
- -- std.functional.map(print, std.npairs, {'foo', 'bar', [4]='baz', d=5})
- npairs = X('npairs(table)', npairs),
-
- --- Enhance core `pairs` to respect `__pairs` even in Lua 5.1.
- -- @function pairs
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table *t*, the table being iterated over
- -- @return *key*, the previous iteration key
- -- @see elems
- -- @see ipairs
- -- @usage
- -- --> 1 foo
- -- --> 2 bar
- -- --> 4 baz
- -- --> d 5
- -- std.functional.map(print, std.pairs, {'foo', 'bar', [4]='baz', d=5})
- pairs = X('pairs(table)', pairs),
-
- --- An iterator like ipairs, but in reverse.
- -- Apart from the order of the elements returned, this function follows
- -- the same rules as @{ipairs} for determining first and last elements.
- -- @function ripairs
- -- @tparam table t any table
- -- @treturn function iterator function
- -- @treturn table *t*
- -- @treturn number `#t + 1`
- -- @see ipairs
- -- @see rnpairs
- -- @usage
- -- --> 2 bar
- -- --> 1 foo
- -- std.functional.map(print, std.ripairs, {'foo', 'bar', [4]='baz', d=5})
- ripairs = X('ripairs(table)', ripairs),
-
- --- An iterator like npairs, but in reverse.
- -- Apart from the order of the elements returned, this function follows
- -- the same rules as @{npairs} for determining first and last elements.
- -- @function rnpairs
- -- @tparam table t a table
- -- @treturn function iterator function
- -- @treturn table t
- -- @see npairs
- -- @see ripairs
- -- @usage
- -- --> 4 baz
- -- --> 3 nil
- -- --> 2 bar
- -- --> 1 foo
- -- std.functional.map(print, std.rnpairs, {'foo', 'bar', [4]='baz', d=5})
- rnpairs = X('rnpairs(table)', rnpairs),
-}
-
-
---- Metamethods
--- @section Metamethods
-
-return setmetatable(M, {
- --- Lazy loading of stdlib modules.
- -- Don't load everything on initial startup, wait until first attempt
- -- to access a submodule, and then load it on demand.
- -- @function __index
- -- @string name submodule name
- -- @treturn table|nil the submodule that was loaded to satisfy the missing
- -- `name`, otherwise `nil` if nothing was found
- -- @usage
- -- local std = require 'std'
- -- local Object = std.object.prototype
- __index = function(self, name)
- local ok, t = pcall(require, 'std.' .. name)
- if ok then
- rawset(self, name, t)
- return t
- end
- end,
-})
diff --git a/lib/std/io.lua b/lib/std/io.lua
deleted file mode 100644
index 1a2b79f..0000000
--- a/lib/std/io.lua
+++ /dev/null
@@ -1,322 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Additions to the core io module.
-
- The module table returned by `std.io` also contains all of the entries from
- the core `io` module table. An hygienic way to import this module, then,
- is simply to override core `io` locally:
-
- local io = require 'std.io'
-
- @corelibrary std.io
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.typecheck.argscheck
-local catfile = _.io.catfile
-local leaves = _.tree.leaves
-local split = _.string.split
-
-_ = nil
-
-
-local _ENV = require 'std.normalize' {
- 'io',
- _G = _G, -- FIXME: don't use the host _G as an API!
- concat = 'table.concat',
- dirsep = 'package.dirsep',
- format = 'string.format',
- gsub = 'string.gsub',
- input = 'io.input',
- insert = 'table.insert',
- io_type = 'io.type',
- merge = 'table.merge',
- open = 'io.open',
- output = 'io.output',
- popen = 'io.popen',
- stderr = 'io.stderr',
- stdin = 'io.stdin',
- write = 'io.write',
-}
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local M
-
-
-local function input_handle(h)
- if h == nil then
- return input()
- elseif type(h) == 'string' then
- return open(h)
- end
- return h
-end
-
-
-local function slurp(file)
- local h, err = input_handle(file)
- if h == nil then
- argerror('std.io.slurp', 1, err, 2)
- end
-
- if h then
- local s = h:read('*a')
- h:close()
- return s
- end
-end
-
-
-local function readlines(file)
- local h, err = input_handle(file)
- if h == nil then
- argerror('std.io.readlines', 1, err, 2)
- end
-
- local l = {}
- for line in h:lines() do
- l[#l + 1] = line
- end
- h:close()
- return l
-end
-
-
-local function writelines(h, ...)
- if io_type(h) ~= 'file' then
- write(h, '\n')
- h = output()
- end
- for v in leaves(ipairs, {...}) do
- h:write(v, '\n')
- end
-end
-
-
-local function process_files(fn)
- -- N.B. 'arg' below refers to the global array of command-line args
- if len(arg) == 0 then
- insert(arg, '-')
- end
- for i, v in ipairs(arg) do
- if v == '-' then
- input(stdin)
- else
- input(v)
- end
- fn(v, i)
- end
-end
-
-
-local function warnfmt(msg, ...)
- local prefix = ''
- local prog = rawget(_G, 'prog') or {}
- local opts = rawget(_G, 'opts') or {}
- if prog.name then
- prefix = prog.name .. ':'
- if prog.line then
- prefix = prefix .. str(prog.line) .. ':'
- end
- elseif prog.file then
- prefix = prog.file .. ':'
- if prog.line then
- prefix = prefix .. str(prog.line) .. ':'
- end
- elseif opts.program then
- prefix = opts.program .. ':'
- if opts.line then
- prefix = prefix .. str(opts.line) .. ':'
- end
- end
- if #prefix > 0 then
- prefix = prefix .. ' '
- end
- return prefix .. format(msg, ...)
-end
-
-
-local function warn(msg, ...)
- writelines(stderr, warnfmt(msg, ...))
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.io.' .. decl, fn) or fn
-end
-
-
-M = {
- --- Diagnostic functions
- -- @section diagnosticfuncs
-
- --- Die with error.
- -- This function uses the same rules to build a message prefix
- -- as @{warn}.
- -- @function die
- -- @string msg format string
- -- @param ... additional arguments to plug format string specifiers
- -- @see warn
- -- @usage
- -- die('oh noes!(%s)', tostring(obj))
- die = X('die(string, [any...])', function(...)
- error(warnfmt(...), 0)
- end),
-
- --- Give warning with the name of program and file(if any).
- -- If there is a global `prog` table, prefix the message with
- -- `prog.name` or `prog.file`, and `prog.line` if any. Otherwise
- -- if there is a global `opts` table, prefix the message with
- -- `opts.program` and `opts.line` if any.
- -- @function warn
- -- @string msg format string
- -- @param ... additional arguments to plug format string specifiers
- -- @see die
- -- @usage
- -- local OptionParser = require 'std.optparse'
- -- local parser = OptionParser 'eg 0\nUsage: eg\n'
- -- _G.arg, _G.opts = parser:parse(_G.arg)
- -- if not _G.opts.keep_going then
- -- require 'std.io'.warn 'oh noes!'
- -- end
- warn = X('warn(string, [any...])', warn),
-
-
- --- Path Functions
- -- @section pathfuncs
-
- --- Concatenate directory names into a path.
- -- @function catdir
- -- @string ... path components
- -- @return path without trailing separator
- -- @see catfile
- -- @usage
- -- dirpath = catdir('', 'absolute', 'directory')
- catdir = X('catdir(string...)', function(...)
- return(gsub(concat({...}, dirsep), '^$', dirsep))
- end),
-
- --- Concatenate one or more directories and a filename into a path.
- -- @function catfile
- -- @string ... path components
- -- @treturn string path
- -- @see catdir
- -- @see splitdir
- -- @usage
- -- filepath = catfile('relative', 'path', 'filename')
- catfile = X('catfile(string...)', catfile),
-
- --- Remove the last dirsep delimited element from a path.
- -- @function dirname
- -- @string path file path
- -- @treturn string a new path with the last dirsep and following
- -- truncated
- -- @usage
- -- dir = dirname '/base/subdir/filename'
- dirname = X('dirname(string)', function(path)
- return(gsub(path, catfile('', '[^', ']*$'), ''))
- end),
-
- --- Split a directory path into components.
- -- Empty components are retained: the root directory becomes `{'', ''}`.
- -- @function splitdir
- -- @param path path
- -- @return list of path components
- -- @see catdir
- -- @usage
- -- dir_components = splitdir(filepath)
- splitdir = X('splitdir(string)', function(path)
- return split(path, dirsep)
- end),
-
-
- --- IO Functions
- -- @section iofuncs
-
- --- Process files specified on the command-line.
- -- Each filename is made the default input source with `io.input`, and
- -- then the filename and argument number are passed to the callback
- -- function. In list of filenames, `-` means `io.stdin`. If no
- -- filenames were given, behave as if a single `-` was passed.
- -- @todo Make the file list an argument to the function.
- -- @function process_files
- -- @tparam fileprocessor fn function called for each file argument
- -- @usage
- -- #! /usr/bin/env lua
- -- -- minimal cat command
- -- local io = require 'std.io'
- -- io.process_files(function() io.write(io.slurp()) end)
- process_files = X('process_files(function)', process_files),
-
- --- Read a file or file handle into a list of lines.
- -- The lines in the returned list are not `\n` terminated.
- -- @function readlines
- -- @tparam[opt=io.input()] file|string file file handle or name;
- -- if file is a file handle, that file is closed after reading
- -- @treturn list lines
- -- @usage
- -- list = readlines '/etc/passwd'
- readlines = X('readlines(?file|string)', readlines),
-
- --- Perform a shell command and return its output.
- -- @function shell
- -- @string c command
- -- @treturn string output, or nil if error
- -- @see os.execute
- -- @usage
- -- users = shell [[cat /etc/passwd | awk -F: '{print $1;}']]
- shell = X('shell(string)', function(c) return slurp(popen(c)) end),
-
- --- Slurp a file handle.
- -- @function slurp
- -- @tparam[opt=io.input()] file|string file file handle or name;
- -- if file is a file handle, that file is closed after reading
- -- @return contents of file or handle, or nil if error
- -- @see process_files
- -- @usage
- -- contents = slurp(filename)
- slurp = X('slurp(?file|string)', slurp),
-
- --- Write values adding a newline after each.
- -- @function writelines
- -- @tparam[opt=io.output()] file h open writable file handle;
- -- the file is **not** closed after writing
- -- @tparam string|number ... values to write(as for write)
- -- @usage
- -- writelines(io.stdout, 'first line', 'next line')
- writelines = X('writelines(?file|string|number, [string|number...])', writelines),
-}
-
-
-return merge(io, M)
-
-
-
---- Types
--- @section Types
-
---- Signature of @{process_files} callback function.
--- @function fileprocessor
--- @string filename filename
--- @int i argument number of *filename*
--- @usage
--- local fileprocessor = function(filename, i)
--- io.write(tostring(i) .. ':\n===\n' .. io.slurp(filename) .. '\n')
--- end
--- io.process_files(fileprocessor)
diff --git a/lib/std/math.lua b/lib/std/math.lua
deleted file mode 100644
index d955862..0000000
--- a/lib/std/math.lua
+++ /dev/null
@@ -1,92 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Additions to the core math module.
-
- The module table returned by `std.math` also contains all of the entries from
- the core math table. An hygienic way to import this module, then, is simply
- to override the core `math` locally:
-
- local math = require 'std.math'
-
- @corelibrary std.math
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.typecheck.argscheck
-
-_ = nil
-
-
-local _ENV = require 'std.normalize' {
- 'math',
- merge = 'table.merge',
-}
-
-
-
---[[ ================= ]]--
---[[ Implementatation. ]]--
---[[ ================= ]]--
-
-
-local M
-
-
-local _floor = math.floor
-
-local function floor(n, p)
- if(p or 0) == 0 then
- return _floor(n)
- end
- local e = 10 ^ p
- return _floor(n * e) / e
-end
-
-
-local function round(n, p)
- local e = 10 ^(p or 0)
- return _floor(n * e + 0.5) / e
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.math.' .. decl, fn) or fn
-end
-
-
-M = {
- --- Core Functions
- -- @section corefuncs
-
- --- Extend `math.floor` to take the number of decimal places.
- -- @function floor
- -- @number n number
- -- @int[opt=0] p number of decimal places to truncate to
- -- @treturn number `n` truncated to `p` decimal places
- -- @usage
- -- tenths = floor(magnitude, 1)
- floor = X('floor(number, ?int)', floor),
-
- --- Round a number to a given number of decimal places.
- -- @function round
- -- @number n number
- -- @int[opt=0] p number of decimal places to round to
- -- @treturn number `n` rounded to `p` decimal places
- -- @usage
- -- roughly = round(exactly, 2)
- round = X('round(number, ?int)', round),
-}
-
-
-return merge(math, M)
diff --git a/lib/std/package.lua b/lib/std/package.lua
deleted file mode 100644
index e3e8243..0000000
--- a/lib/std/package.lua
+++ /dev/null
@@ -1,263 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Additions to the core package module.
-
- The module table returned by `std.package` also contains all of the entries
- from the core `package` table. An hygienic way to import this module, then, is
- simply to override core `package` locally:
-
- local package = require 'std.package'
-
- Manage `package.path` with normalization, duplicate removal,
- insertion & removal of elements and automatic folding of '/' and '?'
- onto `package.dirsep` and `package.pathmark`, for easy addition of
- new paths. For example, instead of all this:
-
- lib = std.io.catfile('.', 'lib', package.pathmark .. '.lua')
- paths = std.string.split(package.path, package.pathsep)
- for i, path in ipairs(paths) do
- -- ... lots of normalization code...
- end
- i = 1
- while i <= #paths do
- if paths[i] == lib then
- table.remove(paths, i)
- else
- i = i + 1
- end
- end
- table.insert(paths, 1, lib)
- package.path = table.concat(paths, package.pathsep)
-
- You can now write just:
-
- package.path = package.normalize('./lib/?.lua', package.path)
-
- @corelibrary std.package
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.typecheck.argscheck
-local catfile = _.io.catfile
-local escape_pattern = _.string.escape_pattern
-local invert = _.table.invert
-local split = _.string.split
-
-_ = nil
-
-local _ENV = require 'std.normalize' {
- 'package',
- concat = 'table.concat',
- dirsep = 'package.dirsep',
- gsub = 'string.gsub',
- merge = 'table.merge',
- pathmark = 'package.pathmark',
- pathsep = 'package.pathsep',
- string_find = 'string.find',
- table_insert = 'table.insert',
- table_remove = 'table.remove',
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
---- Make named constants for `package.config`
--- (undocumented in 5.1; see luaconf.h for C equivalents).
--- @table package
--- @string dirsep directory separator
--- @string pathsep path separator
--- @string pathmark string that marks substitution points in a path template
--- @string execdir(Windows only) replaced by the executable's directory in a path
--- @string igmark Mark to ignore all before it when building `luaopen_` function name.
-
-
-local function pathsub(path)
- return gsub(path, '%%?.', function(capture)
- if capture == '?' then
- return pathmark
- elseif capture == '/' then
- return dirsep
- else
- return gsub(capture, '^%%', '', 1)
- end
- end)
-end
-
-
-local function find(pathstrings, patt, init, plain)
- local paths = split(pathstrings, pathsep)
- if plain then
- patt = escape_pattern(patt)
- end
- init = init or 1
- if init < 0 then
- init = #paths - init
- end
- for i = init, #paths do
- if string_find(paths[i], patt) then
- return i, paths[i]
- end
- end
-end
-
-
-local function normalize(...)
- local i, paths, pathstrings = 1, {}, concat({...}, pathsep)
- for _, path in ipairs(split(pathstrings, pathsep)) do
- path = gsub(pathsub(path), catfile('^[^', ']'), catfile('.', '%0'))
- path = gsub(path, catfile('', '%.', ''), dirsep)
- path = gsub(path, catfile('', '%.$'), '')
- path = gsub(path, catfile('^%.', '%..', ''), catfile('..', ''))
- path = gsub(path, catfile('', '$'), '')
-
- -- Carefully remove redundant /foo/../ matches.
- repeat
- local again = false
- path = gsub(path, catfile('', '([^', ']+)', '%.%.', ''),
- function(dir1)
- if dir1 == '..' then -- don't remove /../../
- return catfile('', '..', '..', '')
- else
- again = true
- return dirsep
- end
- end)
- path = gsub(path, catfile('', '([^', ']+)', '%.%.$'),
- function(dir1)
- if dir1 == '..' then -- don't remove /../..
- return catfile('', '..', '..')
- else
- again = true
- return ''
- end
- end)
- until again == false
-
- -- Build an inverted table of elements to eliminate duplicates after
- -- normalization.
- if not paths[path] then
- paths[path], i = i, i + 1
- end
- end
- return concat(invert(paths), pathsep)
-end
-
-
-local function insert(pathstrings, ...)
- local paths = split(pathstrings, pathsep)
- table_insert(paths, ...)
- return normalize(unpack(paths, 1, len(paths)))
-end
-
-
-local function mappath(pathstrings, callback, ...)
- for _, path in ipairs(split(pathstrings, pathsep)) do
- local r = callback(path, ...)
- if r ~= nil then
- return r
- end
- end
-end
-
-
-local function remove(pathstrings, pos)
- local paths = split(pathstrings, pathsep)
- table_remove(paths, pos)
- return concat(paths, pathsep)
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.package.' .. decl, fn) or fn
-end
-
-
-local M = {
- --- Look for a path segment match of *patt* in *pathstrings*.
- -- @function find
- -- @string pathstrings `pathsep` delimited path elements
- -- @string patt a Lua pattern to search for in *pathstrings*
- -- @int[opt=1] init element(not byte index!) to start search at.
- -- Negative numbers begin counting backwards from the last element
- -- @bool[opt=false] plain unless false, treat *patt* as a plain
- -- string, not a pattern. Note that if *plain* is given, then *init*
- -- must be given as well.
- -- @return the matching element number(not byte index!) and full text
- -- of the matching element, if any; otherwise nil
- -- @usage
- -- i, s = find(package.path, '^[^' .. package.dirsep .. '/]')
- find = X('find(string, string, ?int, ?boolean|:plain)', find),
-
- --- Insert a new element into a `package.path` like string of paths.
- -- @function insert
- -- @string pathstrings a `package.path` like string
- -- @int[opt=n+1] pos element index at which to insert *value*, where `n` is
- -- the number of elements prior to insertion
- -- @string value new path element to insert
- -- @treturn string a new string with the new element inserted
- -- @usage
- -- package.path = insert(package.path, 1, install_dir .. '/?.lua')
- insert = X('insert(string, [int], string)', insert),
-
- --- Call a function with each element of a path string.
- -- @function mappath
- -- @string pathstrings a `package.path` like string
- -- @tparam mappathcb callback function to call for each element
- -- @param ... additional arguments passed to *callback*
- -- @return nil, or first non-nil returned by *callback*
- -- @usage
- -- mappath(package.path, searcherfn, transformfn)
- mappath = X('mappath(string, function, [any...])', mappath),
-
- --- Normalize a path list.
- -- Removing redundant `.` and `..` directories, and keep only the first
- -- instance of duplicate elements. Each argument can contain any number
- -- of `pathsep` delimited elements; wherein characters are subject to
- -- `/` and `?` normalization, converting `/` to `dirsep` and `?` to
- -- `pathmark`(unless immediately preceded by a `%` character).
- -- @function normalize
- -- @param ... path elements
- -- @treturn string a single normalized `pathsep` delimited paths string
- -- @usage
- -- package.path = normalize(user_paths, sys_paths, package.path)
- normalize = X('normalize(string...)', normalize),
-
- --- Remove any element from a `package.path` like string of paths.
- -- @function remove
- -- @string pathstrings a `package.path` like string
- -- @int[opt=n] pos element index from which to remove an item, where `n`
- -- is the number of elements prior to removal
- -- @treturn string a new string with given element removed
- -- @usage
- -- package.path = remove(package.path)
- remove = X('remove(string, ?int)', remove),
-}
-
-
-return merge(package, M)
-
-
---- Types
--- @section Types
-
---- Function signature of a callback for @{mappath}.
--- @function mappathcb
--- @string element an element from a `pathsep` delimited string of
--- paths
--- @param ... additional arguments propagated from @{mappath}
--- @return non-nil to break, otherwise continue with the next element
diff --git a/lib/std/string.lua b/lib/std/string.lua
deleted file mode 100644
index 6ad9014..0000000
--- a/lib/std/string.lua
+++ /dev/null
@@ -1,505 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Additions to the core string module.
-
- The module table returned by `std.string` also contains all of the entries
- from the core string table. An hygienic way to import this module, then, is
- simply to override the core `string` locally:
-
- local string = require 'std.string'
-
- @corelibrary std.string
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.std.typecheck.argscheck
-local escape_pattern = _.string.escape_pattern
-local split = _.string.split
-
-_ = nil
-
-
-local _ENV = require 'std.normalize' {
- 'string',
- abs = 'math.abs',
- concat = 'table.concat',
- find = 'string.find',
- floor = 'math.floor',
- format = 'string.format',
- gsub = 'string.gsub',
- insert = 'table.insert',
- match = 'string.match',
- merge = 'table.merge',
- render = 'string.render',
- sort = 'table.sort',
- sub = 'string.sub',
- upper = 'string.upper',
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local M
-
-
-local function toqstring(x, xstr)
- if type(x) ~= 'string' then
- return xstr
- end
- return format('%q', x)
-end
-
-
-local concatvfns = {
- elem = tostring,
- term = function(x)
- return type(x) ~= 'table' or getmetamethod(x, '__tostring')
- end,
- sort = function(keys)
- return keys
- end,
- open = function(x) return '{' end,
- close = function(x) return '}' end,
- pair = function(x, kp, vp, k, v, kstr, vstr, seqp)
- return toqstring(k, kstr) .. '=' .. toqstring(v, vstr)
- end,
- sep = function(x, kp, vp, kn, vn, seqp)
- return kp ~= nil and kn ~= nil and ',' or ''
- end,
-}
-
-
-local function __concat(s, o)
- -- Don't use normalize.str here, because we don't want ASCII escape rendering.
- return render(s, concatvfns) .. render(o, concatvfns)
-end
-
-
-local function __index(s, i)
- if type(i) == 'number' then
- return sub(s, i, i)
- else
- -- Fall back to module metamethods
- return M[i]
- end
-end
-
-
-local _format = string.format
-
-local function format(f, arg1, ...)
- return(arg1 ~= nil) and _format(f, arg1, ...) or f
-end
-
-
-local function tpack(from, to, ...)
- return from, to, {...}
-end
-
-local function tfind(s, ...)
- return tpack(find(s, ...))
-end
-
-
-local function finds(s, p, i, ...)
- i = i or 1
- local l = {}
- local from, to, r
- repeat
- from, to, r = tfind(s, p, i, ...)
- if from ~= nil then
- insert(l, {from, to, capt=r})
- i = to + 1
- end
- until not from
- return l
-end
-
-
-local function caps(s)
- return(gsub(s, '(%w)([%w]*)', function(l, ls)
- return upper(l) .. ls
- end))
-end
-
-
-local function escape_shell(s)
- return(gsub(s, '([ %(%)%\\%[%]\'"])', '\\%1'))
-end
-
-
-local function ordinal_suffix(n)
- n = abs(n) % 100
- local d = n % 10
- if d == 1 and n ~= 11 then
- return 'st'
- elseif d == 2 and n ~= 12 then
- return 'nd'
- elseif d == 3 and n ~= 13 then
- return 'rd'
- else
- return 'th'
- end
-end
-
-
-local function pad(s, w, p)
- p = string.rep(p or ' ', abs(w))
- if w < 0 then
- return string.sub(p .. s, w)
- end
- return string.sub(s .. p, 1, w)
-end
-
-
-local function wrap(s, w, ind, ind1)
- w = w or 78
- ind = ind or 0
- ind1 = ind1 or ind
- assert(ind1 < w and ind < w,
- 'the indents must be less than the line width')
- local r = {string.rep(' ', ind1)}
- local i, lstart, lens = 1, ind1, len(s)
- while i <= lens do
- local j = i + w - lstart
- while len(s[j]) > 0 and s[j] ~= ' ' and j > i do
- j = j - 1
- end
- local ni = j + 1
- while s[j] == ' ' do
- j = j - 1
- end
- insert(r, sub(s, i, j))
- i = ni
- if i < lens then
- insert(r, '\n' .. string.rep(' ', ind))
- lstart = ind
- end
- end
- return concat(r)
-end
-
-
-local function numbertosi(n)
- local SIprefix = {
- [-8]='y', [-7]='z', [-6]='a', [-5]='f',
- [-4]='p', [-3]='n', [-2]='mu', [-1]='m',
- [0]='', [1]='k', [2]='M', [3]='G',
- [4]='T', [5]='P', [6]='E', [7]='Z',
- [8]='Y'
- }
- local t = _format('% #.2e', n)
- local _, _, m, e = find(t, '.(.%...)e(.+)')
- local man, exp = tonumber(m), tonumber(e)
- local siexp = floor(exp / 3)
- local shift = exp - siexp * 3
- local s = SIprefix[siexp] or 'e' .. tostring(siexp)
- man = man *(10 ^ shift)
- return _format('%0.f', man) .. s
-end
-
-
--- Ordor numbers first then asciibetically.
-local function keycmp(a, b)
- if type(a) == 'number' then
- return type(b) ~= 'number' or a < b
- end
- return type(b) ~= 'number' and tostring(a) < tostring(b)
-end
-
-
-local render_fallbacks = {
- __index = concatvfns,
-}
-
-
-local function prettytostring(x, indent, spacing)
- indent = indent or '\t'
- spacing = spacing or ''
- return render(x, setmetatable({
- elem = function(x)
- if type(x) ~= 'string' then
- return tostring(x)
- end
- return format('%q', x)
- end,
-
- sort = function(keylist)
- sort(keylist, keycmp)
- return keylist
- end,
-
- open = function()
- local s = spacing .. '{'
- spacing = spacing .. indent
- return s
- end,
-
- close = function()
- spacing = string.gsub(spacing, indent .. '$', '')
- return spacing .. '}'
- end,
-
- pair = function(x, _, _, k, v, kstr, vstr)
- local type_k = type(k)
- local s = spacing
- if type_k ~= 'string' or match(k, '[^%w_]') then
- s = s .. '['
- if type_k == 'table' then
- s = s .. '\n'
- end
- s = s .. kstr
- if type_k == 'table' then
- s = s .. '\n'
- end
- s = s .. ']'
- else
- s = s .. k
- end
- s = s .. ' ='
- if type(v) == 'table' then
- s = s .. '\n'
- else
- s = s .. ' '
- end
- s = s .. vstr
- return s
- end,
-
- sep = function(_, k)
- local s = '\n'
- if k then
- s = ',' .. s
- end
- return s
- end,
- }, render_fallbacks))
-end
-
-
-local function trim(s, r)
- r = r or '%s+'
- return (gsub(gsub(s, '^' .. r, ''), r .. '$', ''))
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.string.' .. decl, fn) or fn
-end
-
-M = {
- --- Metamethods
- -- @section metamethods
-
- --- String concatenation operation.
- -- @function __concat
- -- @string s initial string
- -- @param o object to stringify and concatenate
- -- @return s .. tostring(o)
- -- @usage
- -- local string = setmetatable('', require 'std.string')
- -- concatenated = 'foo' .. {'bar'}
- __concat = __concat,
-
- --- String subscript operation.
- -- @function __index
- -- @string s string
- -- @tparam int|string i index or method name
- -- @return `sub(s, i, i)` if i is a number, otherwise
- -- fall back to a `std.string` metamethod(if any).
- -- @usage
- -- getmetatable('').__index = require 'std.string'.__index
- -- third =('12345')[3]
- __index = __index,
-
-
- --- Core Functions
- -- @section corefuncs
-
- --- Capitalise each word in a string.
- -- @function caps
- -- @string s any string
- -- @treturn string *s* with each word capitalized
- -- @usage
- -- userfullname = caps(input_string)
- caps = X('caps(string)', caps),
-
- --- Remove any final newline from a string.
- -- @function chomp
- -- @string s any string
- -- @treturn string *s* with any single trailing newline removed
- -- @usage
- -- line = chomp(line)
- chomp = X('chomp(string)', function(s)
- return(gsub(s, '\n$', ''))
- end),
-
- --- Escape a string to be used as a pattern.
- -- @function escape_pattern
- -- @string s any string
- -- @treturn string *s* with active pattern characters escaped
- -- @usage
- -- substr = match(inputstr, escape_pattern(literal))
- escape_pattern = X('escape_pattern(string)', escape_pattern),
-
- --- Escape a string to be used as a shell token.
- -- Quotes spaces, parentheses, brackets, quotes, apostrophes and
- -- whitespace.
- -- @function escape_shell
- -- @string s any string
- -- @treturn string *s* with active shell characters escaped
- -- @usage
- -- os.execute('echo ' .. escape_shell(outputstr))
- escape_shell = X('escape_shell(string)', escape_shell),
-
- --- Repeatedly `string.find` until target string is exhausted.
- -- @function finds
- -- @string s target string
- -- @string pattern pattern to match in *s*
- -- @int[opt=1] init start position
- -- @bool[opt] plain inhibit magic characters
- -- @return list of `{from, to; capt={captures}}`
- -- @see std.string.tfind
- -- @usage
- -- for t in std.elems(finds('the target string', '%S+')) do
- -- print(tostring(t.capt))
- -- end
- finds = X('finds(string, string, ?int, ?boolean|:plain)', finds),
-
- --- Extend to work better with one argument.
- -- If only one argument is passed, no formatting is attempted.
- -- @function format
- -- @string f format string
- -- @param[opt] ... arguments to format
- -- @return formatted string
- -- @usage
- -- print(format '100% stdlib!')
- format = X('format(string, [any...])', format),
-
- --- Remove leading matter from a string.
- -- @function ltrim
- -- @string s any string
- -- @string[opt='%s+'] r leading pattern
- -- @treturn string *s* with leading *r* stripped
- -- @usage
- -- print('got: ' .. ltrim(userinput))
- ltrim = X('ltrim(string, ?string)', function(s, r)
- return (gsub(s, '^' ..(r or '%s+'), ''))
- end),
-
- --- Write a number using SI suffixes.
- -- The number is always written to 3 s.f.
- -- @function numbertosi
- -- @tparam number|string n any numeric value
- -- @treturn string *n* simplifed using largest available SI suffix.
- -- @usage
- -- print(numbertosi(bitspersecond) .. 'bps')
- numbertosi = X('numbertosi(number|string)', numbertosi),
-
- --- Return the English suffix for an ordinal.
- -- @function ordinal_suffix
- -- @tparam int|string n any integer value
- -- @treturn string English suffix for *n*
- -- @usage
- -- local now = os.date '*t'
- -- print('%d%s day of the week', now.day, ordinal_suffix(now.day))
- ordinal_suffix = X('ordinal_suffix(int|string)', ordinal_suffix),
-
- --- Justify a string.
- -- When the string is longer than w, it is truncated(left or right
- -- according to the sign of w).
- -- @function pad
- -- @string s a string to justify
- -- @int w width to justify to(-ve means right-justify; +ve means
- -- left-justify)
- -- @string[opt=' '] p string to pad with
- -- @treturn string *s* justified to *w* characters wide
- -- @usage
- -- print(pad(trim(outputstr, 78)) .. '\n')
- pad = X('pad(string, int, ?string)', pad),
-
- --- Pretty-print a table, or other object.
- -- @function prettytostring
- -- @param x object to convert to string
- -- @string[opt='\t'] indent indent between levels
- -- @string[opt=''] spacing space before every line
- -- @treturn string pretty string rendering of *x*
- -- @usage
- -- print(prettytostring(std, ' '))
- prettytostring = X('prettytostring(?any, ?string, ?string)', prettytostring),
-
- --- Remove trailing matter from a string.
- -- @function rtrim
- -- @string s any string
- -- @string[opt='%s+'] r trailing pattern
- -- @treturn string *s* with trailing *r* stripped
- -- @usage
- -- print('got: ' .. rtrim(userinput))
- rtrim = X('rtrim(string, ?string)', function(s, r)
- return (gsub(s, (r or '%s+') .. '$', ''))
- end),
-
- --- Split a string at a given separator.
- -- Separator is a Lua pattern, so you have to escape active characters,
- -- `^$()%.[]*+-?` with a `%` prefix to match a literal character in *s*.
- -- @function split
- -- @string s to split
- -- @string[opt='%s+'] sep separator pattern
- -- @return list of strings
- -- @usage
- -- words = split 'a very short sentence'
- split = X('split(string, ?string)', split),
-
- --- Do `string.find`, returning a table of captures.
- -- @function tfind
- -- @string s target string
- -- @string pattern pattern to match in *s*
- -- @int[opt=1] init start position
- -- @bool[opt] plain inhibit magic characters
- -- @treturn int start of match
- -- @treturn int end of match
- -- @treturn table list of captured strings
- -- @see std.string.finds
- -- @usage
- -- b, e, captures = tfind('the target string', '%s', 10)
- tfind = X('tfind(string, string, ?int, ?boolean|:plain)', tfind),
-
- --- Remove leading and trailing matter from a string.
- -- @function trim
- -- @string s any string
- -- @string[opt='%s+'] r trailing pattern
- -- @treturn string *s* with leading and trailing *r* stripped
- -- @usage
- -- print('got: ' .. trim(userinput))
- trim = X('trim(string, ?string)', trim),
-
- --- Wrap a string into a paragraph.
- -- @function wrap
- -- @string s a paragraph of text
- -- @int[opt=78] w width to wrap to
- -- @int[opt=0] ind indent
- -- @int[opt=ind] ind1 indent of first line
- -- @treturn string *s* wrapped to *w* columns
- -- @usage
- -- print(wrap(copyright, 72, 4))
- wrap = X('wrap(string, ?int, ?int, ?int)', wrap),
-}
-
-
-return merge(string, M)
-
diff --git a/lib/std/table.lua b/lib/std/table.lua
deleted file mode 100644
index 7bda608..0000000
--- a/lib/std/table.lua
+++ /dev/null
@@ -1,439 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2002-2018 stdlib authors
-]]
---[[--
- Extensions to the core table module.
-
- The module table returned by `std.table` also contains all of the entries from
- the core table module. An hygienic way to import this module, then, is simply
- to override the core `table` locally:
-
- local table = require 'std.table'
-
- @corelibrary std.table
-]]
-
-
-local _ = require 'std._base'
-
-local argscheck = _.typecheck and _.typecheck.argscheck
-local invert = _.table.invert
-local maxn = _.table.maxn
-
-_ = nil
-
-local _ENV = require 'std.normalize' {
- 'table',
- merge = 'table.merge',
- min = 'math.min',
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local M
-
-
-local function merge_allfields(t, u, map, nometa)
- if type(map) ~= 'table' then
- map, nometa = nil, map
- end
-
- if not nometa then
- setmetatable(t, getmetatable(u))
- end
- if map then
- for k, v in pairs(u) do
- t[map[k] or k] = v
- end
- else
- for k, v in pairs(u) do
- t[k] = v
- end
- end
- return t
-end
-
-
-local function merge_namedfields(t, u, keys, nometa)
- if type(keys) ~= 'table' then
- keys, nometa = nil, keys
- end
-
- if not nometa then
- setmetatable(t, getmetatable(u))
- end
- for _, k in pairs(keys or {}) do
- t[k] = u[k]
- end
- return t
-end
-
-
-local function depair(ls)
- local t = {}
- for _, v in ipairs(ls) do
- t[v[1]] = v[2]
- end
- return t
-end
-
-
-local function enpair(t)
- local tt = {}
- for i, v in pairs(t) do
- tt[#tt + 1] = {i, v}
- end
- return tt
-end
-
-
-local _insert = table.insert
-
-local function insert(t, pos, v)
- if v == nil then
- pos, v = len(t) + 1, pos
- end
- if pos < 1 or pos > len(t) + 1 then
- argerror('std.table.insert', 2, 'position ' .. pos .. ' out of bounds', 2)
- end
- _insert(t, pos, v)
- return t
-end
-
-
-local function keys(t)
- local l = {}
- for k in pairs(t) do
- l[#l + 1] = k
- end
- return l
-end
-
-
-local function new(x, t)
- return setmetatable(t or {}, {__index = function(t, i)
- return x
- end})
-end
-
-
-local function project(fkey, tt)
- local r = {}
- for _, t in ipairs(tt) do
- r[#r + 1] = t[fkey]
- end
- return r
-end
-
-
-local function size(t)
- local n = 0
- for _ in pairs(t) do
- n = n + 1
- end
- return n
-end
-
-
--- Preserve core table sort function.
-local _sort = table.sort
-
-local function sort(t, c)
- _sort(t, c)
- return t
-end
-
-
-local _remove = table.remove
-
-local function remove(t, pos)
- local lent = len(t)
- pos = pos or lent
- if pos < min(1, lent) or pos > lent + 1 then -- +1? whu? that's what 5.2.3 does!?!
- argerror('std.table.remove', 2, 'position ' .. pos .. ' out of bounds', 2)
- end
- return _remove(t, pos)
-end
-
-
-local _unpack = unpack
-
-local function unpack(t, i, j)
- if j == nil then
- -- if j was not given, respect __len, otherwise use maxn
- local m = getmetamethod(t, '__len')
- j = m and m(t) or maxn(t)
- end
- return _unpack(t, tonumber(i) or 1, tonumber(j))
-end
-
-
-local function values(t)
- local l = {}
- for _, v in pairs(t) do
- l[#l + 1] = v
- end
- return l
-end
-
-
-
---[[ ================= ]]--
---[[ Public Interface. ]]--
---[[ ================= ]]--
-
-
-local function X(decl, fn)
- return argscheck and argscheck('std.table.' .. decl, fn) or fn
-end
-
-M = {
- --- Core Functions
- -- @section corefuncs
-
- --- Enhance core *table.insert* to return its result.
- -- If *pos* is not given, respect `__len` metamethod when calculating
- -- default append. Also, diagnose out of bounds *pos* arguments
- -- consistently on any supported version of Lua.
- -- @function insert
- -- @tparam table t a table
- -- @int[opt=len(t)] pos index at which to insert new element
- -- @param v value to insert into *t*
- -- @treturn table *t*
- -- @usage
- -- --> {1, 'x', 2, 3, 'y'}
- -- insert(insert({1, 2, 3}, 2, 'x'), 'y')
- insert = X('insert(table, [int], any)', insert),
-
- --- Largest integer key in a table.
- -- @function maxn
- -- @tparam table t a table
- -- @treturn int largest integer key in *t*
- -- @usage
- -- --> 42
- -- maxn {'a', b='c', 99, [42]='x', 'x', [5]=67}
- maxn = X('maxn(table)', maxn),
-
- --- Turn a tuple into a list, with tuple-size in field `n`
- -- @function pack
- -- @param ... tuple
- -- @return list-like table, with tuple-size in field `n`
- -- @usage
- -- --> {1, 2, 'ax', n=3}
- -- pack(find('ax1', '(%D+)'))
- pack = pack,
-
- --- Enhance core *table.remove* to respect `__len` when *pos* is omitted.
- -- Also, diagnose out of bounds *pos* arguments consistently on any supported
- -- version of Lua.
- -- @function remove
- -- @tparam table t a table
- -- @int[opt=len(t)] pos index from which to remove an element
- -- @return removed value, or else `nil`
- -- @usage
- -- --> {1, 2, 5}
- -- t = {1, 2, 'x', 5}
- -- remove(t, 3) == 'x' and t
- remove = X('remove(table, ?int)', remove),
-
- --- Enhance core *table.sort* to return its result.
- -- @function sort
- -- @tparam table t unsorted table
- -- @tparam[opt=std.operator.lt] comparator c ordering function callback
- -- @return *t* with keys sorted according to *c*
- -- @usage
- -- table.concat(sort(object))
- sort = X('sort(table, ?function)', sort),
-
- --- Enhance core *table.unpack* to always unpack up to __len or maxn.
- -- @function unpack
- -- @tparam table t table to act on
- -- @int[opt=1] i first index to unpack
- -- @int[opt=table.maxn(t)] j last index to unpack
- -- @return ... values of numeric indices of *t*
- -- @usage
- -- return unpack(results_table)
- unpack = X('unpack(table, ?int, ?int)', unpack),
-
-
- --- Accessor Functions
- -- @section accessorfuncs
-
- --- Make a shallow copy of a table, including any metatable.
- -- @function clone
- -- @tparam table t source table
- -- @tparam[opt={}] table map table of `{old_key=new_key, ...}`
- -- @bool[opt] nometa if non-nil don't copy metatable
- -- @return copy of *t*, also sharing *t*'s metatable unless *nometa*
- -- is true, and with keys renamed according to *map*
- -- @see merge
- -- @see clone_select
- -- @usage
- -- shallowcopy = clone(original, {rename_this='to_this'}, ':nometa')
- clone = X('clone(table, [table], ?boolean|:nometa)', function(...)
- return merge_allfields({}, ...)
- end),
-
- --- Make a partial clone of a table.
- --
- -- Like `clone`, but does not copy any fields by default.
- -- @function clone_select
- -- @tparam table t source table
- -- @tparam[opt={}] table keys list of keys to copy
- -- @bool[opt] nometa if non-nil don't copy metatable
- -- @treturn table copy of fields in *selection* from *t*, also sharing *t*'s
- -- metatable unless *nometa*
- -- @see clone
- -- @see merge_select
- -- @usage
- -- partialcopy = clone_select(original, {'this', 'and_this'}, true)
- clone_select = X('clone_select(table, [table], ?boolean|:nometa)', function(...)
- return merge_namedfields({}, ...)
- end),
-
- --- Turn a list of pairs into a table.
- -- @todo Find a better name.
- -- @function depair
- -- @tparam table ls list of lists
- -- @treturn table a flat table with keys and values from *ls*
- -- @see enpair
- -- @usage
- -- --> {a=1, b=2, c=3}
- -- depair {{'a', 1}, {'b', 2}, {'c', 3}}
- depair = X('depair(list of lists)', depair),
-
- --- Turn a table into a list of pairs.
- -- @todo Find a better name.
- -- @function enpair
- -- @tparam table t a table `{i1=v1, ..., in=vn}`
- -- @treturn table a new list of pairs containing `{{i1, v1}, ..., {in, vn}}`
- -- @see depair
- -- @usage
- -- --> {{1, 'a'}, {2, 'b'}, {3, 'c'}}
- -- enpair {'a', 'b', 'c'}
- enpair = X('enpair(table)', enpair),
-
- --- Return whether table is empty.
- -- @function empty
- -- @tparam table t any table
- -- @treturn boolean `true` if *t* is empty, otherwise `false`
- -- @usage
- -- if empty(t) then error 'ohnoes' end
- empty = X('empty(table)', function(t)
- return not next(t)
- end),
-
- --- Make a table with a default value for unset keys.
- -- @function new
- -- @param[opt=nil] x default entry value
- -- @tparam[opt={}] table t initial table
- -- @treturn table table whose unset elements are *x*
- -- @usage
- -- t = new(0)
- new = X('new(?any, ?table)', new),
-
- --- Project a list of fields from a list of tables.
- -- @function project
- -- @param fkey field to project
- -- @tparam table tt a list of tables
- -- @treturn table list of *fkey* fields from *tt*
- -- @usage
- -- --> {1, 3, 'yy'}
- -- project('xx', {{'a', xx=1, yy='z'}, {'b', yy=2}, {'c', xx=3}, {xx='yy'})
- project = X('project(any, list of tables)', project),
-
- --- Find the number of elements in a table.
- -- @function size
- -- @tparam table t any table
- -- @treturn int number of non-nil values in *t*
- -- @usage
- -- --> 3
- -- size {foo=true, bar=true, baz=false}
- size = X('size(table)', size),
-
- --- Make the list of values of a table.
- -- @function values
- -- @tparam table t any table
- -- @treturn table list of values in *t*
- -- @see keys
- -- @usage
- -- --> {'a', 'c', 42}
- -- values {'a', b='c', [-1]=42}
- values = X('values(table)', values),
-
-
- --- Mutator Functions
- -- @section mutatorfuncs
-
- --- Invert a table.
- -- @function invert
- -- @tparam table t a table with `{k=v, ...}`
- -- @treturn table inverted table `{v=k, ...}`
- -- @usage
- -- --> {a=1, b=2, c=3}
- -- invert {'a', 'b', 'c'}
- invert = X('invert(table)', invert),
-
- --- Make the list of keys in table.
- -- @function keys
- -- @tparam table t a table
- -- @treturn table list of keys from *t*
- -- @see values
- -- @usage
- -- globals = keys(_G)
- keys = X('keys(table)', keys),
-
- --- Destructively merge one table's fields into another.
- -- @function merge
- -- @tparam table t destination table
- -- @tparam table u table with fields to merge
- -- @tparam[opt={}] table map table of `{old_key=new_key, ...}`
- -- @bool[opt] nometa if `true` or ':nometa' don't copy metatable
- -- @treturn table *t* with fields from *u* merged in
- -- @see clone
- -- @see merge_select
- -- @usage
- -- merge(_G, require 'std.debug', {say='log'}, ':nometa')
- merge = X('merge(table, table, [table], ?boolean|:nometa)', merge_allfields),
-
- --- Destructively merge another table's named fields into *table*.
- --
- -- Like `merge`, but does not merge any fields by default.
- -- @function merge_select
- -- @tparam table t destination table
- -- @tparam table u table with fields to merge
- -- @tparam[opt={}] table keys list of keys to copy
- -- @bool[opt] nometa if `true` or ':nometa' don't copy metatable
- -- @treturn table copy of fields in *selection* from *t*, also sharing *t*'s
- -- metatable unless *nometa*
- -- @see merge
- -- @see clone_select
- -- @usage
- -- merge_select(_G, require 'std.debug', {'say'}, false)
- merge_select = X('merge_select(table, table, [table], ?boolean|:nometa)',
- merge_namedfields),
-}
-
-
-return merge(table, M)
-
-
-
---- Types
--- @section Types
-
---- Signature of a @{sort} comparator function.
--- @function comparator
--- @param a any object
--- @param b any object
--- @treturn boolean `true` if *a* sorts before *b*, otherwise `false`
--- @see sort
--- @usage
--- local reversor = function(a, b) return a > b end
--- sort(t, reversor)
diff --git a/modules/std.debug.html b/modules/std.debug.html
new file mode 100644
index 0000000..052f34c
--- /dev/null
+++ b/modules/std.debug.html
@@ -0,0 +1,857 @@
+
+
+
+
+ stdlib 41.2.2 Reference
+
+
+
+
+
The module table returned by std.debug also contains all of the entries
+ from the core debug table. An hygienic way to import this module, then, is
+ simply to override the core debug locally:
+
+
+
+localdebug = require"std.debug"
+
+
+
The behaviour of the functions in this module are controlled by the value
+ of the global _DEBUG. Not setting _DEBUG prior to requiring any of
+ stdlib's modules is equivalent to having _DEBUG = true.
+
+
The first line of Lua code in production quality projects that use stdlib
+ should be either:
+
+
+
+_DEBUG = false
+
+
+
or alternatively, if you need to be careful not to damage the global
+ environment:
Split a typespec string into a table of normalized type names.
+
+
+
+
+
+
+
+
Functions
+ Methods
+
+
+
+ DEPRECATED (version, name[, extramsg], fn)
+
+
+ Provide a deprecated function definition according to _DEBUG.deprecate.
+ You can check whether your covered code uses deprecated functions by
+ setting _DEBUG.deprecate to true before loading any stdlib modules,
+ or silence deprecation warnings by setting _DEBUG.deprecate = false.
+
+
+
Parameters:
+
+
version
+ string
+ first deprecation release version
+
+
name
+ string
+ function name for automatic warning message
+
+
extramsg
+ string
+ additional warning text
+ (optional)
+
+
fn
+ func
+ deprecated function
+
+
+
+
Returns:
+
+
+ a function to show the warning on first call, and hand off to fn
+
+
+
+
+
+
+ argcheck (name, i, expected, actual[, level=2])
+
+
+ Check the type of an argument against expected types.
+ Equivalent to luaL_argcheck in the Lua C API.
+
+
Call argerror if there is a type mismatch.
+
+
Argument actual must match one of the types from in expected, each
+ of which can be the name of a primitive Lua type, a stdlib object type,
+ or one of the special options below:
+
+
#table accept any non-empty table
+any accept any non-nil argument type
+file accept an open file object
+function accept a function, or object with a __call metamethod
+int accept an integer valued number
+list accept a table where all keys are a contiguous 1-based integer range
+#list accept any non-empty list
+object accept any std.Object derived type
+:foo accept only the exact string ":foo", works for any :-prefixed string
+
+
+
The :foo format allows for type-checking of self-documenting
+ boolean-like constant string parameters predicated on nil versus
+ :option instead of false versus true. Or you could support
+ both:
A very common pattern is to have a list of possible types including
+ "nil" when the argument is optional. Rather than writing long-hand
+ as above, prepend a question mark to the list of types and omit the
+ explicit "nil" entry:
Normally, you should not need to use the level parameter, as the
+ default is to blame the caller of the function using argcheck in
+ error messages; which is almost certainly what you want.
+
+
+
Parameters:
+
+
name
+ string
+ function to blame in error message
+
+
i
+ int
+ argument number to blame in error message
+
+
expected
+ string
+ specification for acceptable argument types
+
+
actual
+ argument passed
+
+
level
+ int
+ call stack level to blame for the error
+ (default 2)
+
+ Raise a bad argument error.
+ Equivalent to luaL_argerror in the Lua C API. This function does not
+ return. The level argument behaves just like the core error
+ function.
+
+
+
Parameters:
+
+
name
+ string
+ function to callout in error message
+
+
i
+ int
+ argument number
+
+
extramsg
+ string
+ additional text to append to message inside parentheses
+ (optional)
+
+
level
+ int
+ call stack level to blame for the error
+ (default 1)
+
+ localfunction slurp (file)
+ local h, err = input_handle (file)
+ if h == nilthen argerror ("std.io.slurp", 1, err, 2) end
+ ...
+
+
+
+
+
+ argscheck (decl, inner)
+
+
+
+
Wrap a function definition with argument type and arity checking.
+ In addition to checking that each argument type matches the corresponding
+ element in the types table with argcheck, if the final element of
+ types ends with an ellipsis, remaining unchecked arguments are checked
+ against that type:
+
+
format = argscheck ("string.format (string, ?any...)", string.format)
+
+
+
A colon in the function name indicates that the argument type list does
+ not have a type for self:
+
+
format = argscheck ("string:format (?any...)", string.format)
+
+
+
If an argument can be omitted entirely, then put its type specification
+ in square brackets:
+ if fmt ~= nilandtype (fmt) ~= "string"then
+ argerror ("format", 1, extramsg_mismatch ("?string", fmt))
+ end
+
+
+
+
+
+ parsetypes (types)
+
+
+ Compact permutation list into a list of valid types at each argument.
+ Eliminate bracketed types by combining all valid types at each position
+ for all permutations of typelist.
+
+
+
+
+
+ list
+ valid types for each positional parameter
+
+
+
+
+
+
+
+
+ say ([n=1], ...)
+
+
+ Print a debugging message to io.stderr.
+ Display arguments passed through std.tostring and separated by tab
+ characters when _DEBUG is true and n is 1 or less; or _DEBUG.level
+ is a number greater than or equal to n. If _DEBUG is false or
+ nil, nothing is written.
+
+
+
Parameters:
+
+
n
+ int
+ debugging level, smaller is higher priority
+ (default 1)
+
+
...
+ objects to print (as for print)
+
+
+
+
+
+
+
Usage:
+
+
+ local _DEBUG = require"std.debug_init"._DEBUG
+ _DEBUG.level = 3
+ say (2, "_DEBUG table contents:", _DEBUG)
+
+
+
+
+
+ trace (event)
+
+
+ Trace function calls.
+ Use as debug.sethook (trace, "cr"), which is done automatically
+ when _DEBUG.call is set.
+ Based on test/trace-calls.lua from the Lua distribution.
+
+
+
+ Control std.debug function behaviour.
+ To declare debugging state, set _DEBUG either to false to disable all
+ runtime debugging; to any "truthy" value (equivalent to enabling everything
+ except call, or as documented below.
+
+
+
deprecate
+ if false, deprecated APIs are defined,
+ and do not issue deprecation warnings when used; if nil issue a
+ deprecation warning each time a deprecated api is used; any other
+ value causes deprecated APIs not to be defined at all
+ (default nil)
+
+ if maxn (argt) > 7then
+ argerror ("sevenses", 8, extramsg_toomany ("argument", 7, maxn (argt)))
+ end
+
+
+
+
+
+ getfenv
+
+
+ Extend debug.getfenv to unwrap functables correctly.
+
+
+
+
fn
+ int, function or functable
+ target function, or stack level
+
+
+
+
+
+
+
+
+
+
+ resulterror
+
+
+ Raise a bad result error.
+ Like argerror for bad results. This function does not
+ return. The level argument behaves just like the core error
+ function.
+
+
+
+
name
+ string
+ function to callout in error message
+
+
i
+ int
+ argument number
+
+
extramsg
+ string
+ additional text to append to message inside parentheses
+ (optional)
+
+
level
+ int
+ call stack level to blame for the error
+ (default 1)
+
+
+
+
+
+
+
Usage:
+
+
+ localfunction slurp (file)
+ local h, err = input_handle (file)
+ if h == nilthen argerror ("std.io.slurp", 1, err, 2) end
+ ...
+
+
+
+
+
+ setfenv
+
+
+ Extend debug.setfenv to unwrap functables correctly.
+
+
+
+
+
+ function with argt arguments already bound
+
+
+
+
+
Usage:
+
+
cube = bind (std.operator.pow, {[2] = 3})
+
+
+
+
+
+ callable (x)
+
+
+ Identify callable types.
+
+
+
Parameters:
+
+
x
+ an object or primitive
+
+
+
+
Returns:
+
+
+ true if x can be called, otherwise false
+
+
+
+
+
Usage:
+
+
if callable (functable) then functable (args) end
+
+
+
+
+
+ case (with, branches)
+
+
+ A rudimentary case statement.
+ Match with against keys in branches table.
+
+
+
Parameters:
+
+
with
+ expression to match
+
+
branches
+ table
+ map possible matches to functions
+
+
+
+
Returns:
+
+
+ the value associated with a matching key, or the first non-key
+ value if no key matches. Function or functable valued matches are
+ called using with as the sole argument, and the result of that call
+ returned; otherwise the matching value associated with the matching
+ key is returned directly; or else nil if there is no match and no
+ default.
+
+
+
+
+
+
+ function
+ composition of fnN .. fn1: note that this is the
+ reverse of what you might expect, but means that code like:
+
+
functional.compose (function (x) return f (x) end,
+ function (x) return g (x) end))
+
+
+
can be read from top to bottom.
+
+
+
+
+
Usage:
+
+
+ vpairs = compose (table.invert, ipairs)
+ for v, i in vpairs {"a", "b", "c"} do process (v, i) end
+
+
+
+
+
+ cond (expr, branch, ...)
+
+
+ A rudimentary condition-case statement.
+ If expr is "truthy" return branch if given, otherwise expr
+ itself. If the return value is a function or functable, then call it
+ with expr as the sole argument and return the result; otherwise
+ return it explicitly. If expr is "falsey", then recurse with the
+ first two arguments stripped.
+
+
+
Parameters:
+
+
expr
+ a Lua expression
+
+
branch
+ a function, functable or value to use if expr is
+ "truthy"
+
+
...
+ additional arguments to retry if expr is "falsey"
+
+ Fold a binary function left associatively.
+ If parameter d is omitted, the first element of t is used,
+ and t treated as if it had been passed without that element.
+
+
+
+ Fold a binary function right associatively.
+ If parameter d is omitted, the last element of t is used,
+ and t treated as if it had been passed without that element.
+
+
+
Parameters:
+
+
fn
+ func
+ binary function
+
+
d
+ initial right-most argument
+ (default t[1])
+
+ Compile a lambda string into a Lua function.
+
+
A valid lambda string takes one of the following forms:
+
+
+
'=expression': equivalent to function (...) return expression end
+
'|args|expression': equivalent to function (args) return expression end
+
+
+
The first form (starting with '=') automatically assigns the first
+ nine arguments to parameters '_1' through '_9' for use within the
+ expression body. The parameter '_1' is aliased to '_', and if the
+ first non-whitespace of the whole expression is '_', then the
+ leading '=' can be omitted.
+
+
The results are memoized, so recompiling a previously compiled
+ lambda string is extremely fast.
+
+
+
+ Memoize a function, by wrapping it in a functable.
+
+
To ensure that memoize always returns the same results for the same
+ arguments, it passes arguments to fn. You can specify a more
+ sophisticated function if memoize should handle complicated argument
+ equivalencies.
+
+
+
Parameters:
+
+
fn
+ func
+ pure function: a function with no side effects
+
+
normfn
+ normalize
+ function to normalize arguments
+ (default std.tostring)
+
+
+
+
Returns:
+
+
+ functable
+ memoized function
+
+
+
+
+
Usage:
+
+
local fast = memoize (function (...) --[[ slow code ]]end)
+
+
+
+
+
+ nop ()
+
+
+ No operation.
+ This function ignores all arguments, and returns no values.
+
+
+
+
+
+
+ Zip a table of tables.
+ Make a new table, with lists of elements at the same index in the
+ original table. This function is effectively its own inverse.
+
+
+
+
+
+ table
+ a new table of results from calls to fn with arguments
+ made from all elements the same key in the original tables; effectively
+ the "columns" in a simple list
+ of lists.
+
+
+
+
This module contains a selection of improved Lua core functions, among
+ others.
+
+
Also, after requiring this module, simply referencing symbols in the
+ submodule hierarchy will load the necessary modules on demand.
+
+
By default there are no changes to any global symbols, or monkey
+ patching of core module tables and metatables. However, sometimes it's
+ still convenient to do that: For example, when using stdlib from the
+ REPL, or in a prototype where you want to throw caution to the wind and
+ compatibility with other modules be damned. In that case, you can give
+ stdlib permission to scribble all over your namespaces by using the
+ various monkey_patch calls in the library.
Apply allmonkey_patch functions. Additionally, for backwards
+ compatibility only, write a selection of sub-module functions into
+ the given namespace.
+
+
+
Parameters:
+
+
namespace
+ table
+ where to install global functions
+ (default _G)
+
for v in std.ielems {"a", "b", "c"} do process (v) end
+
+
+
+
+
+ ipairs (t)
+
+
+ An iterator over elements of a sequence, until the first nil value.
+
+
Like Lua 5.1 and 5.3, but unlike Lua 5.2 (which looks for and uses the
+ __ipairs metamethod), this iterator returns successive key-value
+ pairs with integer keys starting at 1, up to the first nil valued
+ pair.
+
+
+
+ -- length of sequence
+ args = {"first", "second", nil, "last"}
+ --> 1=first
+--> 2=second
+for i, v in std.ipairs (args) do
+ print (string.format ("%d=%s", i, v))
+ end
+
+
+
+
+
+ ireverse (t)
+
+
+ Return a new table with element order reversed.
+ Apart from the order of the elments returned, this function follows
+ the same rules as ipairs for determining first and last elements.
+
+
+
+ Enhance core require to assert version number compatibility.
+ By default match against the last substring of (dot-delimited)
+ digits in the module version string.
+
+
+
+ An iterator like ipairs, but in reverse.
+ Apart from the order of the elments returned, this function follows
+ the same rules as ipairs for determining first and last elements.
+
+
+
+ An iterator like npairs, but in reverse.
+ Apart from the order of the elments returned, this function follows
+ the same rules as npairs for determining first and last elements.
+
+
+
In addition to the functions documented on this page, and a version
+ field, references to other submodule functions will be loaded on
+ demand.
+
+
+
Fields:
+
+
version
+ release version string
+
+
+
+
+
+
+
+
+
+
Metamethods
+
+
+
+
+
+ __index (name)
+
+
+ Lazy loading of stdlib modules.
+ Don't load everything on initial startup, wait until first attempt
+ to access a submodule, and then load it on demand.
+
+
+
The module table returned by std.io also contains all of the entries from
+ the core io module table. An hygienic way to import this module, then,
+ is simply to override core io locally:
+ Process files specified on the command-line.
+ Each filename is made the default input source with io.input, and
+ then the filename and argument number are passed to the callback
+ function. In list of filenames, - means io.stdin. If no
+ filenames were given, behave as if a single - was passed.
+
+
+
Parameters:
+
+
fn
+ fileprocessor
+ function called for each file argument
+
+ Give warning with the name of program and file (if any).
+ If there is a global prog table, prefix the message with
+ prog.name or prog.file, and prog.line if any. Otherwise
+ if there is a global opts table, prefix the message with
+ opts.program and opts.line if any. std.optparse:parse
+ returns an opts table that provides the required program
+ field, as long as you assign it back to _G.opts.
+
+
+
The module table returned by std.math also contains all of the entries from
+ the core math table. An hygienic way to import this module, then, is simply
+ to override the core math locally:
The module table returned by std.package also contains all of the entries
+ from the core package table. An hygienic way to import this module, then, is
+ simply to override core package locally:
+ Look for a path segment match of patt in pathstrings.
+
+
+
Parameters:
+
+
pathstrings
+ string
+ pathsep delimited path elements
+
+
patt
+ string
+ a Lua pattern to search for in pathstrings
+
+
init
+ int
+ element (not byte index!) to start search at.
+ Negative numbers begin counting backwards from the last element
+ (default 1)
+
+
plain
+ bool
+ unless false, treat patt as a plain
+ string, not a pattern. Note that if plain is given, then init
+ must be given as well.
+ (default false)
+
+
+
+
Returns:
+
+
+ the matching element number (not byte index!) and full text
+ of the matching element, if any; otherwise nil
+
+
+
+
+
Usage:
+
+
i, s = find (package.path, "^[^" .. package.dirsep .. "/]")
+
+
+
+
+
+ insert (pathstrings[, pos=n+1], value)
+
+
+ Insert a new element into a package.path like string of paths.
+
+
+
Parameters:
+
+
pathstrings
+ string
+ a package.path like string
+
+
pos
+ int
+ element index at which to insert value, where n is
+ the number of elements prior to insertion
+ (default n+1)
+
+ Call a function with each element of a path string.
+
+
+
Parameters:
+
+
pathstrings
+ string
+ a package.path like string
+
+
callback
+ mappathcb
+ function to call for each element
+
+
...
+ additional arguments passed to callback
+
+
+
+
Returns:
+
+
+ nil, or first non-nil returned by callback
+
+
+
+
+
Usage:
+
+
mappath (package.path, searcherfn, transformfn)
+
+
+
+
+
+ normalize (...)
+
+
+ Normalize a path list.
+ Removing redundant . and .. directories, and keep only the first
+ instance of duplicate elements. Each argument can contain any number
+ of pathsep delimited elements; wherein characters are subject to
+ / and ? normalization, converting / to dirsep and ? to
+ path_mark (unless immediately preceded by a % character).
+
+
+
Parameters:
+
+
...
+ path elements
+
+
+
+
Returns:
+
+
+ string
+ a single normalized pathsep delimited paths string
+
+
+
+
+
All global variables must be 'declared' through a regular
+ assignment (even assigning nil will do) in a top-level
+ chunk before being used anywhere or assigned to inside a function.
+
+
To use this module, just require it near the start of your program.
The module table returned by std.string also contains all of the entries
+ from the core string table. An hygienic way to import this module, then, is
+ simply to override the core string locally:
+
+
+ string
+ s with trailing r stripped
+
+
+
+
+
Usage:
+
+
print ("got: " .. rtrim (userinput))
+
+
+
+
+
+ split (s[, sep="%s+"])
+
+
+ Split a string at a given separator.
+ Separator is a Lua pattern, so you have to escape active characters,
+ ^$()%.[]*+-? with a % prefix to match a literal character in s.
+
+
+
+ Signature of render pair callback.
+ Trying to re-render key or value here will break recursion
+ detection, use strkey and strvalue pre-rendered values instead.
+
+
+
Parameters:
+
+
t
+ table
+ table containing pair being rendered
+
The module table returned by std.table also contains all of the entries from
+ the core table module. An hygienic way to import this module, then, is simply
+ to override the core table locally:
+ Enhance core table.insert to return its result.
+ If pos is not given, respect __len metamethod when calculating
+ default append. Also, diagnose out of bounds pos arguments
+ consistently on any supported version of Lua.
+
+
+
+ Enhance core table.remove to respect __len when pos is omitted.
+ Also, diagnose out of bounds pos arguments consistently on any supported
+ version of Lua.
+
+
+
pos
+ int
+ index from which to remove an element
+ (default len (t))
+
+
+
+
Returns:
+
+
+ removed value, or else nil
+
+
+
+
+
Usage:
+
+
+ --> {1, 2, 5}
+ t = {1, 2, "x", 5}
+ remove (t, 3) == "x"and t
+
+
+
+
+
+ shape (dims, t)
+
+
+ Shape a table according to a list of dimensions.
+
+
Dimensions are given outermost first and items from the original
+ list are distributed breadth first; there may be one 0 indicating
+ an indefinite number. Hence, {0} is a flat list,
+ {1} is a singleton, {2, 0} is a list of
+ two lists, and {0, 2} is a list of pairs.
+
+
Algorithm: turn shape into all positive numbers, calculating
+ the zero if necessary and making sure there is at most one;
+ recursively walk the shape, adding empty tables until the bottom
+ level is reached at which point add table items instead, using a
+ counter to walk the flattened original list.
+
+
+
+ local reversor = function (a, b) return a > b end
+ sort (t, reversor)
+
+
+
+
+
+
+
+
+
+generated by LDoc 1.4.3
+Last updated 2018-09-03 17:48:42
+
+
+
+
diff --git a/spec/debug_spec.yaml b/spec/debug_spec.yaml
deleted file mode 100644
index 5102723..0000000
--- a/spec/debug_spec.yaml
+++ /dev/null
@@ -1,222 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before: |
- base_module = 'debug'
- this_module = 'std.debug'
- global_table = '_G'
-
- extend_base = {'getfenv', 'setfenv', 'say', 'trace'}
-
- M = require(this_module)
-
-
-specify std.debug:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core debug table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core debug table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).
- to_equal {}
- - it does not touch the core debug table:
- expect(show_apis {added_to=base_module, by='std'}).
- to_equal {}
-
-
-- describe debug:
- - it does nothing when std._debug is disabled:
- expect(luaproc [[
- require 'std._debug'(false)
- require 'std.debug'('nothing to see here')
- ]]).not_to_contain_error 'nothing to see here'
- - it writes to stderr when std._debug is not set:
- expect(luaproc [[
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
- - it writes to stderr when std._debug is enabled:
- expect(luaproc [[
- require 'std._debug'(true)
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
- - it writes to stderr when std._debug.level is not set:
- expect(luaproc [[
- require 'std._debug'()
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
- - it writes to stderr when std._debug.level is specified:
- expect(luaproc [[
- require 'std._debug'.level = 0
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
- expect(luaproc [[
- require 'std._debug'.level = 1
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
- expect(luaproc [[
- require 'std._debug'.level = 2
- require 'std.debug'('debugging')
- ]]).to_contain_error 'debugging'
-
-
-- describe say:
- - it uses normalize.str:
- expect(luaproc [[require 'std.debug'.say {'debugging'}]]).
- to_contain_error(require 'std.normalize'.str {'debugging'})
- - context when std._debug is disabled:
- - before:
- preamble = [[
- require 'std._debug'(false)
- ]]
- - it does nothing when message level is not set:
- expect(luaproc(preamble .. [[
- require 'std.debug'.say 'nothing to see here'
- ]])).not_to_contain_error 'nothing to see here'
- - it does nothing when message is set:
- for _, level in next, {-999, 0, 1, 2, 999} do
- expect(luaproc(preamble .. [[
- require 'std.debug'.say(]] .. level .. [[, 'nothing to see here')
- ]])).not_to_contain_error 'nothing to see here'
- end
- - context when std._debug is not set:
- - it writes to stderr when message level is not set:
- expect(luaproc [[
- require 'std.debug'.say 'debugging'
- ]]).to_contain_error 'debugging'
- - it writes to stderr when message level is 1 or lower:
- for _, level in next, {-999, 0, 1} do
- expect(luaproc([[
- require 'std.debug'.say(]] .. level .. [[, 'debugging')
- ]])).to_contain_error 'debugging'
- end
- - it does nothing when message level is 2 or higher:
- for _, level in next, {2, 999} do
- expect(luaproc([[
- require 'std.debug'.say(]] .. level .. [[, 'nothing to see here')
- ]])).not_to_contain_error 'nothing to see here'
- end
- - context when std._debug is enabled:
- - before:
- preamble = [[
- require 'std._debug'(true)
- ]]
- - it writes to stderr when message level is not set:
- expect(luaproc(preamble .. [[
- require 'std.debug'.say 'debugging'
- ]])).to_contain_error 'debugging'
- - it writes to stderr when message level is 1 or lower:
- for _, level in next, {-999, 0, 1} do
- expect(luaproc(preamble .. [[
- require 'std.debug'.say(]] .. level .. [[, 'debugging')
- ]])).to_contain_error 'debugging'
- end
- - it does nothing when message level is 2 or higher:
- for _, level in next, {2, 999} do
- expect(luaproc(preamble .. [[
- require 'std.debug'.say(]] .. level .. [[, 'nothing to see here')
- ]])).not_to_contain_error 'nothing to see here'
- end
- - context when std._debug.level is not set:
- - it writes to stderr when message level is not set:
- expect(luaproc [[
- require 'std.debug'.say 'debugging'
- ]]).to_contain_error 'debugging'
- - it writes to stderr when message level is 1 or lower:
- for _, level in next, {-999, 0, 1} do
- expect(luaproc([[
- require 'std.debug'.say(]] .. level .. [[, 'debugging')
- ]])).to_contain_error 'debugging'
- end
- - it does nothing when message level is 2 or higher:
- for _, level in next, {2, 999} do
- expect(luaproc([[
- require 'std.debug'.say(]] .. level .. [[, 'nothing to see here')
- ]])).not_to_contain_error 'nothing to see here'
- end
- - context when std._debug.level is specified:
- - it writes to stderr when message level is 1 or lower:
- for _, level in next, {0, 1, 2} do
- expect(luaproc([[
- require 'std._debug'.level = ]] .. level .. [[
- require 'std.debug'.say 'debugging'
- ]])).to_contain_error 'debugging'
- end
- - it does nothing when message level is higher than debug level:
- expect(luaproc [[
- require 'std._debug'.level = 2
- require 'std.debug'.say(3, 'nothing to see here')
- ]]).not_to_contain_error 'nothing to see here'
- - it writes to stderr when message level equals debug level:
- expect(luaproc [[
- require 'std._debug'.level = 2
- require 'std.debug'.say(2, 'debugging')
- ]]).to_contain_error 'debugging'
- - it writes to stderr when message level is lower than debug level:
- expect(luaproc [[
- require 'std._debug'.level = 2
- require 'std.debug'.say(1, 'debugging')
- ]]).to_contain_error 'debugging'
-
-
-- describe trace:
- - before:
- f = init(M, this_module, 'trace')
-
- - it does nothing when debug hint is disabled:
- expect(luaproc [[
- require 'std._debug'(false)
- require 'std.debug'
- os.exit(0)
- ]]).to_succeed_with ''
- - it does nothing when debug hint is not set:
- expect(luaproc [[
- require 'std.debug'
- os.exit(0)
- ]]).to_succeed_with ''
- - it does nothing when debug hint is enabled:
- expect(luaproc [[
- require 'std._debug'(true)
- require 'std.debug'
- os.exit(0)
- ]]).to_succeed_with ''
- - it enables automatically when std._debug.call is set: |
- expect(luaproc [[
- require 'std._debug'.call = true
- require 'std.debug'
- os.exit(1)
- ]]).to_fail_while_containing ':3 call exit'
- - it is enabled manually with debug.sethook: |
- expect(luaproc [[
- local debug = require 'std.debug'
- debug.sethook(debug.trace, 'cr')
- os.exit(1)
- ]]).to_fail_while_containing ':3 call exit'
- - it writes call trace log to standard error: |
- expect(luaproc [[
- local debug = require 'std.debug'
- debug.sethook(debug.trace, 'cr')
- os.exit(0)
- ]]).to_contain_error ':3 call exit'
- - it traces lua calls: |
- expect(luaproc [[
- local debug = require 'std.debug' -- line 1
- local function incr(i) return i + 1 end -- line 2
- debug.sethook(debug.trace, 'cr') -- line 3
- os.exit(incr(41)) -- line 4
- ]]).to_fail_while_matching '.*:4 call incr <2:.*:4 return incr <2:.*'
- - it traces C api calls: |
- expect(luaproc [[
- local debug = require 'std.debug'
- local function incr(i) return i + 1 end
- debug.sethook(debug.trace, 'cr')
- os.exit(incr(41))
- ]]).to_fail_while_matching '.*:4 call exit %[C%]%s$'
diff --git a/spec/io_spec.yaml b/spec/io_spec.yaml
deleted file mode 100644
index 67b850f..0000000
--- a/spec/io_spec.yaml
+++ /dev/null
@@ -1,439 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before: |
- base_module = 'io'
- this_module = 'std.io'
- global_table = '_G'
-
- extend_base = {'catdir', 'catfile', 'die', 'dirname',
- 'process_files', 'readlines', 'shell', 'slurp',
- 'splitdir', 'warn', 'writelines'}
-
- dirsep = string.match(package.config, '^([^\n]+)\n')
-
- M = require(this_module)
-
-
-specify std.io:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core io table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core io table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).
- to_equal {}
- - it does not touch the core io table:
- expect(show_apis {added_to=base_module, by='std'}).
- to_equal {}
-
-
-- describe catdir:
- - before: |
- f = M.catdir
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.catdir(string*)')
-
- - it treats initial empty string as root directory:
- expect(f('')).to_be(dirsep)
- expect(f('', '')).to_be(dirsep)
- expect(f('', 'root')).to_be(dirsep .. 'root')
- - it returns a single argument unchanged:
- expect(f('hello')).to_be 'hello'
- - it joins multiple arguments with platform directory separator:
- expect(f('one', 'two')).to_be('one' .. dirsep .. 'two')
- expect(f('1', '2', '3', '4', '5')).
- to_be(table.concat({'1', '2', '3', '4', '5'}, dirsep))
-
-
-- describe catfile:
- - before:
- f = M.catfile
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.catfile(string*)')
-
- - it treats initial empty string as root directory:
- expect(f('', '')).to_be(dirsep)
- expect(f('', 'root')).to_be(dirsep .. 'root')
- - it returns a single argument unchanged:
- expect(f('')).to_be ''
- expect(f('hello')).to_be 'hello'
- - it joins multiple arguments with platform directory separator:
- expect(f('one', 'two')).to_be('one' .. dirsep .. 'two')
- expect(f('1', '2', '3', '4', '5')).
- to_be(table.concat({'1', '2', '3', '4', '5'}, dirsep))
-
-
-- describe die:
- - before: |
- script = [[require 'std.io'.die "By 'eck!"]]
-
- f = M.die
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.die(string, ?any*)')
-
- - it outputs a message to stderr: |
- expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n"
- - it ignores `prog.line` without `prog.file` or `prog.name`: |
- script = [[prog = {line=125};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n"
- - it ignores `opts.line` without `opts.program`: |
- script = [[opts = {line=99};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": By 'eck!\n"
- - it prefixes `prog.name` if any: |
- script = [[prog = {name='name'};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": name: By 'eck!\n"
- - it appends `prog.line` if any, to `prog.name`: |
- script = [[prog = {line=125, name='name'};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": name:125: By 'eck!\n"
- - it prefixes `prog.file` if any: |
- script = [[prog = {file='file'};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": file: By 'eck!\n"
- - it appends `prog.line` if any, to `prog.name`: |
- script = [[prog = {file='file', line=125};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": file:125: By 'eck!\n"
- - it prefers `prog.name` to `prog.file` or `opts.program`: |
- script = [[
- prog = {file='file', name='name'}
- opts = {program='program'}
- ]] .. script
- expect(luaproc(script)).to_fail_while_matching ": name: By 'eck!\n"
- - it appends `prog.line` if any to `prog.name` over anything else: |
- script = [[
- prog = {file='file', line=125, name='name'}
- opts = {line=99, program='program'}
- ]] .. script
- expect(luaproc(script)).to_fail_while_matching ": name:125: By 'eck!\n"
- - it prefers `prog.file` to `opts.program`: |
- script = [[
- prog = {file='file'}; opts = {program='program'}
- ]] .. script
- expect(luaproc(script)).to_fail_while_matching ": file: By 'eck!\n"
- - it appends `prog.line` if any to `prog.file` over using `opts`: |
- script = [[
- prog = {file='file', line=125}
- opts = {line=99, program='program'}
- ]] .. script
- expect(luaproc(script)).to_fail_while_matching ": file:125: By 'eck!\n"
- - it prefixes `opts.program` if any: |
- script = [[opts = {program='program'};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": program: By 'eck!\n"
- - it appends `opts.line` if any, to `opts.program`: |
- script = [[opts = {line=99, program='program'};]] .. script
- expect(luaproc(script)).to_fail_while_matching ": program:99: By 'eck!\n"
-
-
-- describe dirname:
- - before:
- f = M.dirname
- path = table.concat({'', 'one', 'two', 'three'}, dirsep)
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.dirname(string)')
-
- - it removes final separator and following:
- expect(f(path)).to_be(table.concat({'', 'one', 'two'}, dirsep))
-
-
-- describe process_files:
- - before:
- name = 'Makefile'
- names = {'LICENSE.md', 'Makefile', 'README.md'}
- ascript = [[
- require 'std.io'.process_files(function(a)
- print(a)
- end)
- ]]
- lscript = [[
- require 'std.io'.process_files('=print(_1)')
- ]]
- iscript = [[
- require 'std.io'.process_files(function(_, i)
- print(i)
- end)
- ]]
- catscript = [[
- require 'std.io'.process_files(function()
- io.write(io.input():read '*a')
- end)
- ]]
-
- f = M.process_files
-
- - context with bad arguments: |
- badargs.diagnose(f, 'std.io.process_files(func)')
-
- examples {
- ["it diagnoses non-file 'arg' elements"] = function()
- expect(luaproc(ascript, 'not-an-existing-file')).to_contain_error.any_of {
- "cannot open file 'not-an-existing-file'", -- Lua 5.2
- "bad argument #1 to 'input' (not-an-existing-file:", -- Lua 5.1
- }
- end
- }
-
- - it defaults to `-` if no arguments were passed:
- expect(luaproc(ascript)).to_output '-\n'
- - it iterates over arguments with supplied function:
- expect(luaproc(ascript, name)).to_output(name .. '\n')
- expect(luaproc(ascript, names)).
- to_output(table.concat(names, '\n') .. '\n')
- - it passes argument numbers to supplied function:
- expect(luaproc(iscript, names)).to_output '1\n2\n3\n'
- - it sets each file argument as the default input:
- expect(luaproc(catscript, name)).to_output(concat_file_content(name))
- expect(luaproc(catscript, names)).
- to_output(concat_file_content(unpack(names)))
- - it processes io.stdin if no arguments were passed:
- ## FIXME: where does that closing newline come from??
- expect(luaproc(catscript, nil, 'some\nlines\nof input')).to_output 'some\nlines\nof input\n'
- - it processes io.stdin for `-` argument:
- ## FIXME: where does that closing newline come from??
- expect(luaproc(catscript, '-', 'some\nlines\nof input')).to_output 'some\nlines\nof input\n'
-
-
-- describe readlines:
- - before: |
- name = 'Makefile'
- h = io.open(name)
- lines = {}
- for l in h:lines() do
- lines[#lines + 1] = l
- end
- h:close()
-
- defaultin = io.input()
-
- f, badarg = init(M, this_module, 'readlines')
- - after:
- if io.type(defaultin) ~= 'closed file' then
- io.input(defaultin)
- end
-
- - context with bad arguments: |
- badargs.diagnose(f, 'std.io.readlines(?file|string)')
-
- if have_typecheck then
- examples {
- ['it diagnoses non-existent file'] = function()
- expect(f 'not-an-existing-file').
- to_raise "bad argument #1 to 'std.io.readlines'(" -- system dependent error message
- end
- }
- closed = io.open(name, 'r') closed:close()
- examples {
- ['it diagnoses closed file argument'] = function()
- expect(f(closed)).to_raise(badarg(1, '?file|string', 'closed file'))
- end
- }
- end
-
- - it closes file handle upon completion:
- h = io.open(name)
- expect(io.type(h)).not_to_be 'closed file'
- f(h)
- expect(io.type(h)).to_be 'closed file'
- - it reads lines from an existing named file:
- expect(f(name)).to_equal(lines)
- - it reads lines from an open file handle:
- expect(f(io.open(name))).to_equal(lines)
- - it reads from default input stream with no arguments:
- io.input(name)
- expect(f()).to_equal(lines)
-
-
-- describe shell:
- - before:
- f = M.shell
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.shell(string)')
-
- - it returns the output from a shell command string:
- expect(f [[printf '%s\n' 'foo' 'bar']]).to_be 'foo\nbar\n'
-
-
-- describe slurp:
- - before: |
- name = 'Makefile'
- h = io.open(name)
- content = h:read '*a'
- h:close()
-
- defaultin = io.input()
- f, badarg = init(M, this_module, 'slurp')
- - after:
- if io.type(defaultin) ~= 'closed file' then
- io.input(defaultin)
- end
-
- - context with bad arguments: |
- badargs.diagnose(f, 'std.io.slurp(?file|string)')
-
- if have_typecheck then
- examples {
- ['it diagnoses non-existent file'] = function()
- expect(f 'not-an-existing-file').
- to_raise "bad argument #1 to 'std.io.slurp'(" -- system dependent error message
- end
- }
- closed = io.open(name, 'r') closed:close()
- examples {
- ['it diagnoses closed file argument'] = function()
- expect(f(closed)).to_raise(badarg(1, '?file|string', 'closed file'))
- end
- }
- end
-
- - it reads content from an existing named file:
- expect(f(name)).to_be(content)
- - it reads content from an open file handle:
- expect(f(io.open(name))).to_be(content)
- - it closes file handle upon completion:
- h = io.open(name)
- expect(io.type(h)).not_to_be 'closed file'
- f(h)
- expect(io.type(h)).to_be 'closed file'
- - it reads from default input stream with no arguments:
- io.input(name)
- expect(f()).to_be(content)
-
-
-- describe splitdir:
- - before:
- f = M.splitdir
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.splitdir(string)')
-
- - it returns a filename as a one element list:
- expect(f('hello')).to_equal {'hello'}
- - it splits root directory in two empty elements:
- expect(f(dirsep)).to_equal {'', ''}
- - it returns initial empty string for absolute path:
- expect(f(dirsep .. 'root')).to_equal {'', 'root'}
- - it returns multiple components split at platform directory separator:
- expect(f('one' .. dirsep .. 'two')).to_equal {'one', 'two'}
- expect(f(table.concat({'1', '2', '3', '4', '5'}, dirsep))).
- to_equal {'1', '2', '3', '4', '5'}
-
-
-- describe warn:
- - before:
- script = [[require 'std.io'.warn 'Ayup!']]
- f = M.warn
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.io.warn(string, ?any*)')
-
- - it outputs a message to stderr:
- expect(luaproc(script)).to_output_error 'Ayup!\n'
- - it ignores `prog.line` without `prog.file`, `prog.name` or `opts.program`:
- script = [[prog = {line=125};]] .. script
- expect(luaproc(script)).to_output_error 'Ayup!\n'
- - it prefixes `prog.name` if any: |
- script = [[prog = {name='name'};]] .. script
- expect(luaproc(script)).to_output_error 'name: Ayup!\n'
- - it appends `prog.line` if any, to `prog.name`: |
- script = [[prog = {line=125, name='name'};]] .. script
- expect(luaproc(script)).to_output_error 'name:125: Ayup!\n'
- - it prefixes `prog.file` if any: |
- script = [[prog = {file='file'};]] .. script
- expect(luaproc(script)).to_output_error 'file: Ayup!\n'
- - it appends `prog.line` if any, to `prog.name`: |
- script = [[prog = {file='file', line=125};]] .. script
- expect(luaproc(script)).to_output_error 'file:125: Ayup!\n'
- - it prefers `prog.name` to `prog.file` or `opts.program`: |
- script = [[
- prog = {file='file', name='name'}
- opts = {program='program'}
- ]] .. script
- expect(luaproc(script)).to_output_error 'name: Ayup!\n'
- - it appends `prog.line` if any to `prog.name` over anything else: |
- script = [[
- prog = {file='file', line=125, name='name'}
- opts = {line=99, program='program'}
- ]] .. script
- expect(luaproc(script)).to_output_error 'name:125: Ayup!\n'
- - it prefers `prog.file` to `opts.program`: |
- script = [[
- prog = {file='file'}; opts = {program='program'}
- ]] .. script
- expect(luaproc(script)).to_output_error 'file: Ayup!\n'
- - it appends `prog.line` if any to `prog.file` over using `opts`: |
- script = [[
- prog = {file='file', line=125}
- opts = {line=99, program='program'}
- ]] .. script
- expect(luaproc(script)).to_output_error 'file:125: Ayup!\n'
- - it prefixes `opts.program` if any: |
- script = [[opts = {program='program'};]] .. script
- expect(luaproc(script)).to_output_error 'program: Ayup!\n'
- - it appends `opts.line` if any, to `opts.program`: |
- script = [[opts = {line=99, program='program'};]] .. script
- expect(luaproc(script)).to_output_error 'program:99: Ayup!\n'
-
-
-- describe writelines:
- - before: |
- name = os.tmpname()
- h = io.open(name, 'w')
- lines = M.readlines(io.open 'Makefile')
-
- defaultout = io.output()
- f, badarg = init(M, this_module, 'writelines')
- - after:
- if io.type(defaultout) ~= 'closed file' then
- io.output(defaultout)
- end
- h:close()
- os.remove(name)
-
- - context with bad arguments:
- - 'it diagnoses argument #1 type not FILE*, string, number or nil':
- if have_typecheck then
- expect(f(false)).to_raise(badarg(1, '?file|string|number', 'boolean'))
- end
- - 'it diagnoses argument #2 type not string, number or nil':
- if have_typecheck then
- expect(f(1, false)).to_raise(badarg(2, 'string|number', 'boolean'))
- end
- - 'it diagnoses argument #3 type not string, number or nil':
- if have_typecheck then
- expect(f(1, 2, false)).to_raise(badarg(3, 'string|number', 'boolean'))
- end
- - it diagnoses closed file argument: |
- closed = io.open(name, 'r') closed:close()
- if have_typecheck then
- expect(f(closed)).to_raise(badarg(1, '?file|string|number', 'closed file'))
- end
-
- - it does not close the file handle upon completion:
- expect(io.type(h)).not_to_be 'closed file'
- f(h, 'foo')
- expect(io.type(h)).not_to_be 'closed file'
- - it writes lines to an open file handle:
- f(h, unpack(lines))
- h:flush()
- expect(M.readlines(io.open(name))).to_equal(lines)
- - it accepts number valued arguments:
- f(h, 1, 2, 3)
- h:flush()
- expect(M.readlines(io.open(name))).to_equal {'1', '2', '3'}
- - it writes to default output stream with non-file first argument:
- io.output(h)
- f(unpack(lines))
- h:flush()
- expect(M.readlines(io.open(name))).to_equal(lines)
diff --git a/spec/math_spec.yaml b/spec/math_spec.yaml
deleted file mode 100644
index ed08753..0000000
--- a/spec/math_spec.yaml
+++ /dev/null
@@ -1,99 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before:
- base_module = 'math'
- this_module = 'std.math'
- global_table = '_G'
-
- extend_base = {'floor', 'round'}
-
- M = require(this_module)
-
-
-specify std.math:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core math table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core math table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).
- to_equal {}
- - it does not touch the core math table:
- expect(show_apis {added_to=base_module, by='std'}).
- to_equal {}
-
-
-- describe floor:
- - before:
- f = M.floor
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.math.floor(number, ?int)')
-
- - it rounds to the nearest smaller integer:
- expect(f(1.2)).to_be(1)
- expect(f(1.9)).to_be(1)
- expect(f(999e-2)).to_be(9)
- expect(f(999e-3)).to_be(0)
- - it rounds down to specified number of decimal places:
- expect(f(1.2345, 0)).to_be(1.0)
- expect(f(1.2345, 1)).to_be(1.2)
- expect(f(1.2345, 2)).to_be(1.23)
- expect(f(9.9999, 2)).to_be(9.99)
- expect(f(99999e-3, 3)).to_be(99999e-3)
- expect(f(99999e-4, 3)).to_be(9999e-3)
- expect(f(99999e-5, 3)).to_be(999e-3)
-
-
-- describe round:
- - before:
- f = M.round
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.math.round(number, ?int)')
-
- - it rounds to the nearest integer:
- expect(f(1.2)).to_be(1)
- expect(f(1.9)).to_be(2)
- expect(f(949e-2)).to_be(9)
- expect(f(999e-2)).to_be(10)
- - it rounds to specified number of decimal places:
- expect(f(1.234, 0)).to_be(1.0)
- expect(f(5.678, 0)).to_be(6.0)
- expect(f(1.234, 1)).to_be(1.2)
- expect(f(5.678, 1)).to_be(5.7)
- expect(f(1.234, 2)).to_be(1.23)
- expect(f(5.678, 2)).to_be(5.68)
- expect(f(9.999, 2)).to_be(10)
- expect(f(11111e-2, 3)).to_be(11111e-2)
- expect(f(99999e-2, 3)).to_be(99999e-2)
- expect(f(11111e-3, 3)).to_be(11111e-3)
- expect(f(99999e-3, 3)).to_be(99999e-3)
- expect(f(11111e-4, 3)).to_be(1111e-3)
- expect(f(99999e-4, 3)).to_be(10)
- expect(f(99999e-5, 3)).to_be(1)
- - it rounds negative values correctly:
- expect(f(-1.234, 0)).to_be(-1.0)
- expect(f(-5.678, 0)).to_be(-6.0)
- expect(f(-1.234, 1)).to_be(-1.2)
- expect(f(-5.678, 1)).to_be(-5.7)
- expect(f(-1.234, 2)).to_be(-1.23)
- expect(f(-5.678, 2)).to_be(-5.68)
- expect(f(-9.999, 2)).to_be(-10)
- expect(f(-11111e-2, 3)).to_be(-11111e-2)
- expect(f(-99999e-2, 3)).to_be(-99999e-2)
- expect(f(-11111e-3, 3)).to_be(-11111e-3)
- expect(f(-99999e-3, 3)).to_be(-99999e-3)
- expect(f(-11111e-4, 3)).to_be(-1111e-3)
- expect(f(-99999e-4, 3)).to_be(-10)
- expect(f(-99999e-5, 3)).to_be(-1)
diff --git a/spec/package_spec.yaml b/spec/package_spec.yaml
deleted file mode 100644
index 23ce961..0000000
--- a/spec/package_spec.yaml
+++ /dev/null
@@ -1,202 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before: |
- base_module = 'package'
- this_module = 'std.package'
- global_table = '_G'
-
- extend_base = {'find', 'insert', 'mappath', 'normalize', 'remove'}
-
- M = require(this_module)
-
- path = M.normalize('begin', 'middle', 'end')
-
- function catfile(...)
- return table.concat({...}, M.dirsep)
- end
- function catpath(...)
- return table.concat({...}, M.pathsep)
- end
-
-
-specify std.package:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core package table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core package table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).
- to_equal {}
- - it does not touch the core package table:
- expect(show_apis {added_to=base_module, by='std'}).
- to_equal {}
-
-
-- describe find:
- - before: |
- path = table.concat({'begin', 'm%ddl.', 'end'}, M.pathsep)
-
- f = M.find
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.package.find(string, string, ?int, ?boolean|:plain)')
-
- - it returns nil for unmatched element:
- expect(f(path, 'unmatchable')).to_be(nil)
- - it returns the element index for a matched element:
- expect(f(path, 'end')).to_be(3)
- - it returns the element text for a matched element:
- i, element = f(path, 'e.*n')
- expect({i, element}).to_equal {1, 'begin'}
- - it accepts a search start element argument:
- i, element = f(path, 'e.*n', 2)
- expect({i, element}).to_equal {3, 'end'}
- - it works with plain text search strings:
- expect(f(path, 'm%ddl.')).to_be(nil)
- i, element = f(path, '%ddl.', 1, ':plain')
- expect({i, element}).to_equal {2, 'm%ddl.'}
-
-
-- describe insert:
- - before:
- f = M.insert
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.package.insert(string, [int], string)')
-
- - it appends by default:
- expect(f(path, 'new')).
- to_be(M.normalize('begin', 'middle', 'end', 'new'))
- - it prepends with pos set to 1:
- expect(f(path, 1, 'new')).
- to_be(M.normalize('new', 'begin', 'middle', 'end'))
- - it can insert in the middle too:
- expect(f(path, 2, 'new')).
- to_be(M.normalize('begin', 'new', 'middle', 'end'))
- expect(f(path, 3, 'new')).
- to_be(M.normalize('begin', 'middle', 'new', 'end'))
- - it normalizes the returned path:
- path = table.concat({'begin', 'middle', 'end'}, M.pathsep)
- expect(f(path, 'new')).
- to_be(M.normalize('begin', 'middle', 'end', 'new'))
- expect(f(path, 1, './x/../end')).
- to_be(M.normalize('end', 'begin', 'middle'))
-
-
-- describe mappath:
- - before: |
- expected = require 'std.string'.split(path, M.pathsep)
-
- f = M.mappath
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.package.mappath(string, function, ?any*)')
-
- - it calls a function with each path element:
- t = {}
- f(path, function(e)
- t[#t + 1] = e
- end)
- expect(t).to_equal(expected)
- - it passes additional arguments through: |
- reversed = {}
- for i = #expected, 1, -1 do
- table.insert(reversed, expected[i])
- end
- t = {}
- f(path, function(e, pos)
- table.insert(t, pos, e)
- end, 1)
- expect(t).to_equal(reversed)
-
-
-- describe normalize:
- - before:
- f = M.normalize
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.package.normalize(string*)')
-
- - context with a single element:
- - it strips redundant . directories:
- expect(f './x/./y/.').to_be(catfile('.', 'x', 'y'))
- - it strips redundant .. directories:
- expect(f '../x/../y/z/..').to_be(catfile('..', 'y'))
- expect(f '../x/../y/z/..').to_be(catfile('..', 'y'))
- expect(f '../../x/../y/z/..').to_be(catfile('..', '..', 'y'))
- expect(f '../../x/../y/./..').to_be(catfile('..', '..'))
- expect(f '../../w/x/../../y/z/..').to_be(catfile('..', '..', 'y'))
- expect(f '../../w/./../.././z/..').to_be(catfile('..', '..', '..'))
- - it leaves leading .. directories unmolested:
- expect(f '../../1').to_be(catfile('..', '..', '1'))
- expect(f './../../1').to_be(catfile('..', '..', '1'))
- - it normalizes / to platform dirsep:
- expect(f '/foo/bar').to_be(catfile('', 'foo', 'bar'))
- - it normalizes ? to platform pathmark:
- expect(f '?.lua').
- to_be(catfile('.', M.pathmark .. '.lua'))
- - it strips redundant trailing /:
- expect(f '/foo/bar/').to_be(catfile('', 'foo', 'bar'))
- - it inserts missing ./ for relative paths:
- for _, path in ipairs {'x', './x'} do
- expect(f(path)).to_be(catfile('.', 'x'))
- end
- - context with multiple elements:
- - it strips redundant . directories:
- expect(f('./x/./y/.', 'x')).
- to_be(catpath(catfile('.', 'x', 'y'), catfile('.', 'x')))
- - it strips redundant .. directories:
- expect(f('../x/../y/z/..', 'x')).
- to_be(catpath(catfile('..', 'y'), catfile('.', 'x')))
- - it normalizes / to platform dirsep:
- expect(f('/foo/bar', 'x')).
- to_be(catpath(catfile('', 'foo', 'bar'), catfile('.', 'x')))
- - it normalizes ? to platform pathmark:
- expect(f('?.lua', 'x')).
- to_be(catpath(catfile('.', M.pathmark .. '.lua'), catfile('.', 'x')))
- - it strips redundant trailing /:
- expect(f('/foo/bar/', 'x')).
- to_be(catpath(catfile('', 'foo', 'bar'), catfile('.', 'x')))
- - it inserts missing ./ for relative paths:
- for _, path in ipairs {'x', './x'} do
- expect(f(path, 'a')).
- to_be(catpath(catfile('.', 'x'), catfile('.', 'a')))
- end
- - it eliminates all but the first equivalent elements:
- expect(f(catpath('1', 'x', '2', './x', './2', './x/../x'))).
- to_be(catpath('./1', './x', './2'))
-
-
-- describe remove:
- - before:
- f = M.remove
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.package.remove(string, ?int)')
-
- - it removes the last item by default:
- expect(f(path)).to_be(M.normalize('begin', 'middle'))
- - it pops the first item with pos set to 1:
- expect(f(path, 1)).to_be(M.normalize('middle', 'end'))
- - it can remove from the middle too:
- expect(f(path, 2)).to_be(M.normalize('begin', 'end'))
- - it does not normalize the returned path:
- path = table.concat({'begin', 'middle', 'end'}, M.pathsep)
- expect(f(path)).
- to_be(table.concat({'begin', 'middle'}, M.pathsep))
-
-
-- it splits package.config up:
- expect(string.format('%s\n%s\n%s\n%s\n%s\n',
- M.dirsep, M.pathsep, M.pathmark, M.execdir, M.igmark)
- ).to_contain(package.config)
diff --git a/spec/spec_helper.lua b/spec/spec_helper.lua
deleted file mode 100644
index 642712f..0000000
--- a/spec/spec_helper.lua
+++ /dev/null
@@ -1,416 +0,0 @@
---[[
- General Lua Libraries for Lua 5.1, 5.2 & 5.3
- Copyright (C) 2011-2018 stdlib authors
-]]
-
-local typecheck
-have_typecheck, typecheck = pcall(require, 'typecheck')
-
-local inprocess = require 'specl.inprocess'
-local hell = require 'specl.shell'
-local std = require 'specl.std'
-
-badargs = require 'specl.badargs'
-
-
-local top_srcdir = os.getenv 'top_srcdir' or '.'
-local top_builddir = os.getenv 'top_builddir' or '.'
-
-package.path = std.package.normalize(
- top_builddir .. '/lib/?.lua',
- top_builddir .. '/lib/?/init.lua',
- top_srcdir .. '/lib/?.lua',
- top_srcdir .. '/lib/?/init.lua',
- package.path
-)
-
-
--- Allow user override of LUA binary used by hell.spawn, falling
--- back to environment PATH search for 'lua' if nothing else works.
-local LUA = os.getenv 'LUA' or 'lua'
-
-
--- Simplified version for specifications, does not support functable
--- valued __len metamethod, so don't write examples that need that!
-function len(x)
- local __len = getmetatable(x) or {}
- if type(__len) == 'function' then
- return __len(x)
- end
- if type(x) ~= 'table' then
- return #x
- end
-
- local n = #x
- for i = 1, n do
- if x[i] == nil then
- return i -1
- end
- end
- return n
-end
-
-
--- Make sure we have a maxn even when _VERSION ~= 5.1
--- @fixme remove this when we get unpack from specl.std
-maxn = table.maxn or function(t)
- local n = 0
- for k in pairs(t) do
- if type(k) == 'number' and k > n then
- n = k
- end
- end
- return n
-end
-
-
-pack = table.pack or function(...)
- return {n=select('#', ...), ...}
-end
-
-
--- Take care to always unpack upto the highest numeric index, for
--- consistency across Lua versions.
-local _unpack = table.unpack or unpack
-
--- @fixme pick this up from specl.std with the next release
-function unpack(t, i, j)
- return _unpack(t, tonumber(i) or 1, tonumber(j or t.n or len(t)))
-end
-
-
--- In case we're not using a bleeding edge release of Specl...
-_diagnose = badargs.diagnose
-badargs.diagnose = function(...)
- if have_typecheck then
- return _diagnose(...)
- end
-end
-
-badargs.result = badargs.result or function(fname, i, want, got)
- if want == nil then -- numbers only for narg error
- i, want = i - 1, i
- end
-
- if got == nil and type(want) == 'number' then
- local s = "bad result #%d from '%s'(no more than %d result%s expected, got %d)"
- return s:format(i + 1, fname, i, i == 1 and '' or 's', want)
- end
-
- local function showarg(s)
- return('|' .. s .. '|'):
- gsub('|%?', '|nil|'):
- gsub('|nil|', '|no value|'):
- gsub('|any|', '|any value|'):
- gsub('|#', '|non-empty '):
- gsub('|func|', '|function|'):
- gsub('|file|', '|FILE*|'):
- gsub('^|', ''):
- gsub('|$', ''):
- gsub('|([^|]+)$', 'or %1'):
- gsub('|', ', ')
- end
-
- return string.format("bad result #%d from '%s'(%s expected, got %s)",
- i, fname, showarg(want), got or 'no value')
-end
-
-
--- Wrap up badargs function in a succinct single call.
-function init(M, mname, fname)
- local name =(mname .. '.' .. fname):gsub('^%.', '')
- return M[fname],
- function(...)
- return badargs.format(name, ...)
- end,
- function(...)
- return badargs.result(name, ...)
- end
-end
-
-
--- A copy of base.lua:type, so that an unloadable base.lua doesn't
--- prevent everything else from working.
-function objtype(o)
- return(getmetatable(o) or {})._type or io.type(o) or type(o)
-end
-
-
-function nop() end
-
-
--- Error message specifications use this to shorten argument lists.
--- Copied from functional.lua to avoid breaking all tests if functional
--- cannot be loaded correctly.
-function bind(f, fix)
- return function(...)
- local arg = {}
- for i, v in pairs(fix) do
- arg[i] = v
- end
- local i = 1
- for _, v in pairs {...} do
- while arg[i] ~= nil do
- i = i + 1
- end
- arg[i] = v
- end
- return f(unpack(arg))
- end
-end
-
-
-local function mkscript(code)
- local f = os.tmpname()
- local h = io.open(f, 'w')
- h:write(code)
- h:close()
- return f
-end
-
-
---- Run some Lua code with the given arguments and input.
--- @string code valid Lua code
--- @tparam[opt={}] string|table arg single argument, or table of
--- arguments for the script invocation.
--- @string[opt] stdin standard input contents for the script process
--- @treturn specl.shell.Process|nil status of resulting process if
--- execution was successful, otherwise nil
-function luaproc(code, arg, stdin)
- local f = mkscript(code)
- if type(arg) ~= 'table' then
- arg = {arg}
- end
- local cmd = {LUA, f, unpack(arg)}
- -- inject env and stdin keys separately to avoid truncating `...` in
- -- cmd constructor
- cmd.env = {LUA_PATH=package.path, LUA_INIT='', LUA_INIT_5_2=''}
- cmd.stdin = stdin
- local proc = hell.spawn(cmd)
- os.remove(f)
- return proc
-end
-
-
---- Check deprecation output when calling a named function in the given module.
--- Note that the script fragments passed in *argstr* and *objectinit*
--- can reference the module table as `M`, and(where it would make sense)
--- an object prototype as `P` and instance as `obj`.
--- @param deprecate value of `std._debug.deprecate`
--- @string module dot delimited module path to load
--- @string fname name of a function in the table returned by requiring *module*
--- @param[opt=''] args arguments to pass to *fname* call, must be stringifiable
--- @string[opt=nil] objectinit object initializer to instantiate an
--- object for object method deprecation check
--- @treturn specl.shell.Process|nil status of resulting process if
--- execution was successful, otherwise nil
-function deprecation(deprecate, module, fname, args, objectinit)
- args = args or ''
- local script
- if objectinit == nil then
- script = string.format([[
- require 'std._debug'.deprecate = %s
- M = require '%s'
- P = M.prototype
- print(M.%s(%s))
- ]], tostring(deprecate), module, fname, tostring(args))
- else
- script = string.format([[
- require 'std._debug'.deprecate = %s
- local M = require '%s'
- local P = M.prototype
- local obj = P(%s)
- print(obj:%s(%s))
- ]], tostring(deprecate), module, objectinit, fname, tostring(args))
- end
- return luaproc(script)
-end
-
-
---- Concatenate the contents of listed existing files.
--- @string ... names of existing files
--- @treturn string concatenated contents of those files
-function concat_file_content(...)
- local t = {}
- for _, name in ipairs {...} do
- h = io.open(name)
- t[#t + 1] = h:read '*a'
- end
- return table.concat(t)
-end
-
-
-local function tabulate_output(code)
- local proc = luaproc(code)
- if proc.status ~= 0 then
- return error(proc.errout)
- end
- local r = {}
- proc.output:gsub('(%S*)[%s]*',
- function(x)
- if x ~= '' then
- r[x] = true
- end
- end)
- return r
-end
-
-
---- Show changes to tables wrought by a require statement.
--- There are a few modes to this function, controlled by what named
--- arguments are given. Lists new keys in T1 after `require 'import'`:
---
--- show_apis {added_to=T1, by=import}
---
--- List keys returned from `require 'import'`, which have the same
--- value in T1:
---
--- show_apis {from=T1, used_by=import}
---
--- List keys from `require 'import'`, which are also in T1 but with
--- a different value:
---
--- show_apis {from=T1, enhanced_by=import}
---
--- List keys from T2, which are also in T1 but with a different value:
---
--- show_apis {from=T1, enhanced_in=T2}
---
--- @tparam table argt one of the combinations above
--- @treturn table a list of keys according to criteria above
-function show_apis(argt)
- local added_to, from, not_in, enhanced_in, enhanced_after, by =
- argt.added_to, argt.from, argt.not_in, argt.enhanced_in,
- argt.enhanced_after, argt.by
-
- if added_to and by then
- return tabulate_output([[
- local before, after = {}, {}
- for k in pairs(]] .. added_to .. [[) do
- before[k] = true
- end
-
- local M = require ']] .. by .. [['
- for k in pairs(]] .. added_to .. [[) do
- after[k] = true
- end
-
- for k in pairs(after) do
- if not before[k] then
- print(k)
- end
- end
- ]])
-
- elseif from and not_in then
- return tabulate_output([[
- local _ENV = require 'std.normalize' {
- from = ']] .. from .. [[',
- M = require ']] .. not_in .. [[',
- }
-
- for k in pairs(M) do
- -- M[1] is typically the module namespace name, don't match
- -- that!
- if k ~= 1 and from[k] ~= M[k] then
- print(k)
- end
- end
- ]])
-
- elseif from and enhanced_in then
- return tabulate_output([[
- local _ENV = require 'std.normalize' {
- from = ']] .. from .. [[',
- M = require ']] .. enhanced_in .. [[',
- }
-
- for k, v in pairs(M) do
- if from[k] ~= M[k] and from[k] ~= nil then
- print(k)
- end
- end
- ]])
-
- elseif from and enhanced_after then
- return tabulate_output([[
- local _ENV = require 'std.normalize' {
- from = ']] .. from .. [[',
- }
- local before, after = {}, {}
- for k, v in pairs(from) do
- before[k] = v
- end
- ]] .. enhanced_after .. [[
- for k, v in pairs(from) do
- after[k] = v
- end
-
- for k, v in pairs(before) do
- if after[k] ~= nil and after[k] ~= v then
- print(k)
- end
- end
- ]])
- end
-
- assert(false, 'missing argument to show_apis')
-end
-
-
--- Stub inprocess.capture if necessary; new in Specl 12.
-capture = inprocess.capture or function(f, arg)
- return nil, nil, f(unpack(arg or {}))
-end
-
-
-do
- -- Custom matcher for set size and set membership.
-
- local util = require 'specl.util'
- local matchers = require 'specl.matchers'
-
- local Matcher, matchers, q =
- matchers.Matcher, matchers.matchers, matchers.stringify
-
- matchers.have_size = Matcher {
- function(self, actual, expect)
- local size = 0
- for _ in pairs(actual) do
- size = size + 1
- end
- return size == expect
- end,
-
- actual = 'table',
-
- format_expect = function(self, expect)
- return ' a table containing ' .. expect .. ' elements, '
- end,
-
- format_any_of = function(self, alternatives)
- return ' a table with any of ' ..
- util.concat(alternatives, util.QUOTED) .. ' elements, '
- end,
- }
-
- matchers.have_member = Matcher {
- function(self, actual, expect)
- return actual[expect] ~= nil
- end,
-
- actual = 'set',
-
- format_expect = function(self, expect)
- return ' a set containing ' .. q(expect) .. ', '
- end,
-
- format_any_of = function(self, alternatives)
- return ' a set containing any of ' ..
- util.concat(alternatives, util.QUOTED) .. ', '
- end,
- }
-
- -- Alias that doesn't tickle sc_error_message_uppercase.
- matchers.raise = matchers.error
-end
diff --git a/spec/std_spec.yaml b/spec/std_spec.yaml
deleted file mode 100644
index b747abf..0000000
--- a/spec/std_spec.yaml
+++ /dev/null
@@ -1,444 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before: |
- this_module = 'std'
- global_table = '_G'
-
- exported_apis = {'assert', 'elems', 'eval', 'getmetamethod',
- 'ielems', 'ipairs', 'npairs', 'pairs',
- 'require', 'ripairs', 'rnpairs'}
-
- -- Tables with iterator metamethods used by various examples.
- __pairs = setmetatable({content='a string'}, {
- __pairs = function(t)
- return function(x, n)
- if n < #x.content then
- return n+1, string.sub(x.content, n+1, n+1)
- end
- end, t, 0
- end,
- })
- __index = setmetatable({content='a string'}, {
- __index = function(t, n)
- if n <= #t.content then
- return t.content:sub(n, n)
- end
- end,
- __len = function(t)
- return #t.content
- end,
- })
-
- M = require(this_module)
- M.version = nil -- previous specs may have autoloaded it
-
-
-specify std:
-- context when required:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it exports the documented apis:
- t = {}
- for k in pairs(M) do
- t[#t + 1] = k
- end
- expect(t).to_contain.a_permutation_of(exported_apis)
-
-- context when lazy loading:
- - it has no submodules on initial load:
- for _, v in pairs(M) do
- expect(type(v)).not_to_be 'table'
- end
- - it loads submodules on demand:
- lazy = M.math
- expect(lazy).to_be(require 'std.math')
- - it loads submodule functions on demand:
- expect(M.math.round(3.141592)).to_be(3)
-
-- describe assert:
- - before:
- f = M.assert
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.assert(?any, ?string, ?any*)')
-
- - context when it does not trigger:
- - it has a truthy initial argument:
- expect(f(1)).not_to_raise 'any error'
- expect(f(true)).not_to_raise 'any error'
- expect(f 'yes').not_to_raise 'any error'
- expect(f(false == false)).not_to_raise 'any error'
- - it returns the initial argument:
- expect(f(1)).to_be(1)
- expect(f(true)).to_be(true)
- expect(f 'yes').to_be 'yes'
- expect(f(false == false)).to_be(true)
- - context when it triggers:
- - it has a falsey initial argument:
- expect(f()).to_raise()
- expect(f(false)).to_raise()
- expect(f(1 == 0)).to_raise()
- - it throws an optional error string:
- expect(f(false, 'ah boo')).to_raise 'ah boo'
- - it plugs specifiers with string.format: |
- expect(f(nil, '%s %d: %q', 'here', 42, 'a string')).
- to_raise(string.format('%s %d: %q', 'here', 42, 'a string'))
-
-
-- describe elems:
- - before:
- f = M.elems
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.elems(table)')
-
- - it is an iterator over table values:
- t = {}
- for e in f {'foo', bar='baz', 42} do
- t[#t + 1] = e
- end
- expect(t).to_contain.a_permutation_of {'foo', 'baz', 42}
- - it respects __pairs metamethod: |
- t = {}
- for v in f(__pairs) do
- t[#t + 1] = v
- end
- expect(t).
- to_contain.a_permutation_of {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'}
- - it works for an empty list:
- t = {}
- for e in f {} do
- t[#t + 1] = e
- end
- expect(t).to_equal {}
-
-
-- describe eval:
- - before:
- f = M.eval
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.eval(string)')
-
- - it diagnoses invalid lua:
- # Some internal error when eval tries to call uncompilable '=' code.
- expect(f '=').to_raise()
- - it evaluates a string of lua code:
- expect(f 'math.min(2, 10)').to_be(math.min(2, 10))
-
-
-- describe getmetamethod:
- - before:
- f = M.getmetamethod
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.getmetamethod(?any, string)')
-
- - context with a table:
- - before:
- method = function()
- return 'called'
- end
- functor = setmetatable({}, {__call=method})
- t = setmetatable({}, {
- _type='table', _method=method, _functor=functor,
- })
- - it returns nil for missing metamethods:
- expect(f(t, 'not a metamethod on t')).to_be(nil)
- - it returns nil for non-callable metatable entries:
- expect(f(t, '_type')).to_be(nil)
- - it returns a method from the metatable:
- expect(f(t, '_method')).to_be(method)
- expect(f(t, '_method')()).to_be 'called'
- - it returns a functor from the metatable:
- expect(f(t, '_functor')).to_be(functor)
- expect(f(t, '_functor')()).to_be 'called'
-
-
-- describe ielems:
- - before:
- f = M.ielems
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.ielems(table)')
-
- - it is an iterator over integer-keyed table values:
- t = {}
- for e in f {'foo', 42} do
- t[#t + 1] = e
- end
- expect(t).to_equal {'foo', 42}
- - it ignores the dictionary part of a table:
- t = {}
- for e in f {'foo', 42; bar='baz', qux='quux'} do
- t[#t + 1] = e
- end
- expect(t).to_equal {'foo', 42}
- - it respects __len metamethod:
- t = {}
- for v in f(__index) do
- t[#t + 1] = v
- end
- expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'}
- - it works for an empty list:
- t = {}
- for e in f {} do
- t[#t + 1] = e
- end
- expect(t).to_equal {}
-
-
-- describe ipairs:
- - before:
- f = M.ipairs
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.ipairs(table)')
-
- - it is an iterator over integer-keyed table values:
- t = {}
- for i, v in f {'foo', 42} do
- t[i] = v
- end
- expect(t).to_equal {'foo', 42}
- - it ignores the dictionary part of a table:
- t = {}
- for i, v in f {'foo', 42; bar='baz', qux='quux'} do
- t[i] = v
- end
- expect(t).to_equal {'foo', 42}
- - it respects __len metamethod:
- t = {}
- for k, v in f(__index) do
- t[k] = v
- end
- expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'}
- - it works for an empty list:
- t = {}
- for i, v in f {} do
- t[i] = v
- end
- expect(t).to_equal {}
-
-
-- describe npairs:
- - before:
- f = M.npairs
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.npairs(table)')
-
- - it is an iterator over integer-keyed table values:
- t = {}
- for i, v in f {'foo', 42, nil, nil, 'five'} do
- t[i] = v
- end
- expect(t).to_equal {'foo', 42, nil, nil, 'five'}
- - it ignores the dictionary part of a table:
- t = {}
- for i, v in f {'foo', 42, nil, nil, 'five'; bar='baz', qux='quux'} do
- t[i] = v
- end
- expect(t).to_equal {'foo', 42, nil, nil, 'five'}
- - it respects __len metamethod:
- t = {}
- for _, v in f(setmetatable({[2]=false}, {__len=function(self) return 4 end})) do
- t[#t + 1] = tostring(v)
- end
- expect(table.concat(t, ',')).to_be 'nil,false,nil,nil'
- - it works for an empty list:
- t = {}
- for i, v in f {} do
- t[i] = v
- end
- expect(t).to_equal {}
-
-
-- describe pairs:
- - before:
- f = M.pairs
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.pairs(table)')
-
- - it is an iterator over all table values:
- t = {}
- for k, v in f {'foo', bar='baz', 42} do
- t[k] = v
- end
- expect(t).to_equal {'foo', bar='baz', 42}
- - it respects __pairs metamethod: |
- t = {}
- for k, v in f(__pairs) do
- t[k] = v
- end
- expect(t).
- to_contain.a_permutation_of {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'}
- - it works for an empty list:
- t = {}
- for k, v in f {} do
- t[k] = v
- end
- expect(t).to_equal {}
-
-
-- describe require:
- - before:
- f = M.require
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.require(string, ?string, ?string, ?string)')
-
- - it diagnoses non-existent module:
- expect(f('module-not-exists', '', '')).to_raise 'module-not-exists'
- - it diagnoses module too old:
- expect(f('std', '9999', '9999')).
- to_raise "require 'std' with at least version 9999,"
- - it diagnoses module too new:
- expect(f('std', '0', '0')).
- to_raise "require 'std' with version less than 0,"
- - context when the module version is compatible:
- - it returns the module table:
- expect(f('std', '0', '9999')).to_be(require 'std')
- - it places no upper bound by default:
- expect(f('std', '0')).to_be(require 'std')
- - it places no lower bound by default:
- expect(f 'std').to_be(require 'std')
- - it uses _VERSION when version field is nil:
- expect(luaproc [[
- package.loaded['poop'] = {_VERSION='41.1'}
- f = require 'std'.require
- print(f('poop', '41', '9999')._VERSION)
- ]]).to_succeed_with '41.1\n'
- - context with semantic versioning:
- - before:
- std = require 'std'
- ver = std.version
- std.version = '1.2.3'
- - after:
- std.version = ver
- - it diagnoses module too old:
- expect(f('std', '1.2.4')).
- to_raise "require 'std' with at least version 1.2.4,"
- expect(f('std', '1.3')).
- to_raise "require 'std' with at least version 1.3,"
- expect(f('std', '2.1.2')).
- to_raise "require 'std' with at least version 2.1.2,"
- expect(f('std', '2')).
- to_raise "require 'std' with at least version 2,"
- expect(f('std', '1.2.10')).
- to_raise "require 'std' with at least version 1.2.10,"
- - it diagnoses module too new:
- expect(f('std', nil, '1.2.2')).
- to_raise "require 'std' with version less than 1.2.2,"
- expect(f('std', nil, '1.1')).
- to_raise "require 'std' with version less than 1.1,"
- expect(f('std', nil, '1.1.2')).
- to_raise "require 'std' with version less than 1.1.2,"
- expect(f('std', nil, '1')).
- to_raise "require 'std' with version less than 1,"
- - it returns modules with version in range:
- expect(f('std')).to_be(std)
- expect(f('std', '1')).to_be(std)
- expect(f('std', '1.2.3')).to_be(std)
- expect(f('std', nil, '2')).to_be(std)
- expect(f('std', nil, '1.3')).to_be(std)
- expect(f('std', nil, '1.2.10')).to_be(std)
- expect(f('std', '1.2.3', '1.2.4')).to_be(std)
- - context with several numbers in version string:
- - before:
- std = require 'std'
- ver = std.version
- std.version = 'standard library for Lua 5.3 / 41.0.0'
- - after:
- std.version = ver
- - it diagnoses module too old:
- expect(f('std', '42')).to_raise()
- - it diagnoses module too new:
- expect(f('std', nil, '40')).to_raise()
- - it returns modules with version in range:
- expect(f('std')).to_be(std)
- expect(f('std', '1')).to_be(std)
- expect(f('std', '41')).to_be(std)
- expect(f('std', nil, '42')).to_be(std)
- expect(f('std', '41', '42')).to_be(std)
-
-
-- describe ripairs:
- - before:
- f = M.ripairs
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.ripairs(table)')
-
- - it returns a function, the table and a number:
- fn, t, i = f {1, 2, 3}
- expect({type(fn), t, type(i)}).to_equal {'function', {1, 2, 3}, 'number'}
- - it iterates over the array part of a table:
- t, u = {1, 2, 3; a=4, b=5, c=6}, {}
- for i, v in f(t) do
- u[i] = v
- end
- expect(u).to_equal {1, 2, 3}
- - it returns elements in reverse order:
- t, u = {'one', 'two', 'five'}, {}
- for _, v in f(t) do
- u[#u + 1] = v
- end
- expect(u).to_equal {'five', 'two', 'one'}
- - it respects __len metamethod:
- t = {}
- for i, v in f(__index) do
- t[i] = v
- end
- expect(t).to_equal {'a', ' ', 's', 't', 'r', 'i', 'n', 'g'}
- t = {}
- for _, v in f(__index) do
- t[#t + 1] = v
- end
- expect(t).to_equal {'g', 'n', 'i', 'r', 't', 's', ' ', 'a'}
- - it works with the empty list:
- t = {}
- for k, v in f {} do
- t[k] = v
- end
- expect(t).to_equal {}
-
-
-- describe rnpairs:
- - before:
- f = M.rnpairs
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.rnpairs(table)')
-
- - it returns a function, the table and a number:
- fn, t, i = f {1, 2, nil, nil, 3}
- expect({type(fn), t, type(i)}).
- to_equal {'function', {1, 2, nil, nil, 3}, 'number'}
- - it iterates over the array part of a table:
- t, u = {1, 2, nil, nil, 3; a=4, b=5, c=6}, {}
- for i, v in f(t) do
- u[i] = v
- end
- expect(u).to_equal {1, 2, nil, nil, 3}
- - it returns elements in reverse order:
- t, u, i = {'one', 'two', nil, nil, 'five'}, {}, 1
- for _, v in f(t) do
- u[i], i = v, i + 1
- end
- expect(u).to_equal {'five', nil, nil, 'two', 'one'}
- - it respects __len metamethod:
- t = {}
- for _, v in f(setmetatable({[2]=false}, {__len=function(self) return 4 end})) do
- t[#t + 1] = tostring(v)
- end
- expect(table.concat(t, ',')).to_be 'nil,nil,false,nil'
- - it works with the empty list:
- t = {}
- for k, v in f {} do
- t[k] = v
- end
- expect(t).to_equal {}
diff --git a/spec/string_spec.yaml b/spec/string_spec.yaml
deleted file mode 100644
index 2fa47f2..0000000
--- a/spec/string_spec.yaml
+++ /dev/null
@@ -1,549 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before:
- base_module = 'string'
- this_module = 'std.string'
- global_table = '_G'
-
- extend_base = {'__concat', '__index',
- 'caps', 'chomp', 'escape_pattern', 'escape_shell',
- 'finds', 'format', 'ltrim',
- 'numbertosi', 'ordinal_suffix', 'pad',
- 'prettytostring', 'rtrim', 'split',
- 'tfind', 'trim', 'wrap'}
-
- M = require(this_module)
- getmetatable('').__concat = M.__concat
- getmetatable('').__index = M.__index
-
-specify std.string:
-- before:
- subject = 'a string \n\n'
-
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core string table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core string table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).
- to_equal {}
- - it does not touch the core string table:
- expect(show_apis {added_to=base_module, by='std'}).
- to_equal {}
-
-- describe ..:
- - it concatenates string arguments:
- target = 'a string \n\n another string'
- expect(subject .. ' another string').to_be(target)
- - it stringifies non-string arguments:
- argument = {'a table'}
- expect(subject .. argument).to_be(subject .. '{1="a table"}')
- - it stringifies nil arguments:
- argument = nil
- expect(subject .. argument).
- to_be(string.format('%s%s', subject, require 'std.normalize'.str(argument)))
- - it does not perturb the original subject:
- original = subject
- newstring = subject .. ' concatenate something'
- expect(subject).to_be(original)
-
-
-- describe caps:
- - before:
- f = M.caps
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.caps(string)')
-
- - it capitalises words of a string:
- target = 'A String \n\n'
- expect(f(subject)).to_be(target)
- - it changes only the first letter of each word:
- expect(f 'a stRiNg').to_be 'A StRiNg'
- - it is available as a string metamethod:
- expect(('a stRiNg'):caps()).to_be 'A StRiNg'
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject)
- expect(subject).to_be(original)
-
-
-- describe chomp:
- - before:
- target = 'a string \n'
- f = M.chomp
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.chomp(string)')
-
- - it removes a single trailing newline from a string:
- expect(f(subject)).to_be(target)
- - it does not change a string with no trailing newline:
- subject = 'a string '
- expect(f(subject)).to_be(subject)
- - it is available as a string metamethod:
- expect(subject:chomp()).to_be(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject)
- expect(subject).to_be(original)
-
-
-- describe escape_pattern:
- - before:
- magic = {}
- meta = '^$()%.[]*+-?'
- for i = 1, string.len(meta) do
- magic[meta:sub(i, i)] = true
- end
- f = M.escape_pattern
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.escape_pattern(string)')
-
- - context with each printable ASCII char:
- - before:
- subject, target = '', ''
- for c = 32, 126 do
- s = string.char(c)
- subject = subject .. s
- if magic[s] then
- target = target .. '%'
- end
- target = target .. s
- end
- - 'it inserts a % before any non-alphanumeric in a string':
- expect(f(subject)).to_be(target)
- - it is available as a string metamethod:
- expect(subject:escape_pattern()).to_be(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject)
- expect(subject).to_be(original)
-
-
-- describe escape_shell:
- - before:
- f = M.escape_shell
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.escape_shell(string)')
-
- - context with each printable ASCII char:
- - before:
- subject, target = '', ''
- for c = 32, 126 do
- s = string.char(c)
- subject = subject .. s
- if s:match('[][ ()\\\'"]') then
- target = target .. '\\'
- end
- target = target .. s
- end
- - 'it inserts a \\ before any shell metacharacters':
- expect(f(subject)).to_be(target)
- - it is available as a string metamethod:
- expect(subject:escape_shell()).to_be(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject)
- expect(subject).to_be(original)
- - 'it diagnoses non-string arguments':
- if typecheck then
- expect(f()).to_raise('string expected')
- expect(f {'a table'}).to_raise('string expected')
- end
-
-
-- describe finds:
- - before:
- subject = 'abcd'
- f = M.finds
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.finds(string, string, ?int, ?boolean|:plain)')
-
- - context given a complex nested list:
- - before:
- target = {{1, 2; capt={'a', 'b'}}, {3, 4; capt={'c', 'd'}}}
- - it creates a list of pattern captures:
- expect({f(subject, '(.)(.)')}).to_equal({target})
- - it is available as a string metamethod:
- expect({subject:finds('(.)(.)')}).to_equal({target})
- - it creates an empty list where no captures are matched:
- target = {}
- expect({f(subject, '(x)')}).to_equal({target})
- - it creates an empty list for a pattern without captures:
- target = {{1, 1; capt={}}}
- expect({f(subject, 'a')}).to_equal({target})
- - it starts the search at a specified index into the subject:
- target = {{8, 9; capt={'a', 'b'}}, {10, 11; capt={'c', 'd'}}}
- expect({f('garbage' .. subject, '(.)(.)', 8)}).to_equal({target})
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, '...')
- expect(subject).to_be(original)
-
-
-- describe format:
- - before:
- subject = 'string=%s, number=%d'
-
- f = M.format
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.format(string, ?any*)')
-
- - it returns a single argument without attempting formatting:
- expect(f(subject)).to_be(subject)
- - it is available as a string metamethod:
- expect(subject:format()).to_be(subject)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject)
- expect(subject).to_be(original)
-
-
-- describe ltrim:
- - before:
- subject = ' \t\r\n a short string \t\r\n '
-
- f = M.ltrim
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.ltrim(string, ?string)')
-
- - it removes whitespace from the start of a string:
- target = 'a short string \t\r\n '
- expect(f(subject)).to_equal(target)
- - it supports custom removal patterns:
- target = '\r\n a short string \t\r\n '
- expect(f(subject, '[ \t\n]+')).to_equal(target)
- - it is available as a string metamethod:
- target = '\r\n a short string \t\r\n '
- expect(subject:ltrim('[ \t\n]+')).to_equal(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, '%W')
- expect(subject).to_be(original)
-
-
-- describe numbertosi:
- - before:
- f = M.numbertosi
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.numbertosi(number|string)')
-
- - it returns a number using SI suffixes:
- target = {'1e-9', '1y', '1z', '1a', '1f', '1p', '1n', '1mu', '1m', '1',
- '1k', '1M', '1G', '1T', '1P', '1E', '1Z', '1Y', '1e9'}
- subject = {}
- for n = -28, 28, 3 do
- m = 10 *(10 ^ n)
- table.insert(subject, f(m))
- end
- expect(subject).to_equal(target)
- - it coerces string arguments to a number:
- expect(f '1000').to_be '1k'
-
-
-- describe ordinal_suffix:
- - before:
- f = M.ordinal_suffix
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.ordinal_suffix(int|string)')
-
- - it returns the English suffix for a number:
- subject, target = {}, {}
- for n = -120, 120 do
- suffix = 'th'
- m = math.abs(n) % 10
- if m == 1 and math.abs(n) % 100 ~= 11 then
- suffix = 'st'
- elseif m == 2 and math.abs(n) % 100 ~= 12 then
- suffix = 'nd'
- elseif m == 3 and math.abs(n) % 100 ~= 13 then
- suffix = 'rd'
- end
- table.insert(target, n .. suffix)
- table.insert(subject, n .. f(n))
- end
- expect(subject).to_equal(target)
- - it coerces string arguments to a number:
- expect(f '-91').to_be 'st'
-
-
-- describe pad:
- - before:
- width = 20
-
- f = M.pad
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.pad(string, int, ?string)')
-
- - context when string is shorter than given width:
- - before:
- subject = 'short string'
- - it right pads a string to the given width with spaces:
- target = 'short string '
- expect(f(subject, width)).to_be(target)
- - it left pads a string to the given negative width with spaces:
- width = -width
- target = ' short string'
- expect(f(subject, width)).to_be(target)
- - it is available as a string metamethod:
- target = 'short string '
- expect(subject:pad(width)).to_be(target)
-
- - context when string is longer than given width:
- - before:
- subject = "a string that's longer than twenty characters"
- - it truncates a string to the given width:
- target = "a string that's long"
- expect(f(subject, width)).to_be(target)
- - it left pads a string to given width with spaces:
- width = -width
- target = 'an twenty characters'
- expect(f(subject, width)).to_be(target)
- - it is available as a string metamethod:
- target = "a string that's long"
- expect(subject:pad(width)).to_be(target)
-
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, width)
- expect(subject).to_be(original)
-
-
-- describe prettytostring:
- - before:
- f = M.prettytostring
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.prettytostring(?any, ?string, ?string)')
-
- - it renders nil exactly like system tostring:
- expect(f(nil)).to_be(tostring(nil))
- - it renders booleans exactly like system tostring:
- expect(f(true)).to_be(tostring(true))
- expect(f(false)).to_be(tostring(false))
- - it renders numbers exactly like system tostring:
- n = 8723643
- expect(f(n)).to_be(tostring(n))
- - it renders functions exactly like system tostring:
- expect(f(f)).to_be(tostring(f))
- - it renders strings with format '%q' styling:
- s = 'a string'
- expect(f(s)).to_be(string.format('%q', s))
- - it renders empty tables as a pair of braces:
- expect(f {}).to_be('{\n}')
- - it renders an array prettily:
- a = {'one', 'two', 'three'}
- expect(f(a, '')).
- to_be '{\n[1] = "one",\n[2] = "two",\n[3] = "three",\n}'
- - it renders a table prettily:
- t = {one=true, two=2, three={3}}
- expect(f(t, '')).
- to_be '{\none = true,\nthree =\n{\n[1] = 3,\n},\ntwo = 2,\n}'
- - it renders table keys in table.sort order:
- t = {one=3, two=5, three=4, four=2, five=1}
- expect(f(t, '')).
- to_be '{\nfive = 1,\nfour = 2,\none = 3,\nthree = 4,\ntwo = 5,\n}'
- - it renders keys with invalid symbol names in long hand:
- t = {_=0, word=0, ['?']=1, ['a-key']=1, ['[]']=1}
- expect(f(t, '')).
- to_be '{\n["?"] = 1,\n["[]"] = 1,\n_ = 0,\n["a-key"] = 1,\nword = 0,\n}'
-
-
-- describe rtrim:
- - before:
- subject = ' \t\r\n a short string \t\r\n '
-
- f = M.rtrim
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.rtrim(string, ?string)')
-
- - it removes whitespace from the end of a string:
- target = ' \t\r\n a short string'
- expect(f(subject)).to_equal(target)
- - it supports custom removal patterns:
- target = ' \t\r\n a short string \t\r'
- expect(f(subject, '[ \t\n]+')).to_equal(target)
- - it is available as a string metamethod:
- target = ' \t\r\n a short string \t\r'
- expect(subject:rtrim('[ \t\n]+')).to_equal(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, '%W')
- expect(subject).to_be(original)
-
-
-- describe split:
- - before:
- target = {'first', 'the second one', 'final entry'}
- subject = table.concat(target, ', ')
-
- f = M.split
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.split(string, ?string)')
-
- - it falls back to '%s+' when no pattern is given:
- expect(f(subject)).
- to_equal {'first,', 'the', 'second', 'one,', 'final', 'entry'}
- - it returns a one-element list for an empty string:
- expect(f('', ', ')).to_equal {''}
- - it makes a table of substrings delimited by a separator:
- expect(f(subject, ', ')).to_equal(target)
- - it returns n+1 elements for n separators:
- expect(f(subject, 'zero')).to_have_size(1)
- expect(f(subject, 'c')).to_have_size(2)
- expect(f(subject, 's')).to_have_size(3)
- expect(f(subject, 't')).to_have_size(4)
- expect(f(subject, 'e')).to_have_size(5)
- - it returns an empty string element for consecutive separators:
- expect(f('xyzyzxy', 'yz')).to_equal {'x', '', 'xy'}
- - it returns an empty string element when starting with separator:
- expect(f('xyzyzxy', 'xyz')).to_equal {'', 'yzxy'}
- - it returns an empty string element when ending with separator:
- expect(f('xyzyzxy', 'zxy')).to_equal {'xyzy', ''}
- - it returns a table of 1-character strings for '' separator:
- expect(f('abcdef', '')).to_equal {'', 'a', 'b', 'c', 'd', 'e', 'f', ''}
- - it is available as a string metamethod:
- expect(subject:split ', ').to_equal(target)
- expect(('/foo/bar/baz.quux'):split '/').
- to_equal {'', 'foo', 'bar', 'baz.quux'}
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, 'e')
- expect(subject).to_be(original)
- - it takes a Lua pattern as a separator:
- expect(f(subject, '%s+')).
- to_equal {'first,', 'the', 'second', 'one,', 'final', 'entry'}
-
-
-- describe tfind:
- - before:
- subject = 'abc'
-
- f = M.tfind
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.tfind(string, string, ?int, ?boolean|:plain)')
-
- - it creates a list of pattern captures:
- target = {1, 3, {'a', 'b', 'c'}}
- expect({f(subject, '(.)(.)(.)')}).to_equal(target)
- - it creates an empty list where no captures are matched:
- target = {nil, nil, {}}
- expect({f(subject, '(x)(y)(z)')}).to_equal(target)
- - it creates an empty list for a pattern without captures:
- target = {1, 1, {}}
- expect({f(subject, 'a')}).to_equal(target)
- - it starts the search at a specified index into the subject:
- target = {8, 10, {'a', 'b', 'c'}}
- expect({f('garbage' .. subject, '(.)(.)(.)', 8)}).to_equal(target)
- - it is available as a string metamethod:
- target = {8, 10, {'a', 'b', 'c'}}
- expect({('garbage' .. subject):tfind('(.)(.)(.)', 8)}).to_equal(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, '...')
- expect(subject).to_be(original)
-
-
-- describe trim:
- - before:
- subject = ' \t\r\n a short string \t\r\n '
-
- f = M.trim
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.trim(string, ?string)')
-
- - it removes whitespace from each end of a string:
- target = 'a short string'
- expect(f(subject)).to_equal(target)
- - it supports custom removal patterns:
- target = '\r\n a short string \t\r'
- expect(f(subject, '[ \t\n]+')).to_equal(target)
- - it is available as a string metamethod:
- target = '\r\n a short string \t\r'
- expect(subject:trim('[ \t\n]+')).to_equal(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, '%W')
- expect(subject).to_be(original)
-
-
-- describe wrap:
- - before:
- subject = 'This is a collection of Lua libraries for Lua 5.1 ' ..
- 'and 5.2. The libraries are copyright by their authors 2000' ..
- '-2015 (see the AUTHORS file for details), and released und' ..
- 'er the MIT license (the same license as Lua itself). There' ..
- ' is no warranty.'
-
- f = M.wrap
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.string.wrap(string, ?int, ?int, ?int)')
-
- - it inserts newlines to wrap a string:
- target = 'This is a collection of Lua libraries for Lua 5.1 a' ..
- 'nd 5.2. The libraries are\ncopyright by their authors 2000' ..
- '-2015 (see the AUTHORS file for details), and\nreleased un' ..
- 'der the MIT license (the same license as Lua itself). Ther' ..
- 'e is no\nwarranty.'
- expect(f(subject)).to_be(target)
- - it honours a column width parameter:
- target = 'This is a collection of Lua libraries for Lua 5.1 a' ..
- 'nd 5.2. The libraries\nare copyright by their authors 2000' ..
- '-2015 (see the AUTHORS file for\ndetails), and released un' ..
- 'der the MIT license (the same license as Lua\nitself). The' ..
- 're is no warranty.'
- expect(f(subject, 72)).to_be(target)
- - it supports indenting by a fixed number of columns:
- target = ' This is a collection of Lua libraries for L' ..
- 'ua 5.1 and 5.2. The\n libraries are copyright by th' ..
- 'eir authors 2000-2015 (see the\n AUTHORS file for d' ..
- 'etails), and released under the MIT license\n (the ' ..
- 'same license as Lua itself). There is no warranty.'
- expect(f(subject, 72, 8)).to_be(target)
- - context given a long unwrapped string:
- - before:
- target = ' This is a collection of Lua libraries for Lua 5' ..
- '.1 and 5.2.\n The libraries are copyright by their author' ..
- 's 2000-2015 (see\n the AUTHORS file for details), and rel' ..
- 'eased under the MIT\n license (the same license as Lua it' ..
- 'self). There is no\n warranty.'
- - it can indent the first line differently:
- expect(f(subject, 64, 2, 4)).to_be(target)
- - it is available as a string metamethod:
- expect(subject:wrap(64, 2, 4)).to_be(target)
- - it does not perturb the original subject:
- original = subject
- newstring = f(subject, 55, 5)
- expect(subject).to_be(original)
- - it diagnoses indent greater than line width:
- expect(f(subject, 10, 12)).to_raise('less than the line width')
- expect(f(subject, 99, 99)).to_raise('less than the line width')
- - it diagnoses non-string arguments:
- if have_typecheck then
- expect(f()).to_raise('string expected')
- expect(f {'a table'}).to_raise('string expected')
- end
diff --git a/spec/table_spec.yaml b/spec/table_spec.yaml
deleted file mode 100644
index d9fed0c..0000000
--- a/spec/table_spec.yaml
+++ /dev/null
@@ -1,589 +0,0 @@
-# General Lua Libraries for Lua 5.1, 5.2 & 5.3
-# Copyright (C) 2011-2018 stdlib authors
-
-before: |
- base_module = 'table'
- this_module = 'std.table'
- global_table = '_G'
-
- extend_base = {'clone', 'clone_select', 'depair', 'empty',
- 'enpair', 'insert', 'invert', 'keys', 'maxn',
- 'merge', 'merge_select', 'new',
- 'pack', 'project', 'remove', 'size', 'sort',
- 'unpack', 'values'}
-
- M = require(this_module)
-
-
-specify std.table:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by=this_module}).
- to_equal {}
- - it does not touch the core table table:
- expect(show_apis {added_to=base_module, by=this_module}).
- to_equal {}
- - it contains apis from the core table table:
- expect(show_apis {from=base_module, not_in=this_module}).
- to_contain.a_permutation_of(extend_base)
-
- - context via the std module:
- - it does not touch the global table:
- expect(show_apis {added_to=global_table, by='std'}).to_equal {}
- - it does not touch the core table table:
- expect(show_apis {added_to=base_module, by='std'}).to_equal {}
-
-
-- describe clone:
- - before:
- subject = {k1={'v1'}, k2={'v2'}, k3={'v3'}}
- withmt = setmetatable(M.clone(subject), {'meta!'})
-
- f = M.clone
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.clone(table, [table], ?boolean|:nometa)')
-
- - it does not just return the subject:
- expect(f(subject)).not_to_be(subject)
- - it does copy the subject:
- expect(f(subject)).to_equal(subject)
- - it only makes a shallow copy of field values:
- expect(f(subject).k1).to_be(subject.k1)
- - it does not perturb the original subject:
- target = {k1=subject.k1, k2=subject.k2, k3=subject.k3}
- copy = f(subject)
- expect(subject).to_equal(target)
- expect(subject).to_be(subject)
-
- - context with metatables:
- - it copies the metatable by default:
- expect(getmetatable(f(withmt))).to_be(getmetatable(withmt))
- - it treats non-table arg2 as nometa parameter:
- expect(getmetatable(f(withmt, ':nometa'))).to_be(nil)
- - it treats table arg2 as a map parameter:
- expect(getmetatable(f(withmt, {}))).to_be(getmetatable(withmt))
- - it supports 3 arguments with nometa as arg3:
- expect(getmetatable(f(withmt, {}, ':nometa'))).to_be(nil)
-
- - context when renaming some keys:
- - it renames during cloning:
- target = {newkey=subject.k1, k2=subject.k2, k3=subject.k3}
- expect(f(subject, {k1 = 'newkey'})).to_equal(target)
- - it does not perturb the value in the renamed key field:
- expect(f(subject, {k1 = 'newkey'}).newkey).to_be(subject.k1)
-
-
-- describe clone_select:
- - before:
- subject = {k1={'v1'}, k2={'v2'}, k3={'v3'}}
- withmt = setmetatable(M.clone(subject), {'meta!'})
-
- f = M.clone_select
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.clone_select(table, [table], ?boolean|:nometa)')
-
- - it does not just return the subject:
- expect(f(subject)).not_to_be(subject)
- - it copies the keys selected:
- expect(f(subject, {'k1', 'k2'})).to_equal({k1={'v1'}, k2={'v2'}})
- - it does copy the subject when supplied with a full list of keys:
- expect(f(subject, {'k1', 'k2', 'k3'})).to_equal(subject)
- - it only makes a shallow copy:
- expect(f(subject, {'k1'}).k1).to_be(subject.k1)
- - it does not perturb the original subject:
- target = {k1=subject.k1, k2=subject.k2, k3=subject.k3}
- copy = f(subject, {'k1', 'k2', 'k3'})
- expect(subject).to_equal(target)
- expect(subject).to_be(subject)
-
- - context with metatables:
- - it treats non-table arg2 as nometa parameter:
- expect(getmetatable(f(withmt, ':nometa'))).to_be(nil)
- - it treats table arg2 as a map parameter:
- expect(getmetatable(f(withmt, {}))).to_be(getmetatable(withmt))
- expect(getmetatable(f(withmt, {'k1'}))).to_be(getmetatable(withmt))
- - it supports 3 arguments with nometa as arg3:
- expect(getmetatable(f(withmt, {}, ':nometa'))).to_be(nil)
- expect(getmetatable(f(withmt, {'k1'}, ':nometa'))).to_be(nil)
-
-
-- describe depair:
- - before:
- t = {'first', 'second', third = 4}
- l = M.enpair(t)
-
- f = M.depair
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.depair(list of lists)')
-
- - it returns a primitive table:
- expect(objtype(f(l))).to_be 'table'
- - it works with an empty table:
- expect(f {}).to_equal {}
- - it is the inverse of enpair:
- expect(f(l)).to_equal(t)
-
-
-- describe empty:
- - before:
- f = M.empty
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.empty(table)')
-
- - it returns true for an empty table:
- expect(f {}).to_be(true)
- expect(f {nil}).to_be(true)
- - it returns false for a non-empty table:
- expect(f {'stuff'}).to_be(false)
- expect(f {{}}).to_be(false)
- expect(f {false}).to_be(false)
-
-
-- describe enpair:
- - before:
- t = {'first', 'second', third = 4}
- l = M.enpair(t)
-
- f = M.enpair
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.enpair(table)')
-
- - it returns a table:
- expect(objtype(f(t))).to_be 'table'
- - it works for an empty table:
- expect(f {}).to_equal {}
- - it turns a table into a table of pairs:
- expect(f(t)).to_equal {{1, 'first'}, {2, 'second'}, {'third', 4}}
- - it is the inverse of depair:
- expect(f(t)).to_equal(l)
-
-
-- describe insert:
- - before:
- f, badarg = init(M, this_module, 'insert')
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.insert(table, [int], any)')
-
- examples {
- ['it diagnoses more than 2 arguments with no pos'] = function()
- pending '#issue 76'
- expect(f({}, false, false)).to_raise(badarg(3))
- end
- }
- examples {
- ['it diagnoses out of bounds pos arguments'] = function()
- expect(f({}, 0, 'x')).to_raise 'position 0 out of bounds'
- expect(f({}, 2, 'x')).to_raise 'position 2 out of bounds'
- expect(f({1}, 5, 'x')).to_raise 'position 5 out of bounds'
- end
- }
-
- - it returns the modified table:
- t = {}
- expect(f(t, 1)).to_be(t)
- - it append a new element at the end by default:
- expect(f({1, 2}, 'x')).to_equal {1, 2, 'x'}
- - it fills holes by default:
- expect(f({1, 2, [5]=3}, 'x')).to_equal {1, 2, 'x', [5]=3}
- - it respects __len when appending:
- t = setmetatable({1, 2, [5]=3}, {__len = function() return 42 end})
- expect(f(t, 'x')).to_equal {1, 2, [5]=3, [43]='x'}
- - it moves other elements up if necessary:
- expect(f({1, 2}, 1, 'x')).to_equal {'x', 1, 2}
- expect(f({1, 2}, 2, 'x')).to_equal {1, 'x', 2}
- expect(f({1, 2}, 3, 'x')).to_equal {1, 2, 'x'}
- - it inserts a new element according to pos argument:
- expect(f({}, 1, 'x')).to_equal {'x'}
-
-
-- describe invert:
- - before:
- subject = {k1=1, k2=2, k3=3}
-
- f = M.invert
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.invert(table)')
-
- - it returns a new table:
- expect(f(subject)).not_to_be(subject)
- - it inverts keys and values in the returned table:
- expect(f(subject)).to_equal {'k1', 'k2', 'k3'}
- - it is reversible:
- expect(f(f(subject))).to_equal(subject)
- - it seems to copy a list of 1..n numbers:
- subject = {1, 2, 3}
- expect(f(subject)).to_copy(subject)
-
-
-- describe keys:
- - before:
- subject = {k1=1, k2=2, k3=3}
-
- f = M.keys
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.keys(table)')
-
- - it returns an empty list when subject is empty:
- expect(f {}).to_equal {}
- - it makes a list of table keys:
- cmp = function(a, b)
- return a < b
- end
- expect(M.sort(f(subject), cmp)).to_equal {'k1', 'k2', 'k3'}
- - it does not guarantee stable ordering:
- subject = {}
- -- is this a good test? there is a vanishingly small possibility the
- -- returned table will have all 10000 keys in the same order...
- for i = 10000, 1, -1 do
- table.insert(subject, i)
- end
- expect(f(subject)).not_to_equal(subject)
-
-
-- describe maxn:
- - before:
- f = M.maxn
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.maxn(table)')
-
- - it returns the largest numeric key of a table:
- expect(f {'a', 'b', 'c'}).to_be(3)
- expect(f {1, 2, 5, a=10, 3}).to_be(4)
- - it works with an empty table:
- expect(f {}).to_be(0)
- - it ignores holes:
- expect(f {1, 2, [5]=3}).to_be(5)
- - it ignores __len metamethod:
- t = setmetatable({1, 2, [5]=3}, {__len = function() return 42 end})
- expect(f(t)).to_be(5)
-
-
-- describe merge:
- - before: |
- -- Additional merge keys which are moderately unusual
- t1 = {k1={'v1'}, k2='if', k3={'?'}}
- t2 = {['if']=true, [{'?'}]=false, _='underscore', k3=t1.k1}
- t1mt = setmetatable(M.clone(t1), {'meta!'})
- target = {}
- for k, v in pairs(t1) do
- target[k] = v
- end
- for k, v in pairs(t2) do
- target[k] = v
- end
-
- f, badarg = init(M, this_module, 'merge')
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.merge(table, table, [table], ?boolean|:nometa)')
-
- examples {
- ['it diagnoses more than 2 arguments with no pos'] = function()
- pending '#issue 76'
- expect(f({}, {}, ':nometa', false)).to_raise(badarg(4))
- end
- }
-
- - it does not create a whole new table:
- expect(f(t1, t2)).to_be(t1)
- - it does not change t1 when t2 is empty:
- expect(f(t1, {})).to_be(t1)
- - it copies t2 when t1 is empty:
- expect(f({}, t1)).to_copy(t1)
- - it merges keys from t2 into t1:
- expect(f(t1, t2)).to_equal(target)
- - it gives precedence to values from t2:
- original = M.clone(t1)
- m = f(t1, t2) -- Merge is destructive, do it once only.
- expect(m.k3).to_be(t2.k3)
- expect(m.k3).not_to_be(original.k3)
- - it only makes a shallow copy of field values:
- expect(f({}, t1).k1).to_be(t1.k1)
-
- - context with metatables:
- - it copies the metatable by default:
- expect(getmetatable(f({}, t1mt))).to_be(getmetatable(t1mt))
- expect(getmetatable(f({}, t1mt, {'k1'}))).to_be(getmetatable(t1mt))
- - it treats non-table arg3 as nometa parameter:
- expect(getmetatable(f({}, t1mt, ':nometa'))).to_be(nil)
- - it treats table arg3 as a map parameter:
- expect(getmetatable(f({}, t1mt, {}))).to_be(getmetatable(t1mt))
- expect(getmetatable(f({}, t1mt, {'k1'}))).to_be(getmetatable(t1mt))
- - it supports 4 arguments with nometa as arg4:
- expect(getmetatable(f({}, t1mt, {}, ':nometa'))).to_be(nil)
- expect(getmetatable(f({}, t1mt, {'k1'}, ':nometa'))).to_be(nil)
-
- - context when renaming some keys:
- - it renames during merging:
- target = {newkey=t1.k1, k2=t1.k2, k3=t1.k3}
- expect(f({}, t1, {k1 = 'newkey'})).to_equal(target)
- - it does not perturb the value in the renamed key field:
- expect(f({}, t1, {k1 = 'newkey'}).newkey).to_be(t1.k1)
-
-
-- describe merge_select:
- - before: |
- -- Additional merge keys which are moderately unusual
- tablekey = {'?'}
- t1 = {k1={'v1'}, k2='if', k3={'?'}}
- t1mt = setmetatable(M.clone(t1), {'meta!'})
- t2 = {['if']=true, [tablekey]=false, _='underscore', k3=t1.k1}
- t2keys = {'if', tablekey, '_', 'k3'}
- target = {}
- for k, v in pairs(t1) do
- target[k] = v
- end
- for k, v in pairs(t2) do
- target[k] = v
- end
-
- f, badarg = init(M, this_module, 'merge_select')
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.merge_select(table, table, [table], ?boolean|:nometa)')
-
- examples {
- ['it diagnoses more than 2 arguments with no pos'] = function()
- pending '#issue 76'
- expect(f({}, {}, ':nometa', false)).to_raise(badarg(4))
- end
- }
-
- - it does not create a whole new table:
- expect(f(t1, t2)).to_be(t1)
- - it does not change t1 when t2 is empty:
- expect(f(t1, {})).to_be(t1)
- - it does not change t1 when key list is empty:
- expect(f(t1, t2, {})).to_be(t1)
- - it copies the named fields:
- expect(f({}, t2, t2keys)).to_equal(t2)
- - it makes a shallow copy:
- expect(f({}, t1, {'k1'}).k1).to_be(t1.k1)
- - it copies exactly named fields of t2 when t1 is empty:
- expect(f({}, t1, {'k1', 'k2', 'k3'})).to_copy(t1)
- - it merges keys from t2 into t1:
- expect(f(t1, t2, t2keys)).to_equal(target)
- - it gives precedence to values from t2:
- original = M.clone(t1)
- m = f(t1, t2, t2keys) -- Merge is destructive, do it once only.
- expect(m.k3).to_be(t2.k3)
- expect(m.k3).not_to_be(original.k3)
-
- - context with metatables:
- - it copies the metatable by default:
- expect(getmetatable(f({}, t1mt))).to_be(getmetatable(t1mt))
- expect(getmetatable(f({}, t1mt, {'k1'}))).to_be(getmetatable(t1mt))
- - it treats non-table arg3 as nometa parameter:
- expect(getmetatable(f({}, t1mt, ':nometa'))).to_be(nil)
- - it treats table arg3 as a map parameter:
- expect(getmetatable(f({}, t1mt, {}))).to_be(getmetatable(t1mt))
- expect(getmetatable(f({}, t1mt, {'k1'}))).to_be(getmetatable(t1mt))
- - it supports 4 arguments with nometa as arg4:
- expect(getmetatable(f({}, t1mt, {}, ':nometa'))).to_be(nil)
- expect(getmetatable(f({}, t1mt, {'k1'}, ':nometa'))).to_be(nil)
-
-
-- describe new:
- - before:
- f = M.new
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.new(?any, ?table)')
-
- - context when not setting a default:
- - before: default = nil
- - it returns a new table when nil is passed:
- expect(f(default, nil)).to_equal {}
- - it returns any table passed in:
- t = {'unique table'}
- expect(f(default, t)).to_be(t)
-
- - context when setting a default:
- - before:
- default = 'default'
- - it returns a new table when nil is passed:
- expect(f(default, nil)).to_equal {}
- - it returns any table passed in:
- t = {'unique table'}
- expect(f(default, t)).to_be(t)
-
- - it returns the stored value for existing keys:
- t = f('default')
- v = {'unique value'}
- t[1] = v
- expect(t[1]).to_be(v)
- - it returns the constructor default for unset keys:
- t = f('default')
- expect(t[1]).to_be 'default'
- - it returns the actual default object:
- default = {'unique object'}
- t = f(default)
- expect(t[1]).to_be(default)
-
-
-- describe pack:
- - before:
- unpack = unpack or table.unpack
- t = {'one', 'two', 'five', n=3}
- f = M.pack
- - it creates an empty table with no arguments:
- expect(f()).to_equal {n=0}
- - it creates a table with arguments as elements:
- expect(f('one', 'two', 'five')).to_equal(t)
- - it is the inverse operation to unpack:
- expect(f(unpack(t))).to_equal(t)
- - it saves the tuple length in field n:
- expect(f(1, 2, 5).n).to_be(3)
- expect(f('', false, nil).n).to_be(3)
- expect(f(nil, nil, nil).n).to_be(3)
-
-
-- describe project:
- - before:
- l = {
- {first = false, second = true, third = true},
- {first = 1, second = 2, third = 3},
- {first = '1st', second = '2nd', third = '3rd'},
- }
-
- f = M.project
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.project(any, list of tables)')
-
- - it returns a table:
- expect(objtype(f('third', l))).to_be 'table'
- - it works with an empty table:
- expect(f('third', {})).to_equal {}
- - it projects a table of fields from a table of tables:
- expect(f('third', l)).to_equal {true, 3, '3rd'}
- - it projects fields with a falsey value correctly:
- expect(f('first', l)).to_equal {false, 1, '1st'}
-
-
-- describe remove:
- - before:
- f = M.remove
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.remove(table, ?int)')
-
- examples {
- ['it diagnoses out of bounds pos arguments'] = function()
- expect(f({1}, 0)).to_raise 'position 0 out of bounds'
- expect(f({1}, 3)).to_raise 'position 3 out of bounds'
- expect(f({1}, 5)).to_raise 'position 5 out of bounds'
- end
- }
-
- - it returns the removed element:
- t = {'one', 'two', 'five'}
- expect(f({'one', 2, 5}, 1)).to_be 'one'
- - it removes an element from the end by default:
- expect(f {1, 2, 'five'}).to_be 'five'
- - it ignores holes:
- t = {'second', 'first', [5]='invisible'}
- expect(f(t)).to_be 'first'
- expect(f(t)).to_be 'second'
- - it respects __len when defaulting pos:
- t = setmetatable({1, 2, [43]='invisible'}, {__len = function() return 42 end})
- expect(f(t)).to_be(nil)
- expect(f(t)).to_be(nil)
- expect(t).to_equal {1, 2, [43]='invisible'}
- - it moves other elements down if necessary:
- t = {1, 2, 5, 'third', 'first', 'second', 42}
- expect(f(t, 5)).to_be 'first'
- expect(t).to_equal {1, 2, 5, 'third', 'second', 42}
- expect(f(t, 5)).to_be 'second'
- expect(t).to_equal {1, 2, 5, 'third', 42}
- expect(f(t, 4)).to_be 'third'
- expect(t).to_equal {1, 2, 5, 42}
-
-
-- describe size:
- - before: |
- -- - 1 - ------- 2 ------- -- 3 --
- subject = {'one', {{'two'}, 'three'}, four=5}
-
- f = M.size
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.size(table)')
-
- - it counts the number of keys in a table:
- expect(f(subject)).to_be(3)
- - it counts no keys in an empty table:
- expect(f {}).to_be(0)
-
-
-- describe sort:
- - before:
- subject = {5, 2, 4, 1, 0, 3}
- target = {0, 1, 2, 3, 4, 5}
- cmp = function(a, b) return a < b end
-
- f = M.sort
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.sort(table, ?function)')
-
- - it sorts elements in place:
- f(subject, cmp)
- expect(subject).to_equal(target)
- - it returns the sorted table:
- expect(f(subject, cmp)).to_equal(target)
-
-
-- describe unpack:
- - before:
- t = {'one', 'two', 'five'}
- f = M.unpack
- - it returns nil for an empty table:
- expect(f {}).to_be(nil)
- - it returns numeric indexed table elements:
- expect({f(t)}).to_equal(t)
- - it respects __len metamethod:
- function two(t)
- return setmetatable(t, {__len=function() return 2 end})
- end
- expect(pack(f(two {})).n).to_be(2)
- expect(pack(f(two(t))).n).to_be(2)
- - it returns holes in numeric indices as nil:
- expect({f {nil, 2}}).to_equal {[2] = 2}
- expect({f {nil, nil, 3}}).to_equal {[3] = 3}
- expect({f {1, nil, nil, 4}}).to_equal {1, [4] = 4}
- - it is the inverse operation to pack:
- expect({f(M.pack('one', 'two', 'five'))}).to_equal(t)
-
-
-- describe values:
- - before:
- subject = {k1={1}, k2={2}, k3={3}}
-
- f = M.values
-
- - context with bad arguments:
- badargs.diagnose(f, 'std.table.values(table)')
-
- - it returns an empty list when subject is empty:
- expect(f {}).to_equal {}
- - it makes a list of table values:
- cmp = function(a, b) return a[1] < b[1] end
- expect(M.sort(f(subject), cmp)).to_equal {{1}, {2}, {3}}
- - it does guarantee stable ordering:
- subject = {}
- -- is this a good test? or just requiring an implementation quirk?
- for i = 10000, 1, -1 do
- table.insert(subject, i)
- end
- expect(f(subject)).to_equal(subject)
diff --git a/stdlib-git-1.rockspec b/stdlib-git-1.rockspec
deleted file mode 100644
index 504aee8..0000000
--- a/stdlib-git-1.rockspec
+++ /dev/null
@@ -1,51 +0,0 @@
-local _MODREV, _SPECREV = 'git', '-1'
-
-package = 'stdlib'
-version = _MODREV .. _SPECREV
-
-description = {
- summary = 'General Lua Libraries',
- detailed = [[
- stdlib is a library of modules for common programming tasks,
- including list and table operations, and pretty-printing.
- ]],
- homepage = 'http://lua-stdlib.github.io/lua-stdlib',
- license = 'MIT/X11',
-}
-
-source = (function(gitp)
- if gitp then
- return {
- url = 'git://github.com/lua-stdlib/lua-stdlib.git',
- }
- else
- return {
- url = 'http://github.com/lua-stdlib/lua-stdlib/archive/v' .. _MODREV .. '.zip',
- dir = 'lua-stdlib-' .. _MODREV,
- }
- end
-end)(_MODREV == 'git')
-
-dependencies = {
- 'lua >= 5.1, < 5.4',
- 'std._debug',
- 'std.normalize >= 2.0',
-}
-
-if _MODREV == 'git' then
- dependencies[#dependencies + 1] = 'ldoc'
-end
-
-build = {
- type = 'builtin',
- modules = {
- std = 'lib/std/init.lua',
- ['std._base'] = 'lib/std/_base.lua',
- ['std.debug'] = 'lib/std/debug.lua',
- ['std.io'] = 'lib/std/io.lua',
- ['std.math'] = 'lib/std/math.lua',
- ['std.package'] = 'lib/std/package.lua',
- ['std.string'] = 'lib/std/string.lua',
- ['std.table'] = 'lib/std/table.lua',
- },
-}