Code contracts for javascript - implemented through a series of precondition validators.
Install the module with: npm install handshake
var handshake = require('handshake');
handshake.preconditions(true, 'myVar').isTrue(); // "does not throw"
handshake.preconditions(false, 'myVar').isTrue(); // "throws"
Download the production version or the development version.
In your web page:
<script src="dist/handshake.min.js"></script>
<script>
preconditions(true, 'myVar').isTrue(); // "does not throw"
preconditions(false, 'myVar').isTrue(); // "throws"
</script>
In your code, you can attach handshake's methods to any object.
<script>
this.exports = Bocoup.utils;
</script>
<script src="dist/handshake.min.js"></script>
<script>
Bocoup.utils.preconditions(true, 'myVar').isTrue(); // "does not throw"
Bocoup.utils.preconditions(false, 'myVar').isTrue(); // "throws"
</script>
Preconditions are a method of ensuring that you can trust your inputs, they act as a barrier between untrusted calls to your methods and the script internals.
Setting up a precondition is simple
var foo = 'foo';
function myMethod(value) {
handshake.precondition(value, 'values name').isNotNullOrUndefined();
// we can now trust value will never be null or undefined.
return value;
}
myMethod(foo);
myMethod(null); // will throw.
myMethod(); // will throw.
Preconditions required you to at least provide a value to validate but also will take a name for the attribute
precondition('foo','myFoo') // value is 'foo' argument name is 'myFoo'
The argument name is used in the default error messages.
It is suggested that you handle these exceptions in a sensible way, for example on the server logging them or on the browser using an alert (in development) or alternate means in a production environment.
The following conditions can be applied as a precondition of an argument.
isNotNullOrUndefined()
- will throw if the value isnull
orundefined
.isNotNull()
- will throw if the value isnull
.isNotUndefined()
- will throw is the value isundefined
.isNotEmpty()
- will throw if the value does not have alength
attribute or if that attribute returns a length of less than 1.isString()
- will throw if the value is not of typestring
.isInt()
- will throw if the value is not of typeint
.isBoolean()
- will throw if the value is not of typebool
.isArray()
- will throw if the value is not anarray
type.isTrue()
- will throw if the value is nottrue
, this will not allow truthy values (since these are a path to madness).isFalse()
- will throw if the value is notfalse
.
All methods can be chained like so:
precondition('foo').isNotNullOrUndefined().isString().isNotEmpty()
Preconditions will fail fast so it best practice to use the most general condition to least.
There are sensible defaults for error messages but should you wish to change them the conditions will accept a string with a new message.
precondition('').isNotEmpty('Argument: foo should have been filled in
);`
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using grunt.
Also, please don't edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "lib" subdirectory!
(Nothing yet - pre beta - here be dragons.)
Copyright (c) 2012 Stephen Binns
Licensed under the MIT license.