diff --git a/README.md b/README.md index 2bbf78d..34fb32e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ bower i -S guard npm i -S guard-bit ``` ### File -Save [guard.min.js](https://raw.githubusercontent.com/iofjuupasli/guard/v1.0.3/guard.min.js) or [guard.js](https://raw.githubusercontent.com/iofjuupasli/guard/v1.0.3/guard.js) to your assets folder +Save [guard.min.js](https://raw.githubusercontent.com/iofjuupasli/guard/v1.0.4/guard.min.js) or [guard.js](https://raw.githubusercontent.com/iofjuupasli/guard/v1.0.4/guard.js) to your assets folder Examples ============= @@ -151,7 +151,7 @@ guard(function (message) { // level === 1 guard('@:profile:read', function () { console.log('My Profile'); -})(); // 'My Profile' immediately +})(); // 'My Profile' immediately (but async) guard('adminFeature', function () { console.log('called!'); diff --git a/bower.json b/bower.json index 67ce4a2..6178b11 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "guard", "description": "Utility to split opportunities by the account level (free\\pro\\enterprise\\etc.) for frontend and node", "main": "guard.js", - "version": "1.0.3", + "version": "1.0.4", "homepage": "https://github.com/iofjuupasli/guard", "authors": [ "iofjuupasli " diff --git a/guard.js b/guard.js index 6cb64d2..be90e07 100644 --- a/guard.js +++ b/guard.js @@ -52,17 +52,23 @@ function reqThenCallback(feature, callback) { return function () { - if (!config[level].request) { + var args = arguments; + if (checkAccess(feature)) { + setTimeout(function () { + callback.apply(null, args); + }, 0); return; } - var args = arguments; requestQueue.push(callback); if (isRequesting) { return; - } else { - isRequesting = true; } - config[level].request(function (err) { + isRequesting = true; + if (config[level].request) { + config[level].request(requestHandler); + } + + function requestHandler(err) { isRequesting = false; if (err) { requestQueue = []; @@ -70,14 +76,14 @@ } guard.setLevel(level + 1); while (requestQueue.length) { - if (feature) { - guard(feature, requestQueue.shift()) - .apply(null, args); + var nextRequest = requestQueue.shift(); + if (feature != null) { + guard(feature, nextRequest).apply(null, args); } else { - guard(requestQueue.shift()).apply(null, args); + guard(nextRequest).apply(null, args); } } - }); + } }; } @@ -87,11 +93,7 @@ } if (arguments.length === 1) { if (_.isFunction(arguments[0])) { - if (checkAccess()) { - return arguments[0]; - } else { - return reqThenCallback(null, arguments[0]); - } + return reqThenCallback(null, arguments[0]); } else { return checkAccess(arguments[0]); } @@ -99,11 +101,7 @@ if (!_.isFunction(arguments[1])) { throw new TypeError(); } - if (checkAccess(arguments[0])) { - return arguments[1]; - } else { - return reqThenCallback(arguments[0], arguments[1]); - } + return reqThenCallback(arguments[0], arguments[1]); }; guard.request = function (callback) { diff --git a/guard.min.js b/guard.min.js index 2c60268..8cbe91c 100644 --- a/guard.min.js +++ b/guard.min.js @@ -1 +1 @@ -(function(root,factory){"use strict";if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{root.Guard=factory()}})(this,function(){"use strict";return function(initConfig){var level=0;var config;var listeners=[];var isRequesting=false;var requestQueue=[];var _={isFunction:function(value){return typeof value=="function"},isArray:function(value){return Array.isArray(value)},isRegExp:function(value){return value instanceof RegExp}};function checkAccess(requestRule){if(!requestRule){return level>0}return function(){for(var i=0;i<=level;i++){var rules=config[i].allowed;for(var j=0;j0}return function(){for(var i=0;i<=level;i++){var rules=config[i].allowed;for(var j=0;j0 level', function () { guard('one').should.be.false; @@ -181,11 +200,14 @@ describe('guard', function () { guard('one').should.be.true; }); it('request for 2 level when request for 2 level rule', - function () { + function (done) { + var spy = chai.spy(function () { + levelZeroReqSpy.should.not.have.been.called(); + levelOneReqSpy.should.have.been.called.once; + spy.should.have.been.called.once; + done(); + }); guard('two', spy)(); - levelZeroReqSpy.should.not.have.been.called(); - levelOneReqSpy.should.have.been.called.once; - spy.should.have.been.called.once; }); it('forbids rules on >1 level', function () { guard('two').should.be.false; @@ -198,131 +220,15 @@ describe('guard', function () { guard.bind(null, 'rule', 'invalidType').should.throw(TypeError); }); }); - - /// OLD TESTS - it('should forbid on 0 level w/o feature specified', function () { - var guard = Guard(); - guard().should.be.false; - }); - it('should allow on > 0 level w/o feature specified', function () { - var guard = Guard(); - guard.setLevel(1); - guard().should.be.true; - }); - it('with any rule should forbidden by default', function () { - var guard = Guard(); - guard('anyRule').should.be.false; - }); - it('with any rule should be allowed when authorized', function () { - var guard = Guard(); - guard.setLevel(1); - guard('anyRule').should.be.true; - }); - it('should ignore callback on 0 level', function () { - var guard = Guard(); - var spy = chai.spy(noop); - guard(spy)(); - spy.should.have.not.been.called(); - }); - it('should call callback on > 0 level', function () { - var guard = Guard(); - var spy = chai.spy(noop); - guard.setLevel(1); - guard(spy)(); - spy.should.have.been.called.once; - }); - it('should increase level when next level request success', - function () { - var requestSpy = chai.spy(successRequest); - var guard = Guard(requestSpy); - guard.getLevel().should.equal(0); - guard.request(); - requestSpy.should.have.been.called(); - guard.getLevel().should.equal(1); - }); - it('should save level when next level request fails', function () { - var requestSpy = chai.spy(failRequest); - var guard = Guard(requestSpy); - guard.getLevel().should.equal(0); - guard.request(); - requestSpy.should.have.been.called(); - guard.getLevel().should.equal(0); - }); - it('should return private callback if authorized', function () { - var requestSpy = chai.spy(successRequest); - var guard = Guard(requestSpy); - guard.request(); - requestSpy.should.have.been.called(); - guard(noop).should.equal(noop); - }); - it('should calls private callback after request', function () { - var requestSpy = chai.spy(successRequest); - var guard = Guard(requestSpy); - var spy = chai.spy(noop); - guard(spy)(); - requestSpy.should.have.been.called.once; - spy.should.have.been.called.once; - }); - it('shouldn\'t call request when already requesting', function (done) { - var requestSpy = chai.spy(asyncSuccess); - var guard = Guard(requestSpy); - var spy = chai.spy(function () { - spy.should.have.been.called.once; - }); - guard(spy)(); - requestSpy.should.have.been.called.once; - var secondCallbackSpy = chai.spy(function () { - spy.should.have.been.called.once; - requestSpy.should.have.been.called.once; - secondCallbackSpy.should.have.been.called.once; - done(); - }); - guard(secondCallbackSpy)(); - }); - it('should call request and then callback if feature not allowed', - function () { - var requestSpy = chai.spy(successRequest); - var guard = Guard(requestSpy); - var spy = chai.spy(noop); - guard('check', spy)(); - spy.should.have.been.called.once; - requestSpy.should.have.been.called.once; - }); - it('should throw when args invalid', function () { - var guard = Guard(); - guard.bind(null, 'anyRule', 'invalidType').should.throw(TypeError); - }); - it('should ignore rest args', function () { - Guard(successRequest) - .bind(null, 'anyRule', noop, 'else').should.not.throw(); - }); - it('should call all request on path to private feature', function () { - var firstRequest = chai.spy(successRequest); - var secondRequest = chai.spy(successRequest); - var guard = Guard([{ - allowed: [], - request: firstRequest - }, { - allowed: [], - request: secondRequest - }, { - allowed: ['*'] - }]); - var spy = chai.spy(noop); - guard('private', spy)(); - firstRequest.should.have.been.called.once; - secondRequest.should.have.been.called.once; - spy.should.have.been.called.once; - }); }); describe('constructor', function () { - it('should use "*" rule as any regexp', function () { + it('uses "*" rule as any regexp', function () { var guard = Guard([{ allowed: ['one.*.three'] }]); guard('one.two.three').should.be.true; }); - it('should use regexp for rules', function () { + it('uses regexp for rules', function () { var guard = Guard([{ allowed: [/(one|two)/] }]); @@ -332,14 +238,14 @@ describe('guard', function () { }); }); describe('listen', function () { - it('should call listeners on level change', function () { + it('calls listeners on level change', function () { var guard = Guard(); var spy = chai.spy(noop); guard.listen(spy); guard.setLevel(1); spy.should.have.been.called.once; }); - it('shouldn\'t call listeners after unsubscribe', function () { + it('doesn\'t call listeners after unsubscribe', function () { var guard = Guard(); var spy = chai.spy(noop); var unsubscribe = guard.listen(spy); @@ -347,7 +253,7 @@ describe('guard', function () { guard.setLevel(1); spy.should.have.not.been.called; }); - it('should unsubscribe only once', function () { + it('unsubscribes only once', function () { var guard = Guard(); var spy = chai.spy(noop); var unsubscribe = guard.listen(spy); @@ -358,16 +264,26 @@ describe('guard', function () { }); }); describe('request', function () { - it('should throw when invalid args', function () { + it('throws when invalid args', function () { Guard().request .bind(null, 'shouldBeAFunction').should.throw(TypeError); }); - it('should request then call callback', function () { + it('requests then call callback', function (done) { var guard = Guard(successRequest); - var spy = chai.spy(noop); + var spy = chai.spy(function () { + spy.should.have.been.called.once; + guard.getLevel().should.equal(1); + done(); + }); guard.request(spy); - spy.should.have.been.called.once; - guard.getLevel().should.equal(1); + }); + it('requests w/o callback', function (done) { + var guard = Guard(successRequest); + guard.request(); + setTimeout(function () { + guard.getLevel().should.equal(1); + done(); + }, 0); }); }); });