Skip to content

Commit

Permalink
feat: Adds some and every functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mblarsen committed Oct 20, 2017
1 parent f2c24b0 commit fe41e6b
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Note: policies takes precedence over rules.
- [rule](#rule)
- [policy](#policy)
- [can](#can)
- [some](#some)
- [every](#every)
- [mixin](#mixin)
- [subjectMapper](#subjectmapper)

Expand Down Expand Up @@ -138,12 +140,48 @@ the mixin:

Returns **any** Boolean

### some

Like can but subject is an array where only some has to be
true for the rule to match.

Note the subjects do not need to be of the same kind.

**Parameters**

- `user` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `verb`
- `subjects` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<([Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))>**
- `args` **...any** Any other param is passed into rule

Returns **any** Boolean

### every

Like can but subject is an array where all has to be
true for the rule to match.

Note the subjects do not need to be of the same kind.

**Parameters**

- `user` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `verb`
- `subjects` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)<([Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))>**
- `args` **...any** Any other param is passed into rule

Returns **any** Boolean

### mixin

Mix in augments your user class with a `can` function. This
Mix in augments your user class with a `can` function object. This
is optional and you can always call `can` directly on your
Acl instance.

user.can()
user.can.some()
user.can.every()

**Parameters**

- `User` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)** A user class or contructor function
Expand Down
47 changes: 46 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,50 @@ class Acl {

return Boolean(rules[verb])
}

/**
* Like can but subject is an array where only some has to be
* true for the rule to match.
*
* Note the subjects do not need to be of the same kind.
*
* @access public
* @param {Object} user
* @param {Array<Function|Object|string>} subjects
* @param {...*} args Any other param is passed into rule
* @return Boolean
*/
some(user, verb, subjects, ...args) {
return subjects.some(s => this.can(user, verb, s, ...args))
}

/**
* Like can but subject is an array where all has to be
* true for the rule to match.
*
* Note the subjects do not need to be of the same kind.
*
* @access public
* @param {Object} user
* @param {Array<Function|Object|string>} subjects
* @param {...*} args Any other param is passed into rule
* @return Boolean
*/
every(user, verb, subjects, ...args) {
return subjects.every(s => this.can(user, verb, s, ...args))
}

/**
* Mix in augments your user class with a `can` function. This
* Mix in augments your user class with a `can` function object. This
* is optional and you can always call `can` directly on your
* Acl instance.
*
* ```
* user.can()
* user.can.some()
* user.can.every()
* ```
*
* @access public
* @param {Function} User A user class or contructor function
*/
Expand All @@ -141,6 +180,12 @@ class Acl {
User.prototype.can = function () {
return acl.can(this, ...arguments)
}
User.prototype.can.every = function () {
return acl.every(this, ...arguments)
}
User.prototype.can.some = function () {
return acl.some(this, ...arguments)
}
}

/**
Expand Down
51 changes: 51 additions & 0 deletions test/Acl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,57 @@ describe('The basics', () => {
})
})

describe('Multiple', () => {
test('Can eat some apples', () => {
const acl = new Acl()
acl.mixin(User)
acl.rule('eat', Apple, (_, a) => !Boolean(a.rotten))
const user = new User()
const fine = new Apple()
const rotten = new Apple()
rotten.rotten = true
expect(user.can('eat', fine)).toBe(true)
expect(user.can('eat', rotten)).toBe(false)
expect(acl.some(user, 'eat', [fine, rotten])).toBe(true)
expect(acl.some(user, 'eat', [rotten, rotten])).toBe(false)
})

test('Can eat some apples and jobs', () => {
const acl = new Acl()
acl.rule('eat', Apple)
acl.rule('eat', Job)
const user = new User()
expect(acl.can(user, 'eat', new Apple())).toBe(true)
expect(acl.can(user, 'eat', new Job())).toBe(true)
expect(acl.some(user, 'eat', [new Apple(), new Job()])).toBe(true)
})

test('Can eat every apple', () => {
const acl = new Acl()
acl.mixin(User)
acl.rule('eat', Apple, (_, a) => !Boolean(a.rotten))
const user = new User()
const fine = new Apple()
const rotten = new Apple()
rotten.rotten = true
expect(user.can('eat', fine)).toBe(true)
expect(user.can('eat', rotten)).toBe(false)
expect(acl.every(user, 'eat', [fine, rotten])).toBe(false)
expect(acl.every(user, 'eat', [fine, new Apple()])).toBe(true)
})

test('User can eat some apples', () => {
const acl = new Acl()
acl.mixin(User)
acl.rule('eat', Apple, (_, a) => !Boolean(a.rotten))
const user = new User()
const fine = new Apple()
const rotten = new Apple()
rotten.rotten = true
expect(user.can.some('eat', [fine, rotten])).toBe(true)
})
})

describe('Strict mode', () => {
test('Throws on unknown verb', () => {
const acl = new Acl({strict: true})
Expand Down

0 comments on commit fe41e6b

Please sign in to comment.