protoblast
Advanced tools
Comparing version 0.3.3 to 0.3.4
@@ -0,1 +1,12 @@ | ||
## 0.3.4 (2017-01-21) | ||
* Fix bug in `Object.checksum` using `valueOf` on an object without prototype | ||
* Fix constructors not getting static methods when in non-native-modifying mode | ||
* Fix: `unmethodize` and `methodize` shouldn't get stuck in a loop because of the function name | ||
* Test: creating an anonymous function is a bit harder in new node versions | ||
* Improve `Object.alike` performance and add tests | ||
* Added 4th parameter to `Function.inherits` that skips constitutors when falsy | ||
* Fixed bug where constitutors would be executed twice for delayed inheritance | ||
* Add `String.decodeAttributes` | ||
## 0.3.3 (2016-10-14) | ||
@@ -2,0 +13,0 @@ |
@@ -94,3 +94,3 @@ module.exports = function BlastInheritance(Blast, Collection) { | ||
* @since 0.1.3 | ||
* @version 0.3.2 | ||
* @version 0.3.4 | ||
* | ||
@@ -100,6 +100,7 @@ * @param {String|Function|Array} _parent Parent class to inherit from | ||
* @param {Function} _newConstructor New class constructor | ||
* @param {Boolean} _do_constitutors Do the constitutors [true] | ||
* | ||
* @return {Function} | ||
*/ | ||
Blast.defineStatic('Function', 'inherits', function inherits(_parent, _namespace, _newConstructor) { | ||
Blast.defineStatic('Function', 'inherits', function inherits(_parent, _namespace, _newConstructor, _do_constitutors) { | ||
@@ -152,2 +153,6 @@ var parent_namespace, | ||
if (_do_constitutors == null) { | ||
_do_constitutors = true; | ||
} | ||
if (Array.isArray(names)) { | ||
@@ -182,3 +187,3 @@ | ||
inherits(names, namespace, newConstructor); | ||
inherits(names, namespace, newConstructor, false); | ||
@@ -197,10 +202,8 @@ if (!oldProto.waitingForClass || !oldProto.hasOwnProperty('waitingForClass')) return; | ||
// Get the parent constitutors and execute them | ||
// Add the parent constitutors to the new constructor | ||
if (newConstructor.super.constitutors != null) { | ||
Blast.defineValue(newConstructor, 'constitutors', newConstructor.super.constitutors.slice()); | ||
for (i = 0; i < newConstructor.constitutors.length; i++) { | ||
newConstructor.constitutors[i].call(newConstructor); | ||
for (i = 0; i < newConstructor.super.constitutors.length; i++) { | ||
newConstructor.constitute(newConstructor.super.constitutors[i]); | ||
} | ||
} | ||
}; | ||
@@ -218,2 +221,5 @@ for (i = 0; i < oldProto.waitingConstitute.length; i++) { | ||
// Ensure the constructor has static methods | ||
ensureConstructorStaticMethods(newConstructor); | ||
return newConstructor; | ||
@@ -234,3 +240,3 @@ } | ||
inherits(superConstructor, namespace, newConstructor); | ||
inherits(superConstructor, namespace, newConstructor, _do_constitutors); | ||
} | ||
@@ -294,11 +300,6 @@ | ||
// Get the parent constitutors and execute them | ||
if (parentConstructor.constitutors != null) { | ||
Blast.defineValue(newConstructor, 'constitutors', parentConstructor.constitutors.slice()); | ||
// Execute the constitutors once blast has loaded | ||
Blast.loaded(function goConstitutors() { | ||
for (var i = 0; i < parentConstructor.constitutors.length; i++) { | ||
parentConstructor.constitutors[i].call(newConstructor); | ||
} | ||
}); | ||
if (_do_constitutors && parentConstructor.constitutors != null) { | ||
for (i = 0; i < parentConstructor.constitutors.length; i++) { | ||
newConstructor.constitute(parentConstructor.constitutors[i]); | ||
} | ||
} | ||
@@ -312,19 +313,4 @@ } else { | ||
// So we add it to this extended class' constructor | ||
if (typeof newConstructor.setMethod !== 'function') { | ||
Blast.defineValue(newConstructor, 'prepareStaticProperty', protoPrepareStaticProperty); | ||
Blast.defineValue(newConstructor, 'setStaticProperty', protoSetStaticProperty); | ||
Blast.defineValue(newConstructor, 'prepareProperty', protoPrepareProperty); | ||
Blast.defineValue(newConstructor, 'staticCompose', protoStaticCompose); | ||
Blast.defineValue(newConstructor, 'getChildren', protoGetChildren); | ||
Blast.defineValue(newConstructor, 'setProperty', protoSetProperty); | ||
Blast.defineValue(newConstructor, 'constitute', protoConstitute); | ||
Blast.defineValue(newConstructor, 'setStatic', protoSetStatic); | ||
Blast.defineValue(newConstructor, 'setMethod', protoSetMethod); | ||
Blast.defineValue(newConstructor, 'compose', protoCompose); | ||
ensureConstructorStaticMethods(newConstructor); | ||
if (newConstructor.extend == null) { | ||
Blast.defineValue(newConstructor, 'extend', protoExtend); | ||
} | ||
} | ||
if (!targetPath) { | ||
@@ -1110,2 +1096,31 @@ // See if we need to set a namespace | ||
/** | ||
* Ensure a constructor has the required static methods | ||
* | ||
* @author Jelle De Loecker <jelle@kipdola.be> | ||
* @since 0.3.4 | ||
* @version 0.3.4 | ||
* | ||
* @param {Function} newConstructor | ||
*/ | ||
function ensureConstructorStaticMethods(newConstructor) { | ||
if (typeof newConstructor.setMethod !== 'function') { | ||
Blast.defineValue(newConstructor, 'prepareStaticProperty', protoPrepareStaticProperty); | ||
Blast.defineValue(newConstructor, 'setStaticProperty', protoSetStaticProperty); | ||
Blast.defineValue(newConstructor, 'prepareProperty', protoPrepareProperty); | ||
Blast.defineValue(newConstructor, 'staticCompose', protoStaticCompose); | ||
Blast.defineValue(newConstructor, 'getChildren', protoGetChildren); | ||
Blast.defineValue(newConstructor, 'setProperty', protoSetProperty); | ||
Blast.defineValue(newConstructor, 'constitute', protoConstitute); | ||
Blast.defineValue(newConstructor, 'setStatic', protoSetStatic); | ||
Blast.defineValue(newConstructor, 'setMethod', protoSetMethod); | ||
Blast.defineValue(newConstructor, 'compose', protoCompose); | ||
if (newConstructor.extend == null) { | ||
Blast.defineValue(newConstructor, 'extend', protoExtend); | ||
} | ||
} | ||
} | ||
Blast.definePrototype('Function', 'prepareStaticProperty', protoPrepareStaticProperty); | ||
@@ -1112,0 +1127,0 @@ Blast.definePrototype('Function', 'setStaticProperty', protoSetStaticProperty); |
@@ -285,3 +285,3 @@ module.exports = function BlastFunction(Blast, Collection) { | ||
return fnc.apply(this, args); | ||
return m_fnc.apply(this, args); | ||
}; | ||
@@ -298,3 +298,3 @@ | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* @version 0.3.4 | ||
* | ||
@@ -307,22 +307,28 @@ * @param {String} name The name to use for the wrapper | ||
var fnc, sourcecode; | ||
var sourcecode, | ||
m_fnc; | ||
if (this._methodized) return this._methodized; | ||
fnc = this; | ||
m_fnc = this; | ||
if (typeof name == 'undefined') { | ||
name = fnc.name; | ||
name = m_fnc.name; | ||
} | ||
// Add an underscore should anyone ever use this name | ||
if (name == 'm_fnc') { | ||
name = '_m_fnc'; | ||
} | ||
// Get the sourcecode | ||
sourcecode = 'function ' + name + method; | ||
eval('Blast.defineProperty(fnc, "_methodized", {value:' + sourcecode + '});'); | ||
eval('Blast.defineProperty(m_fnc, "_methodized", {value:' + sourcecode + '});'); | ||
// Make sure a methodized function doesn't get methodized | ||
Blast.defineProperty(fnc._methodized, '_methodized', {value: fnc._methodized}); | ||
Blast.defineProperty(m_fnc._methodized, '_methodized', {value: m_fnc._methodized}); | ||
// Add the unmethodized function | ||
Blast.defineProperty(fnc, '_unmethodized', {value: fnc}); | ||
Blast.defineProperty(m_fnc, '_unmethodized', {value: m_fnc}); | ||
@@ -342,3 +348,3 @@ return this._methodized; | ||
return fnc.apply(arguments[0], args); | ||
return u_fnc.apply(arguments[0], args); | ||
}; | ||
@@ -355,3 +361,3 @@ | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* @version 0.3.4 | ||
* | ||
@@ -364,22 +370,28 @@ * @param {String} name The name to use for the wrapper | ||
var fnc, sourcecode; | ||
var sourcecode, | ||
u_fnc; | ||
if (this._unmethodized) return this._unmethodized; | ||
fnc = this; | ||
u_fnc = this; | ||
if (typeof name == 'undefined') { | ||
name = fnc.name; | ||
name = u_fnc.name; | ||
} | ||
// Add an underscore should anyone ever use this name | ||
if (name == 'u_fnc') { | ||
name = '_u_fnc'; | ||
} | ||
// Get the sourcecode | ||
sourcecode = 'function ' + name + unmethod; | ||
eval('Blast.defineProperty(fnc, "_unmethodized", {value:' + sourcecode + '});'); | ||
eval('Blast.defineProperty(u_fnc, "_unmethodized", {value:' + sourcecode + '});'); | ||
// Make sure an unmethodized function doesn't get unmethodized | ||
Blast.defineProperty(fnc._unmethodized, '_unmethodized', {value: fnc._unmethodized}); | ||
Blast.defineProperty(u_fnc._unmethodized, '_unmethodized', {value: u_fnc._unmethodized}); | ||
// Add the methodized function | ||
Blast.defineProperty(fnc, '_methodized', {value: fnc}); | ||
Blast.defineProperty(u_fnc, '_methodized', {value: u_fnc}); | ||
@@ -386,0 +398,0 @@ return this._unmethodized; |
@@ -210,3 +210,3 @@ module.exports = function BlastObject(Blast, Collection) { | ||
* @since 0.1.3 | ||
* @version 0.1.3 | ||
* @version 0.3.4 | ||
* | ||
@@ -234,18 +234,16 @@ * @param {Object} obj | ||
if (Collection.Object.isPlainObject(obj)) { | ||
return Object.keys(obj).length; | ||
} | ||
len = Object.keys(obj).length; | ||
} else { | ||
type = typeof obj; | ||
type = typeof obj; | ||
if (type == 'number' || typeof (0+obj) == 'number') { | ||
return 0+obj; | ||
} | ||
if (type == 'number' || typeof (0+obj) == 'number') { | ||
return 0+obj; | ||
} | ||
if (type == 'boolean') { | ||
return Number(obj); | ||
if (type == 'boolean') { | ||
return Number(obj); | ||
} | ||
} | ||
// Get the length of all the enumerable keys | ||
len = Object.keys(obj).length; | ||
// Do a (slow) iterate if we have to filter out undefineds | ||
@@ -1145,3 +1143,3 @@ if (includeUndefined === false) { | ||
* @since 0.1.3 | ||
* @version 0.3.2 | ||
* @version 0.3.4 | ||
* | ||
@@ -1173,3 +1171,3 @@ * @param {Object|Array} obj | ||
// Make sure primitives are primitive | ||
if (type == 'object' && obj != null) { | ||
if (type == 'object' && obj != null && typeof obj.valueOf == 'function') { | ||
@@ -1269,3 +1267,3 @@ // Get the value of the object | ||
* @since 0.1.3 | ||
* @version 0.1.3 | ||
* @version 0.3.4 | ||
* | ||
@@ -1279,4 +1277,6 @@ * @param {Object} a | ||
var key; | ||
// If they're equals, return true | ||
if (a == b) { | ||
if (a === b) { | ||
return true; | ||
@@ -1290,3 +1290,42 @@ } | ||
return Blast.Bound.Object.checksum(a) == Blast.Bound.Object.checksum(b); | ||
// Do primitive values first | ||
for (key in a) { | ||
// Skip entries that are identical | ||
if (a[key] === b[key]) { | ||
continue; | ||
} | ||
switch (typeof a[key]) { | ||
case 'number': | ||
case 'string': | ||
case 'boolean': | ||
if (a[key] !== b[key]) { | ||
return false; | ||
} | ||
break; | ||
} | ||
} | ||
for (key in a) { | ||
// Skip entries that are identical | ||
if (a[key] === b[key]) { | ||
continue; | ||
} | ||
switch (typeof a[key]) { | ||
case 'number': | ||
case 'string': | ||
case 'boolean': | ||
continue; | ||
default: | ||
if (!alike(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
}); | ||
@@ -1293,0 +1332,0 @@ |
@@ -43,2 +43,59 @@ module.exports = function BlastString(Blast, Collection) { | ||
/** | ||
* Serialize the given parameter to valid HTML attributes | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.3.4 | ||
* @version 0.3.4 | ||
* | ||
* @param {Object} value The string to decode | ||
* @param {RegExp} separator The value separator | ||
* | ||
* @return {Object} | ||
*/ | ||
Blast.defineStatic('String', 'decodeAttributes', function decodeAttributes(value, separator) { | ||
var result = {}, | ||
pieces, | ||
index, | ||
pair, | ||
key, | ||
val, | ||
i; | ||
if (value == null) { | ||
return result; | ||
} | ||
if (typeof separator == 'string') { | ||
separator = Blast.Bound.RegExp.interpret(separator); | ||
} else if (!separator) { | ||
separator = /, */; | ||
} | ||
pieces = value.split(separator) | ||
for (i = 0; i < pieces.length; i++) { | ||
pair = pieces[i]; | ||
index = pair.indexOf('='); | ||
// Skip pieces that aren't key-vals separated by a equal sign | ||
if (index < 0) { | ||
key = pair; | ||
val = undefined; | ||
} else { | ||
// Get the key, trim it now | ||
key = pair.substr(0, index).trim(); | ||
// The value will be trimmed later | ||
val = pair.substr(index + 1, pair.length); | ||
val = Collection.String.decodeJSONURI(val); | ||
} | ||
result[key] = val; | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Decode a uri encoded component. | ||
@@ -106,3 +163,3 @@ * Return the given value should it fail | ||
* @since 0.1.4 | ||
* @version 0.1.4 | ||
* @version 0.3.4 | ||
* | ||
@@ -114,36 +171,3 @@ * @param {String} value | ||
Blast.defineStatic('String', 'decodeCookies', function decodeCookies(value) { | ||
var result = {}, | ||
pieces, | ||
index, | ||
pair, | ||
key, | ||
val, | ||
i; | ||
if (value == null) { | ||
return result; | ||
} | ||
pieces = value.split(/; */) | ||
for (i = 0; i < pieces.length; i++) { | ||
pair = pieces[i]; | ||
index = pair.indexOf('='); | ||
// Skip pieces that aren't key-vals separated by a equal sign | ||
if (index < 0) { | ||
continue; | ||
} | ||
// Get the key, trim it now | ||
key = pair.substr(0, index).trim(); | ||
// The value will be trimmed later | ||
val = pair.substr(index + 1, pair.length); | ||
result[key] = Collection.String.decodeJSONURI(val); | ||
} | ||
return result; | ||
return Blast.Bound.String.decodeAttributes(value, /; */); | ||
}); | ||
@@ -150,0 +174,0 @@ |
{ | ||
"name": "protoblast", | ||
"description": "Native object expansion library", | ||
"version": "0.3.3", | ||
"version": "0.3.4", | ||
"author": "Jelle De Loecker <jelle@develry.be>", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
@@ -41,3 +41,3 @@ var assert = require('assert'), | ||
var anon = function () {}, | ||
var anon = (function() {return function(){}}()), | ||
xerr; | ||
@@ -126,5 +126,118 @@ | ||
}); | ||
}); | ||
describe('.constitute(fnc)', function() { | ||
var ConstituteTestBase, | ||
i = 0; | ||
before(function() { | ||
ConstituteTestBase = Blast.Bound.Function.inherits(function ConstituteTestBase() {}); | ||
}); | ||
it('should execute on the class', function(done) { | ||
var done_count = 0; | ||
ConstituteTestBase.constitute(function doFirst() { | ||
if (!this.first_count) { | ||
this.first_count = 0; | ||
} | ||
// This should remain 1, we'll test that later | ||
this.first_count++; | ||
this.first_time = i++; | ||
done_count++; | ||
}); | ||
ConstituteTestBase.constitute(function doSecond() { | ||
if (!this.second_count) { | ||
this.second_count = 0; | ||
} | ||
// This should remain 1, we'll test that later | ||
this.second_count++; | ||
this.second_time = i++; | ||
done_count++; | ||
if (done_count == 2 && this.second_count == 1) { | ||
done(); | ||
} | ||
}); | ||
}); | ||
it('should execute in the expected order', function(done) { | ||
var CTOne, | ||
CTTwo, | ||
i = 0; | ||
// This will inherit a class that doesn't exist yet | ||
CTTwo = Blast.Bound.Function.inherits('CTOne', function CTTwo() {}); | ||
CTTwo.constitute(function doThird() { | ||
this.third_time = i++; | ||
checker(); | ||
}); | ||
// This is the main class | ||
setTimeout(function() { | ||
CTOne = Blast.Bound.Function.inherits(function CTOne() {}); | ||
CTOne.constitute(function doFirst() { | ||
this.first_time = i++; | ||
checker(); | ||
}); | ||
CTOne.constitute(function doSecond() { | ||
this.second_time = i++; | ||
checker(); | ||
}); | ||
}, 10); | ||
// This will check if everything is happening in the correct order | ||
function checker() { | ||
if (i == 1) { | ||
assert.equal(CTOne.first_time, 0); | ||
assert.equal(CTOne.second_time, undefined); | ||
assert.equal(CTOne.third_time, undefined); | ||
} else if (i == 2) { | ||
assert.equal(CTOne.first_time, 0); | ||
assert.equal(CTOne.second_time, 1); | ||
assert.equal(CTOne.third_time, undefined); | ||
} else if (i == 3) { | ||
assert.equal(CTOne.first_time, 0); | ||
assert.equal(CTOne.second_time, 1); | ||
assert.equal(CTOne.third_time, undefined); | ||
assert.equal(CTTwo.first_time, 2); | ||
assert.equal(CTTwo.second_time, undefined); | ||
assert.equal(CTTwo.third_time, undefined); | ||
} else if (i == 4) { | ||
assert.equal(CTOne.first_time, 0); | ||
assert.equal(CTOne.second_time, 1); | ||
assert.equal(CTOne.third_time, undefined); | ||
assert.equal(CTTwo.first_time, 2); | ||
assert.equal(CTTwo.second_time, 3); | ||
assert.equal(CTTwo.third_time, undefined); | ||
} else if (i == 5) { | ||
assert.equal(CTOne.first_time, 0); | ||
assert.equal(CTOne.second_time, 1); | ||
assert.equal(CTOne.third_time, undefined); | ||
assert.equal(CTTwo.first_time, 2); | ||
assert.equal(CTTwo.second_time, 3); | ||
assert.equal(CTTwo.third_time, 4); | ||
done(); | ||
} | ||
} | ||
}); | ||
}); | ||
}); |
@@ -215,2 +215,45 @@ var assert = require('assert'), | ||
describe('.alike(a, b)', function() { | ||
var a = {alpha: 'alpha', b: 1}, | ||
b = {alpha: 'alpha', b: 1}, | ||
c = {alpha: 'alpha', b: 1, extra: true}, | ||
d = {alpha: 'beta', b: 1}, | ||
e = {alpha: 'alpha', b: 1, extra: undefined}, | ||
f = {b: 1, alpha: 'alpha'}, | ||
aa = {a: 1, ref: a}, | ||
ab = {a: 1, ref: b}; | ||
it('should return true when both objects are the same reference', function() { | ||
assert.equal(true, Object.alike(a, a)); | ||
}); | ||
it('should return true when both object are identical', function() { | ||
assert.equal(true, Object.alike(a, b)); | ||
assert.equal(true, Object.alike(b, a)); | ||
assert.equal(true, Object.alike(aa, ab)); | ||
assert.equal(true, Object.alike(ab, aa)); | ||
}); | ||
it('should return true when identical objects have different order', function() { | ||
assert.equal(true, Object.alike(a, f)); | ||
assert.equal(true, Object.alike(f, a)); | ||
}); | ||
it('should return false when objects have different amount of entries', function() { | ||
assert.equal(false, Object.alike(a, c)); | ||
assert.equal(false, Object.alike(c, a)); | ||
}); | ||
it('should return false when the values are not the same', function() { | ||
assert.equal(false, Object.alike(a, d)); | ||
assert.equal(false, Object.alike(d, a)); | ||
}); | ||
it('should return true when the values are the same, ignoring undefined values', function() { | ||
assert.equal(true, Object.alike(a, e)); | ||
assert.equal(true, Object.alike(e, a)); | ||
}); | ||
}); | ||
describe('.flatten(obj)', function() { | ||
@@ -217,0 +260,0 @@ it('flatten an object', function() { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
597621
18874