diff --git a/lib/ArgVerifier.js b/lib/ArgVerifier.js index e181954..8856fe2 100644 --- a/lib/ArgVerifier.js +++ b/lib/ArgVerifier.js @@ -3,9 +3,12 @@ var topiarist = require('topiarist'); function verifierMethod(verifier, methodName) { return function() { - if(this.argValue === undefined) throw new ArgumentError(this.argName + ' argument must be provided.'); + if(!this.skipVerification) { + if(this.argValue === undefined) throw new ArgumentError(this.argName + ' argument must be provided.'); + + verifier[methodName].apply(this, arguments); + } - verifier[methodName].apply(this, arguments); return this.argsVerifier; }; } @@ -22,4 +25,14 @@ ArgVerifier.addVerifier = function(verifier) { } }; +Object.defineProperty(ArgVerifier.prototype, 'optionally', { + get: function optionally() { + if((this.argValue === undefined) || (this.argValue === null)) { + this.skipVerification = true; + } + + return this; + } +}); + module.exports = ArgVerifier; diff --git a/package.json b/package.json index 5bffdbb..676cc12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typester", - "version": "0.1.1", + "version": "0.2.0", "description": "Fluent type verification for JavaScript", "main": "lib/typester.js", "dependencies": { diff --git a/spec/test/typester.js b/spec/test/typester.js index c1f1612..d579833 100644 --- a/spec/test/typester.js +++ b/spec/test/typester.js @@ -5,41 +5,63 @@ var ArgumentError = typester.ArgumentError; describe('typester', function() { it('throws an ArgumentError if we try to validate a non-existent argument', function() { function func() { - using([]) + using(arguments) .verify('num').isA(Number); } func.should.throw('num argument must be provided'); func.should.throw(ArgumentError); + func.bind(func, 10).should.not.throw(); }); - it('works with real function argument arrays', function() { + it('throws an ArgumentError if we try to validate a subsequent non-existent argument', function() { function func() { using(arguments) + .verify('bool').isA(Boolean) .verify('num').isA(Number); } - func.bind(func, undefined).should.throw(ArgumentError); - func.bind(func, 10).should.not.throw(); + func.bind(func, true).should.throw('num argument must be provided'); + func.bind(func, true).should.throw(ArgumentError); + func.bind(func, true, 10).should.not.throw(); }); - it('throws an ArgumentError if we try to validate a subsequent non-existent argument', function() { + it('throws a TypeError if we try to validate a provided argument is of the wrong type', function() { function func() { using([true]) - .verify('bool').isA(Boolean) .verify('num').isA(Number); } - func.should.throw('num argument must be provided'); - func.should.throw(ArgumentError); + func.should.throw(TypeError); + func.should.throw('num argument must be a Number'); }); - it('throws a TypeError if we try to validate a provided argument is of the wrong type', function() { + it('does not require optional arguments to be provided, but throws if they are incorrect', function() { function func() { - using([true]) - .verify('num').isA(Number); + using(arguments) + .verify('bool').isA(Boolean) + .verify('num').optionally.isA(Number); } - func.should.throw(TypeError); + func.bind(func, true).should.not.throw(); + func.bind(func, true, 10).should.not.throw(); + func.bind(func, true, '10').should.throw(TypeError); + func.bind(func, true, '').should.throw(TypeError); + func.bind(func, true, []).should.throw(TypeError); + }); + + it('allows mandatory arguments to appear after an optional argument', function() { + function func() { + using(arguments) + .verify('num').optionally.isA(Number) + .verify('bool').isA(Boolean); + } + + func.bind(func, null, true).should.not.throw(); + func.bind(func, undefined, true).should.not.throw(); + func.bind(func, null).should.throw(ArgumentError); + func.bind(func, null, {}).should.throw(TypeError); + func.bind(func, '10', true).should.throw(TypeError); + func.bind(func, '10', true).should.throw('num argument must be a Number'); }); });