custom-ability
Advanced tools
Comparing version 1.3.5 to 1.4.0
@@ -49,3 +49,3 @@ (function() { | ||
module.exports = function(abilityClass, aCoreMethod, isGetClassFunc) { | ||
var abilityFn, filter, getAdditionalAbility; | ||
var abilityFn, filter, getAdditionalAbility, hasAbilityOnParent, injectAdditionalAbility; | ||
if (isBoolean(aCoreMethod)) { | ||
@@ -56,3 +56,3 @@ isGetClassFunc = aCoreMethod; | ||
abilityFn = function(aClass, aOptions) { | ||
var $abilities, AbilityClass, filterMethods, i, vAbilities, vExcludes, vFilter, vHasAddtionalAbility, vIncludes, vName, vOptions, vhasCoreMethod; | ||
var $abilities, AbilityClass, aClassPrototype, filterMethods, vAbilities, vAddtionalAbilityInjected, vExcludes, vFilter, vIncludes, vName, vParentHasAbility, vhasCoreMethod; | ||
AbilityClass = abilityClass; | ||
@@ -67,15 +67,17 @@ if (isGetClassFunc === true) { | ||
if (aClass != null) { | ||
vhasCoreMethod = aClass.prototype[(isArray(aCoreMethod) ? aCoreMethod[0] : aCoreMethod)]; | ||
if (vName && aClass.prototype.$abilities) { | ||
aClassPrototype = aClass.prototype; | ||
vhasCoreMethod = isArray(aCoreMethod) ? aCoreMethod[0] : aCoreMethod; | ||
vhasCoreMethod = aClass.prototype.hasOwnProperty(vhasCoreMethod); | ||
if (vName) { | ||
$abilities = aClass.prototype.$abilities; | ||
vParentHasAbility = hasAbilityOnParent(aClass, vName); | ||
if (!aClass.prototype.hasOwnProperty('$abilities')) { | ||
$abilities = null; | ||
} | ||
} | ||
vHasAddtionalAbility = vName && $abilities && $abilities[vName]; | ||
if (!(vhasCoreMethod || ($abilities && $abilities['$' + vName]))) { | ||
if (vName) { | ||
if (!$abilities) { | ||
defineProperty(aClass.prototype, '$abilities', $abilities = {}); | ||
if ((aOptions == null) || !(aOptions.include || aOptions.exclude)) { | ||
if (vName) { | ||
vAddtionalAbilityInjected = injectAdditionalAbility(aClass, vName, filterMethods); | ||
} | ||
$abilities['$' + vName] = abilityFn; | ||
} | ||
if ((aOptions == null) || !(aOptions.include || aOptions.exclude)) { | ||
vExcludes = injectMethodsFromNonEnum(aClass, AbilityClass); | ||
@@ -85,6 +87,11 @@ extendFilter(aClass, AbilityClass, function(k) { | ||
}); | ||
vExcludes = injectMethodsFromNonEnum(aClass.prototype, AbilityClass.prototype); | ||
extend(aClass.prototype, AbilityClass.prototype, function(k) { | ||
return !(__indexOf.call(vExcludes, k) >= 0); | ||
}); | ||
if (vAddtionalAbilityInjected) { | ||
aClassPrototype = vAddtionalAbilityInjected.prototype; | ||
} | ||
if (!vParentHasAbility) { | ||
vExcludes = injectMethodsFromNonEnum(aClassPrototype, AbilityClass.prototype); | ||
extend(aClassPrototype, AbilityClass.prototype, function(k) { | ||
return !(__indexOf.call(vExcludes, k) >= 0); | ||
}); | ||
} | ||
} else { | ||
@@ -131,42 +138,18 @@ vIncludes = aOptions.include; | ||
}; | ||
if (vHasAddtionalAbility) { | ||
vAbilities = getAdditionalAbility(aClass, vName); | ||
i = vAbilities.length; | ||
while (--i >= 0) { | ||
vOptions = vAbilities[i](); | ||
if (vOptions != null) { | ||
filterMethods(vOptions.methods); | ||
filterMethods(vOptions.classMethods); | ||
if (vOptions.methods instanceof Object) { | ||
injectMethods(aClass.prototype, vOptions.methods, vOptions); | ||
} | ||
if (vOptions.classMethods instanceof Object) { | ||
injectMethods(aClass, vOptions.classMethods, vOptions); | ||
} | ||
} | ||
} | ||
if (vName) { | ||
vAddtionalAbilityInjected = injectAdditionalAbility(aClass, vName, filterMethods); | ||
} | ||
extendFilter(aClass, AbilityClass, vFilter); | ||
extendFilter(aClass.prototype, AbilityClass.prototype, vFilter); | ||
if (vAddtionalAbilityInjected) { | ||
aClassPrototype = vAddtionalAbilityInjected.prototype; | ||
} | ||
if (!vParentHasAbility) { | ||
extendFilter(aClassPrototype, AbilityClass.prototype, vFilter); | ||
} | ||
filterMethods(aOptions.methods); | ||
filterMethods(aOptions.classMethods); | ||
} | ||
if (vHasAddtionalAbility && !vAbilities) { | ||
vAbilities = getAdditionalAbility(aClass, vName); | ||
i = vAbilities.length; | ||
while (--i >= 0) { | ||
vOptions = vAbilities[i](); | ||
if (vOptions != null) { | ||
if (vOptions.methods instanceof Object) { | ||
injectMethods(aClass.prototype, vOptions.methods, vOptions); | ||
} | ||
if (vOptions.classMethods instanceof Object) { | ||
injectMethods(aClass, vOptions.classMethods, vOptions); | ||
} | ||
} | ||
} | ||
} | ||
if (aOptions != null) { | ||
if (aOptions.methods instanceof Object) { | ||
injectMethods(aClass.prototype, aOptions.methods, aOptions); | ||
if (!vParentHasAbility && aOptions.methods instanceof Object) { | ||
injectMethods(aClassPrototype, aOptions.methods, aOptions); | ||
} | ||
@@ -177,2 +160,12 @@ if (aOptions.classMethods instanceof Object) { | ||
} | ||
if (vName) { | ||
if (aClassPrototype !== aClass.prototype) { | ||
aClassPrototype = aClass.prototype; | ||
} | ||
if (!aClassPrototype.hasOwnProperty('$abilities')) { | ||
$abilities = {}; | ||
defineProperty(aClassPrototype, '$abilities', $abilities); | ||
} | ||
$abilities['$' + vName] = abilityFn; | ||
} | ||
} | ||
@@ -199,9 +192,45 @@ } else { | ||
}; | ||
hasAbilityOnParent = function(aClass, aName) { | ||
var result; | ||
result = false; | ||
while (!result && aClass && aClass.prototype) { | ||
if (aClass.prototype.hasOwnProperty('$abilities') && aClass.prototype.$abilities.hasOwnProperty('$' + aName)) { | ||
result = true; | ||
} | ||
aClass = aClass.super_; | ||
} | ||
return result; | ||
}; | ||
getAdditionalAbility = function(aClass, aName) { | ||
var result, vAbility; | ||
var result; | ||
result = []; | ||
while (aClass && aClass.prototype) { | ||
if (aClass.prototype.hasOwnProperty('$abilities') && !aClass.prototype.$abilities['$' + aName] && aClass.prototype.$abilities[aName]) { | ||
result.push(aClass); | ||
} | ||
aClass = aClass.super_; | ||
} | ||
return result; | ||
}; | ||
injectAdditionalAbility = function(aClass, aName, filterMethods) { | ||
var $abilities, result, vAbility, vOptions; | ||
while (aClass && aClass.prototype) { | ||
if (aClass.prototype.hasOwnProperty('$abilities')) { | ||
if (vAbility = aClass.prototype.$abilities[aName]) { | ||
result.push(vAbility); | ||
$abilities = aClass.prototype.$abilities; | ||
if (!$abilities['$' + aName] && (vAbility = $abilities[aName])) { | ||
vOptions = vAbility(); | ||
$abilities['$' + aName] = abilityFn; | ||
result = aClass; | ||
if (vOptions != null) { | ||
if (filterMethods) { | ||
filterMethods(vOptions.methods); | ||
filterMethods(vOptions.classMethods); | ||
} | ||
if (vOptions.methods instanceof Object) { | ||
injectMethods(aClass.prototype, vOptions.methods, vOptions); | ||
} | ||
if (vOptions.classMethods instanceof Object) { | ||
injectMethods(aClass, vOptions.classMethods, vOptions); | ||
} | ||
} | ||
} | ||
@@ -208,0 +237,0 @@ } |
{ | ||
"name": "custom-ability", | ||
"version": "1.3.5", | ||
"version": "1.4.0", | ||
"description": "make custom ability more easy. generate the ability which can be added to any class directly.", | ||
@@ -19,3 +19,3 @@ "homepage": "https://github.com/snowyu/custom-ability.js", | ||
"dependencies": { | ||
"inherits-ex": "~1.1.2", | ||
"inherits-ex": "~1.1.3", | ||
"util-ex": "^0.3.10" | ||
@@ -22,0 +22,0 @@ }, |
@@ -216,2 +216,63 @@ ### custom-ability [![Build Status](https://img.shields.io/travis/snowyu/custom-ability.js/master.png)](http://travis-ci.org/snowyu/custom-ability.js) [![npm](https://img.shields.io/npm/v/custom-ability.svg)](https://npmjs.org/package/custom-ability) [![downloads](https://img.shields.io/npm/dm/custom-ability.svg)](https://npmjs.org/package/custom-ability) [![license](https://img.shields.io/npm/l/custom-ability.svg)](https://npmjs.org/package/custom-ability) | ||
## V1.4.x | ||
* Inject additional ability to each parent classes When the some parent classes has additional ability, | ||
and mark it has been injected. note: the additional ability does not include the ability itself. | ||
* The methods of ability itself will be injected to the `farthest` parent class if possible. The static | ||
methods of it will be inject to the current class, and mark it has been injected too. | ||
* Known Issues: | ||
* the `middle` parent classes has no the static methods of ability. | ||
```coffee | ||
customAbility = require 'custom-ability' | ||
class Test | ||
one: -> | ||
@one: -> | ||
testable = customAbility Test #convert the class to testable ability | ||
class Root | ||
$abilities: | ||
Test: -> # additinal ability to Test | ||
methods: | ||
additional:-> | ||
two: -> | ||
class Mid | ||
inherits Mid, Root | ||
$abilities: | ||
Test: -> # additinal ability to Test | ||
methods: | ||
additional:-> Mid.__super__.additional.apply(@, arguments) | ||
three: -> | ||
class A | ||
inherits A, Mid | ||
testable A # make the class A testable. | ||
# A should have all static methods of Test | ||
# Mid,Root should have no any methods of Test | ||
for k, v of Test | ||
Mid.should.not.have.ownProperty k | ||
Root.should.not.have.ownProperty k | ||
A.should.have.ownProperty k | ||
v.should.be.equal A[k] | ||
# A and Mid should have no any methods of Test | ||
# the Root should have all methods of Test | ||
for k, v of Test:: | ||
A::should.not.have.ownProperty k | ||
Mid::should.not.have.ownProperty k | ||
Root::should.have.ownProperty k | ||
# Root should have additional methods: | ||
Root::should.have.ownProperty 'additional' | ||
Root::should.have.ownProperty 'two' | ||
Mid::should.have.ownProperty 'additional' | ||
Mid::should.have.ownProperty 'three' | ||
``` | ||
## V1.3.x | ||
@@ -228,2 +289,4 @@ | ||
The AbstractObject need to hook some methods to make the eventable ability work correctly. | ||
```coffee | ||
@@ -230,0 +293,0 @@ AbstractObject = require('./lib/abstract-object') |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
50765
243
379
Updatedinherits-ex@~1.1.3