func-deleglate
Function arguments validate and call chainning
Usage
npm install func-delegate --save
describe("func-delegate", function() { describe("#normal-only-type", function() { var add = function(a, b) { return a + b; }; add = delegate(add, [{ name: 'num1', type: Number }, { name: 'num2', type: Number }]); it("Type assert", function(done) { assert.ok(add instanceof Function, '处理后的仍然是一个函数'); assert.ok(add.num1 instanceof Function, '接收参数的函数 num1'); assert.ok(add.num2 instanceof Function, '接收参数的函数 num2'); done(); }); it("exec assert", function(done) { assert.equal(3, add(1, 2), '正常执行'); assert.equal(3, add.num1(1).num2(2).exec(), '链式调用'); done(); }); it("Exception assert", function(done) { assert.throws(function() { add(1, '2'); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }, 'Num2 is string'); assert.throws(function() { add.num2('2').num1(1).exec(); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }, '链式调用 num2 is string') assert.throws(function() { add.num1(1).num2('2').exec(); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }, '链式调用 num2 是 string, 顺序无关') done(); }); }); describe("#validate allowNull", function() { var add = function(a, b, sqrt) { var sum = a + b; if (sqrt === true) { return Math.sqrt(sum); } else { return sum; } }; add = delegate(add, [{ name: 'num1', type: Number }, { name: 'num2', type: Number }, { name: 'sqrt', type: Boolean, allowNull: true }]); it("type assert", function(done) { assert.ok(add instanceof Function, '处理后的仍然是一个函数'); assert.ok(add.num1 instanceof Function, 'num1 是接收参数的函数'); assert.ok(add.num2 instanceof Function, 'num2 是接收参数的函数'); assert.ok(add.sqrt instanceof Function, 'sqrt 是接收参数的函数'); done(); }); it("exec assert", function(done) { assert.equal(3, add(1, 2), '普通调用,缺失 sqrt 参数'); assert.equal(16, add.num1(7).num2(9).exec(), '链式执行缺失 sqrt 参数'); assert.equal(4, add.num1(7).num2(9).sqrt(true).exec(), '链式执行 sqrt true'); assert.equal(16, add.num1(7).num2(9).sqrt(false).exec(), 'sqrt false'); assert.equal(16, add.sqrt(false).num1(7).num2(9).exec(), '顺序无关'); done(); }); it("Exception assert", function(done) { assert.throws(function() { add(1, '2'); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }); assert.throws(function() { add.num2('2').num1(1).exec(); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }) assert.throws(function() { add.num1(1).num2('2').exec(); }, function(err) { return (err instanceof Error) && err.message === 'Argument `num2` type must be `Number`'; }) assert.throws(function() { add.num1(1).num2(2).sqrt('hello').exec(); }, function(err) { return (err instanceof Error) && err.message === 'Argument `sqrt` type must be `Boolean`'; }) done(); }); }); describe("#validate rule and defaultValue", function() { var person = function(name, email, age) { return { name: name, email: email, age: age }; }; person = delegate(person, [{ name: 'Name', type: String, validate: { matches: /^赵/, length: function(v) { return v.length > 1 && v.length < 4; } }, message: 'Name must be a string, start with `赵`, lenght gt 1 and lt 4' }, { name: 'email', type: String, validate: { isEmail: true } }, { name: 'age', type: Number, defaultValue: 18, allowNull: true, validate: { max: 200 }, message: "Age must be a number, max value is 200, default is 18" }]); it("Type assert", function(done) { assert.ok(person instanceof Function, '处理后的仍然是一个函数'); assert.ok(person.Name instanceof Function, 'Name'); assert.ok(person.email instanceof Function, 'email'); assert.ok(person.age instanceof Function, 'age'); done() }); it("exec assert", function(done) { assert.deepEqual({ email: '13740080@qq.com', name: '赵雄飞', age: 18 }, person('赵雄飞', '13740080@qq.com')); assert.deepEqual({ email: '13740080@qq.com', name: '赵雄飞', age: 18 }, person.Name('赵雄飞').email('13740080@qq.com').exec()); assert.deepEqual({ email: '13740080@qq.com', name: '赵雄飞', age: 36 }, person.Name('赵雄飞').email('13740080@qq.com').age(36).exec()); done() }); it("Exception assert", function(done) { assert.throws(function() { person('王方', '223251686@qq.com') }, function(err) { return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4' }); assert.throws(function() { person('赵导耳机', '223251686@qq.com') }, function(err) { return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4' }); assert.throws(function() { person.Name('王方').email('223251686@qq.com').exec(); }, function(err) { return (err instanceof Error) && err.message === 'Name must be a string, start with `赵`, lenght gt 1 and lt 4' }) assert.throws(function() { person.Name('赵星梦').email('223251686').exec(); }, function(err) { return (err instanceof Error) && err.message === '`email` validate failure: isEmail' }) done(); }); }); describe("#iterator validate", function() { var lib = function(books) { return { books: books, size: books.length }; }; lib = delegate(lib, [{ name: 'books', type: Array, iterator: { name: { type: String, allowNull: false, validate: { length: [1, 20] }, message: '书名必填是字符串,长度为 1 - 20' }, price: { type: Number, allowNull: true, validate: { max: 300, min: 10 }, message: '价格选填,数字类型,最大 300, 最小 10' } } }]); it("Type assert", function(done) { assert.ok(lib instanceof Function, '处理后的仍然是一个函数'); assert.ok(lib.books instanceof Function, 'books 是接收参数的函数'); assert.ok(lib.exec instanceof Function, 'exec 是执行函数'); done() }); it("exec assert", function(done) { assert.deepEqual({ books: [{ name: 'JavaScript 权威指南', price: 35.26 }, { name: 'MySQL 性能优化' }], size: 2 }, lib([{name: 'JavaScript 权威指南', price: 35.26}, {name: 'MySQL 性能优化'}])) assert.deepEqual({ books: [{ name: 'JavaScript 权威指南', price: 35.26 }, { name: 'MySQL 性能优化' }], size: 2 }, lib.books([{name: 'JavaScript 权威指南', price: 35.26}, {name: 'MySQL 性能优化'}]).exec()); done() }); it("Exception assert", function(done) { assert.throws(function() { lib('hello world'); }, function(err) { return (err instanceof Error) && err.message === 'Argument `books` type must be `Array`' }, '参数类型错误'); assert.throws(function() { lib([{name: []}]); }, function(err) { return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20' }, 'iterator 里类型错误'); assert.throws(function() { lib.books([{name: 'Hello world', price: 'Redstone'}]).exec(); }, function(err) { return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10' }, 'iterator 价格类型不对'); assert.throws(function() { lib.books([{name: 'Hello world', price: 500}]).exec(); }, function(err) { return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10' }, 'iterator 价格类型不对'); assert.throws(function() { lib.books([{name: 'Hello world', price: 5}]).exec(); }, function(err) { return (err instanceof Error) && err.message === '价格选填,数字类型,最大 300, 最小 10' }, 'iterator 价格类型不对'); assert.throws(function() { lib.books([{name: 'Hello world'}, {name: []}]).exec(); }, function(err) { return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20' }, 'iterator 时某些数据的类型不正确'); assert.throws(function() { lib.books([{name: 'Hello world Hello world Hello world Hello world'}]).exec(); }, function(err) { return (err instanceof Error) && err.message === '书名必填是字符串,长度为 1 - 20' }, 'iterator 内书名超出长度'); done(); }); });});