diff --git a/README.md b/README.md index b540e01..148c9c5 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/lib/bitmask-flags.coffee b/lib/bitmask-flags.coffee index 61ebe49..6c598d6 100644 --- a/lib/bitmask-flags.coffee +++ b/lib/bitmask-flags.coffee @@ -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.") diff --git a/lib/bitmask-flags.js b/lib/bitmask-flags.js index cdd483b..778a2d7 100644 --- a/lib/bitmask-flags.js +++ b/lib/bitmask-flags.js @@ -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)) { diff --git a/package.json b/package.json index 07bcacd..7a99f8b 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/test.js b/test.js index 43149f8..9a79b98 100644 --- a/test.js +++ b/test.js @@ -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.