diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml
deleted file mode 100644
index 484a51b..0000000
--- a/.github/workflows/spec.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-name: spec
-
-on:
- push:
- branches: [ '*' ]
- pull_request:
- branches: [ 'master' ]
-
-jobs:
- test:
- strategy:
- fail-fast: false
- matrix:
- lua-version: ["5.4", "5.3", "5.2", "5.1", "luajit"]
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v2
-
- - uses: leafo/gh-actions-lua@v8.0.0
- with:
- luaVersion: ${{ matrix.lua-version }}
-
- - uses: leafo/gh-actions-luarocks@v4.0.0
-
- - name: install
- run: |
- sudo apt-get install -y libyaml-dev
- luarocks install ansicolors
- luarocks install ldoc
- luarocks install luacov
- luarocks install specl
-
- - name: build
- run: |
- make all doc
- luarocks make
-
- - name: test
- run: |
- make check SPECL_OPTS='-vfreport --coverage'
- bash <(curl -s https://codecov.io/bash) -f luacov.report.out
diff --git a/.gitignore b/.gitignore
index f57d2b9..6009d70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,3 @@
-*~
.DS_Store
-/*.src.rock
-/build-aux/config.ld
/doc
-/luacov.*.out
-/lib/std/prototype/version.lua
-/prototype-*.tar.gz
+!/doc/config.ld.in
diff --git a/.luacov b/.luacov
deleted file mode 100644
index b44eaef..0000000
--- a/.luacov
+++ /dev/null
@@ -1,51 +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/prototype/_base$",
- "lib/std/prototype/container$",
- "lib/std/prototype/init$",
- "lib/std/prototype/object$",
- "lib/std/prototype/set$",
- "lib/std/prototype/strbuf$",
- "lib/std/prototype/trie$",
- "lib/std/prototype/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/AUTHORS.md b/AUTHORS.md
deleted file mode 100644
index 3cff008..0000000
--- a/AUTHORS.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# prototype's contributors
-
-This file lists major contributors to [prototype][]. 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 _prototype_, having rewritten and
-reorganised all the original code from [lua-stdlib][], in addition to
-to adding a lot of new functionality.
-
-Reuben Thomas started the standard libraries project, which included the
-original implementation of many of the functions now distributed with
-this package.
-
-[github issue]: https://github.com/lua-stdlib/prototype/issues
-[lua-stdlib]: https://github.com/lua-stdlib/lua-stdlib
-[prototype]: https://github.com/lua-stdlib/prototype
diff --git a/LICENSE.md b/LICENSE.md
deleted file mode 100644
index fae68ec..0000000
--- a/LICENSE.md
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (C) 2002-2022 prototype 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 c52772f..0000000
--- a/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-# Prototype Oriented Programming with Lua
-# Copyright (C) 2002-2022 std.prototype authors
-
-LDOC = ldoc
-LUA = lua
-MKDIR = mkdir -p
-SED = sed
-SPECL = specl
-
-VERSION = git
-
-luadir = lib/std/prototype
-SOURCES = \
- $(luadir)/_base.lua \
- $(luadir)/container.lua \
- $(luadir)/init.lua \
- $(luadir)/object.lua \
- $(luadir)/set.lua \
- $(luadir)/strbuf.lua \
- $(luadir)/trie.lua \
- $(luadir)/version.lua \
- $(NOTHING_ELSE)
-
-
-all: doc $(luadir)/version.lua
-
-
-$(luadir)/version.lua: .FORCE
- @echo 'return "Prototype Object Libraries / $(VERSION)"' > '$@T'; \
- if cmp -s '$@' '$@T'; then \
- rm -f '$@T'; \
- else \
- echo 'echo return "Prototype Object 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: $(SOURCES)
- LUA=$(LUA) $(SPECL) $(SPECL_OPTS) spec/*_spec.yaml
-
-
-.FORCE:
diff --git a/NEWS.md b/NEWS.md
deleted file mode 100644
index 9226529..0000000
--- a/NEWS.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# std.prototype NEWS - User visible changes
-
-## Noteworthy changes in release ?.? (????-??-??) [?]
-
-### New Features
-
- - Initial support for Lua 5.4.
-
-
-## Noteworthy changes in release 1.0.1 (2016-02-07) [stable]
-
-### Bug fixes
-
- - The former lua-stdlib `strict` module, has moved to `std.strict`
- to avoid confusion with the original PUC-Rio strict.lua. The base
- module now looks for it there.
-
-
-## Noteworthy changes in release 1.0 (2016-02-07) [stable]
-
-### New features (since lua-stdlib-41.2)
-
- - Initial release, now separated out from lua-stdlib.
-
- - Objects and Modules are no longer conflated - what you get back from
- a `require "std.prototype.something"` is now ALWAYS a module:
-
- ```lua
- local object = require "std.prototype.object"
- assert (object.type (object) == "Module")
- ```
-
- And the modules that provide objects have a new `prototype` field
- that contains the prototye for that kind of object:
-
- ```lua
- local Object = object.prototype
- assert (object.type (Object) == "Object")
- ```
-
- For backwards compatibility, if you call the module with a
- constructor table, the previous recommended way to disambiguate
- between a module and the object it prototyped, that table is passed
- through to the module's object prototype.
-
- - Now that we have proper separation of concerns between module tables
- and object prototype tables, the central `std.prototype.object.mapfields`
- instantiation function is much cleaner and faster.
-
- - We used to have an object module method, `std.object.type`, which
- often got imported using:
-
- ```lua
- local prototype = require "std.object".type
- ```
-
- So we renamed it to `std.object.prototype` to avoid a name clash with
- the `type` symbol, and subsequently deprecated the earlier equivalent
- `type` method; but that was a mistake, because core Lua provides `type`,
- and `io.type` (and in recent releases, `math.type`). So now, for
- orthogonality with core Lua, we're going back to using
- `std.prototype.object.type`, because that just makes more sense. Sorry!
-
-### Bug fixes
-
- - You can now derive other types from `std.prototype.set` by passing a
- `_type` field in the init argument, just like the other table argument
- objects.
-
- - In-order iteration with `__pairs` metamethod has been reinstated.
- There were no spec examples, and the implementation mysteriously
- went missing in a previous round of refactoring.
-
-### Incompatible changes
-
- - Deprecated methods and functions have all been removed.
-
- - `std.tree` is now `std.prototype.trie` and defines a Trie object, not a
- Tree object. The implementation has been a _Radix Tree_ (aka _Trie_)
- all along.
-
- - Objects no longer honor mangling and stripping `_functions` tables
- from objects during instantiation, instead move your actual object
- into the module `prototype` field, and add the module functions to
- the parent table returned when the module is required.
diff --git a/README.md b/README.md
deleted file mode 100644
index 014b660..0000000
--- a/README.md
+++ /dev/null
@@ -1,93 +0,0 @@
-Prototype Oriented Programming with Lua
-=======================================
-
-Copyright (C) 2000-2022 [std.prototype authors][authors]
-
-[](http://mit-license.org)
-[](https://github.com/lua-stdlib/prototype/actions)
-[](https://codecov.io/github/lua-stdlib/prototype?branch=master)
-
-
-This is a collection of Prototype Oriented Programming libraries for
-Lua 5.1 (including LuaJIT), 5.2, 5.3 and 5.4. 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.
-
-_prototype_ has no run-time prerequisites beyond a standard Lua system,
-though it will take advantage of [stdlib][], [strict][] and [typecheck][]
-if they are installed.
-
-[authors]: http://github.com/lua-stdlib/prototype/blob/master/AUTHORS.md
-[github]: http://github.com/lua-stdlib/prototype/ "Github repository"
-[lua]: http://www.lua.org "The Lua Project"
-[mit]: http://mit-license.org "MIT License"
-[stdlib]: https://github.com/lua-stdlib/lua-stdlib "Standard Lua Libraries"
-[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 prototype is with [LuaRocks][]. To
-install the latest release (recommended):
-
-```bash
- luarocks install prototype
-```
-
-To install current git master (for testing, before submitting a bug
-report for example):
-
-```bash
- luarocks install http://raw.githubusercontent.com/lua-stdlib/prototype/master/prototype-git-1.rockspec
-```
-
-The best way to install without [LuaRocks][] is to copy the `prototype`
-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/prototype
-
-
-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/prototype/issues
diff --git a/build-aux/config.ld.in b/build-aux/config.ld.in
deleted file mode 100644
index 34e9df3..0000000
--- a/build-aux/config.ld.in
+++ /dev/null
@@ -1,74 +0,0 @@
---[[
- Prototype Oriented Programming with Lua
- Copyright (C) 2002-2022 std.prototype authors
-]]
-
-title = 'std.prototype @PACKAGE_VERSION@ Reference'
-project = 'std.prototype @PACKAGE_VERSION@'
-description = [[
-# Prototype Oriented Programming with Lua
-
-A straight forward prototype-based object system, and a selection of
-useful objects built on it.
-
-This is a collection of light-weight libraries for Lua 5.1 (including
-LuaJIT), 5.2, 5.3 and 5.4 written in pure Lua.
-
-Each of the modules in this package returns a table with an empty
-prototype object in the `prototype` field, and often a selection of
-_module functions_ not related to a specific instance. That is, when
-you require one of these modules, you get a conventional table of
-functions plus an empty object of some sort:
-
-
- local object = require 'std.prototype.object'
- for k, v in pairs (object) do print (k, type (v)) end
- --> prototype table
- --> type function
-
-In this case, a module function called `type` which looks up the
-`_type` field in any prototype's metatable, and an empty `Object`:
-
- print (object.prototype)
- --> Object {}
-
-You can instantiate additional copies of a prototype by calling it with
-a table of specialised attributes:
-
- print (object.prototype { myattribute = 'my value' })
- --> Object {myattribute=my value}
-
-As a convenience, calling the module itself passes the argument table
-through to that module's prototype, although its faster to save an
-empty instance of the prototype in a `local` and use that:
-
- print (object { 1, 2, foo = 'bar' })
- --> Object {1, 2; foo=bar}
-
- local Object = object.prototype
- print (Object { 'Woo!' })
- --> Object {Woo!}
-
-## 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/prototype/init.lua',
- '../lib/std/prototype/container.lua',
- '../lib/std/prototype/object.lua',
- '../lib/std/prototype/set.lua',
- '../lib/std/prototype/strbuf.lua',
- '../lib/std/prototype/trie.lua',
-}
-
-new_type ('object', 'Objects', false, 'Fields')
-new_type ('init', 'Initialisation', false, 'Parameters')
-
-format = 'markdown'
-backtick_references = false
-sort = false
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..bf7ea27
--- /dev/null
+++ b/index.html
@@ -0,0 +1,138 @@
+
+
+
+
A straight forward prototype-based object system, and a selection of
+useful objects built on it.
+
+
This is a collection of light-weight libraries for Lua 5.1 (including
+LuaJIT), 5.2 and 5.3 written in pure Lua.
+
+
Each of the modules in this package returns a table with an empty
+prototype object in the prototype field, and often a selection of
+module functions not related to a specific instance. That is, when
+you require one of these modules, you get a conventional table of
+functions plus an empty object of some sort:
+
+
+
local object = require "std.prototype.object"
+for k, v in pairs (object) do print (k, type (v)) end
+--> prototype table
+--> type function
+
+
+
In this case, a module function called type which looks up the
+_type field in any prototype's metatable, and an empty Object:
+
+
print (object.prototype)
+--> Object {}
+
+
+
You can instantiate additional copies of a prototype by calling it with
+a table of specialised attributes:
As a convenience, calling the module itself passes the argument table
+through to that module's prototype, although its faster to save an
+empty instance of the prototype in a local and use that:
+generated by LDoc 1.4.3
+Last updated 2016-02-08 00:31:49
+
+
+
+
diff --git a/ldoc.css b/ldoc.css
new file mode 100644
index 0000000..ce77ac8
--- /dev/null
+++ b/ldoc.css
@@ -0,0 +1,304 @@
+/* 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 {
+ background-color: rgb(245, 245, 245);
+ border: 1px solid #C0C0C0; /* silver */
+ padding: 10px;
+ margin: 10px 0 10px 0;
+ overflow: auto;
+ font-family: "Andale Mono", monospace;
+}
+
+pre.example {
+ font-size: .85em;
+}
+
+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 .user-keyword { color: #800080; }
+pre .prompt { color: #558817; }
+pre .url { color: #272fc2; text-decoration: underline; }
+
diff --git a/lib/std/prototype/_base.lua b/lib/std/prototype/_base.lua
deleted file mode 100644
index 72009a4..0000000
--- a/lib/std/prototype/_base.lua
+++ /dev/null
@@ -1,65 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
-
-local _ENV = require 'std.normalize' {
- nonempty = next,
- sub = string.sub,
-}
-
-local argscheck
-do
- local ok, typecheck = pcall(require, 'typecheck')
- if ok then
- argscheck = typecheck.argscheck
- else
- argscheck = function(decl, fn)
- return fn
- end
- end
-end
-
-
-return {
- Module = function(t)
- return setmetatable(t, {
- _type = 'Module',
- __call = function(self, ...)
- return self.prototype(...)
- end,
- })
- end,
-
- argscheck = argscheck,
-
- mapfields = function(obj, src, map)
- local mt = getmetatable(obj) or {}
-
- -- Map key pairs.
- -- Copy all pairs when `map == nil`, but discard unmapped src keys
- -- when map is provided(i.e. if `map == {}`, copy nothing).
- if map == nil or nonempty(map) then
- map = map or {}
- for k, v in next, src do
- local key, dst = map[k] or k, obj
- local kind = type(key)
- if kind == 'string' and sub(key, 1, 1) == '_' then
- mt[key] = v
- elseif nonempty(map) and kind == 'number' and len(dst) + 1 < key then
- -- When map is given, but has fewer entries than src, stop copying
- -- fields when map is exhausted.
- break
- else
- dst[key] = v
- end
- end
- end
-
- -- Only set non-empty metatable.
- if nonempty(mt) then
- setmetatable(obj, mt)
- end
- return obj
- end,
-}
diff --git a/lib/std/prototype/container.lua b/lib/std/prototype/container.lua
deleted file mode 100644
index fd8449b..0000000
--- a/lib/std/prototype/container.lua
+++ /dev/null
@@ -1,296 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- Container Prototype.
-
- This module supplies 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.
-
- The functionality of a container based object is entirely defined by its
- *meta*methods. However, since we can store *any* object in a container,
- we cannot rely on the `__index` metamethod, because it is only a
- fallback for when that key is not already in the container itself. Of
- course that does not entirely preclude the use of `__index` with
- containers, so long as this limitation is observed.
-
- When making your own prototypes, derive from @{prototype.container.prototype}
- if you want to access the contents of your containers with the `[]`
- operator, otherwise from @{prototype.object.prototype} if you want to access
- the functionality of your objects with named object methods.
-
- Prototype Chain
- ---------------
-
- table
- `-> Container
-
- @module std.prototype.container
-]]
-
-
-local _ENV = require 'std.normalize' {
- Module = require 'std.prototype._base'.Module,
- argscheck = require 'std.prototype._base'.argscheck,
- concat = table.concat,
- mapfields = require 'std.prototype._base'.mapfields,
- nonempty = next,
- sort = table.sort,
-}
-
-
-
---[[ ================= ]]--
---[[ Helper Functions. ]]--
---[[ ================= ]]--
-
-
-local function keysort(a, b)
- if type(a) == 'number' then
- return type(b) ~= 'number' or a < b
- else
- return type(b) ~= 'number' and tostring(a) < tostring(b)
- end
-end
-
-
-local function shallow_copy(t)
- local r = {}
- for k, v in next, t do
- r[k] = v
- end
- return r
-end
-
-
---- Instantiate a new object based on *proto*.
---
--- This is equivalent to:
---
--- merge(copy(proto), t or {})
---
--- Except that, by not checking arguments or metatables, it is faster.
--- @tparam table proto base object to copy from
--- @tparam[opt={}] table t additional fields to merge in
--- @treturn table a new table with fields from proto and t merged in.
-local function instantiate(proto, t)
- local obj = {}
- for k, v in next, proto do
- obj[k] = v
- end
- for k, v in next, t or {} do
- obj[k] = v
- end
- return obj
-end
-
-
-
---[[ ================= ]]--
---[[ Container Object. ]]--
---[[ ================= ]]--
-
-
---- Container prototype.
--- @object prototype
--- @string[opt='Container'] _type object name
--- @tfield[opt] table|function _init object initialisation
--- @usage
--- local Container = require 'prototype.container'.prototype
--- local Graph = Container { _type = 'Graph' }
--- local function nodes(graph)
--- local n = 0
--- for _ in pairs(graph) do
--- n = n + 1
--- end
--- return n
--- end
--- local g = Graph { 'node1', 'node2' }
--- assert(nodes(g) == 2)
-local prototype = {
- _type = 'Container',
-
- --- Metamethods
- -- @section metamethods
-
- --- Return a clone of this container and its metatable.
- --
- -- Like any Lua table, a container is essentially a collection of
- -- `field_n = value_n` pairs, except that field names beginning with
- -- an underscore `_` are usually kept in that container's metatable
- -- where they define the behaviour of a container object rather than
- -- being part of its actual contents. In general, cloned objects
- -- also clone the behaviour of the object they cloned, unless...
- --
- -- When calling @{prototype.container.prototype}, you pass a single table
- -- argument with additional fields(and values) to be merged into the
- -- clone. Any field names beginning with an underscore `_` are copied
- -- to the clone's metatable, and all other fields to the cloned
- -- container itself. For instance, you can change the name of the
- -- cloned object by setting the `_type` field in the argument table.
- --
- -- The `_init` private field is also special: When set to a sequence of
- -- field names, unnamed fields in the call argument table are assigned
- -- to those field names in subsequent clones, like the example below.
- --
- -- Alternatively, you can set the `_init` private field of a cloned
- -- container object to a function instead of a sequence, in which case
- -- all the arguments passed when *it* is called/cloned(including named
- -- and unnamed fields in the initial table argument, if there is one)
- -- are passed through to the `_init` function, following the nascent
- -- cloned object. See the @{mapfields} usage example below.
- -- @function prototype:__call
- -- @param ... arguments to prototype's *\_init*, often a single table
- -- @treturn prototype clone of this container, with shared or
- -- merged metatable as appropriate
- -- @usage
- -- local Cons = Container {_type='Cons', _init={'car', 'cdr'}}
- -- local list = Cons {'head', Cons {'tail', nil}}
- __call = function(self, ...)
- local mt = getmetatable(self)
- local obj_mt = mt
- local obj = {}
-
- -- This is the slowest part of cloning for any objects that have
- -- a lot of fields to test and copy.
- for k, v in next, self do
- obj[k] = v
- end
-
- if type(mt._init) == 'function' then
- obj = mt._init(obj, ...)
- else
- obj = (self.mapfields or mapfields)(obj, (...), mt._init)
- end
-
- -- If a metatable was set, then merge our fields and use it.
- if nonempty(getmetatable(obj) or {}) then
- obj_mt = instantiate(mt, getmetatable(obj))
-
- -- Merge object methods.
- if type(obj_mt.__index) == 'table' and
- type((mt or {}).__index) == 'table'
- then
- obj_mt.__index = instantiate(mt.__index, obj_mt.__index)
- end
- end
-
- return setmetatable(obj, obj_mt)
- end,
-
- --- Return an in-order iterator over public object fields.
- -- @function prototype:__pairs
- -- @treturn function iterator function
- -- @treturn Object *self*
- -- @usage
- -- for k, v in pairs(anobject) do
- -- process(k, v)
- -- end
- __pairs = function(self)
- local keys, i = {}, 0
- for k in next, self do
- keys[#keys + 1] = k
- end
- sort(keys, keysort)
- return function(t)
- i = i + 1
- local k = keys[i]
- if k ~= nil then
- return k, t[k]
- end
- end, self
- end,
-
- --- Return a compact string representation of this object.
- --
- -- First the container name, and then between { and } an ordered list
- -- of the array elements of the contained values with numeric keys,
- -- followed by asciibetically sorted remaining public key-value pairs.
- --
- -- This metamethod doesn't recurse explicitly, but relies upon
- -- suitable `__tostring` metamethods for non-primitive content objects.
- -- @function prototype:__tostring
- -- @treturn string stringified object representation
- -- @see tostring
- -- @usage
- -- assert(tostring(list) == 'Cons {car='head', cdr=Cons {car='tail'}}')
- __tostring = function(self)
- return concat {
- -- Pass a shallow copy to render to avoid triggering __tostring
- -- again and blowing the stack.
- getmetatable(self)._type, ' ', str(shallow_copy(self)),
- }
- end,
-}
-
-
-if argcheck then
- local __call = prototype.__call
-
- prototype.__call = function(self, ...)
- local mt = getmetatable(self)
-
- -- A function initialised object can be passed arguments of any
- -- type, so only argcheck non-function initialised objects.
- if type(mt._init) ~= 'function' then
- local name, n = mt._type, select('#', ...)
- -- Don't count `self` as an argument for error messages, because
- -- it just refers back to the object being called: `prototype {'x'}.
- argcheck(name, 1, 'table',(...))
- if n > 1 then
- argerror(name, 2, extramsg_toomany('argument', 1, n), 2)
- end
- end
-
- return __call(self, ...)
- end
-end
-
-
-local function X(decl, fn)
- return argscheck('prototype.container.' .. decl, fn)
-end
-
-
-return Module {
- prototype = setmetatable({}, prototype),
-
- --- Module Functions
- -- @section modulefunctions
-
- --- Return *new* with references to the fields of *src* merged in.
- --
- -- This is the function used to instantiate the contents of a newly
- -- cloned container, as called by @{__call} above, to split the
- -- fields of a @{__call} argument table into private '_' prefixed
- -- field namess, -- which are merged into the *new* metatable, and
- -- public(everything else) names, which are merged into *new* itself.
- --
- -- You might want to use this function from `_init` functions of your
- -- own derived containers.
- -- @function mapfields
- -- @tparam table new partially instantiated clone container
- -- @tparam table src @{__call} argument table that triggered cloning
- -- @tparam[opt={}] table map key renaming specification in the form
- -- `{old_key=new_key, ...}`
- -- @treturn table merged public fields from *new* and *src*, with a
- -- metatable of private fields(if any), both renamed according to
- -- *map*
- -- @usage
- -- local Bag = Container {
- -- _type = 'Bag',
- -- _init = function(new, ...)
- -- if type(...) == 'table' then
- -- return container.mapfields(new,(...))
- -- end
- -- return functional.reduce(operator.set, new, ipairs, {...})
- -- end,
- -- }
- -- local groceries = Bag('apple', 'banana', 'banana')
- -- local purse = Bag {_type = 'Purse'}('cards', 'cash', 'id')
- mapfields = X('mapfields(table, table|object, ?table)', mapfields),
-}
diff --git a/lib/std/prototype/init.lua b/lib/std/prototype/init.lua
deleted file mode 100644
index 87280ad..0000000
--- a/lib/std/prototype/init.lua
+++ /dev/null
@@ -1,48 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- Module table.
-
- Lazy loading of submodules, and metadata for the Prototype package.
-
- @module std.prototype
-]]
-
-
-local _ENV = require 'std.normalize' {}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-return setmetatable({
- --- Module table.
- -- @table prototype
- -- @field version Release version string
-}, {
- --- Metamethods
- -- @section Metamethods
-
- --- Lazy loading of prototype 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 prototype = require 'prototype'
- -- local Object = prototype.object.prototype
- __index = function(self, name)
- local ok, t = pcall(require, 'std.prototype.' .. name)
- if ok then
- rawset(self, name, t)
- return t
- end
- end,
-})
diff --git a/lib/std/prototype/object.lua b/lib/std/prototype/object.lua
deleted file mode 100644
index 523a105..0000000
--- a/lib/std/prototype/object.lua
+++ /dev/null
@@ -1,137 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- Object Prototype.
-
- This module provides a specialization of the @{prototype.container.prototype}
- with the addition of object methods. In addition to the functionality
- described here, object prototypes also have all the methods and
- metamethods of the @{prototype.container.prototype}.
-
- Note that object methods are stored in the `__index` field of their
- metatable, and so cannot also use the `__index` metamethod to lookup
- references with square brackets. Use a @{prototype.container.prototype} based
- object if you want to do that.
-
- Prototype Chain
- ---------------
-
- table
- `-> Container
- `-> Object
-
- @module std.prototype.object
-]]
-
-
-local _ENV = require 'std.normalize' {
- Container = require 'std.prototype.container'.prototype,
- Module = require 'std.prototype._base'.Module,
- argscheck = require 'std.prototype._base'.argscheck,
- mapfields = require 'std.prototype._base'.mapfields,
-}
-
-
-
---[[ ======= ]]--
---[[ Object. ]]--
---[[ ======= ]]--
-
-
-local function X(decl, fn)
- return argscheck('std.prototype.object.' .. decl, fn)
-end
-
-
---- Object prototype.
--- @object prototype
--- @string[opt='Object'] _type object name
--- @tfield[opt] table|function _init object initialisation
--- @usage
--- local Object = require 'std.prototype.object'.prototype
--- 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
--- }
-
-local Object = Container {
- _type = 'Object',
-
- --- Methods
- -- @section methods
-
- __index = {
- --- Return a clone of this object and its metatable.
- --
- -- This function is useful if you need to override the normal use of
- -- the `__call` metamethod for object cloning, without losing the
- -- ability to clone an object.
- -- @function prototype:clone
- -- @param ... arguments to prototype's *\_init*, often a single table
- -- @treturn prototype a clone of this object, with shared or merged
- -- metatable as appropriate
- -- @see prototype.container.__call
- -- @usage
- -- local Node = Object {_type='Node'}
- -- -- A trivial FSA to recognize powers of 10, either '0' or a '1'
- -- -- followed by zero or more '0's can transition to state 'finish'
- -- local states; states = {
- -- start = Node {['1']=states[1], ['0']=states.finish},
- -- [1] = Node {['0']=states[1], ['']=states.finish},
- -- finish = Node {},
- -- }
- clone = getmetamethod(Container, '__call'),
-
- --- Return *new* with references to the fields of *src* merged in.
- --
- -- You can change the value of this function in an object, and that
- -- new function will be called during cloning instead of the
- -- standard @{prototype.container.mapfields} implementation.
- -- @function prototype.mapfields
- -- @tparam table new partially instantiated clone container
- -- @tparam table src @{clone} argument table that triggered cloning
- -- @tparam[opt={}] table map key renaming specification in the form
- -- `{old_key=new_key, ...}`
- -- @treturn table merged public fields from *new* and *src*, with a
- -- metatable of private fields(if any), both renamed according to
- -- *map*
- -- @see prototype.container.mapfields
- mapfields = X('mapfields(table, table|object, ?table)', mapfields),
- },
-}
-
-
-return Module {
- prototype = Object,
-
- --- Module Functions
- -- @section modulefunctions
-
- --- Type of an object.
- --
- -- It's conventional to organise similar objects according to a string
- -- valued `_type` field, which can then be queried using this
- -- function.
- -- @function type
- -- @param x an object
- -- @treturn string type of *x*, or `nil` if *x* has no `_type`
- -- metatable entry.
- -- @usage
- -- local Object = require 'std.object'.prototype
- -- assert(object.type(Object) == 'Object')
- -- local Stack = Object {
- -- _type = 'Stack',
- -- ...
- -- }
- -- local stack = Stack {'some stuff'}
- -- assert(object.type(stack) == getmetatable(stack)._type)
- type = function(x)
- return(getmetatable(x) or {})._type
- end,
-}
diff --git a/lib/std/prototype/set.lua b/lib/std/prototype/set.lua
deleted file mode 100644
index a006ace..0000000
--- a/lib/std/prototype/set.lua
+++ /dev/null
@@ -1,377 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- Set Prototype.
-
- This module returns a table of set operators, as well as the prototype
- for a Set container object.
-
- Every possible object or primitive value is always present in any Set
- container exactly zero or one times.
-
- In addition to the functionality described here, Set containers also
- have all the methods and metamethods of the @{prototype.container.prototype}
-(except where overridden here).
-
- Prototype Chain
- ---------------
-
- table
- `-> Container
- `-> Set
-
- @module std.prototype.set
-]]
-
-
-local _ENV = require 'std.normalize' {
- Container = require 'std.prototype.container'.prototype,
- Module = require 'std.prototype._base'.Module,
- argscheck = require 'std.prototype._base'.argscheck,
- concat = table.concat,
- nonempty = next,
- sort = table.sort,
- sub = string.sub,
-}
-
-
-local Set -- forward declaration
-
-
-
---[[ ==================== ]]--
---[[ Primitive Functions. ]]--
---[[ ==================== ]]--
-
-
--- These functions know about internal implementatation.
--- The representation is a table whose tags are the elements, and
--- whose values are true.
-
-
-local function insert(set, e)
- return rawset(set, e, true)
-end
-
-
-local function member(set, e)
- return rawget(set, e) == true
-end
-
-
-
---[[ ===================== ]]--
---[[ High Level Functions. ]]--
---[[ ===================== ]]--
-
-
--- These functions are independent of the internal implementation.
-
-
-local difference, symmetric_difference, intersection, union, subset,
- proper_subset, equal
-
-
-function difference(set1, set2)
- local r = Set {}
- for e in next, set1 do
- if not member(set2, e) then
- insert(r, e)
- end
- end
- return r
-end
-
-
-function symmetric_difference(set1, set2)
- return difference(union(set1, set2), intersection(set2, set1))
-end
-
-
-function intersection(set1, set2)
- local r = Set {}
- for e in next, set1 do
- if member(set2, e) then
- insert(r, e)
- end
- end
- return r
-end
-
-
-function union(set1, set2)
- local r = set1 {}
- for e in next, set2 do
- insert(r, e)
- end
- return r
-end
-
-
-function subset(set1, set2)
- for e in next, set1 do
- if not member(set2, e) then
- return false
- end
- end
- return true
-end
-
-
-function proper_subset(set1, set2)
- return subset(set1, set2) and not subset(set2, set1)
-end
-
-
-function equal(set1, set2)
- return subset(set1, set2) and subset(set2, set1)
-end
-
-
-
---[[ =========== ]]--
---[[ Set Object. ]]--
---[[ =========== ]]--
-
-
-local function X(decl, fn)
- return argscheck('std.prototype.set.' .. decl, fn)
-end
-
-
---- Set prototype object.
--- @object prototype
--- @string[opt='Set'] _type object name
--- @see prototype.container.prototype
--- @usage
--- local Set = require 'std.prototype.set'.prototype
--- assert(prototype.type(Set) == 'Set')
-
-
-Set = Container {
- _type = 'Set',
-
- --- Set object initialisation.
- --
- -- Returns partially initialised Set container with contents
- -- from *t*.
- -- @init prototype._init
- -- @tparam table new uninitialised Set container object
- -- @tparam table t initialisation table from `__call`
- _init = function(new, t)
- local mt = {}
- for k, v in pairs(t) do
- local type_k = type(k)
- if type_k == 'number' then
- insert(new, v)
- elseif type_k == 'string' and sub(k, 1, 1) == '_' then
- mt[k] = v
- end
- -- non-underscore-prefixed string keys are discarded!
- end
- return nonempty(mt) and setmetatable(new, mt) or new
- end,
-
- --- Metamethods
- -- @section metamethods
-
- --- Union operation.
- -- @function prototype:__add
- -- @tparam prototype s another set
- -- @treturn prototype everything from *this* set plus everything from *s*
- -- @see union
- -- @usage
- -- union = this + s
- __add = union,
-
- --- Difference operation.
- -- @function prototype:__sub
- -- @tparam prototype s another set
- -- @treturn prototype everything from *this* set that is not also in *s*
- -- @see difference
- -- @usage
- -- difference = this - s
- __sub = difference,
-
- --- Intersection operation.
- -- @function prototype:__mul
- -- @tparam prototype s another set
- -- @treturn prototype anything in both *this* set and in *s*
- -- @see intersection
- -- @usage
- -- intersection = this * s
- __mul = intersection,
-
- --- Symmetric difference operation.
- -- @function prototype:__div
- -- @tparam prototype s another set
- -- @treturn prototype everything in *this* set or in *s* but not in both
- -- @see symmetric_difference
- -- @usage
- -- symmetric_difference = this / s
- __div = symmetric_difference,
-
- --- Subset operation.
- -- @static
- -- @function prototype:__le
- -- @tparam prototype s another set
- -- @treturn boolean `true` if everything in *this* set is also in *s*
- -- @see subset
- -- @usage
- -- issubset = this <= s
- __le = subset,
-
- --- Proper subset operation.
- -- @function prototype:__lt
- -- @tparam prototype s another set
- -- @treturn boolean `true` if *s* is not equal to *this* set, but does
- -- contain everything from *this* set
- -- @see proper_subset
- -- @usage
- -- ispropersubset = this < s
- __lt = proper_subset,
-
- --- Return a string representation of this set.
- -- @function prototype:__tostring
- -- @treturn string string representation of a set.
- -- @see tostring
- __tostring = function(self)
- local keys = {}
- for k in pairs(self) do
- keys[#keys + 1] = str(k)
- end
- sort(keys)
- return getmetatable(self)._type .. ' {' .. concat(keys, ', ') .. '}'
- end,
-}
-
-
-return Module {
- prototype = Set,
-
- --- Module Functions
- -- @section modulefunctions
-
- --- Delete an element from a set.
- -- @function delete
- -- @tparam prototype set a set
- -- @param e element
- -- @treturn prototype the modified *set*
- -- @usage
- -- set.delete(available, found)
- delete = X('delete(Set, any)', function(set, e)
- return rawset(set, e, nil)
- end),
-
- --- Find the difference of two sets.
- -- @function difference
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn prototype a copy of *set1* with elements of *set2* removed
- -- @usage
- -- all = set.difference(all, Set {32, 49, 56})
- difference = X('difference(Set, Set)', difference),
-
- --- Iterator for sets.
- -- @function elems
- -- @tparam prototype set a set
- -- @return *set* iterator
- -- @todo Make the iterator return only the key
- -- @usage
- -- for code in set.elems(isprintable) do
- -- print(code)
- -- end
- elems = X('elems(Set)', pairs),
-
- --- Find whether two sets are equal.
- -- @function equal
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn boolean `true` if *set1* and *set2* each contain identical
- -- elements, `false` otherwise
- -- @usage
- -- if set.equal(keys, Set {META, CTRL, 'x'}) then
- -- process(keys)
- -- end
- equal = X( 'equal(Set, Set)', equal),
-
- --- Insert an element into a set.
- -- @function insert
- -- @tparam prototype set a set
- -- @param e element
- -- @treturn prototype the modified *set*
- -- @usage
- -- for byte = 32,126 do
- -- set.insert(isprintable, string.char(byte))
- -- end
- insert = X('insert(Set, any)', insert),
-
- --- Find the intersection of two sets.
- -- @function intersection
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn prototype a new set with elements in both *set1* and *set2*
- -- @usage
- -- common = set.intersection(a, b)
- intersection = X('intersection(Set, Set)', intersection),
-
- --- Say whether an element is in a set.
- -- @function difference
- -- @tparam prototype set a set
- -- @param e element
- -- @return `true` if *e* is in *set*, otherwise `false`
- -- otherwise
- -- @usage
- -- if not set.member(keyset, pressed) then
- -- return nil
- -- end
- member = X('member(Set, any)', member),
-
- --- Find whether one set is a proper subset of another.
- -- @function proper_subset
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn boolean `true` if *set2* contains all elements in *set1*
- -- but not only those elements, `false` otherwise
- -- @usage
- -- if set.proper_subset(a, b) then
- -- for e in set.elems(set.difference(b, a)) do
- -- set.delete(b, e)
- -- end
- -- end
- -- assert(set.equal(a, b))
- proper_subset = X('proper_subset(Set, Set)', proper_subset),
-
- --- Find whether one set is a subset of another.
- -- @function subset
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn boolean `true` if all elements in *set1* are also in *set2*,
- -- `false` otherwise
- -- @usage
- -- if set.subset(a, b) then
- -- a = b
- -- end
- subset = X('subset(Set, Set)', subset),
-
- --- Find the symmetric difference of two sets.
- -- @function symmetric_difference
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn prototype a new set with elements that are in *set1* or *set2*
- -- but not both
- -- @usage
- -- unique = set.symmetric_difference(a, b)
- symmetric_difference = X('symmetric_difference(Set, Set)', symmetric_difference),
-
- --- Find the union of two sets.
- -- @function union
- -- @tparam prototype set1 a set
- -- @tparam prototype set2 another set
- -- @treturn prototype a copy of *set1* with elements in *set2* merged in
- -- @usage
- -- all = set.union(a, b)
- union = X('union(Set, Set)', union),
-}
diff --git a/lib/std/prototype/strbuf.lua b/lib/std/prototype/strbuf.lua
deleted file mode 100644
index 05f16cf..0000000
--- a/lib/std/prototype/strbuf.lua
+++ /dev/null
@@ -1,126 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- StrBuf Prototype.
-
- Buffers are mutable by default, but being based on objects, they can
- also be used in a functional style:
-
- local StrBuf = require 'std.prototype.strbuf'.prototype
- 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
-
- In addition to the functionality described here, StrBuf objects also
- have all the methods and metamethods of the @{prototype.object.prototype}
- (except where overridden here),
-
- Prototype Chain
- ---------------
-
- table
- `-> Container
- `-> Object
- `-> StrBuf
-
- @module std.prototype.strbuf
-]]
-
-
-local _ENV = require 'std.normalize' {
- Module = require 'std.prototype._base'.Module,
- Object = require 'std.prototype.object'.prototype,
- argscheck = require 'std.prototype._base'.argscheck,
- concat = table.concat,
-}
-
-
-
---[[ ================= ]]--
---[[ Helper Functions. ]]--
---[[ ================= ]]--
-
-
-local function __concat(self, x)
- self[#self + 1] = x
- return self
-end
-
-
-
---[[ ============== ]]--
---[[ StrBuf Object. ]]--
---[[ ============== ]]--
-
-
---- StrBuf prototype object.
--- @object prototype
--- @string[opt='StrBuf'] _type object name
--- @see prototype.object.prototype
--- @usage
--- local StrBuf = require 'std.prototype.strbuf'.prototype
--- local a = StrBuf {1, 2, 3}
--- local b = StrBuf {a, 'five', 'six'}
--- a = a .. 4
--- b = b:concat 'seven'
--- print(a, b) --> 1234 1234fivesixseven
--- os.exit(0)
-
-
-local function X(decl, fn)
- return argscheck('std.prototype.strbuf.' .. decl, fn)
-end
-
-
-return Module {
- prototype = Object {
- _type = 'StrBuf',
-
- __index = {
- --- Methods
- -- @section methods
-
- --- Add a object to a buffer.
- -- Elements are stringified lazily, so if you add a table and then
- -- change its contents, the contents of the buffer will be affected
- -- too.
- -- @function prototype:concat
- -- @param x object to add to buffer
- -- @treturn prototype modified buffer
- -- @usage
- -- c = StrBuf {} :concat 'append this' :concat(StrBuf {' and', ' this'})
- concat = X('concat(StrBuf, any)', __concat),
- },
-
-
- --- Metamethods
- -- @section metamethods
-
- --- Support concatenation to StrBuf objects.
- -- @function prototype:__concat
- -- @param x a string, or object that can be coerced to a string
- -- @treturn prototype modified *buf*
- -- @see concat
- -- @usage
- -- buf = buf .. x
- __concat = __concat,
-
- --- Support fast conversion to Lua string.
- -- @function prototype:__tostring
- -- @treturn string concatenation of buffer contents
- -- @see tostring
- -- @usage
- -- str = tostring(buf)
- __tostring = function(self)
- local strs = {}
- for _, e in ipairs(self) do
- strs[#strs + 1] = tostring(e)
- end
- return concat(strs)
- end,
- },
-}
diff --git a/lib/std/prototype/trie.lua b/lib/std/prototype/trie.lua
deleted file mode 100644
index 53989ef..0000000
--- a/lib/std/prototype/trie.lua
+++ /dev/null
@@ -1,324 +0,0 @@
---[[
- Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
- Copyright (C) 2000-2022 std.prototype authors
-]]
---[[--
- Trie Prototype.
-
- This module returns a table of trie operators, as well as the prototype
- for a Trie container object.
-
- This is not a search tree, but rather a radix tree to efficiently store
- and retrieve values stored with a path as a key, such as a multi-key
- keytable. Although it does have iterators for walking the trie with
- various algorithms.
-
- In addition to the functionality described here, Trie containers also
- have all the methods and metamethods of the @{prototype.container.prototype}
- (except where overridden here),
-
- Prototype Chain
- ---------------
-
- table
- `-> Container
- `-> Trie
-
- @module std.prototype.trie
-]]
-
-
-local _ENV = require 'std.normalize' {
- Container = require 'std.prototype.container'.prototype,
- Module = require 'std.prototype._base'.Module,
- argscheck = require 'std.prototype._base'.argscheck,
- remove = table.remove,
- wrap = coroutine.wrap,
- yield = coroutine.yield,
-}
-
-
-
---[[ =============== ]]--
---[[ Implementation. ]]--
---[[ =============== ]]--
-
-
-local function _nodes(it, tr)
- local p = {}
- local function visit(n)
- if type(n) == 'table' then
- yield('branch', p, n)
- for i, v in it(n) do
- p[#p + 1] = i
- visit(v)
- remove(p)
- end
- yield('join', p, n)
- else
- yield('leaf', p, n)
- end
- end
- return wrap(visit), tr
-end
-
-
-local function clone(t, nometa)
- local r = {}
- if not nometa then
- setmetatable(r, getmetatable(t))
- end
- local d = {[t]=r}
- local function deep_copy(o, x)
- for i, v in pairs(x) do
- if type(v) == 'table' then
- if not d[v] then
- d[v] = {}
- if not nometa then
- setmetatable(d[v], getmetatable(v))
- end
- o[i] = deep_copy(d[v], v)
- else
- o[i] = d[v]
- end
- else
- o[i] = v
- end
- end
- return o
- end
- return deep_copy(r, t)
-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 merge(t, u)
- for ty, p, n in _nodes(pairs, u) do
- if ty == 'leaf' then
- t[p] = n
- end
- end
- return t
-end
-
-
-
---[[ ============ ]]--
---[[ Trie Object. ]]--
---[[ ============ ]]--
-
-
-local function X(decl, fn)
- return argscheck('std.prototype.trie.' .. decl, fn)
-end
-
-
---- Return the object type, if set, otherwise the Lua type.
--- @param x item to act on
--- @treturn string object type of *x*, otherwise `type(x)`
-local function _type(x)
- return(getmetatable(x) or {})._type or type(x)
-end
-
-
---- Trie prototype object.
--- @object prototype
--- @string[opt='Trie'] _type object name
--- @see prototype.container.prototype
--- @usage
--- local trie = require 'std.prototype.trie'
--- local Trie = trie.prototype
--- local tr = Trie {}
--- tr[{'branch1', 1}] = 'leaf1'
--- tr[{'branch1', 2}] = 'leaf2'
--- tr[{'branch2', 1}] = 'leaf3'
--- print(tr[{'branch1'}]) --> Trie {leaf1, leaf2}
--- print(tr[{'branch1', 2}]) --> leaf2
--- print(tr[{'branch1', 3}]) --> nil
--- --> leaf1 leaf2 leaf3
--- for leaf in trie.leaves(tr) do
--- io.write(leaf .. '\t')
--- end
-
-local Trie
-
-Trie = Container {
- _type = 'Trie',
-
- --- Metamethods
- -- @section metamethods
-
- --- Deep retrieval.
- -- @function prototype:__index
- -- @param i non-table, or list of keys `{i1, ...i_n}`
- -- @return `tr[i1]...[i_n]` if *i* is a key list, `tr[i]` otherwise
- -- @todo the following doesn't treat list keys correctly
- -- e.g. tr[{{1, 2}, {3, 4}}], maybe flatten first?
- -- @usage
- -- del_other_window = keymap[{'C-x', '4', KEY_DELETE}]
- __index = function(tr, i)
- if _type(i) == 'table' then
- local r = tr
- for j = 1, len(i) do
- if r == nil then
- return nil
- end
- r = r[i[j]]
- end
- return r
- else
- return rawget(tr, i)
- end
- end,
-
- --- Deep insertion.
- -- @function prototype:__newindex
- -- @param i non-table, or list of keys `{i1, ...i_n}`
- -- @param[opt] v value
- -- @usage
- -- function bindkey(keylist, fn)
- -- keymap[keylist] = fn
- -- end
- __newindex = function(tr, i, v)
- if _type(i) == 'table' then
- for n = 1, len(i) - 1 do
- if _type(tr[i[n]]) ~= 'Trie' then
- rawset(tr, i[n], Trie {})
- end
- tr = tr[i[n]]
- end
- rawset(tr, i[len(i)], v)
- else
- rawset(tr, i, v)
- end
- end,
-}
-
-
-return Module {
- prototype = Trie,
-
- --- Module Functions
- -- @section modulefunctions
-
- --- Make a deep copy of a trie or table, including any metatables.
- -- @function clone
- -- @tparam table tr trie or trie-like table
- -- @tparam boolean nometa if non-`nil` don't copy metatables
- -- @treturn prototype|table a deep copy of *tr*
- -- @see prototype.object.clone
- -- @usage
- -- tr = {'one', {two=2}, {{'three'}, four=4}}
- -- copy = clone(tr)
- -- copy[2].two=5
- -- assert(tr[2].two == 2)
- clone = X('clone(table, ?boolean|:nometa)', clone),
-
- --- Trie iterator which returns just numbered leaves, in order.
- -- @function ileaves
- -- @tparam prototype|table tr trie or trie-like table
- -- @treturn function iterator function
- -- @treturn prototype|table the trie *tr*
- -- @see inodes
- -- @see leaves
- -- @usage
- -- --> t = {'one', 'three', 'five'}
- -- for leaf in ileaves {'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'}
- -- do
- -- t[#t + 1] = leaf
- -- end
- ileaves = X('ileaves(table)', function(t)
- return leaves(ipairs, t)
- end),
-
- --- Trie iterator over numbered nodes, in order.
- --
- -- The iterator function behaves like @{nodes}, but only traverses the
- -- array part of the nodes of *tr*, ignoring any others.
- -- @function inodes
- -- @tparam prototype|table tr trie or trie-like table to iterate over
- -- @treturn function iterator function
- -- @treturn trie|table the trie, *tr*
- -- @see nodes
- inodes = X('inodes(table)', function(t)
- return _nodes(ipairs, t)
- end),
-
- --- Trie iterator which returns just leaves.
- -- @function leaves
- -- @tparam table t trie or trie-like table
- -- @treturn function iterator function
- -- @treturn table *t*
- -- @see ileaves
- -- @see nodes
- -- @usage
- -- for leaf in leaves {'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'}
- -- do
- -- t[#t + 1] = leaf
- -- end
- -- --> t = {2, 4, 'five', 'foo', 'one', 'three'}
- -- table.sort(t, lambda '=tostring(_1) < tostring(_2)')
- leaves = X('leaves(table)', function(t)
- return leaves(pairs, t)
- end),
-
- --- Destructively deep-merge one trie into another.
- -- @function merge
- -- @tparam table t destination trie
- -- @tparam table u table with nodes to merge
- -- @treturn table *t* with nodes from *u* merged in
- -- @usage
- -- merge(dest, {{exists=1}, {{not = {present = {inside='dest'}}}}})
- merge = X('merge(table, table)', merge),
-
- --- Trie iterator over all nodes.
- --
- -- The returned iterator function performs a depth-first traversal of
- -- `tr`, and at each node it returns `{node-type, trie-path, trie-node}`
- -- where `node-type` is `branch`, `join` or `leaf`; `trie-path` is a
- -- list of keys used to reach this node, and `trie-node` is the current
- -- node.
- --
- -- Note that the `trie-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 `trie-path` list before the next iteration
- -- changes it.
- -- @function nodes
- -- @tparam prototype|table tr trie or trie-like table to iterate over
- -- @treturn function iterator function
- -- @treturn prototype|table the trie, *tr*
- -- @see inodes
- -- @usage
- -- -- trie = +-- node1
- -- -- | +-- leaf1
- -- -- | '-- leaf2
- -- -- '-- leaf 3
- -- trie = Trie {Trie {'leaf1', 'leaf2'}, 'leaf3'}
- -- for node_type, path, node in nodes(trie) do
- -- print(node_type, path, node)
- -- end
- -- --> 'branch' {} {{'leaf1', 'leaf2'}, 'leaf3'}
- -- --> 'branch' {1} {'leaf1', 'leaf2')
- -- --> 'leaf' {1,1} 'leaf1'
- -- --> 'leaf' {1,2} 'leaf2'
- -- --> 'join' {1} {'leaf1', 'leaf2'}
- -- --> 'leaf' {2} 'leaf3'
- -- --> 'join' {} {{'leaf1', 'leaf2'}, 'leaf3'}
- -- os.exit(0)
- nodes = X('nodes(table)', function(t)
- return _nodes(pairs, t)
- end),
-}
diff --git a/modules/std.prototype.container.html b/modules/std.prototype.container.html
new file mode 100644
index 0000000..0db69ae
--- /dev/null
+++ b/modules/std.prototype.container.html
@@ -0,0 +1,368 @@
+
+
+
+
+ std.prototype 1.0.1 Reference
+
+
+
+
+
This module supplies 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.
+
+
The functionality of a container based object is entirely defined by its
+ metamethods. However, since we can store any object in a container,
+ we cannot rely on the __index metamethod, because it is only a
+ fallback for when that key is not already in the container itself. Of
+ course that does not entirely preclude the use of __index with
+ containers, so long as this limitation is observed.
+
+
When making your own prototypes, derive from prototype.container.prototype
+ if you want to access the contents of your containers with the []
+ operator, otherwise from prototype.object.prototype if you want to access
+ the functionality of your objects with named object methods.
Return new with references to the fields of src merged in.
+
+
+
+
+
+
+
+
Objects
+
+
+
+
+ prototype
+
+
+ Container prototype.
+
+
+
Fields:
+
+
_init
+ table or function
+ object initialisation
+ (optional)
+
+
_type
+ string
+ object name
+ (default "Container")
+
+
+
+
+
+
+
Usage:
+
+
+ local Container = require"prototype.container".prototype
+ local Graph = Container { _type = "Graph" }
+ localfunction nodes (graph)
+ local n = 0
+ for _ inpairs (graph) do n = n + 1end
+ return n
+ end
+ local g = Graph { "node1", "node2" }
+ assert (nodes (g) == 2)
+
+
+
+
+
Metamethods
+
+
+
+
+ prototype:__call (...)
+
+
+ Return a clone of this container and its metatable.
+
+
Like any Lua table, a container is essentially a collection of
+ field_n = value_n pairs, except that field names beginning with
+ an underscore _ are usually kept in that container's metatable
+ where they define the behaviour of a container object rather than
+ being part of its actual contents. In general, cloned objects
+ also clone the behaviour of the object they cloned, unless...
+
+
When calling prototype.container.prototype, you pass a single table
+ argument with additional fields (and values) to be merged into the
+ clone. Any field names beginning with an underscore _ are copied
+ to the clone's metatable, and all other fields to the cloned
+ container itself. For instance, you can change the name of the
+ cloned object by setting the _type field in the argument table.
+
+
The _init private field is also special: When set to a sequence of
+ field names, unnamed fields in the call argument table are assigned
+ to those field names in subsequent clones, like the example below.
+
+
Alternatively, you can set the _init private field of a cloned
+ container object to a function instead of a sequence, in which case
+ all the arguments passed when it is called/cloned (including named
+ and unnamed fields in the initial table argument, if there is one)
+ are passed through to the _init function, following the nascent
+ cloned object. See the mapfields usage example below.
+
+
+
Parameters:
+
+
...
+ arguments to prototype's _init, often a single table
+
+
+
+
Returns:
+
+
+ prototype
+ clone of this container, with shared or
+ merged metatable as appropriate
+
+
+
+
+
Usage:
+
+
+ local Cons = Container {_type="Cons", _init={"car", "cdr"}}
+ local list = Cons {"head", Cons {"tail", nil}}
+
+
+
+
+
+ prototype:__pairs ()
+
+
+ Return an in-order iterator over public object fields.
+
+
+
+
Returns:
+
+
+ function
+ iterator function
+
+ Object
+ self
+
+
+
+
+
Usage:
+
+
for k, v inpairs (anobject) do process (k, v) end
+
+
+
+
+
+ prototype:__tostring ()
+
+
+ Return a compact string representation of this object.
+
+
First the container name, and then between { and } an ordered list
+ of the array elements of the contained values with numeric keys,
+ followed by asciibetically sorted remaining public key-value pairs.
+
+
This metamethod doesn't recurse explicitly, but relies upon
+ suitable __tostring metamethods for non-primitive content objects.
+
+
+
+
+ Return new with references to the fields of src merged in.
+
+
This is the function used to instantiate the contents of a newly
+ cloned container, as called by __call above, to split the
+ fields of a __call argument table into private "_" prefixed
+ field namess, -- which are merged into the new metatable, and
+ public (everything else) names, which are merged into new itself.
+
+
You might want to use this function from _init functions of your
+ own derived containers.
+
+
+
Parameters:
+
+
new
+ table
+ partially instantiated clone container
+
+ Lazy loading of prototype modules.
+ Don't load everything on initial startup, wait until first attempt
+ to access a submodule, and then load it on demand.
+
+
+
This module provides a specialization of the prototype.container.prototype
+ with the addition of object methods. In addition to the functionality
+ described here, object prototypes also have all the methods and
+ metamethods of the prototype.container.prototype.
+
+
Note that object methods are stored in the __index field of their
+ metatable, and so cannot also use the __index metamethod to lookup
+ references with square brackets. Use a prototype.container.prototype based
+ object if you want to do that.
+ Return a clone of this object and its metatable.
+
+
This function is useful if you need to override the normal use of
+ the __call metamethod for object cloning, without losing the
+ ability to clone an object.
+
+
+
Parameters:
+
+
...
+ arguments to prototype's _init, often a single table
+
+
+
+
Returns:
+
+
+ prototype
+ a clone of this object, with shared or merged
+ metatable as appropriate
+
+
+
+
+ local Node = Object { _type = "Node" }
+ -- A trivial FSA to recognize powers of 10, either "0" or a "1"
+-- followed by zero or more "0"s can transition to state 'finish'
+local states; states = {
+ start = Node { ["1"] = states[1], ["0"] = states.finish },
+ [1] = Node { ["0"] = states[1], [""] = states.finish },
+ finish = Node {},
+ }
+
+
+
+
+
+ prototype.mapfields (new, src[, map={}])
+
+
+ Return new with references to the fields of src merged in.
+
+
You can change the value of this function in an object, and that
+ new function will be called during cloning instead of the
+ standard prototype.container.mapfields implementation.
+
+
+
Parameters:
+
+
new
+ table
+ partially instantiated clone container
+
This module returns a table of set operators, as well as the prototype
+ for a Set container object.
+
+
Every possible object or primitive value is always present in any Set
+ container exactly zero or one times.
+
+
In addition to the functionality described here, Set containers also
+ have all the methods and metamethods of the prototype.container.prototype
+ (except where overridden here).
Buffers are mutable by default, but being based on objects, they can
+ also be used in a functional style:
+
+
+
+local StrBuf = require"std.prototype.strbuf".prototype
+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
+
+
+
+
In addition to the functionality described here, StrBuf objects also
+ have all the methods and metamethods of the prototype.object.prototype
+ (except where overridden here),
+ local StrBuf = require"std.prototype.strbuf".prototype
+ local a = StrBuf {1, 2, 3}
+ local b = StrBuf {a, "five", "six"}
+ a = a .. 4
+ b = b:concat "seven"
+ print (a, b) --> 1234 1234fivesixseven
+os.exit (0)
+
+
+
+
+
Metamethods
+
+
+
+
+ prototype:__concat (x)
+
+
+ Support concatenation to StrBuf objects.
+
+
+
Parameters:
+
+
x
+ a string, or object that can be coerced to a string
+
+ Add a object to a buffer.
+ Elements are stringified lazily, so if you add a table and then
+ change its contents, the contents of the buffer will be affected
+ too.
+
+
+
This module returns a table of trie operators, as well as the prototype
+ for a Trie container object.
+
+
This is not a search tree, but rather a radix tree to efficiently store
+ and retrieve values stored with a path as a key, such as a multi-key
+ keytable. Although it does have iterators for walking the trie with
+ various algorithms.
+
+
In addition to the functionality described here, Trie containers also
+ have all the methods and metamethods of the prototype.container.prototype
+ (except where overridden here),
The returned iterator function performs a depth-first traversal of
+ tr, and at each node it returns {node-type, trie-path, trie-node}
+ where node-type is branch, join or leaf; trie-path is a
+ list of keys used to reach this node, and trie-node is the current
+ node.
+
+
Note that the trie-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 trie-path list before the next iteration
+ changes it.
+
+
+
Parameters:
+
+
tr
+ prototype or table
+ trie or trie-like table to iterate over
+
+generated by LDoc 1.4.3
+Last updated 2016-02-08 00:31:49
+
+
+
+
diff --git a/spec/container_spec.yaml b/spec/container_spec.yaml
deleted file mode 100644
index fd35da6..0000000
--- a/spec/container_spec.yaml
+++ /dev/null
@@ -1,156 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype.container'
-
- Container = require(this_module).prototype
-
-specify std.prototype.container:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
- - context via the prototype module:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by='std.prototype'}).to_equal {}
-
-- describe construction:
- - context with table _init:
- - it diagnoses missing arguments: |
- if have_typecheck then
- expect(Container()).
- to_raise "bad argument #1 to 'Container'(table expected, got no value)"
- end
- - it diagnoses too many arguments: |
- if have_typecheck then
- expect(Container({}, false)).
- to_raise "bad argument #2 to 'Container'(no more than 1 argument expected, got 2)"
- end
- - context with function _init:
- - before:
- Thing = Container {_type='Thing', _init=function(obj) return obj end}
- - it doesn't diagnose missing arguments:
- expect(Thing()).not_to_raise 'any error'
- - it doesn't diagnose too many args:
- expect(Thing({}, false)).not_to_raise 'any error'
-
- - context from Container prototype:
- - before:
- things = Container {'foo', 'bar', baz='quux'}
- - it constructs a new container:
- expect(things).not_to_be(Container)
- expect(type(things)).to_be 'table'
- expect(objtype(things)).to_be 'Container'
- - it reuses the container metatable:
- o, p = things {'o'}, things {'p'}
- expect(getmetatable(o)).to_be(getmetatable(p))
- - it sets container fields from arguments:
- o = Container {'foo', 'bar', baz='quux'}
- expect(o).to_equal(things)
- - it serves as a prototype for new instances:
- o = things {}
- expect(objtype(o)).to_be 'Container'
- expect(o).to_copy(things)
- expect(getmetatable(o)).to_be(getmetatable(things))
- - it separates '_' prefixed fields:
- expect(Container {foo='bar', _baz='quux'}).
- to_equal(Container {foo='bar'})
- - it puts '_' prefixed fields in a new metatable:
- things = Container {foo='bar', _baz='quux'}
- expect(getmetatable(things)).not_to_be(getmetatable(Container))
- expect(getmetatable(things)._baz).to_be 'quux'
- - it propagates '_type' field:
- things = Container {1}
- u, v = things {'u'}, things {'v'}
- expect(objtype(u)).to_be 'Container'
- expect(objtype(v)).to_be(objtype(Container))
- - context with module functions:
- - before:
- Bag = require 'std.prototype._base'.Module {
- prototype = Container {_type='Bag'},
- count = function(bag)
- local n = 0
- for _, m in pairs(bag) do n = n + m end
- return n
- end,
- }
- - it does not propagate module functions:
- things = Bag {}
- expect(things.count).to_be(nil)
- - it does not provide object methods: |
- things = Bag {}
- expect(things:count()).to_raise.any_of {
- "attempt to call method 'count'",
- "attempt to call a nil value (method 'count'",
- "method 'count' is not callable (a nil value)"
- }
- - it does retain module functions:
- things = Bag {apples=1, oranges=3}
- expect(Bag.count(things)).to_be(4)
- - it does allow elements named after module functions:
- things = Bag {count=1337}
- expect(Bag.count(things)).to_be(1337)
- - it propagates '_type' field:
- things = Bag {bananas=0}
- u, v = things {bananas=1}, things {coconuts=0}
- expect(objtype(u)).to_be 'Bag'
- expect(objtype(v)).to_be(objtype(Bag.prototype))
-
-
-- describe field access:
- - before:
- things = Container {'foo', 'bar', baz='quux'}
- - context with bracket notation:
- - it provides access to existing contents:
- expect(things[1]).to_be 'foo'
- expect(things['baz']).to_be 'quux'
- - it assigns new contents:
- things['new'] = 'value'
- expect(things['new']).to_be 'value'
- - context with dot notation:
- - it provides access to existing contents:
- expect(things.baz).to_be 'quux'
- - it assigns new contents:
- things.new = 'value'
- expect(things.new).to_be 'value'
-
-
-- describe __pairs:
- - before:
- things = Container {'one', 'two', three=3, four=4, 'five', 6}
- iter = getmetatable(things).__pairs
- - it returns a function:
- expect(type(iter)).to_be 'function'
- - it iterates all contents:
- r = {}
- for k, v in iter(things) do r[k] = v end
- expect(r).to_contain.a_permutation_of(copy(things))
- - it returns keys in order:
- keys = {}
- for k in iter(things) do keys[#keys + 1] = k end
- expect(keys).to_equal {1, 2, 3, 4, 'four', 'three'}
-
-
-- describe __tostring:
- - before:
- things = Container {_type='Derived', 'one', 'two', 'three'}
- - it returns a string:
- expect(type(tostring(things))).to_be 'string'
- - it contains the type:
- expect(tostring(Container {})).to_contain 'Container'
- expect(tostring(things)).to_contain(objtype(things))
- - it contains the ordered array part elements:
- expect(tostring(things)).to_contain 'one, two, three'
- - it contains the ordered dictionary part elements:
- expect(tostring(Container {one=true, two=true, three=true})).
- to_contain 'one=true, three=true, two=true'
- expect(tostring(things {one=true, two=true, three=true})).
- to_contain 'one=true, three=true, two=true'
- - it contains a ';' separator only when container has array and dictionary parts:
- expect(tostring(things)).not_to_contain ';'
- expect(tostring(Container {one=true, two=true, three=true})).
- not_to_contain ';'
- expect(tostring(things {one=true, two=true, three=true})).
- to_contain ';'
diff --git a/spec/init_spec.yaml b/spec/init_spec.yaml
deleted file mode 100644
index 5e3117b..0000000
--- a/spec/init_spec.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype'
-
- M = require(this_module)
- M.version = nil -- previous specs may have autoloaded it
-
-
-specify std.prototype:
-- context when required:
- - it does not touch the global table:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
-
-- 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.object
- expect(lazy).to_be(require 'std.prototype.object')
- - it loads submodule functions on demand:
- expect(M.object.type(M.object.prototype)).to_be 'Object'
-
-
-- describe version:
- - before:
- x = M.version
-
- - it returns a string:
- expect(type(M.version)).to_be 'string'
- - it contains package description:
- expect(string.match(M.version, 'Prototype Object Libraries')).
- not_to_be(nil)
diff --git a/spec/object_spec.yaml b/spec/object_spec.yaml
deleted file mode 100644
index 2d3c39a..0000000
--- a/spec/object_spec.yaml
+++ /dev/null
@@ -1,299 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype.object'
-
- object = require(this_module)
- Object = object.prototype
- obj = Object {'foo', 'bar', baz='quux'}
-
- function copy(t)
- local r = {}
- for k, v in pairs(t) do r[k] = v end
- return r
- end
-
-specify std.prototype.object:
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
- - context via the prototype module:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by='std.prototype'}).to_equal {}
-
-- describe construction:
- - context from Object clone method:
- - it constructs a new object:
- o = Object:clone {}
- expect(o).not_to_be(Object)
- expect(type(o)).to_be 'table'
- expect(objtype(o)).to_be 'Object'
- - it reuses the Object metatable:
- o = obj:clone {'o'}
- p = o:clone {'p'}
- expect(p).not_to_be(o)
- expect(getmetatable(o)).to_be(getmetatable(p))
- - it sets object fields from arguments:
- expect(obj:clone {}).to_copy(obj)
- - it serves as a prototype for new instances:
- o = obj:clone {}
- expect(objtype(o)).to_be 'Object'
- expect(o).to_copy(obj)
- expect(getmetatable(o)).to_be(getmetatable(obj))
- - it separates '_' prefixed fields:
- expect(Object:clone {foo='bar', _baz='quux'}).
- to_equal(Object:clone {foo='bar'})
- - it puts '_' prefixed fields in a new metatable:
- o = Object:clone {foo='bar', _baz='quux'}
- expect(getmetatable(o)).not_to_be(getmetatable(Object))
- expect(getmetatable(o)._baz).to_be 'quux'
-
-
-- describe type:
- - before:
- o = Object {}
- fn = object.type
-
- - context when called from the object module:
- - it reports the type stored in the object's metatable:
- expect(fn(o)).to_be 'Object'
- - it reports the type of a cloned object:
- expect(fn(o {})).to_be 'Object'
- - it reports the type of a derived object:
- Example = Object {_type='Example'}
- expect(fn(Example)).to_be 'Example'
- - it reports the type of a cloned derived object:
- Portal = Object {_type='Demon'}
- p = Portal {}
- expect(fn(p)).to_be 'Demon'
- expect(fn(p {})).to_be 'Demon'
- - it returns nil for a primitive object:
- expect(fn(nil)).to_be(nil)
- expect(fn(0.0)).to_be(nil)
- expect(fn('0.0')).to_be(nil)
- expect(fn(function() end)).to_be(nil)
- expect(fn {}).to_be(nil)
-
-
-- describe instantiation from a prototype:
- - context when _init is nil:
- - before:
- Array = Object {
- _type = 'Array',
- 'foo', 'bar', 'baz',
- }
- Array._init = nil
-
- - it contains user-defined fields:
- expect(copy(Array)).
- to_equal {'foo', 'bar', 'baz'}
- - it sets array part of instance object from positional parameters:
- array = Array {'first', 'second', 'third'}
- expect(copy(array)).
- to_equal {'first', 'second', 'third'}
- - it uses prototype values for missing positional parameters:
- array = Array {'first', 'second'}
- expect(copy(array)).
- to_equal {'first', 'second', 'baz'}
- - it merges surplus positional parameters:
- array = Array {'first', 'second', 'third', 'fourth'}
- expect(copy(array)).
- to_equal {'first', 'second', 'third', 'fourth'}
-
- - context when _init is an empty table:
- - before:
- Prototype = Object {
- _type = 'Prototype';
- _init = {},
- 'first', 'second', 'third',
- }
- - it contains user-defined fields:
- expect(copy(Prototype)).
- to_equal {'first', 'second', 'third'}
- - it ignores positional parameters: |
- instance = Prototype {'foo', 'bar'}
- expect(instance).to_copy(Prototype)
-
- - context when _init is a table of field names:
- - before:
- Process = Object {
- _type = 'Process',
- _init = {'status', 'output', 'errout'},
- status = -1,
- output = 'empty',
- errout = 'no errors',
- }
- - it contains user-defined fields:
- expect(copy(Process)).
- to_equal {status=-1, output='empty', errout='no errors'}
- - it sets user-defined fields from positional parameters:
- proc = Process {0, 'output', 'diagnostics'}
- expect(copy(proc)).
- to_equal {status=0, output='output', errout='diagnostics'}
- - it uses prototype values for missing positional parameters:
- proc = Process {0, 'output'}
- expect(copy(proc)).
- to_equal {status=0, output='output', errout='no errors'}
- - it discards surplus positional parameters:
- proc = Process {0, 'output', 'diagnostics', 'garbage'}
- expect(copy(proc)).
- to_equal {status=0, output='output', errout='diagnostics'}
-
- - context when _init is a function:
- - before:
- Prototype = Object {
- _type = 'Prototype',
- f1 = 'proto1', f2 = 'proto2',
- _init = function(self, ...)
- self.args = unpack {...}
- self.count = select('#', ...)
- return self
- end,
- }
- - it passes user defined fields to custom _init function:
- instance = Prototype {'param1', 'param2'}
- expect({instance.f1, instance.f2, instance.args}).
- to_equal {'proto1', 'proto2', {'param1', 'param2'}}
- - it propagates arguments correctly:
- expect(Prototype().count).to_be(0)
- expect(Prototype('one').count).to_be(1)
- expect(Prototype('one', 'two').count).to_be(2)
- - it propagates nil arguments correctly:
- expect(Prototype(nil).count).to_be(1)
- expect(Prototype(false, nil).count).to_be(2)
- expect(Prototype(nil, false).count).to_be(2)
- expect(Prototype(nil, nil).count).to_be(2)
-
-
-- describe field access:
- - before:
- Prototype = Object {
- _type = 'Prototype',
- _init = { 'field', 'method'},
- field = 'in prototype',
- method = function(self, ...)
- return objtype(self) .. ' class, ' ..
- table.concat({...}, ', ')
- end,
- }
- instance = Prototype {'in object', function(self, ...)
- return objtype(self) .. ' instance, ' .. table.concat({...}, ', ')
- end}
-
- - it provides object field access with dot notation:
- expect(instance.field).to_be 'in object'
- - it provides class field acces with dot notation:
- expect(Prototype.field).to_be 'in prototype'
- - it provides object method acces with colon notation:
- expect(instance:method 'object method call').
- to_be 'Prototype instance, object method call'
- - it provides class method access with class dot notation:
- expect(Prototype.method(instance, 'class method call')).
- to_be 'Prototype class, class method call'
- - it allows new instance fields to be added:
- instance.newfield = 'new'
- expect(instance.newfield).to_be 'new'
- - it allows new instance methods to be added:
- instance.newmethod = function(self)
- return objtype(self) .. ', new instance method'
- end
- expect(instance:newmethod()).to_be 'Prototype, new instance method'
- - it allows new class methods to be added:
- Prototype.newmethod = function(self)
- return objtype(self) .. ', new class method'
- end
- expect(Prototype.newmethod(instance)).
- to_be 'Prototype, new class method'
-
-
-- describe object method propagation:
- - context with no custom instance methods:
- # :type is a method defined by the root object
- - it inherits prototype object methods:
- instance = Object {type=object.type}
- expect(instance:type()).to_be 'Object'
- - it propagates prototype methods to derived instances:
- Derived = Object {_type='Derived', type=object.type}
- instance = Derived {}
- expect(instance:type()).to_be 'Derived'
- - context with custom object methods:
- - before:
- bag = Object {
- _type = 'bag',
- __index = {
- add = function(self, item)
- self[item] =(self[item] or 0) + 1
- return self
- end,
- type = object.type,
- },
- }
- - it inherits prototype object methods:
- expect(bag:type()).to_be 'bag'
- - it propagates prototype methods to derived instances:
- instance = bag {}
- expect(instance:type()).to_be 'bag'
- - it supports method calls:
- expect(bag:add 'foo').to_be(bag)
- expect(bag.foo).to_be(1)
-
-
-# Metatable propagation is an important property of Object cloning,
-# because Lua will only call __lt and __le metamethods when both
-# arguments share the same metatable - i.e. the previous behaviour
-# of making each object its own metatable precluded ever being able
-# to use __lt and __le!
-- describe object metatable propagation:
- - before: root_mt = getmetatable(Object)
-
- - context with no custom metamethods:
- - it inherits prototype object metatable:
- instance = Object {}
- expect(getmetatable(instance)).to_be(root_mt)
- - it propagates prototype metatable to derived instances:
- Derived = Object {_type='Derived'}
- instance = Derived {}
- expect(getmetatable(Derived)).not_to_be(root_mt)
- expect(getmetatable(instance)).to_be(getmetatable(Derived))
- - context with custom metamethods:
- - before:
- bag = Object {
- _type = 'bag',
- __lt = function(a, b) return a[1] < b[1] end,
- }
- - it has it's own metatable:
- expect(getmetatable(bag)).not_to_be(root_mt)
- - it propagates prototype metatable to derived instances:
- instance = bag {}
- expect(getmetatable(instance)).to_be(getmetatable(bag))
- - it supports __lt calls: |
- a, b = bag {'a'}, bag {'b'}
- expect(a < b).to_be(true)
- expect(a < a).to_be(false)
- expect(a > b).to_be(false)
-
-
-- describe __tostring:
- - before:
- o = Object {_type='Derived', 'one', 'two', 'three'}
- - it returns a string:
- expect(type(tostring(o))).to_be 'string'
- - it contains the type:
- expect(tostring(Object {})).to_contain 'Object'
- expect(tostring(o)).to_contain(objtype(o))
- - it contains the ordered array part elements:
- expect(tostring(o)).to_contain 'one, two, three'
- - it contains the ordered dictionary part elements:
- expect(tostring(Object {one=true, two=true, three=true})).
- to_contain 'one=true, three=true, two=true'
- expect(tostring(o {one=true, two=true, three=true})).
- to_contain 'one=true, three=true, two=true'
- - it contains a ';' separator only when object has array and dictionary parts:
- expect(tostring(o)).not_to_contain ';'
- expect(tostring(Object {one=true, two=true, three=true})).
- not_to_contain ';'
- expect(tostring(o {one=true, two=true, three=true})).
- to_contain ';'
diff --git a/spec/set_spec.yaml b/spec/set_spec.yaml
deleted file mode 100644
index c44188a..0000000
--- a/spec/set_spec.yaml
+++ /dev/null
@@ -1,313 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype.set'
-
- set = require(this_module)
- Set = set.prototype
- s = Set {'foo', 'bar', 'bar'}
-
-specify std.prototype.set:
-- describe require:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
- - context via the prototype module:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by='std.prototype'}).to_equal {}
-
-
-- describe construction:
- - it constructs a new set:
- s = Set {}
- expect(s).not_to_be(Set)
- expect(objtype(s)).to_be 'Set'
- - it initialises set with constructor parameters:
- t = Set {'foo', 'bar', 'bar'}
- expect(t).to_equal(s)
- - it serves as a prototype for new instances:
- obj = s {}
- expect(objtype(obj)).to_be 'Set'
- expect(obj).to_equal(s)
- expect(getmetatable(obj)).to_be(getmetatable(s))
- - it serves as a prototype for new types:
- Bag = Set {_type='Bag'}
- expect(objtype(Bag)).to_be 'Bag'
- bag = Bag {'goo', 'gar', 'gar'}
- expect(objtype(bag)).to_be 'Bag'
-
-- describe delete:
- - context when called as a Set module function:
- - before:
- fn = set.delete
- s = Set {'foo', 'bar', 'baz'}
- - it returns a set object:
- expect(objtype(fn(s, 'foo'))).to_be 'Set'
- - it is destructive:
- fn(s, 'bar')
- expect(s).not_to_have_member 'bar'
- - it returns the modified set:
- expect(fn(s, 'baz')).not_to_have_member 'baz'
- - it ignores removal of non-members: |
- clone = s {}
- expect(fn(s, 'quux')).to_equal(clone)
- - it deletes a member from the set:
- expect(s).to_have_member 'bar'
- fn(s, 'bar')
- expect(s).not_to_have_member 'bar'
- - it works with an empty set:
- expect(fn(Set {}, 'quux')).to_equal(Set {})
-
-
-- describe difference:
- - before:
- fn = set.difference
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz', 'quux'}
-
- - context when called as a Set module function:
- - it returns a set object:
- expect(objtype(fn(r, s))).to_be 'Set'
- - it is non-destructive:
- fn(r, s)
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members of the first that are not in the second:
- expect(fn(r, s)).to_equal(Set {'foo'})
- - context when called as a set metamethod:
- - it returns a set object:
- expect(objtype(r - s)).to_be 'Set'
- - it is non-destructive:
- q = r - s
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members of the first that are not in the second:
- expect(r - s).to_equal(Set {'foo'})
-
-
-- describe elems:
- - before:
- fn = set.elems
- s = Set {'foo', 'bar', 'baz'}
-
- - context when called as a Set module function:
- - it is an iterator over set members:
- t = {}
- for e in fn(s) do table.insert(t, e) end
- table.sort(t)
- expect(t).to_equal {'bar', 'baz', 'foo'}
- - it works for an empty set:
- t = {}
- for e in fn(Set {}) do table.insert(t, e) end
- expect(t).to_equal {}
-
-
-- describe insert:
- - context when called as a Set module function:
- - before:
- fn = set.insert
- s = Set {'foo'}
- - it returns a set object:
- expect(objtype(fn(s, 'bar'))).to_be 'Set'
- - it is destructive:
- fn(s, 'bar')
- expect(s).to_have_member 'bar'
- - it returns the modified set:
- expect(fn(s, 'baz')).to_have_member 'baz'
- - it ignores insertion of existing members:
- expect(fn(s, 'foo')).to_equal(Set {'foo'})
- - it inserts a new member into the set:
- expect(s).not_to_have_member 'bar'
- fn(s, 'bar')
- expect(s).to_have_member 'bar'
- - it works with an empty set:
- expect(fn(Set {}, 'foo')).to_equal(s)
- - context when called as a set metamethod:
- - before:
- s = Set {'foo'}
- - it returns a set object:
- s['bar'] = true
- expect(objtype(s)).to_be 'Set'
- - it is destructive:
- s['bar'] = true
- expect(s).to_have_member 'bar'
- - it ignores insertion of existing members:
- s['foo'] = true
- expect(s).to_equal(Set {'foo'})
- - it inserts a new member into the set:
- expect(s).not_to_have_member 'bar'
- s['bar'] = true
- expect(s).to_have_member 'bar'
- - it works with an empty set:
- s = Set {}
- s.foo = true
- expect(s).to_equal(s)
-
-
-- describe intersection:
- - before:
- fn = set.intersection
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz', 'quux'}
-
- - context when called as a Set module function:
- - it returns a set object:
- expect(objtype(fn(r, s))).to_be 'Set'
- - it is non-destructive:
- fn(r, s)
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members common to both arguments:
- expect(fn(r, s)).
- to_equal(Set {'bar', 'baz'})
- - context when called as a set metamethod:
- - it returns a set object:
- q = r * s
- expect(objtype(q)).to_be 'Set'
- - it is non-destructive:
- q = r * s
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members common to both arguments:
- expect(r * s).to_equal(Set {'bar', 'baz'})
-
-
-- describe member:
- - before:
- fn = set.member
- s = Set {'foo', 'bar'}
-
- - context when called as a Set module function:
- - it succeeds when set contains the given member:
- expect(fn(s, 'foo')).to_be(true)
- - it fails when set does not contain the given member:
- expect(fn(s, 'baz')).not_to_be(true)
- - it works with the empty set:
- s = Set {}
- expect(fn(s, 'foo')).not_to_be(true)
- - context when called as a set metamethod:
- - it succeeds when set contains the given member:
- expect(s['foo']).to_be(true)
- - it fails when set does not contain the given member:
- expect(s['baz']).not_to_be(true)
- - it works with the empty set:
- s = Set {}
- expect(s['foo']).not_to_be(true)
-
-
-- describe proper_subset:
- - before:
- fn = set.proper_subset
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz'}
-
- - context when called as a Set module function:
- - it succeeds when set contains all elements of another:
- expect(fn(s, r)).to_be(true)
- - it fails when two sets are equal:
- r = s {}
- expect(fn(s, r)).to_be(false)
- - it fails when set does not contain all elements of another:
- s = s + Set {'quux'}
- expect(fn(r, s)).to_be(false)
- - context when called as a set metamethod:
- - it succeeds when set contains all elements of another:
- expect(s < r).to_be(true)
- - it fails when two sets are equal:
- r = s {}
- expect(s < r).to_be(false)
- - it fails when set does not contain all elements of another:
- s = s + Set {'quux'}
- expect(r < s).to_be(false)
-
-
-- describe subset:
- - before:
- fn = set.subset
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz'}
-
- - context when called as a Set module function:
- - it succeeds when set contains all elements of another:
- expect(fn(s, r)).to_be(true)
- - it succeeds when two sets are equal:
- r = s {}
- expect(fn(s, r)).to_be(true)
- - it fails when set does not contain all elements of another:
- s = s + Set {'quux'}
- expect(fn(r, s)).to_be(false)
- - context when called as a set metamethod:
- - it succeeds when set contains all elements of another:
- expect(s <= r).to_be(true)
- - it succeeds when two sets are equal:
- r = s {}
- expect(s <= r).to_be(true)
- - it fails when set does not contain all elements of another:
- s = s + Set {'quux'}
- expect(r <= s).to_be(false)
-
-
-- describe symmetric_difference:
- - before:
- fn = set.symmetric_difference
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz', 'quux'}
-
- - context when called as a Set module function:
- - it returns a set object:
- expect(objtype(fn(r, s))).to_be 'Set'
- - it is non-destructive:
- fn(r, s)
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members in only one argument set:
- expect(fn(r, s)).to_equal(Set {'foo', 'quux'})
- - context when called as a set metamethod:
- - it returns a set object:
- expect(objtype(r / s)).to_be 'Set'
- - it is non-destructive:
- q = r / s
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members in only one argument set:
- expect(r / s).to_equal(Set {'foo', 'quux'})
-
-
-- describe union:
- - before:
- fn = set.union
- r = Set {'foo', 'bar', 'baz'}
- s = Set {'bar', 'baz', 'quux'}
-
- - context when called as a Set module function:
- - it returns a set object:
- expect(objtype(fn(r, s))).to_be 'Set'
- - it is non-destructive:
- fn(r, s)
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members in only one argument set:
- expect(fn(r, s)).
- to_equal(Set {'foo', 'bar', 'baz', 'quux'})
- - context when called as a set metamethod:
- - it returns a set object:
- expect(objtype(r + s)).to_be 'Set'
- - it is non-destructive:
- q = r + s
- expect(r).to_equal(Set {'foo', 'bar', 'baz'})
- expect(s).to_equal(Set {'bar', 'baz', 'quux'})
- - it returns a set containing members in only one argument set:
- expect(r + s).to_equal(Set {'foo', 'bar', 'baz', 'quux'})
-
-
-- describe __tostring:
- - before:
- s = Set {'foo', 'bar', 'baz'}
-
- - it returns a string:
- expect(type(tostring(s))).to_be 'string'
- - it shows the type name:
- expect(tostring(s)).to_contain 'Set'
- - it contains the ordered set elements:
- expect(tostring(s)).to_contain 'bar, baz, foo'
diff --git a/spec/spec_helper.lua b/spec/spec_helper.lua
deleted file mode 100644
index c312489..0000000
--- a/spec/spec_helper.lua
+++ /dev/null
@@ -1,142 +0,0 @@
-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'
-
-package.path = std.package.normalize ('./lib/?.lua', './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'
-
-
--- Allow use of bare 'unpack' even in Lua 5.3.
-unpack = table.unpack or unpack
-
-
-function copy (t)
- local r = {}
- for k, v in next, t do r[k] = v end
- return r
-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
-
-
--- 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
-
-
-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
-
-
-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}
---
--- @tparam table argt one of the combinations above
--- @treturn table a list of keys according to criteria above
-function show_apis (argt)
- return tabulate_output ([[
- local before, after = {}, {}
- for k in pairs (]] .. argt.added_to .. [[) do
- before[k] = true
- end
-
- local M = require ']] .. argt.by .. [['
- for k in pairs (]] .. argt.added_to .. [[) do
- after[k] = true
- end
-
- for k in pairs (after) do
- if not before[k] then print (k) end
- end
- ]])
-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_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/strbuf_spec.yaml b/spec/strbuf_spec.yaml
deleted file mode 100644
index 2d6de60..0000000
--- a/spec/strbuf_spec.yaml
+++ /dev/null
@@ -1,106 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype.strbuf'
-
- StrBuf = require(this_module).prototype
- b = StrBuf {'foo', 'bar'}
-
-
-specify std.prototype.strbuf:
-- describe require:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
- - context via the prototype module:
- - it does not perturb the global namespace:
- expect(show_apis {added_to='_G', by='std.prototype'}).to_equal {}
-
-
-- describe construction:
- - context from StrBuf clone method:
- - it constructs a new strbuf:
- b = StrBuf:clone {}
- expect(b).not_to_be(StrBuf)
- expect(objtype(b)).to_be 'StrBuf'
- - it reuses the StrBuf metatable:
- a, b = StrBuf:clone {'a'}, StrBuf:clone {'b'}
- expect(getmetatable(a)).to_be(getmetatable(b))
- - it initialises strbuf with constructor parameters:
- a = StrBuf:clone {'foo', 'bar'}
- expect(a).to_equal(b)
- - it serves as a prototype for new instances:
- obj = b:clone {}
- expect(objtype(obj)).to_be 'StrBuf'
- expect(obj).to_equal(b)
- expect(getmetatable(obj)).to_be(getmetatable(b))
-
- # StrBuf {args} is just syntactic sugar for StrBuf:clone {args}
- - context from StrBuf object prototype:
- - it constructs a new strbuf:
- b = StrBuf {}
- expect(b).not_to_be(StrBuf)
- expect(objtype(b)).to_be 'StrBuf'
- - it reuses the StrBuf metatable:
- a, b = StrBuf {'a'}, StrBuf {'b'}
- expect(getmetatable(a)).to_be(getmetatable(b))
- - it initialises strbuf with constructor parameters:
- a = StrBuf:clone {'foo', 'bar'}
- expect(a).to_equal(b)
- - it serves as a prototype for new instances:
- obj = b {}
- expect(objtype(obj)).to_be 'StrBuf'
- expect(obj).to_equal(b)
- expect(getmetatable(obj)).to_be(getmetatable(b))
-
-
-- describe tostring:
- - it returns buffered string:
- expect(tostring(b)).to_be 'foobar'
-
-
-- describe concat:
- - before:
- a = StrBuf {'foo', 'bar'}
- b = StrBuf {'baz', 'quux'}
-
- - context as a module function:
- - it appends a string:
- a = StrBuf.concat(a, 'baz')
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbaz'
- - it appends a StrBuf:
- a = StrBuf.concat(a, b)
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbazquux'
- - context as an object method:
- - it appends a string:
- a = a:concat 'baz'
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbaz'
- - it appends a StrBuf:
- a = a:concat(b)
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbazquux'
- - context as a metamethod:
- - it appends a string:
- a = a .. 'baz'
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbaz'
- - it appends a StrBuf:
- a = a .. b
- expect(objtype(a)).to_be 'StrBuf'
- expect(tostring(a)).to_be 'foobarbazquux'
- - it stringifies lazily:
- a = StrBuf {1}
- b = StrBuf {a, 'five'}
- a = a:concat(2)
- expect(tostring(b)).to_be '12five'
- b = StrBuf {tostring(a), 'five'}
- a = a:concat(3)
- expect(tostring(b)).to_be '12five'
- - it can be non-destructive:
- a = StrBuf {1}
- b = a {} .. 2
- expect(tostring(a)).to_be '1'
diff --git a/spec/trie_spec.yaml b/spec/trie_spec.yaml
deleted file mode 100644
index ac8621e..0000000
--- a/spec/trie_spec.yaml
+++ /dev/null
@@ -1,423 +0,0 @@
-# Prototype Oriented Programming for Lua 5.1, 5.2, 5.3 & 5.4
-# Copyright (C) 2014-2022 std.prototype authors
-
-before:
- this_module = 'std.prototype.trie'
-
- trie = require(this_module)
- Trie = trie.prototype
-
-specify std.prototype.trie:
-- before:
- t = {foo='foo', fnord={branch={bar='bar', baz='baz'}}, quux='quux'}
- tr = Trie(t)
-
-- context when required:
- - context by name:
- - it does not touch the global table:
- expect(show_apis {added_to='_G', by=this_module}).
- to_equal {}
-
- - context via the prototype module:
- - it does not touch the global table:
- expect(show_apis {added_to='_G', by='std.prototype'}).
- to_equal {}
-
-- describe construction:
- - it constructs a new trie:
- tr = Trie {}
- expect(tr).not_to_be(Trie)
- expect(objtype(tr)).to_be 'Trie'
- - it turns a table argument into a trie:
- expect(objtype(Trie(t))).to_be 'Trie'
- - it does not turn table argument values into sub-Tries:
- expect(objtype(tr['fnord'])).to_be 'table'
- - it understands branched nodes:
- expect(tr).to_equal(Trie(t))
- expect(tr[{'fnord'}]).to_equal(t.fnord)
- expect(tr[{'fnord', 'branch', 'bar'}]).to_equal(t.fnord.branch.bar)
- - it serves as a prototype for new instances:
- obj = tr {}
- expect(objtype(obj)).to_be 'Trie'
- expect(obj).to_equal(tr)
- expect(getmetatable(obj)).to_be(getmetatable(tr))
-
-
-- describe clone:
- - before:
- subject = {k1={'v1'}, k2={'v2'}, k3={'v3'}}
- f = trie.clone
- - 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 makes a deep copy:
- expect(f(subject).k1).not_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)
- - it diagnoses non-table arguments:
- if have_typecheck then
- expect(f()).to_raise('table expected')
- expect(f 'foo').to_raise('table expected')
- end
-
-
-- describe ileaves:
- - before:
- f = trie.ileaves
- l = {}
- - it iterates over array part of a table argument:
- for v in f {'first', 'second', '3rd'} do l[1+#l]=v end
- expect(l).to_equal {'first', 'second', '3rd'}
- - it iterates over array parts of nested table argument:
- for v in f {{'one', {'two'}, {{'three'}, 'four'}}, 'five'} do
- l[1+#l]=v
- end
- expect(l).to_equal {'one', 'two', 'three', 'four', 'five'}
- - it skips hash part of a table argument:
- for v in f {'first', 'second'; third='2rd'} do l[1+#l]=v end
- expect(l).to_equal {'first', 'second'}
- - it skips hash parts of nested table argument:
- for v in f {{'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'} do
- l[1+#l]=v
- end
- expect(l).to_equal {'one', 'three', 'five'}
- - it works on tries too:
- for v in f(Trie {Trie {'one',
- Trie {two=2},
- Trie {Trie {'three'}, four=4}
- },
- foo='bar', 'five'})
- do
- l[1+#l]=v
- end
- expect(l).to_equal {'one', 'three', 'five'}
- - it diagnoses non-table arguments:
- if have_typecheck then
- expect(f()).to_raise('table expected')
- expect(f 'string').to_raise('table expected')
- end
-
-
-- describe inodes:
- - before: |
- f = trie.inodes
-
- function traverse(subject)
- l = {}
- for ty, p, n in f(subject) do
- l[1+#l]={ty, trie.clone(p), n}
- end
- return l
- end
- - it iterates over array part of a table argument: |
- subject = {'first', 'second', '3rd'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'leaf', {1}, subject[1]}, -- first,
- {'leaf', {2}, subject[2]}, -- second,
- {'leaf', {3}, subject[3]}, -- 3rd,
- {'join', {}, subject}} -- }
- - it iterates over array parts of nested table argument: |
- subject = {{'one', {'two'}, {{'three'}, 'four'}}, 'five'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'leaf', {1,2,1}, subject[1][2][1]}, -- two,
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'leaf', {1,3,2}, subject[1][3][2]}, -- four,
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'join', {}, subject}} -- }
- - it skips hash part of a table argument: |
- subject = {'first', 'second'; third='3rd'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'leaf', {1}, subject[1]}, -- first,
- {'leaf', {2}, subject[2]}, -- second,
- {'join', {}, subject}} -- }
- - it skips hash parts of nested table argument: |
- subject = {{'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'join', {}, subject}} -- }
- - it works on tries too: |
- subject = Trie {Trie {'one',
- Trie {two=2},
- Trie {Trie {'three'}, four=4}},
- foo='bar',
- 'five'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'join', {}, subject}} -- }
- - it diagnoses non-table arguments:
- if have_typecheck then
- expect(f()).to_raise('table expected')
- expect(f 'string').to_raise('table expected')
- end
-
-
-- describe leaves:
- - before:
- f = trie.leaves
- l = {}
- - it iterates over elements of a table argument:
- for v in f {'first', 'second', '3rd'} do l[1+#l]=v end
- expect(l).to_equal {'first', 'second', '3rd'}
- - it iterates over elements of a nested table argument:
- for v in f {{'one', {'two'}, {{'three'}, 'four'}}, 'five'} do
- l[1+#l]=v
- end
- expect(l).to_equal {'one', 'two', 'three', 'four', 'five'}
- - it includes the hash part of a table argument:
- for v in f {'first', 'second'; third='3rd'} do l[1+#l]=v end
- expect(l).to_equal {'first', 'second', '3rd'}
- - it includes hash parts of a nested table argument:
- for v in f {{'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'} do
- l[1+#l]=v
- end
- expect(l).to_contain.
- a_permutation_of {'one', 2, 'three', 4, 'bar', 'five'}
- - it works on tries too:
- for v in f(Trie {Trie {'one',
- Trie {two=2},
- Trie {Trie {'three'}, four=4}
- },
- foo='bar', 'five'})
- do
- l[1+#l]=v
- end
- expect(l).to_contain.
- a_permutation_of {'one', 2, 'three', 4, 'bar', 'five'}
- - it diagnoses non-table arguments:
- if have_typecheck then
- expect(f()).to_raise('table expected')
- expect(f 'string').to_raise('table expected')
- end
-
-
-- describe merge:
- - before: |
- f = trie.merge
-
- -- Additional merge keys which are moderately unusual
- t1 = Trie {k1='v1', k2='if', k3=Trie {'?'}}
- t2 = Trie {['if']=true, [{'?'}]=false, _='underscore', k3='v2'}
-
- target = trie.clone(t1)
- for ty, p, n in trie.nodes(t2) do
- if ty == 'leaf' then target[p] = n end
- 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, Trie {})).to_be(t1)
- - it copies t2 when t1 is empty: |
- expect(f(Trie {}, 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 = trie.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 diagnoses non-table arguments:
- if have_typecheck then
- expect(f(nil, {})).to_raise('table expected')
- expect(f({}, nil)).to_raise('table expected')
- end
-
-
-- describe nodes:
- - before:
- f = trie.nodes
-
- function traverse(subject)
- l = {}
- for ty, p, n in f(subject) do l[1+#l]={ty, trie.clone(p), n} end
- return l
- end
- - it iterates over the elements of a table argument: |
- subject = {'first', 'second', '3rd'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'leaf', {1}, subject[1]}, -- first,
- {'leaf', {2}, subject[2]}, -- second,
- {'leaf', {3}, subject[3]}, -- 3rd,
- {'join', {}, subject}} -- }
- - it iterates over the elements of nested a table argument: |
- subject = {{'one', {'two'}, {{'three'}, 'four'}}, 'five'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'leaf', {1,2,1}, subject[1][2][1]}, -- two,
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'leaf', {1,3,2}, subject[1][3][2]}, -- four,
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'join', {}, subject}} -- }
- - it includes the hash part of a table argument: |
- -- like `pairs`, `nodes` can visit elements in any order, so we cannot
- -- guarantee the array part is always visited before the hash part, or
- -- even that the array elements are visited in order!
- subject = {'first', 'second'; third='3rd'}
- expect(traverse(subject)).to_contain.
- a_permutation_of {{'branch', {}, subject}, -- {
- {'leaf', {1}, subject[1]}, -- first,
- {'leaf', {2}, subject[2]}, -- second,
- {'leaf', {'third'}, subject['third']}, -- 3rd
- {'join', {}, subject}} -- }
- - it includes hash parts of a nested table argument: |
- -- like `pairs`, `nodes` can visit elements in any order, so we cannot
- -- guarantee the array part is always visited before the hash part, or
- -- even that the array elements are visited in order!
- subject = {{'one', {two=2}, {{'three'}, four=4}}, foo='bar', 'five'}
- expect(traverse(subject)).to_contain.
- a_permutation_of {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'leaf', {1,2,'two'}, subject[1][2]['two']}, -- 2,
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'leaf', {1,3,'four'}, subject[1][3]['four']}, -- 4,
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'leaf', {'foo'}, subject['foo']}, -- bar,
- {'join', {}, subject}} -- }
- - it works on tries too: |
- -- like `pairs`, `nodes` can visit elements in any order, so we cannot
- -- guarantee the array part is always visited before the hash part, or
- -- even that the array elements are visited in order!
- subject = Trie {Trie {'one',
- Trie {two=2},
- Trie {Trie {'three'}, four=4}},
- foo='bar',
- 'five'}
- expect(traverse(subject)).to_contain.
- a_permutation_of {{'branch', {}, subject}, -- {
- {'branch', {1}, subject[1]}, -- {
- {'leaf', {1,1}, subject[1][1]}, -- one,
- {'branch', {1,2}, subject[1][2]}, -- {
- {'leaf', {1,2,'two'}, subject[1][2]['two']}, -- 2,
- {'join', {1,2}, subject[1][2]}, -- },
- {'branch', {1,3}, subject[1][3]}, -- {
- {'branch', {1,3,1}, subject[1][3][1]}, -- {
- {'leaf', {1,3,1,1}, subject[1][3][1][1]}, -- three,
- {'join', {1,3,1}, subject[1][3][1]}, -- },
- {'leaf', {1,3,'four'}, subject[1][3]['four']}, -- 4,
- {'join', {1,3}, subject[1][3]}, -- },
- {'join', {1}, subject[1]}, -- },
- {'leaf', {2}, subject[2]}, -- five,
- {'leaf', {'foo'}, subject['foo']}, -- bar,
- {'join', {}, subject}} -- }
- - it generates path key-lists that are valid __index arguments: |
- subject = Trie {'first', Trie {'second'}, '3rd'}
- expect(traverse(subject)).
- to_equal {{'branch', {}, subject[{}]}, -- {
- {'leaf', {1}, subject[{1}]}, -- first,
- {'branch', {2}, subject[{2}]}, -- {
- {'leaf', {2,1}, subject[{2,1}]}, -- second
- {'join', {2}, subject[{2}]}, -- }
- {'leaf', {3}, subject[{3}]}, -- 3rd,
- {'join', {}, subject[{}]}} -- }
- - it diagnoses non-table arguments:
- if have_typecheck then
- expect(f()).to_raise('table expected')
- expect(f 'string').to_raise('table expected')
- end
-
-
-- describe __index:
- - it returns nil for a missing key:
- expect(tr['no such key']).to_be(nil)
- - it returns nil for missing single element key lists:
- expect(tr[{'no such key'}]).to_be(nil)
- - it returns nil for missing multi-element key lists:
- expect(tr[{'fnord', 'foo'}]).to_be(nil)
- expect(tr[{'no', 'such', 'key'}]).to_be(nil)
- - it returns a value for the given key:
- expect(tr['foo']).to_be 'foo'
- expect(tr['quux']).to_be 'quux'
- - it returns trie root for empty key list:
- expect(tr[{}]).to_be(tr)
- - it returns values for single element key lists:
- expect(tr[{'foo'}]).to_be 'foo'
- expect(tr[{'quux'}]).to_be 'quux'
- - it returns values for multi-element key lists:
- expect(tr[{'fnord', 'branch', 'bar'}]).to_be 'bar'
- expect(tr[{'fnord', 'branch', 'baz'}]).to_be 'baz'
-
-
-- describe __newindex:
- - before:
- tr = Trie {}
- - it stores values for simple keys:
- tr['foo'] = 'foo'
- expect(tr).to_equal(Trie {foo='foo'})
- - it stores values for single element key lists:
- tr[{'foo'}] = 'foo'
- expect(tr).to_equal(Trie {foo='foo'})
- - it stores values for multi-element key lists:
- tr[{'foo', 'bar'}] = 'baz'
- expect(tr).to_equal(Trie {foo=Trie {bar='baz'}})
- - it separates branches for diverging key lists:
- tr[{'foo', 'branch', 'bar'}] = 'leaf1'
- tr[{'foo', 'branch', 'baz'}] = 'leaf2'
- expect(tr).to_equal(Trie {foo=Trie {branch=Trie {bar='leaf1', baz='leaf2'}}})
-
-
-- describe __tostring:
- - it returns a string:
- expect(objtype(tostring(tr))).to_be 'string'
- - it shows the type name:
- expect(tostring(tr)).to_contain 'Trie'
- - it shows the contents in order: |
- tr = Trie {foo = 'foo',
- fnord = Trie {branch = Trie {bar='bar', baz='baz'}},
- quux = 'quux'}
- expect(tostring(tr)).
- to_contain 'fnord=Trie {branch=Trie {bar=bar, baz=baz}}, foo=foo, quux=quux'
diff --git a/std.prototype-git-1.rockspec b/std.prototype-git-1.rockspec
deleted file mode 100644
index adb934a..0000000
--- a/std.prototype-git-1.rockspec
+++ /dev/null
@@ -1,50 +0,0 @@
-local _MODREV, _SPECREV = 'git', '-1'
-
-package = 'std.prototype'
-version = _MODREV .. _SPECREV
-
-description = {
- summary = 'Prototype Oriented Programming with Lua',
- detailed = [[
- A straight forward prototype-based object system, and a selection of
- useful objects build on it.
- ]],
- homepage = 'http://lua-stdlib.github.io/prototype',
- license = 'MIT/X11',
-}
-
-source = (function(gitp)
- if gitp then
- return {
- url = 'git://github.com/lua-stdlib/prototype.git',
- }
- else
- return {
- url = 'http://github.com/lua-stdlib/prototype/archive' .. _MODREV .. '.zip',
- dir = 'prototype-' .. _MODREV,
- }
- end
-end)(_MODREV == 'git')
-
-dependencies = {
- 'lua >= 5.1, < 5.5',
- 'std.normalize >= 1.0.3',
-}
-
-if _MODREV == 'git' then
- dependencies[#dependencies + 1] = 'ldoc'
-end
-
-build = {
- type = 'builtin',
- modules = {
- ['std.prototype'] = 'lib/std/prototype/init.lua',
- ['std.prototype._base'] = 'lib/std/prototype/_base.lua',
- ['std.prototype.container'] = 'lib/std/prototype/container.lua',
- ['std.prototype.object'] = 'lib/std/prototype/object.lua',
- ['std.prototype.set'] = 'lib/std/prototype/set.lua',
- ['std.prototype.strbuf'] = 'lib/std/prototype/strbuf.lua',
- ['std.prototype.trie'] = 'lib/std/prototype/trie.lua',
- ['std.prototype.version'] = 'lib/std/prototype/version.lua',
- },
-}