master
Sven Slootweg 9 years ago
parent dc2442976b
commit 9463665252

@ -8,6 +8,12 @@ While the examples in this documentation will show usage for a permission system
[WTFPL](http://www.wtfpl.net/txt/copying/) or [CC0](https://creativecommons.org/publicdomain/zero/1.0/), whichever you prefer.
## Donate
My income consists entirely of donations for my projects. If this module is useful to you, consider [making a donation](http://cryto.net/~joepie91/donate.html)!
You can donate using Bitcoin, PayPal, Gratipay, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else.
## Contributing
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you're editing the `.coffee` files, not the `.js` files.
@ -94,3 +100,95 @@ user.save(); // Done! The inheritance structure will persist, even through datab
```
In this example, `getValue()` will return the effective value (ie. all flags that are set), while `getOriginalValue()` will only return a value consisting of the *explicitly* set flags. This second value is what is used to keep track of inherited permissions, and should be passed as a second argument to `.create` when creating a new value.
## API
### bitmaskFlags(flagMap)
Returns a new bitmaskFlags instance with the given `flagMap`. The `flagMap` is an object that maps flag names to values and, optionally, inheritances.
Each value in the `flagMap` object can either be an object with options, or a number directly. All values should be powers of two. See the Example section for a usage example.
An Error is thrown if there is a problem with the flagMap; eg. one of the values is not a power of two, or one of the inheritances refers to a non-existent flag.
The rest of the API documentation will refer to the returned value as `flagHandler`.
### flagHandler.create([initialValue, [initialOriginalValue]])
Creates a new value.
* __initialValue__: The initial value it should be set to. This is typically the current value from a database. Defaults to 0 (no flags set).
* __initialOriginalValue__: The initial 'original value', when using flag inheritance. This is the value that represents the *explicitly* set flags, so that they are not automatically unset through inheritance. Leaving this out will make inheritance very unpleasant to work with; however, if you do not use inheritance, you can omit this option. __For a 'blank' value, you *must* explicitly set this to 0.__
The rest of the API documentation will refer to the returned value as `flagValue`.
### flagHandler.setFlagMap(flagMap)
Replaces the current `flagMap` of the handler with a new one. The same sanity checks are performed as for `bitmaskFlags(flagMap)`, and the same input is accepted.
### flagHandler.getflagMap()
Returns the current `flagMap`.
### flagHandler.getInheritedFlags(flag)
Returns an array of flags that inherited from the specified flag.
* __flag__: The name of the flag to return the inheritances for. An Error is thrown if it does not exist.
### flagHandler.getFlagValue(flag)
Returns the internal bitmask value for the specified flag. This is the value originally specified in the `flagMap`.
*You almost certainly won't need this; look at the `flagValue` API methods instead.*
* __flag__: The flag to return the internal bitmask value for. An Error is thrown if it does not exist.
### flagValue.add(flag)
Sets the flag (if it is not yet set). Also sets any inherited flags.
* __flag__: The name of the flag to set. An Error is thrown if it does not exist.
### flagValue.remove(flag)
Unsets the flag (if it is set). Also unsets any inherited flags, except for those that were *explicitly* set (assuming an initialOriginalValue was specified).
* __flag__: The name of the flag to unset. An Error is thrown if it does not exist.
### flagValue.has(flag)
Returns whether the specified flag is set or not.
* __flag__: The flag to check. An Error is thrown if it does not exist.
### flagValue.getValue()
Returns the current value as a Number. This is what you'll want to use for storing the effective value in a database.
It is the value that you will pass to `flagHandler.create([initialValue, [initialOriginalValue]])` as the first argument (`initialValue`).
### flagValue.getOriginalValue()
Returns the current 'original value' as a Number. This represents the explicitly set flags, and you will have to store this in your database as a separate value for full inheritance support.
It is the value that you will pass to `flagHandler.create([initialValue, [initialOriginalValue]])` as the second argument (`initialOriginalValue`).
### flagValue.getFlags()
Returns an array of all the flags (names, not values) that are set in the current value, both explicit and inherited.
*You probably won't need this, unless you're trying to debug something.*
## Changelog
### v0.0.2
* More exposed API methods: `getFlagMap`, `getFlags` and `getInheritedFlags`.
* Documentation update; now with a full API documentation and a changelog!
* Shuffled around some functions, so that they are in a sensible place.
### v0.0.1
Initial release.

@ -4,51 +4,59 @@ class Bitmask
constructor: (@handler, initialValue, initialOriginalValue) ->
@value = initialValue
@originalValue = initialOriginalValue
_getFlagValue: (flag) ->
if @handler.flagMap[flag]?
return @handler.flagMap[flag].value
else
throw new Error("No such flag exists.")
_getFlagInheritances: (flag) ->
if @handler.flagMap[flag]?
return @handler.flagMap[flag].inheritedFlags
else
throw new Error("No such flag exists.")
add: (flag) ->
flagValue = @_getFlagValue(flag)
flagInheritances = @_getFlagInheritances(flag)
flagValue = @handler.getFlagValue(flag)
flagInheritances = @handler.getInheritedFlags(flag)
if @originalValue?
@originalValue = @originalValue | flagValue
@value = @value | flagValue
for inheritance in flagInheritances
flagValue = @_getFlagValue(inheritance)
flagValue = @handler.getFlagValue(inheritance)
@value = @value | flagValue
remove: (flag) ->
flagValue = @_getFlagValue(flag)
flagInheritances = @_getFlagInheritances(flag)
flagValue = @handler.getFlagValue(flag)
flagInheritances = @handler.getInheritedFlags(flag)
if @originalValue?
@originalValue = @originalValue & ~flagValue
@value = @value & ~flagValue
for inheritance in flagInheritances
flagValue = @_getFlagValue(inheritance)
flagValue = @handler.getFlagValue(inheritance)
if @originalValue? and !(@originalValue & flagValue)
@value = @value & ~flagValue
has: (flag) ->
flagValue = @_getFlagValue(flag)
flagValue = @handler.getFlagValue(flag)
return !!(@value & flagValue)
getValue: ->
return @value
getOriginalValue: ->
return @originalValue
getFlags: ->
flags = []
for flag, opts of @handler.getFlagMap()
if @has flag
flags.push flag
return flags
class BitmaskHandler
constructor: (flagMap) ->
@setFlagMap flagMap
getFlagValue: (flag) ->
if @flagMap[flag]?
return @flagMap[flag].value
else
throw new Error("No such flag exists.")
getInheritedFlags: (flag) ->
if @flagMap[flag]?
return @flagMap[flag].inheritedFlags
else
throw new Error("No such flag exists.")
getFlagMap: ->
return @flagMap
setFlagMap: (flagMap) ->
# Sanity check
for flag, value of flagMap
@ -61,7 +69,7 @@ class BitmaskHandler
for inheritance in value.inheritedFlags
if inheritance not of flagMap
throw new Error("The #{flag} flag attempts to inherit the non-existent #{inheritance} flag.")
throw new Error("The #{flag} flag attempted to inherit the non-existent #{inheritance} flag.")
if not isPowerOfTwo value.value
throw new Error("The value for the #{flag} flag (#{value.value}) is not a power of two.")

@ -11,26 +11,10 @@ Bitmask = (function() {
this.originalValue = initialOriginalValue;
}
Bitmask.prototype._getFlagValue = function(flag) {
if (this.handler.flagMap[flag] != null) {
return this.handler.flagMap[flag].value;
} else {
throw new Error("No such flag exists.");
}
};
Bitmask.prototype._getFlagInheritances = function(flag) {
if (this.handler.flagMap[flag] != null) {
return this.handler.flagMap[flag].inheritedFlags;
} else {
throw new Error("No such flag exists.");
}
};
Bitmask.prototype.add = function(flag) {
var flagInheritances, flagValue, inheritance, _i, _len, _results;
flagValue = this._getFlagValue(flag);
flagInheritances = this._getFlagInheritances(flag);
flagValue = this.handler.getFlagValue(flag);
flagInheritances = this.handler.getInheritedFlags(flag);
if (this.originalValue != null) {
this.originalValue = this.originalValue | flagValue;
}
@ -38,7 +22,7 @@ Bitmask = (function() {
_results = [];
for (_i = 0, _len = flagInheritances.length; _i < _len; _i++) {
inheritance = flagInheritances[_i];
flagValue = this._getFlagValue(inheritance);
flagValue = this.handler.getFlagValue(inheritance);
_results.push(this.value = this.value | flagValue);
}
return _results;
@ -46,8 +30,8 @@ Bitmask = (function() {
Bitmask.prototype.remove = function(flag) {
var flagInheritances, flagValue, inheritance, _i, _len, _results;
flagValue = this._getFlagValue(flag);
flagInheritances = this._getFlagInheritances(flag);
flagValue = this.handler.getFlagValue(flag);
flagInheritances = this.handler.getInheritedFlags(flag);
if (this.originalValue != null) {
this.originalValue = this.originalValue & ~flagValue;
}
@ -55,7 +39,7 @@ Bitmask = (function() {
_results = [];
for (_i = 0, _len = flagInheritances.length; _i < _len; _i++) {
inheritance = flagInheritances[_i];
flagValue = this._getFlagValue(inheritance);
flagValue = this.handler.getFlagValue(inheritance);
if ((this.originalValue != null) && !(this.originalValue & flagValue)) {
_results.push(this.value = this.value & ~flagValue);
} else {
@ -67,7 +51,7 @@ Bitmask = (function() {
Bitmask.prototype.has = function(flag) {
var flagValue;
flagValue = this._getFlagValue(flag);
flagValue = this.handler.getFlagValue(flag);
return !!(this.value & flagValue);
};
@ -79,6 +63,19 @@ Bitmask = (function() {
return this.originalValue;
};
Bitmask.prototype.getFlags = function() {
var flag, flags, opts, _ref;
flags = [];
_ref = this.handler.getFlagMap();
for (flag in _ref) {
opts = _ref[flag];
if (this.has(flag)) {
flags.push(flag);
}
}
return flags;
};
return Bitmask;
})();
@ -88,6 +85,26 @@ BitmaskHandler = (function() {
this.setFlagMap(flagMap);
}
BitmaskHandler.prototype.getFlagValue = function(flag) {
if (this.flagMap[flag] != null) {
return this.flagMap[flag].value;
} else {
throw new Error("No such flag exists.");
}
};
BitmaskHandler.prototype.getInheritedFlags = function(flag) {
if (this.flagMap[flag] != null) {
return this.flagMap[flag].inheritedFlags;
} else {
throw new Error("No such flag exists.");
}
};
BitmaskHandler.prototype.getFlagMap = function() {
return this.flagMap;
};
BitmaskHandler.prototype.setFlagMap = function(flagMap) {
var flag, inheritance, value, _i, _len, _ref;
for (flag in flagMap) {
@ -105,7 +122,7 @@ BitmaskHandler = (function() {
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
inheritance = _ref[_i];
if (!(inheritance in flagMap)) {
throw new Error("The " + flag + " flag attempts to inherit the non-existent " + inheritance + " flag.");
throw new Error("The " + flag + " flag attempted to inherit the non-existent " + inheritance + " flag.");
}
}
if (!isPowerOfTwo(value.value)) {

@ -1,6 +1,6 @@
{
"name": "bitmask-flags",
"version": "0.0.1",
"version": "0.0.2",
"description": "A utility for dealing with flags and permissions using bitmasks.",
"main": "index.js",
"scripts": {

@ -29,6 +29,8 @@ var permissions = flagHandler.create(0, 0); // Like we saw before...
permissions.add("create_announcements"); // The user now has `create_announcements` AND `edit_anouncements`.
console.log(permissions.getFlags());
console.log(true, permissions.has("edit_announcements")); // true
permissions.remove("create_announcements"); // The user now has no permissions.

Loading…
Cancel
Save