Skip to content

Instantly share code, notes, and snippets.

@NuckChorris
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NuckChorris/61c5e8b1d990d5ab34fc to your computer and use it in GitHub Desktop.
Save NuckChorris/61c5e8b1d990d5ab34fc to your computer and use it in GitHub Desktop.
Contracts implemented in ~25 LOC
/*
* Released under the MIT License
*
* Copyright (c) 2014 Peter Lejeck
*
* 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.
*/
/**
* Tests an assertion
* @private
*/
function _assert (assertion, args, msg, src, cond) {
let result = assertion(...args);
let message = cond + 'Condition failed for ';
message += src ? 'function "' + src + '"' : 'Anonymous Function';
message += ': ' + msg;
throw new Error(message);
}
/**
* Generates a fallback message using the function return statement
* @private
*/
function _functionMessage (fn) {
let str = fn.toString();
let returnStart = str.indexOf('return') + 'return '.length;
let returnEnd = str.indexOf(';', returnStart) || str.indexOf('}', returnStart);
return str.substring(returnStart, returnEnd).trim();
}
/**
* Ensure a function's return value is valid
*
* If the function ever returns a value which the fn returns false for,
* execution is interrupted (by an error) and the msg is displayed in the
* console. If there is no msg provided, one will be generated from the return
* statement in the assertion body.
*/
Function.prototype.ensures = function ensures (fn, msg = null) {
if (msg == null) msg = _functionMessage(fn);
return () => {
let ret = this(...arguments);
_assert(fn, [ret], msg, this.name, 'Post');
return ret;
};
};
/**
* Requires that a parameter is valid
*
* If the function ever recieves a value which the fn returns false for,
* execution is interrupted (by an error) and the msg is displayed in the
* console. If there is no msg provided, one will be generated from the return
* statement in the assertion body.
*/
function requires (fn, msg = null) {
if (msg == null) msg = functionMessage(fn);
_assert(fn, [], msg, arguments.caller.name, 'Pre');
}
import requires from 'contracts-development.js';
// Will error with "PostconditionFailed: r != false"
var failure = function failure () {
return false;
}.ensures((r)=> r != false)
failure();
// And have some preconditions
var failure = function failure (a, b) {
requires(()=> a > b);
return a - b;
};
failure(1, 5);
Function.prototype.ensures = function ensures () { return this; };
export default function requires () {};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment