Adds #90 - Added strictness Lua module
parent
be42334fb7
commit
fefec5d721
|
@ -0,0 +1,20 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
###0.2.0 (06/11/14)
|
||||
* `strictness` no longer create globals. It returns a local table of library functions.
|
||||
* `strictness` can now create (or convert) strict/unstrict tables (or environnements).
|
||||
* Strict/unstrict rules are now applied per table (or environnement).
|
||||
* Strict mode enforces variable declarations and complain on undefined fields access/assignment.
|
||||
* Tables (or environnements) already existing metatables are preserved, including `__index` and `__newindex` fields.
|
||||
* Added `strictness.strict` to convert a normal table (or environnement) to a strict one.
|
||||
* Added `strictness.unstrict` to convert a strict table (or environnement) to a normal one.
|
||||
* Added `strictness.is_strict` to check if a table (or environnement) is strict.
|
||||
* Added `strictness.strictf` to wrap a normal function into a non strict function.
|
||||
* Added `strictness.unstrictf` to wrap a normal function into a strict function.
|
||||
* Added `strictness.run_strict` to run a normal function in strict mode.
|
||||
* Added `strictness.run_unstrict` to run a normal function in non strict mode.
|
||||
* Made compliant with Lua 5.2 new _ENV lexical scoping (although strictly speaking there are no globals in Lua 5.2).
|
||||
|
||||
###0.1.0 (10/05/13)
|
||||
* Initial release
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 Roland Y.
|
||||
|
||||
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 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,63 @@
|
|||
strictness
|
||||
===========
|
||||
|
||||
[![Build Status](https://travis-ci.org/Yonaba/strictness.png)](https://travis-ci.org/Yonaba/strictness)
|
||||
[![Coverage Status](https://coveralls.io/repos/Yonaba/strictness/badge.png?branch=master)](https://coveralls.io/r/Yonaba/strictness?branch=master)
|
||||
[![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE)
|
||||
|
||||
With the __Lua__ programming language, undeclared variables are not detected until runtime, as Lua will not complain when loading code.
|
||||
This is releated to the convention that Lua uses : [global by default](http://www.lua.org/pil/1.2.html). In other words, when a variable is not recognized as *local*, it will be
|
||||
interpreted as a *global* one, and will involve a lookup in the global environment `_G` (for Lua 5.1). Note that this behaviour has been addressed
|
||||
in Lua 5.2, which strictly speaking has no globals, because of its [lexical scoping](http://www.luafaq.org/#T8.2.1).
|
||||
|
||||
*strictness* is a module to track *access and assignment* to undefined variables in your code. It *enforces* to declare globals and modules variables before
|
||||
assigning them values. As such, it helps having a better control on the scope of variables across the code.
|
||||
|
||||
*strictness* is mostly meant to work with Lua [5.1](http://www.lua.org/versions.html#5.1), but it is compatible with Lua [5.2](http://www.lua.org/versions.html#5.2).
|
||||
|
||||
##Installation
|
||||
|
||||
####Git
|
||||
|
||||
git clone git://github.com/Yonaba/strictness
|
||||
|
||||
####Download
|
||||
|
||||
* See [releases](https://github.com/Yonaba/strictness/releases)
|
||||
|
||||
####LuaRocks
|
||||
|
||||
luarocks install strictness
|
||||
|
||||
####MoonRocks
|
||||
|
||||
moonrocks install strictness
|
||||
|
||||
or
|
||||
|
||||
luarocks install strictness --server=http://rocks.moonscript.org strictness
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
See [tutorial.md](doc/tutorial.md).
|
||||
|
||||
##Tests
|
||||
|
||||
This project has specification tests. To run these tests, execute the following command from the project root folder:
|
||||
|
||||
lua spec/tests.lua
|
||||
|
||||
##Similar projects
|
||||
|
||||
Feel free to check those alternate implementations, from with *strictness* takes some inspiration:
|
||||
|
||||
* [strict.lua](http://rtfc.googlecode.com/svn-history/r2/trunk/lua-5.1/etc/strict.lua) which is included in the official Lua 5.1 distribution,
|
||||
* [pl.strict](https://github.com/stevedonovan/Penlight/blob/master/lua/pl/strict.lua) which is part of [Penlight](https://github.com/stevedonovan/Penlight),
|
||||
|
||||
##License
|
||||
This work is under [MIT-LICENSE](http://www.opensource.org/licenses/mit-license.php)<br/>
|
||||
*Copyright (c) 2013-2014 Roland Yonaba*.
|
||||
See [LICENSE](LICENSE).
|
||||
|
||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Yonaba/strictness/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
|
@ -0,0 +1,306 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<head>
|
||||
<title>strictness documentation</title>
|
||||
<link rel="stylesheet" href="ldoc.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="product">
|
||||
<div id="product_logo"></div>
|
||||
<div id="product_name"><big><b></b></big></div>
|
||||
<div id="product_description"></div>
|
||||
</div> <!-- id="product" -->
|
||||
|
||||
|
||||
<div id="main">
|
||||
|
||||
|
||||
<!-- Menu -->
|
||||
|
||||
<div id="navigation">
|
||||
<br/>
|
||||
<h1>strictness</h1>
|
||||
|
||||
|
||||
<h2>Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#Functions">Functions</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Modules</h2>
|
||||
<ul class="$(kind=='Topics' and '' or 'nowrap'">
|
||||
<li><strong>strictness</strong></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<h1>Module <code>strictness</code></h1>
|
||||
<p><em>strictness, a "strict" mode for Lua</em>.</p>
|
||||
<p> Source on <a href="http://github.com/Yonaba/strictness">Github</a></p>
|
||||
<h3>Info:</h3>
|
||||
<ul>
|
||||
<li><strong>Copyright</strong>: 2013-2014</li>
|
||||
<li><strong>License</strong>: MIT</li>
|
||||
<li><strong>Author</strong>: Roland Yonaba</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#strict">strict ([t[, ...]])</a></td>
|
||||
<td class="summary">Makes a given table strict.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#is_strict">is_strict (t)</a></td>
|
||||
<td class="summary">Checks if a given table is strict.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#unstrict">unstrict (t)</a></td>
|
||||
<td class="summary">Makes a given table non-strict.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#strictf">strictf (f)</a></td>
|
||||
<td class="summary">Creates a strict function.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#unstrictf">unstrictf (f)</a></td>
|
||||
<td class="summary">Creates a non-strict function.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#run_strict">run_strict (f[, ...])</a></td>
|
||||
<td class="summary">Returns the result of a function call in strict mode.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" nowrap><a href="#run_unstrict">run_unstrict (f[, ...])</a></td>
|
||||
<td class="summary">Returns the result of a function call in non-strict mode.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<h2><a name="Functions"></a>Functions</h2>
|
||||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "strict"></a>
|
||||
<strong>strict ([t[, ...]])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Makes a given table strict. It mutates the passed-in table (or creates a
|
||||
new table) and returns it. The returned table is strict, indexing or
|
||||
assigning undefined fields will raise an error.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">t</span>
|
||||
a table
|
||||
</li>
|
||||
<li><span class="parameter">...</span>
|
||||
a vararg list of allowed fields in the table.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
the passed-in table <code>t</code> or a new table, patched to be strict.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">
|
||||
<span class="keyword">local</span> t = strictness.strict()
|
||||
<span class="keyword">local</span> t2 = strictness.strict({})
|
||||
<span class="keyword">local</span> t3 = strictness.strict({}, <span class="string">'field1'</span>, <span class="string">'field2'</span>)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "is_strict"></a>
|
||||
<strong>is_strict (t)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Checks if a given table is strict.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">t</span>
|
||||
a table
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<code>true</code> if the table is strict, <code>false</code> otherwise.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> is_strict = strictness.is_strict(a_table)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "unstrict"></a>
|
||||
<strong>unstrict (t)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Makes a given table non-strict. It mutates the passed-in table and
|
||||
returns it. The returned table is non-strict.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">t</span>
|
||||
a table
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> unstrict_table = strictness.unstrict(trict_table)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "strictf"></a>
|
||||
<strong>strictf (f)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Creates a strict function. Wraps the given function and returns the wrapper.
|
||||
The new function will always run in strict mode in its environment, whether
|
||||
or not this environment is strict.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">f</span>
|
||||
a function, or a callable value.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">
|
||||
<span class="keyword">local</span> strict_f = strictness.strictf(a_function)
|
||||
<span class="keyword">local</span> result = strict_f(...)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "unstrictf"></a>
|
||||
<strong>unstrictf (f)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Creates a non-strict function. Wraps the given function and returns the wrapper.
|
||||
The new function will always run in non-strict mode in its environment, whether
|
||||
or not this environment is strict.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">f</span>
|
||||
a function, or a callable value.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example">
|
||||
<span class="keyword">local</span> unstrict_f = strictness.unstrictf(a_function)
|
||||
<span class="keyword">local</span> result = unstrict_f(...)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "run_strict"></a>
|
||||
<strong>run_strict (f[, ...])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Returns the result of a function call in strict mode.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">f</span>
|
||||
a function, or a callable value.
|
||||
</li>
|
||||
<li><span class="parameter">...</span>
|
||||
a vararg list of arguments to function <code>f</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> result = strictness.run_strict(a_function, arg1, arg2)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "run_unstrict"></a>
|
||||
<strong>run_unstrict (f[, ...])</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Returns the result of a function call in non-strict mode.
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">f</span>
|
||||
a function, or a callable value.
|
||||
</li>
|
||||
<li><span class="parameter">...</span>
|
||||
a vararg list of arguments to function <code>f</code>.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Usage:</h3>
|
||||
<ul>
|
||||
<pre class="example"><span class="keyword">local</span> result = strictness.run_unstrict(a_function, arg1, arg2)</pre>
|
||||
</ul>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div> <!-- id="content" -->
|
||||
</div> <!-- id="main" -->
|
||||
<div id="about">
|
||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.2</a></i>
|
||||
</div> <!-- id="about" -->
|
||||
</div> <!-- id="container" -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,302 @@
|
|||
/* 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; }
|
||||
span.parameter { font-family:monospace; }
|
||||
span.parameter:after { content:":"; }
|
||||
span.types:before { content:"("; }
|
||||
span.types:after { content:")"; }
|
||||
.type { font-weight: bold; font-style:italic }
|
||||
|
||||
body, p, td, th { font-size: .95em; line-height: 1.2em;}
|
||||
|
||||
p, ul { margin: 10px 0 0 0px;}
|
||||
|
||||
strong { font-weight: bold;}
|
||||
|
||||
em { font-style: italic;}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
h2, h3, h4 { margin: 15px 0 10px 0; }
|
||||
h2 { font-size: 1.25em; }
|
||||
h3 { font-size: 1.15em; }
|
||||
h4 { font-size: 1.06em; }
|
||||
|
||||
a:link { font-weight: bold; color: #004080; text-decoration: none; }
|
||||
a:visited { font-weight: bold; color: #006699; text-decoration: none; }
|
||||
a:link:hover { text-decoration: underline; }
|
||||
|
||||
hr {
|
||||
color:#cccccc;
|
||||
background: #00007f;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
blockquote { margin-left: 3em; }
|
||||
|
||||
ul { list-style-type: disc; }
|
||||
|
||||
p.name {
|
||||
font-family: "Andale Mono", monospace;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
pre.example {
|
||||
background-color: rgb(245, 245, 245);
|
||||
border: 1px solid silver;
|
||||
padding: 10px;
|
||||
margin: 10px 0 10px 0;
|
||||
font-family: "Andale Mono", monospace;
|
||||
font-size: .85em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: rgb(245, 245, 245);
|
||||
border: 1px solid silver;
|
||||
padding: 10px;
|
||||
margin: 10px 0 10px 0;
|
||||
overflow: auto;
|
||||
font-family: "Andale Mono", monospace;
|
||||
}
|
||||
|
||||
|
||||
table.index { border: 1px #00007f; }
|
||||
table.index td { text-align: left; vertical-align: top; }
|
||||
|
||||
#container {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#product {
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
#product big {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#main {
|
||||
background-color: #f0f0f0;
|
||||
border-left: 2px solid #cccccc;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
float: left;
|
||||
width: 18em;
|
||||
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: 18em;
|
||||
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; }
|
||||
|
||||
/* styles for prettification of source */
|
||||
pre .comment { color: #558817; }
|
||||
pre .constant { color: #a8660d; }
|
||||
pre .escape { color: #844631; }
|
||||
pre .keyword { color: #2239a8; font-weight: bold; }
|
||||
pre .library { color: #0e7c6b; }
|
||||
pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; }
|
||||
pre .string { color: #a8660d; }
|
||||
pre .number { color: #f8660d; }
|
||||
pre .operator { color: #2239a8; font-weight: bold; }
|
||||
pre .preprocessor, pre .prepro { color: #a33243; }
|
||||
pre .global { color: #800080; }
|
||||
pre .prompt { color: #558817; }
|
||||
pre .url { color: #272fc2; text-decoration: underline; }
|
|
@ -0,0 +1,277 @@
|
|||
strictness tutorial
|
||||
===================
|
||||
|
||||
# <a name='TOC'>Table of Contents</a>
|
||||
|
||||
* [What is *strictness* ?](#what)
|
||||
* [Tutorial](#tuto)
|
||||
* [Adding *strictness* to your project](#adding)
|
||||
* [The *strictness* module](#module)
|
||||
* [Strict tables](#stricttables)
|
||||
* [Non-strict tables](#unstricttables)
|
||||
* [Checking strictness](#checking)
|
||||
* [Strict functions](#strictf)
|
||||
* [Non-strict functions](#unstrictf)
|
||||
* [Combo functions](#combo)
|
||||
* [License](#license)
|
||||
|
||||
# <a name='what'>What is *strictness* ?</a>
|
||||
|
||||
*strictness* is a Lua module for tracking accesses and assignements to indefined variables in Lua code. It is actually known that [undefined variables](http://lua-users.org/wiki/DetectingUndefinedVariables) and global variables as well can be very problematic especially when working on large projects and maintaining code that spans across several files.
|
||||
|
||||
*strictness* aims to address this problem by providing a solution similar to [strict structs](http://lua-users.org/wiki/StrictStructs), so that accessing undefined fields will always throw an error.
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
# <a name='tuto'>Tutorial</a>
|
||||
|
||||
## <a name='adding'>Adding *strictness* to your project</a>
|
||||
|
||||
Place the file [strictness.lua](strictness.lua) in your Lua project and call it with [require](http://pgl.yoyo.org/luai/i/require). *strictness* does not write anything in the global (or the current) environnement. It rather returns a local module of functions.
|
||||
|
||||
```lua
|
||||
local strictness = require "strictness"
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
## <a name='module'>The *strictness* module</a>
|
||||
|
||||
### <a name='stricttables'>Strict tables</a>
|
||||
|
||||
*strictness* provides the function `strictness.strict` that patches a given table, so that we can no longer access to undefined keys in this table.
|
||||
Let us apply appy this on the global environnement:
|
||||
|
||||
```lua
|
||||
strictness.strict(_G)
|
||||
print(x) --> this line produces an error
|
||||
````
|
||||
|
||||
The statement `print(x)`produces the following error:
|
||||
|
||||
````
|
||||
...\test.lua:2: Attempt to access undeclared variable "x" in <table: 0x00321328>.
|
||||
```
|
||||
|
||||
To avoid this, we now have to __declare explitely__ our globals. Assigning `nil` will do:
|
||||
|
||||
```lua
|
||||
strictness.strict(_G)
|
||||
x = nil
|
||||
print(x) --> nil
|
||||
x = 3
|
||||
print(x) --> 3
|
||||
````
|
||||
|
||||
A table can be made strict with allowed varnames.
|
||||
|
||||
```lua
|
||||
strictness.strict(_G, 'x', 'y', 'z') -- "varnames x, y and z are allowed"
|
||||
print(x, y, z) --> nil, nil, nil
|
||||
x, y, z = 1, 2, 3
|
||||
print(x, y, z) --> 1, 2, 3
|
||||
````
|
||||
|
||||
Also, in case nothing is passed to `strictness.strict`, it will return a new table:
|
||||
|
||||
```lua
|
||||
local t = strictness.strict()
|
||||
print(t.k) --> produces an error
|
||||
t.k = nil --> declare a field "k"
|
||||
print(t.k) --> nil
|
||||
````
|
||||
|
||||
`strictness.strict` preserves the metatable of the passed-in table.
|
||||
|
||||
```lua
|
||||
local t = setmetatable({}, {
|
||||
__call = function() return 'call' end,
|
||||
__tostring = function() return t.name end
|
||||
})
|
||||
t.name = 'table t'
|
||||
strictness.strict(t)
|
||||
print(t()) --> "call"
|
||||
print(t) --> "table t"
|
||||
````
|
||||
|
||||
In case a table was already made strict, passing it again to `strictness.strict` will raise an error:
|
||||
|
||||
```lua
|
||||
local t = {}
|
||||
strictness.strict(t)
|
||||
strictness.strict(t) --> this will produce an error
|
||||
````
|
||||
|
||||
````
|
||||
...\test.lua:3: <table: 0x0032c110> was already made strict.
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
### <a name='unstricttables'>Non-Strict (or normal) tables</a>
|
||||
|
||||
A strict table can be converted back to a normal one via `strictness.unstrict`:
|
||||
|
||||
```lua
|
||||
local t = strictness.strict()
|
||||
strictness.unstrict(t)
|
||||
t.k = 5
|
||||
print(t.k) --> 5
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
### <a name='checking'>Checking strictness</a>
|
||||
|
||||
`strictness.is_strict` checks if a given table was patched via `strictness.strict`:
|
||||
|
||||
```lua
|
||||
local strict_table = strictness.strict()
|
||||
local normal_table = {}
|
||||
|
||||
print(strictness.is_strict(strict_table)) --> true
|
||||
print(strictness.is_strict(normal_table)) --> false
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
### <a name='strictf'>Strict functions</a>
|
||||
|
||||
`strictness.strictf` returns a wrapper function that runs the original function in strict mode. The returned function is not allowed to write or access undefined fields in its environment. Let us draw an example:
|
||||
|
||||
```lua
|
||||
local env = {} -- a blank environment for our functions
|
||||
|
||||
-- A function that writes a varname and assigns it a value
|
||||
local function normal_f(varname, value)
|
||||
env[varname] = value
|
||||
end
|
||||
-- Convert the original function to a strict one
|
||||
local strict_f = strictness.strictf(normal_f)
|
||||
|
||||
-- set environments for functions
|
||||
setfenv(normal_f, env)
|
||||
setfenv(strict_f, env)
|
||||
|
||||
-- Call the normal function, no error
|
||||
normal_f("var1", "hello")
|
||||
print(env.var1) --> "hello"
|
||||
|
||||
|
||||
strict_f("var2", "hello") --> produces an error
|
||||
````
|
||||
|
||||
````
|
||||
...\test.lua:5: Attempt to assign value to an undeclared variable "var2" in <table: 0x0032c440>.
|
||||
````
|
||||
|
||||
Notice that here, the strict function always run in strict mode whether its environment is strict or not.
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
### <a name='unstrictf'>Non-strict functions</a>
|
||||
|
||||
Similarly, `strictness.unstrictf` creates a wrapper function that runs in non-strict mode in its environment. In other terms, the returned function is allowed to access and assign values in its environments, whether or not this environment is strict.
|
||||
|
||||
```lua
|
||||
local env = strictness.strict() -- a blank and strict environment for our functions
|
||||
|
||||
-- A function that assigns a value to a variable named "some_var"
|
||||
local function normal_f(value)
|
||||
some_var = value
|
||||
end
|
||||
|
||||
-- Converts the original function to a non-strict one
|
||||
local unstrict_f = strictness.unstrictf(normal_f)
|
||||
|
||||
-- set environments for functions
|
||||
setfenv(normal_f, env)
|
||||
setfenv(unstrict_f, env)
|
||||
|
||||
-- Call the normal function, it should err because its env is strict
|
||||
normal_f("hello") --> produces an error
|
||||
|
||||
-- Call the non-strict function, no error
|
||||
unstrict_f("hello")
|
||||
print(env.some_var) --> "hello
|
||||
````
|
||||
|
||||
Here is an example with Lua 5.2:
|
||||
|
||||
```lua
|
||||
local new_env = {print = print} -- a new env
|
||||
do
|
||||
local _ENV = strictness.strict(new_env) -- sets a new strict env for the do..end scope
|
||||
local function normal_f(value) some_var = value end -- our normal function
|
||||
normal_f(5) --> produces an error, since normal_f cannot write in the strict _ENV
|
||||
end
|
||||
````
|
||||
|
||||
```lua
|
||||
local new_env = {print = print} -- a new env
|
||||
do
|
||||
local _ENV = strictness.strict(new_env) -- sets a new strict env for the do..end scope
|
||||
local function normal_f(value) some_var = value end -- our normal function
|
||||
local unstrict_f = strictness.unstrictf(normal_f) -- the non-strict version of our normal function
|
||||
unstrict_f(5) -- no longer produces error
|
||||
print(some_var) --> 5
|
||||
end
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
### <a name='combo'>Combo functions</a>
|
||||
|
||||
*strictness* also provides two combo functions, `strictness.run_strict` and `strictness.run_unstrict`. Those functions takes a function `f` plus an optional vararg `...` and return the result of the call `f(...)` in strict and non-strict mode respectively.
|
||||
Syntactically speaking, `strictnes.run_strict` is the equivalent to this:
|
||||
|
||||
```lua
|
||||
local strict_f = strictness.strictf(f)
|
||||
strict_f(...)
|
||||
````
|
||||
|
||||
While `strictness.run_unstrict` is a short for:
|
||||
|
||||
```lua
|
||||
local unstrict_f = strictness.unstrictf(f)
|
||||
unstrict_f(...)
|
||||
````
|
||||
|
||||
Here is an example for `strictness.run_strict`:
|
||||
|
||||
```lua
|
||||
local strictness = require 'strictness'
|
||||
|
||||
local env = {} -- an environment
|
||||
|
||||
-- A function that assigns a value to a variable named "some_var"
|
||||
local function normal_f(value) some_var = value end
|
||||
|
||||
setfenv(normal_f, env) -- defines an env for normal_f
|
||||
strictness.run_strict(normal_f, 3) --> produces an error
|
||||
````
|
||||
|
||||
And another example with `strictness.run_unstrict``:
|
||||
|
||||
```lua
|
||||
local strictness = require 'strictness'
|
||||
|
||||
local env = strictness.strict() -- a strict environment
|
||||
|
||||
-- A function that assigns a value to a variable named "some_var"
|
||||
local function normal_f(value) some_var = value end
|
||||
|
||||
setfenv(normal_f, env) -- defines an env for normal_f
|
||||
strictness.run_unstrict`(normal_f, 3) -- no error!
|
||||
print(env.some_var, some_var) --> 3, nil
|
||||
````
|
||||
|
||||
**[[⬆]](#TOC)**
|
||||
|
||||
# <a name='license'>LICENSE</a>
|
||||
|
||||
This work is under [MIT-LICENSE](http://www.opensource.org/licenses/mit-license.php)<br/>
|
||||
*Copyright (c) 2013-2014 Roland Yonaba*.<br/>
|
||||
See [LICENSE](http://github.com/Yonaba/strictness/blob/master/LICENSE).
|
||||
|
||||
**[[⬆]](#TOC)**
|
|
@ -0,0 +1,259 @@
|
|||
#!/usr/bin/env lua
|
||||
------------------
|
||||
-- *strictness, a "strict" mode for Lua*.
|
||||
-- Source on [Github](http://github.com/Yonaba/strictness)
|
||||
-- @author Roland Yonaba
|
||||
-- @copyright 2013-2014
|
||||
-- @license MIT
|
||||
|
||||
local _LUA52 = _VERSION:match('Lua 5.2')
|
||||
local setmetatable, getmetatable = setmetatable, getmetatable
|
||||
local pairs, ipairs = pairs, ipairs
|
||||
local rawget, rawget = rawget, rawget
|
||||
local unpack = _LUA52 and table.unpack or unpack
|
||||
local tostring, select, error = tostring, select, error
|
||||
local getfenv = getfenv
|
||||
|
||||
local _MODULEVERSION = '0.2.0'
|
||||
|
||||
----------------------------- Private definitions -----------------------------
|
||||
|
||||
if _LUA52 then
|
||||
-- Provide a replacement for getfenv in Lua 5.2, using the debug library
|
||||
-- Taken from: http://lua-users.org/lists/lua-l/2010-06/msg00313.html
|
||||
-- Slightly modified to handle f being nil and return _ENV if f is global.
|
||||
getfenv = function(f)
|
||||
f = (type(f) == 'function' and f or debug.getinfo((f or 0) + 1, 'f').func)
|
||||
local name, val
|
||||
local up = 0
|
||||
repeat
|
||||
up = up + 1
|
||||
name, val = debug.getupvalue(f, up)
|
||||
until name == '_ENV' or name == nil
|
||||
return val~=nil and val or _ENV
|
||||
end
|
||||
end
|
||||
|
||||
-- Lua reserved keywords
|
||||
local is_reserved_keyword = {
|
||||
['and'] = true, ['break'] = true, ['do'] = true, ['else'] = true,
|
||||
['elseif'] = true, ['end'] = true, ['false'] = true, ['for'] = true,
|
||||
['function'] = true, ['if'] = true, ['in'] = true, ['local'] = true,
|
||||
['nil'] = true, ['not'] = true, ['or'] = true, ['repeat'] = true,
|
||||
['return'] = true, ['then'] = true, ['true'] = true, ['until'] = true,
|
||||
['while'] = true,
|
||||
}; if _LUA52 then is_reserved_keyword['goto'] = true end
|
||||
|
||||
-- Throws an error if cond
|
||||
local function complain_if(cond, msg, level)
|
||||
return cond and error(msg, level or 3)
|
||||
end
|
||||
|
||||
-- Checks if iden match an valid Lua identifier syntax
|
||||
local function is_identifier(iden)
|
||||
return tostring(iden):match('^[%a_]+[%w_]*$') and
|
||||
not is_reserved_keyword[iden]
|
||||
end
|
||||
|
||||
-- Checks if all elements of vararg are valid Lua identifiers
|
||||
local function validate_identifiers(...)
|
||||
local arg, varnames= {...}, {}
|
||||
for i, iden in ipairs(arg) do
|
||||
complain_if(not is_identifier(iden),
|
||||
('varname #%d "<%s>" is not a valid Lua identifier.')
|
||||
:format(i, tostring(iden)),4)
|
||||
varnames[iden] = true
|
||||
end
|
||||
return varnames
|
||||
end
|
||||
|
||||
-- add true keys in register all keys in t
|
||||
local function add_allowed_keys(t,register)
|
||||
for key in pairs(t) do
|
||||
if is_identifier(key) then register[key] = true end
|
||||
end
|
||||
return register
|
||||
end
|
||||
|
||||
-- Checks if the given arg is callable
|
||||
local function callable(f)
|
||||
return type(f) == 'function' or (getmetatable(f) and getmetatable(f).__call)
|
||||
end
|
||||
|
||||
------------------------------- Module functions ------------------------------
|
||||
|
||||
--- Makes a given table strict. It mutates the passed-in table (or creates a
|
||||
-- new table) and returns it. The returned table is strict, indexing or
|
||||
-- assigning undefined fields will raise an error.
|
||||
-- @function strictness.strict
|
||||
-- @param[opt] t a table
|
||||
-- @param[opt] ... a vararg list of allowed fields in the table.
|
||||
-- @return the passed-in table `t` or a new table, patched to be strict.
|
||||
-- @usage
|
||||
-- local t = strictness.strict()
|
||||
-- local t2 = strictness.strict({})
|
||||
-- local t3 = strictness.strict({}, 'field1', 'field2')
|
||||
local function make_table_strict(t, ...)
|
||||
t = t or {}
|
||||
local has_mt = getmetatable(t)
|
||||
complain_if(type(t) ~= 'table',
|
||||
('Argument #1 should be a table, not %s.'):format(type(t)),3)
|
||||
local mt = getmetatable(t) or {}
|
||||
complain_if(mt.__strict,
|
||||
('<%s> was already made strict.'):format(tostring(t)),3)
|
||||
|
||||
local varnames = v
|
||||
mt.__allowed = add_allowed_keys(t, validate_identifiers(...))
|
||||
mt.__predefined_index = mt.__index
|
||||
mt.__predefined_newindex = mt.__newindex
|
||||
|
||||
mt.__index = function(tbl, key)
|
||||
if not mt.__allowed[key] then
|
||||
if mt.__predefined_index then
|
||||
local expected_result = mt.__predefined_index(tbl, key)
|
||||
if expected_result then return expected_result end
|
||||
end
|
||||
complain_if(true,
|
||||
('Attempt to access undeclared variable "%s" in <%s>.')
|
||||
:format(key, tostring(tbl)),3)
|
||||
end
|
||||
return rawget(tbl, key)
|
||||
end
|
||||
|
||||
mt.__newindex = function(tbl, key, val)
|
||||
if mt.__predefined_newindex then
|
||||
mt.__predefined_newindex(tbl, key, val)
|
||||
if rawget(tbl, key) ~= nil then return end
|
||||
end
|
||||
if not mt.__allowed[key] then
|
||||
if val == nil then
|
||||
mt.__allowed[key] = true
|
||||
return
|
||||
end
|
||||
complain_if(not mt.__allowed[key],
|
||||
('Attempt to assign value to an undeclared variable "%s" in <%s>.')
|
||||
:format(key,tostring(tbl)),3)
|
||||
mt.__allowed[key] = true
|
||||
end
|
||||
rawset(tbl, key, val)
|
||||
end
|
||||
|
||||
mt.__strict = true
|
||||
mt.__has_mt = has_mt
|
||||
return setmetatable(t, mt)
|
||||
|
||||
end
|
||||
|
||||
--- Checks if a given table is strict.
|
||||
-- @function strictness.is_strict
|
||||
-- @param t a table
|
||||
-- @return `true` if the table is strict, `false` otherwise.
|
||||
-- @usage
|
||||
-- local is_strict = strictness.is_strict(a_table)
|
||||
local function is_table_strict(t)
|
||||
complain_if(type(t) ~= 'table',
|
||||
('Argument #1 should be a table, not %s.'):format(type(t)),3)
|
||||
return not not (getmetatable(t) and getmetatable(t).__strict)
|
||||
end
|
||||
|
||||
--- Makes a given table non-strict. It mutates the passed-in table and
|
||||
-- returns it. The returned table is non-strict.
|
||||
-- @function strictness.unstrict
|
||||
-- @param t a table
|
||||
-- @usage
|
||||
-- local unstrict_table = strictness.unstrict(trict_table)
|
||||
local function make_table_unstrict(t)
|
||||
complain_if(type(t) ~= 'table',
|
||||
('Argument #1 should be a table, not %s.'):format(type(t)),3)
|
||||
if is_table_strict(t) then
|
||||
local mt = getmetatable(t)
|
||||
if not mt.__has_mt then
|
||||
setmetatable(t, nil)
|
||||
else
|
||||
mt.__index, mt.__newindex = mt.__predefined_index, mt.__predefined_newindex
|
||||
mt.__strict, mt.__allowed, mt.__has_mt = nil, nil, nil
|
||||
mt.__predefined_index, mt.__predefined_newindex = nil, nil
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
--- Creates a strict function. Wraps the given function and returns the wrapper.
|
||||
-- The new function will always run in strict mode in its environment, whether
|
||||
-- or not this environment is strict.
|
||||
-- @function strictness.strictf
|
||||
-- @param f a function, or a callable value.
|
||||
-- @usage
|
||||
-- local strict_f = strictness.strictf(a_function)
|
||||
-- local result = strict_f(...)
|
||||
local function make_function_strict(f)
|
||||
complain_if(not callable(f),
|
||||
('Argument #1 should be a callable, not %s.'):format(type(f)),3)
|
||||
return function(...)
|
||||
local ENV = getfenv(f)
|
||||
local was_strict = is_table_strict(ENV)
|
||||
if not was_strict then make_table_strict(ENV) end
|
||||
local results = {f(...)}
|
||||
if not was_strict then make_table_unstrict(ENV) end
|
||||
return unpack(results)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a non-strict function. Wraps the given function and returns the wrapper.
|
||||
-- The new function will always run in non-strict mode in its environment, whether
|
||||
-- or not this environment is strict.
|
||||
-- @function strictness.unstrictf
|
||||
-- @param f a function, or a callable value.
|
||||
-- @usage
|
||||
-- local unstrict_f = strictness.unstrictf(a_function)
|
||||
-- local result = unstrict_f(...)
|
||||
local function make_function_unstrict(f)
|
||||
complain_if(not callable(f),
|
||||
('Argument #1 should be a callable, not %s.'):format(type(f)),3)
|
||||
return function(...)
|
||||
local ENV = getfenv(f)
|
||||
local was_strict = is_table_strict(ENV)
|
||||
make_table_unstrict(ENV)
|
||||
local results = {f(...)}
|
||||
if was_strict then make_table_strict(ENV) end
|
||||
return unpack(results)
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the result of a function call in strict mode.
|
||||
-- @function strictness.run_strict
|
||||
-- @param f a function, or a callable value.
|
||||
-- @param[opt] ... a vararg list of arguments to function `f`.
|
||||
-- @usage
|
||||
-- local result = strictness.run_strict(a_function, arg1, arg2)
|
||||
local function run_strict(f,...)
|
||||
complain_if(not callable(f),
|
||||
('Argument #1 should be a callable, not %s.'):format(type(f)),3)
|
||||
return make_function_strict(f)(...)
|
||||
end
|
||||
|
||||
--- Returns the result of a function call in non-strict mode.
|
||||
-- @function strictness.run_unstrict
|
||||
-- @param f a function, or a callable value.
|
||||
-- @param[opt] ... a vararg list of arguments to function `f`.
|
||||
-- @usage
|
||||
-- local result = strictness.run_unstrict(a_function, arg1, arg2)
|
||||
local function run_unstrict(f,...)
|
||||
complain_if(not callable(f),
|
||||
('Argument #1 should be a callable, not %s.'):format(type(f)),3)
|
||||
return make_function_unstrict(f)(...)
|
||||
end
|
||||
|
||||
return {
|
||||
strict = make_table_strict,
|
||||
unstrict = make_table_unstrict,
|
||||
is_strict = is_table_strict,
|
||||
strictf = make_function_strict,
|
||||
unstrictf = make_function_unstrict,
|
||||
run_strict = run_strict,
|
||||
run_unstrict = run_unstrict,
|
||||
_VERSION = 'strictness v'.._MODULEVERSION,
|
||||
_URL = 'http://github.com/Yonaba/strictness',
|
||||
_LICENSE = 'MIT <http://raw.githubusercontent.com/Yonaba/strictness/master/LICENSE>',
|
||||
_DESCRIPTION = 'Tracking accesses and assignments to undefined variables in Lua code'
|
||||
}
|
Loading…
Reference in New Issue