protoblast
Advanced tools
Comparing version 0.1.1 to 0.1.2
@@ -0,1 +1,40 @@ | ||
## 0.1.2 (2014-08-28) | ||
* Added Array#insert(index, value, ...) | ||
* Added Object.hasProperty(obj, propertyName) | ||
* Added String#truncate(length, word, ellipsis) | ||
* Added String#stripTags() | ||
* Added Date.isDate(variable) | ||
* Object.path(obj, path) now also accepts an array or multiple arguments | ||
* Add Array.range(start, stop, step) method, which behaves like Python's range() | ||
* Add Array#closest(goal) method to find the closest value to the given goal | ||
* Added String#before(needle, first) and String#after(needle, first) | ||
* Added String#beforeLast(needle) and String#afterLast(needle) | ||
* Added Object.isObject(obj) | ||
* Added Object.isPlainObject(obj) | ||
* Added Object.isPrimitiveObject(obj) | ||
* Added String.serializeAttributes(obj) | ||
* Added String#encodeHTML and String#decodeHTML | ||
* Added Object.flatten(obj) | ||
* Added Array#unique() | ||
* Added Function#curry() | ||
* Added Iterator class and Array#createIterator() | ||
* Added Deck class (ordered object) | ||
* Added unit tests for Iterator & Deck | ||
* Added String#dissect(open, close) | ||
* Added RegExp.interpret(pattern) | ||
* Added RegExp#getPattern() | ||
* Added RegExp#getFlags() | ||
* Added RegExp.combine(r1, r2, ... rn) | ||
* Added Function#tokenize(addType, throwErrors) | ||
* Added Function.tokenize(source, addType, throwErrors) and Function.getTokenType(str) | ||
* Added JSONPath, added Object.extract using that class | ||
* Added Number.random(min, max) | ||
* Speed up String#count and add String#replaceAll that doesn't use regexes | ||
* Added Math methods: mean, median, variance and (standard) deviation | ||
* Started adding Benchmarking functions | ||
* Added (asynchronous) function flow controls | ||
* Added Number#humanize method | ||
* Update inflection rules (Ben Lin's From node.inflection, https://github.com/dreamerslab/node.inflection) | ||
## 0.1.1 (2014-06-23) | ||
@@ -2,0 +41,0 @@ |
217
lib/array.js
module.exports = function BlastArray(Blast, Collection) { | ||
var Iterator; | ||
/** | ||
@@ -46,2 +48,55 @@ * Cast a variable to an array. | ||
/** | ||
* Create an array containing arithmetic progressions, | ||
* an implementation of Python's range function | ||
* | ||
* @author Tomasz Jaskowski <http://www.jaskowski.info/> | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} start The first value, defaults to 0 | ||
* @param {Number} stop The last value, is required | ||
* @param {Number} step The step value, defaults to 1 | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Array', 'range', function range(start, stop, step) { | ||
var result = [], | ||
i; | ||
// If only 1 argument is given, interpret it as the stop parameter | ||
if (typeof stop == 'undefined') { | ||
stop = start; | ||
start = 0; | ||
} else { | ||
// Make sure start is a valid number | ||
if (typeof start != 'number') { | ||
start = Number(start) || 0; | ||
} | ||
// Make sure stop is a valid number | ||
if (typeof stop != 'number') { | ||
stop = Number(stop); | ||
} | ||
} | ||
// If no valid step is given, just use a step of 1 | ||
if (typeof step == 'undefined') { | ||
step = 1; | ||
} else if (typeof step != 'number') { | ||
step = Number(step) || 1; | ||
}; | ||
if (!((step>0 && start>=stop) || (step<0 && start<=stop))) { | ||
for (i = start; step > 0 ? i < stop : i > stop; i += step) { | ||
result.push(i); | ||
}; | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Return a string representing the source code of the array. | ||
@@ -101,9 +156,27 @@ * | ||
/** | ||
* Get the first value of an array | ||
* Get the first value of an array, | ||
* or the first nr of wanted values | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} nr Return the first nr of values in a new array | ||
* | ||
* @return {Mixed} | ||
*/ | ||
Blast.definePrototype('Array', 'first', function first() { | ||
Blast.definePrototype('Array', 'first', function first(nr, page) { | ||
if (typeof nr === 'number') { | ||
if (typeof page === 'number') { | ||
page = nr * page; | ||
nr = nr + page; | ||
} else { | ||
page = 0; | ||
} | ||
return this.slice(page, nr); | ||
} | ||
return this[0]; | ||
@@ -117,5 +190,24 @@ }); | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} nr Return the first nr of values in a new array | ||
* | ||
* @return {Mixed} | ||
*/ | ||
Blast.definePrototype('Array', 'last', function last() { | ||
Blast.definePrototype('Array', 'last', function last(nr, page) { | ||
if (typeof nr === 'number') { | ||
nr = 0-nr; | ||
if (typeof page === 'number' && page) { | ||
page = nr * page; | ||
nr = nr + page; | ||
} else { | ||
page = undefined; | ||
} | ||
return this.slice(nr, page); | ||
} | ||
return this[this.length-1]; | ||
@@ -125,2 +217,104 @@ }); | ||
/** | ||
* Get the closest numeric value inside an array | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} goal The goal we want to get the closest value to | ||
* | ||
* @result {Number} | ||
*/ | ||
Blast.definePrototype('Array', 'closest', function closest(goal) { | ||
var closest = null, | ||
i; | ||
for (i = 0; i < this.length; i++) { | ||
if (closest === null || Math.abs(this[i] - goal) < Math.abs(closest - goal)) { | ||
closest = this[i]; | ||
} | ||
} | ||
return closest; | ||
}); | ||
/** | ||
* Get the highest value inside the array | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @result {Number} | ||
*/ | ||
Blast.definePrototype('Array', 'max', function max() { | ||
return Math.max.apply(Math, this); | ||
}); | ||
/** | ||
* Get the lowest value inside the array | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @result {Number} | ||
*/ | ||
Blast.definePrototype('Array', 'min', function min() { | ||
return Math.min.apply(Math, this); | ||
}); | ||
/** | ||
* Insert item at the given index, | ||
* modifies the array in-place | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} index Where to insert the values | ||
* @param {Mixed} value | ||
* | ||
* @return {Array} The same array | ||
*/ | ||
Blast.definePrototype('Array', 'insert', function insert(index, value) { | ||
if (this.length < (index-1)) { | ||
this.length = index-1; | ||
} | ||
this.splice.apply(this, [index, 0].concat( | ||
Array.prototype.slice.call(arguments, 1)) | ||
); | ||
return this; | ||
}); | ||
/** | ||
* Get all the unique values and return them as a new array. | ||
* Object contents will NOT be take into account. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Array} A new array with only unique values | ||
*/ | ||
Blast.definePrototype('Array', 'unique', function unique() { | ||
var result = [], | ||
i; | ||
for (i = 0; i < this.length; i++) { | ||
// If the value isn't in the result yet, add it | ||
if (result.indexOf(this[i]) === -1) { | ||
result.push(this[i]); | ||
} | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Get the shared value between the 2 arrays | ||
@@ -252,2 +446,15 @@ * | ||
/** | ||
* Create an iterator for this array | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Iterator} | ||
*/ | ||
Blast.definePrototype('Array', 'createIterator', function createIterator() { | ||
return new Blast.Classes.Iterator(this); | ||
}); | ||
}; |
(function() { | ||
var useCommon; | ||
@@ -55,4 +57,8 @@ function require(p){ | ||
window.Protoblast = require('init.js')(); | ||
if (useCommon) { | ||
module.exports = require('init.js'); | ||
} else { | ||
window.Protoblast = require('init.js')(); | ||
} | ||
}()); |
@@ -15,2 +15,13 @@ module.exports = function BlastDate(Blast, Collection) { | ||
/** | ||
* Determine is a variable is a date object | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
*/ | ||
Blast.defineStatic('Date', 'isDate', function isDate(variable) { | ||
return Object.prototype.toString.call(variable) === '[object Date]'; | ||
}); | ||
/** | ||
* Return a string representing the source code of the date. | ||
@@ -17,0 +28,0 @@ * |
module.exports = function BlastFunction(Blast, Collection) { | ||
var tokenPatterns, | ||
tokenMatches, | ||
tokenTesters, | ||
patternNames; | ||
tokenPatterns = { | ||
whitespace : /\s+/, | ||
keyword : /\b(?:var|let|for|if|else|in|class|function|typeof|return|with|case|break|switch|export|new|while|do|throw|catch)\b/, | ||
name : /[a-zA-Z_\$][a-zA-Z_\$0-9]*/, | ||
string1 : /"(?:(?:\\\n|\\"|[^"\n]))*?"/, | ||
string2 : /'(?:(?:\\\n|\\'|[^'\n]))*?'/, | ||
comment1 : /\/\*[\s\S]*?\*\//, | ||
comment2 : /\/\/.*?\n/, | ||
number : /\d+(?:\.\d+)?(?:e[+-]?\d+)?/, | ||
parens : /[\(\)]/, | ||
curly : /[{}]/, | ||
square : /[\[\]]/, | ||
punct : /[;.:\?\^%<>=!&|+\-,~]/, | ||
regexp : /\/(?:(?:\\\/|[^\n\/]))*?\// | ||
}; | ||
patternNames = { | ||
string1: 'string', | ||
string2: 'string', | ||
comment1: 'comment', | ||
comment2: 'comment' | ||
}; | ||
Blast.ready(function() { | ||
var patternName; | ||
// Create the matches | ||
tokenMatches = Collection.RegExp.combine.apply(null, Collection.Object.values(tokenPatterns)); | ||
// Create the testers | ||
tokenTesters = {}; | ||
for (patternName in tokenPatterns) { | ||
tokenTesters[patternName] = new RegExp('^' + Collection.RegExp.prototype.getPattern.call(tokenPatterns[patternName]) + '$'); | ||
} | ||
}); | ||
/** | ||
@@ -25,2 +68,90 @@ * Create a function with the given variable as name | ||
/** | ||
* Get the type of the given token | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} tokenString | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.defineStatic('Function', 'getTokenType', function getTokenType(tokenString) { | ||
var patternName; | ||
for (patternName in tokenPatterns) { | ||
if (tokenTesters[patternName].test(tokenString)) { | ||
if (patternNames[patternName]) { | ||
return patternNames[patternName]; | ||
} | ||
return patternName; | ||
} | ||
} | ||
return 'invalid'; | ||
}); | ||
/** | ||
* Convert JavaScript sourcecode to tokens | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} sourceCode | ||
* @param {Boolean} addType Add the type of the token | ||
* @param {Boolean} throwErrors Throw error when invalid token is found | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Function', 'tokenize', function tokenize(sourceCode, addType, throwErrors) { | ||
var tokens = [], | ||
obj, | ||
i; | ||
if (typeof sourceCode !== 'string') { | ||
sourceCode = ''+sourceCode; | ||
} | ||
sourceCode = sourceCode.split(tokenMatches); | ||
for (i = 0; i < sourceCode.length; i++) { | ||
// Every uneven match should be used | ||
if (i % 2) { | ||
tokens.push(sourceCode[i]); | ||
} else if (sourceCode[i] !== '') { | ||
// If an even match contains something, it's invalid | ||
if (throwErrors) { | ||
throw new Error('Invalid token: ' + JSON.stringify(e)); | ||
} | ||
tokens.push(sourceCode[i]); | ||
} | ||
} | ||
if (!addType) { | ||
return tokens; | ||
} | ||
for (i = 0; i < tokens.length; i++) { | ||
obj = { | ||
type: Collection.Function.getTokenType(tokens[i]), | ||
value: tokens[i] | ||
}; | ||
// Replace the original string with the object | ||
tokens[i] = obj; | ||
} | ||
return tokens; | ||
}); | ||
/** | ||
* Return a string representing the source code of the function. | ||
@@ -56,2 +187,52 @@ * Also attempts to return native code references, | ||
/** | ||
* Convert this function sourcecode to tokens | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Boolean} addType Add the type of the token | ||
* @param {Boolean} throwErrors Throw error when invalid token is found | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.definePrototype('Function', 'tokenize', function tokenize(addType, throwErrors) { | ||
return Collection.Function.tokenize(''+this, addType, throwErrors); | ||
}); | ||
/** | ||
* Get a function's body source | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('Function', 'getBodySource', function getBodySource() { | ||
// Get the source code of the function | ||
var src = String(this); | ||
// Slice it | ||
return src.slice(src.indexOf('{')+1, -1); | ||
}); | ||
// method source code | ||
var method = ''+function() { | ||
var args = [this], | ||
len = arguments.length, | ||
i; | ||
// Push all the arguments the old fashioned way, | ||
// this is the fastest method | ||
for (i = 0; i < len; i++) { | ||
args.push(arguments[i]); | ||
} | ||
return fnc.apply(this, args); | ||
}; | ||
/** | ||
* Create a function that will call the given function with 'this' | ||
@@ -64,3 +245,2 @@ * as the first argument. | ||
* | ||
* @param {Function} fnc The function body | ||
* @param {String} name The name to use for the wrapper | ||
@@ -72,3 +252,3 @@ * | ||
var fnc, method, sourcecode; | ||
var fnc, sourcecode; | ||
@@ -79,17 +259,2 @@ if (this._methodized) return this._methodized; | ||
method = function() { | ||
var args = [this], | ||
len = arguments.length, | ||
i; | ||
// Push all the arguments the old fashioned way, | ||
// this is the fastest method | ||
for (i = 0; i < len; i++) { | ||
args.push(arguments[i]); | ||
} | ||
return fnc.apply(this, args); | ||
}; | ||
if (typeof name == 'undefined') { | ||
@@ -100,11 +265,11 @@ name = fnc.name; | ||
// Get the sourcecode | ||
sourcecode = 'function ' + name + String(method).slice(9); | ||
sourcecode = 'function ' + name + method.slice(9); | ||
eval('this._methodized = ' + sourcecode); | ||
eval('Blast.defineProperty(fnc, "_methodized", {value:' + sourcecode + '});'); | ||
// Make sure a methodized function doesn't get methodized | ||
this._methodized._methodized = this._methodized; | ||
Blast.defineProperty(fnc._methodized, '_methodized', {value: fnc._methodized}); | ||
// Add the unmethodized function | ||
this._unmethodized = fnc; | ||
Blast.defineProperty(fnc, '_unmethodized', {value: fnc}); | ||
@@ -114,2 +279,15 @@ return this._methodized; | ||
// Unmethod source code | ||
var unmethod = ''+function() { | ||
var args = [], | ||
i; | ||
for (i = 1; i < arguments.length; i++) { | ||
args.push(arguments[i]); | ||
} | ||
return fnc.apply(arguments[0], args); | ||
}; | ||
/** | ||
@@ -123,3 +301,2 @@ * Create a function that will call the given function with | ||
* | ||
* @param {Function} fnc The function body | ||
* @param {String} name The name to use for the wrapper | ||
@@ -131,3 +308,3 @@ * | ||
var fnc, unmethod, sourcecode; | ||
var fnc, sourcecode; | ||
@@ -138,32 +315,97 @@ if (this._unmethodized) return this._unmethodized; | ||
unmethod = function() { | ||
if (typeof name == 'undefined') { | ||
name = fnc.name; | ||
} | ||
var args = [], | ||
// Get the sourcecode | ||
sourcecode = 'function ' + name + unmethod.slice(9); | ||
eval('Blast.defineProperty(fnc, "_unmethodized", {value:' + sourcecode + '});'); | ||
// Make sure an unmethodized function doesn't get unmethodized | ||
Blast.defineProperty(fnc._unmethodized, '_unmethodized', {value: fnc._unmethodized}); | ||
// Add the methodized function | ||
Blast.defineProperty(fnc, '_methodized', {value: fnc}); | ||
return this._unmethodized; | ||
}); | ||
/** | ||
* Create a function that already contains pre-filled-in arguments | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* | ||
* @return {Function} | ||
*/ | ||
Blast.definePrototype('Function', 'curry', function curry() { | ||
var curryArgs, | ||
curried, | ||
name, | ||
fnc, | ||
i; | ||
// If no arguments are given, return the same function | ||
if (arguments.length === 0) { | ||
return this; | ||
} | ||
fnc = this; | ||
curryArgs = Array.prototype.slice.call(arguments, 0); | ||
curriedSource = function() { | ||
var args, | ||
i; | ||
for (i = 1; i < arguments.length; i++) { | ||
// Clone the pre-filled arguments | ||
args = curryArgs.slice(0); | ||
// Add the new arguments | ||
for (i = 0; i < arguments.length; i++) { | ||
args.push(arguments[i]); | ||
} | ||
return fnc.apply(arguments[0], args); | ||
// Apply the original function, with the curent context | ||
return fnc.apply(this, args); | ||
}; | ||
if (typeof name == 'undefined') { | ||
name = fnc.name; | ||
} | ||
name = fnc.name || ''; | ||
// Get the sourcecode | ||
sourcecode = 'function ' + name + String(unmethod).slice(9); | ||
sourcecode = 'function ' + name + String(curriedSource).slice(9); | ||
eval('this._unmethodized = ' + sourcecode); | ||
eval('curried = ' + sourcecode); | ||
// Make sure a methodized function doesn't get methodized | ||
this._unmethodized._unmethodized = this._unmethodized; | ||
return curried; | ||
}); | ||
// Add the unmethodized function | ||
this._methodized = fnc; | ||
return this._unmethodized; | ||
/** | ||
* Execute a function in a try/catch statement. | ||
* This should be done in a separate function like this because | ||
* try/catch breaks optimization. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Function} fnc | ||
* @param {Array} args | ||
* | ||
* @return {Error} | ||
*/ | ||
Blast.defineStatic('Function', 'tryCatch', function tryCatch(fnc, args, context) { | ||
try { | ||
if (context) { | ||
return fnc.apply(context, args); | ||
} else { | ||
return fnc.apply(void 0, args); | ||
} | ||
} catch (err) { | ||
return err; | ||
} | ||
}); | ||
}; |
@@ -37,23 +37,50 @@ /** | ||
plural_rules: [ | ||
[new RegExp('(business)$', 'gi'), '$1es'], | ||
[new RegExp('(m)an$', 'gi'), '$1en'], | ||
[new RegExp('(pe)rson$', 'gi'), '$1ople'], | ||
[new RegExp('(child)$', 'gi'), '$1ren'], | ||
[new RegExp('^(ox)$', 'gi'), '$1en'], | ||
[new RegExp('(ax|test)is$', 'gi'), '$1es'], | ||
[new RegExp('(octop|vir)us$', 'gi'), '$1i'], | ||
[new RegExp('(alias|status)$', 'gi'), '$1es'], | ||
[new RegExp('(bu)s$', 'gi'), '$1ses'], | ||
[new RegExp('(buffal|tomat|potat)o$', 'gi'), '$1oes'], | ||
[new RegExp('([ti])um$', 'gi'), '$1a'], | ||
[new RegExp('sis$', 'gi'), 'ses'], | ||
[new RegExp('(?:([^f])fe|([lr])f)$', 'gi'), '$1$2ves'], | ||
[new RegExp('(hive)$', 'gi'), '$1s'], | ||
[new RegExp('([^aeiouy]|qu)y$', 'gi'), '$1ies'], | ||
[new RegExp('(x|ch|ss|sh)$', 'gi'), '$1es'], | ||
[new RegExp('(matr|vert|ind)ix|ex$', 'gi'), '$1ices'], | ||
[new RegExp('([m|l])ouse$', 'gi'), '$1ice'], | ||
[new RegExp('(quiz)$', 'gi'), '$1zes'], | ||
[new RegExp('s$', 'gi'), 's'], | ||
[new RegExp('$', 'gi'), 's'] | ||
// do not replace if its already a plural word | ||
[ new RegExp( '(m)en$', 'gi' )], | ||
[ new RegExp( '(pe)ople$', 'gi' )], | ||
[ new RegExp( '(child)ren$', 'gi' )], | ||
[ new RegExp( '([ti])a$', 'gi' )], | ||
[ new RegExp( '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$','gi' )], | ||
[ new RegExp( '(hive)s$', 'gi' )], | ||
[ new RegExp( '(tive)s$', 'gi' )], | ||
[ new RegExp( '(curve)s$', 'gi' )], | ||
[ new RegExp( '([lr])ves$', 'gi' )], | ||
[ new RegExp( '([^fo])ves$', 'gi' )], | ||
[ new RegExp( '([^aeiouy]|qu)ies$', 'gi' )], | ||
[ new RegExp( '(s)eries$', 'gi' )], | ||
[ new RegExp( '(m)ovies$', 'gi' )], | ||
[ new RegExp( '(x|ch|ss|sh)es$', 'gi' )], | ||
[ new RegExp( '([m|l])ice$', 'gi' )], | ||
[ new RegExp( '(bus)es$', 'gi' )], | ||
[ new RegExp( '(o)es$', 'gi' )], | ||
[ new RegExp( '(shoe)s$', 'gi' )], | ||
[ new RegExp( '(cris|ax|test)es$', 'gi' )], | ||
[ new RegExp( '(octop|vir)i$', 'gi' )], | ||
[ new RegExp( '(alias|status)es$', 'gi' )], | ||
[ new RegExp( '^(ox)en', 'gi' )], | ||
[ new RegExp( '(vert|ind)ices$', 'gi' )], | ||
[ new RegExp( '(matr)ices$', 'gi' )], | ||
[ new RegExp( '(quiz)zes$', 'gi' )], | ||
[ new RegExp( '(m)an$', 'gi' ), '$1en' ], | ||
[ new RegExp( '(pe)rson$', 'gi' ), '$1ople' ], | ||
[ new RegExp( '(child)$', 'gi' ), '$1ren' ], | ||
[ new RegExp( '^(ox)$', 'gi' ), '$1en' ], | ||
[ new RegExp( '(ax|test)is$', 'gi' ), '$1es' ], | ||
[ new RegExp( '(octop|vir)us$', 'gi' ), '$1i' ], | ||
[ new RegExp( '(alias|status)$', 'gi' ), '$1es' ], | ||
[ new RegExp( '(bu)s$', 'gi' ), '$1ses' ], | ||
[ new RegExp( '(buffal|tomat|potat)o$', 'gi' ), '$1oes' ], | ||
[ new RegExp( '([ti])um$', 'gi' ), '$1a' ], | ||
[ new RegExp( 'sis$', 'gi' ), 'ses' ], | ||
[ new RegExp( '(?:([^f])fe|([lr])f)$', 'gi' ), '$1$2ves' ], | ||
[ new RegExp( '(hive)$', 'gi' ), '$1s' ], | ||
[ new RegExp( '([^aeiouy]|qu)y$', 'gi' ), '$1ies' ], | ||
[ new RegExp( '(x|ch|ss|sh)$', 'gi' ), '$1es' ], | ||
[ new RegExp( '(matr|vert|ind)ix|ex$', 'gi' ), '$1ices' ], | ||
[ new RegExp( '([m|l])ouse$', 'gi' ), '$1ice' ], | ||
[ new RegExp( '(quiz)$', 'gi' ), '$1zes' ], | ||
[ new RegExp( 's$', 'gi' ), 's' ], | ||
[ new RegExp( '$', 'gi' ), 's' ] | ||
], | ||
@@ -63,29 +90,50 @@ | ||
singular_rules: [ | ||
[new RegExp('(m)en$', 'gi'), '$1an'], | ||
[new RegExp('(pe)ople$', 'gi'), '$1rson'], | ||
[new RegExp('(child)ren$', 'gi'), '$1'], | ||
[new RegExp('([ti])a$', 'gi'), '$1um'], | ||
[new RegExp('((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$','gi'), '$1$2sis'], | ||
[new RegExp('(hive)s$', 'gi'), '$1'], | ||
[new RegExp('(tive)s$', 'gi'), '$1'], | ||
[new RegExp('(curve)s$', 'gi'), '$1'], | ||
[new RegExp('([lr])ves$', 'gi'), '$1f'], | ||
[new RegExp('([^fo])ves$', 'gi'), '$1fe'], | ||
[new RegExp('([^aeiouy]|qu)ies$', 'gi'), '$1y'], | ||
[new RegExp('(s)eries$', 'gi'), '$1eries'], | ||
[new RegExp('(m)ovies$', 'gi'), '$1ovie'], | ||
[new RegExp('(b)usiness$', 'gi'), '$1usiness'], | ||
[new RegExp('(x|ch|ss|sh)es$', 'gi'), '$1'], | ||
[new RegExp('([m|l])ice$', 'gi'), '$1ouse'], | ||
[new RegExp('(bus)es$', 'gi'), '$1'], | ||
[new RegExp('(o)es$', 'gi'), '$1'], | ||
[new RegExp('(shoe)s$', 'gi'), '$1'], | ||
[new RegExp('(cris|ax|test)es$', 'gi'), '$1is'], | ||
[new RegExp('(octop|vir)i$', 'gi'), '$1us'], | ||
[new RegExp('(alias|status|business)es$', 'gi'), '$1'], | ||
[new RegExp('^(ox)en', 'gi'), '$1'], | ||
[new RegExp('(vert|ind)ices$', 'gi'), '$1ex'], | ||
[new RegExp('(matr)ices$', 'gi'), '$1ix'], | ||
[new RegExp('(quiz)zes$', 'gi'), '$1'], | ||
[new RegExp('s$', 'gi'), ''] | ||
// do not replace if its already a singular word | ||
[ new RegExp( '(m)an$', 'gi' )], | ||
[ new RegExp( '(pe)rson$', 'gi' )], | ||
[ new RegExp( '(child)$', 'gi' )], | ||
[ new RegExp( '^(ox)$', 'gi' )], | ||
[ new RegExp( '(ax|test)is$', 'gi' )], | ||
[ new RegExp( '(octop|vir)us$', 'gi' )], | ||
[ new RegExp( '(alias|status)$', 'gi' )], | ||
[ new RegExp( '(bu)s$', 'gi' )], | ||
[ new RegExp( '(buffal|tomat|potat)o$', 'gi' )], | ||
[ new RegExp( '([ti])um$', 'gi' )], | ||
[ new RegExp( 'sis$', 'gi' )], | ||
[ new RegExp( '(?:([^f])fe|([lr])f)$', 'gi' )], | ||
[ new RegExp( '(hive)$', 'gi' )], | ||
[ new RegExp( '([^aeiouy]|qu)y$', 'gi' )], | ||
[ new RegExp( '(x|ch|ss|sh)$', 'gi' )], | ||
[ new RegExp( '(matr|vert|ind)ix|ex$', 'gi' )], | ||
[ new RegExp( '([m|l])ouse$', 'gi' )], | ||
[ new RegExp( '(quiz)$', 'gi' )], | ||
// original rule | ||
[ new RegExp( '(m)en$', 'gi' ), '$1an' ], | ||
[ new RegExp( '(pe)ople$', 'gi' ), '$1rson' ], | ||
[ new RegExp( '(child)ren$', 'gi' ), '$1' ], | ||
[ new RegExp( '([ti])a$', 'gi' ), '$1um' ], | ||
[ new RegExp( '((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$','gi' ), '$1$2sis' ], | ||
[ new RegExp( '(hive)s$', 'gi' ), '$1' ], | ||
[ new RegExp( '(tive)s$', 'gi' ), '$1' ], | ||
[ new RegExp( '(curve)s$', 'gi' ), '$1' ], | ||
[ new RegExp( '([lr])ves$', 'gi' ), '$1f' ], | ||
[ new RegExp( '([^fo])ves$', 'gi' ), '$1fe' ], | ||
[ new RegExp( '(m)ovies$', 'gi' ), '$1ovie' ], | ||
[ new RegExp( '([^aeiouy]|qu)ies$', 'gi' ), '$1y' ], | ||
[ new RegExp( '(s)eries$', 'gi' ), '$1eries' ], | ||
[ new RegExp( '(x|ch|ss|sh)es$', 'gi' ), '$1' ], | ||
[ new RegExp( '([m|l])ice$', 'gi' ), '$1ouse' ], | ||
[ new RegExp( '(bus)es$', 'gi' ), '$1' ], | ||
[ new RegExp( '(o)es$', 'gi' ), '$1' ], | ||
[ new RegExp( '(shoe)s$', 'gi' ), '$1' ], | ||
[ new RegExp( '(cris|ax|test)es$', 'gi' ), '$1is' ], | ||
[ new RegExp( '(octop|vir)i$', 'gi' ), '$1us' ], | ||
[ new RegExp( '(alias|status)es$', 'gi' ), '$1' ], | ||
[ new RegExp( '^(ox)en', 'gi' ), '$1' ], | ||
[ new RegExp( '(vert|ind)ices$', 'gi' ), '$1ex' ], | ||
[ new RegExp( '(matr)ices$', 'gi' ), '$1ix' ], | ||
[ new RegExp( '(quiz)zes$', 'gi' ), '$1' ], | ||
[ new RegExp( 'ss$', 'gi' ), 'ss' ], | ||
[ new RegExp( 's$', 'gi' ), '' ] | ||
], | ||
@@ -122,22 +170,25 @@ | ||
apply_rules: function(str, rules, skip, override) { | ||
var ignore, | ||
i, | ||
j; | ||
if (override) { | ||
str = override; | ||
} else { | ||
var ignore = (skip.indexOf(str.toLowerCase()) > -1); | ||
// Have we found a replacement? | ||
//var success = false; | ||
ignore = (skip.indexOf(str.toLowerCase()) > -1); | ||
if (!ignore) { | ||
for (var x = 0; x < rules.length; x++) { | ||
if (str.match(rules[x][0])) { | ||
str = str.replace(rules[x][0], rules[x][1]); | ||
//success = true; | ||
j = rules.length; | ||
for (i = 0; i < j; i++) { | ||
if (str.match(rules[i][0])){ | ||
if (rules[i][1] !== undefined) { | ||
str = str.replace(rules[i][0], rules[i][1]); | ||
} | ||
break; | ||
} | ||
} | ||
// Make sure we return a useable string | ||
//if (!success) str = '' + str; | ||
} | ||
@@ -144,0 +195,0 @@ } |
123
lib/init.js
@@ -9,2 +9,6 @@ module.exports = function BlastInit(modifyPrototype) { | ||
Blast.isBrowser = false; | ||
Blast.isNode = false; | ||
Blast.__init = BlastInit; | ||
// See if we can modify class prototypes | ||
@@ -17,4 +21,6 @@ if (typeof modifyPrototype === 'undefined') { | ||
Globals = window; | ||
Blast.isBrowser = true; | ||
} else { | ||
Globals = global; | ||
Blast.isNode = true; | ||
} | ||
@@ -38,5 +44,8 @@ | ||
'Date', | ||
'Deck', | ||
'Error', | ||
'Function', | ||
'Iterator', | ||
'JSON', | ||
'JSONPath', | ||
'Math', | ||
@@ -126,2 +135,56 @@ 'Number', | ||
/** | ||
* Define a class constructor | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
*/ | ||
Blast.defineClass = function defineClass(className, constructor, shim) { | ||
var objTarget; | ||
if (shim && Globals[className]) { | ||
Blast.Classes[className] = Globals[className]; | ||
} else { | ||
Blast.Classes[className] = constructor; | ||
if (Blast.modifyPrototype) { | ||
Globals[className] = constructor; | ||
} | ||
} | ||
}; | ||
/** | ||
* Define a global | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
*/ | ||
Blast.defineGlobal = function defineGlobal(name, value, shim) { | ||
if (shim && Globals[name]) { | ||
Blast[name] = Globals[name]; | ||
} else { | ||
// Always add it to Blast | ||
Blast[name] = value; | ||
if (Blast.modifyPrototype) { | ||
if (Blast.isNode) { | ||
// In node, every global is an own property of the `global` object | ||
Globals[name] = constructor; | ||
} else { | ||
// In the browser, it's mostly a property of the window prototype | ||
if (Globals.constructor && Globals.constructor.prototype) { | ||
Globals.constructor.prototype[name] = value; | ||
} else { | ||
Globals[name] = value; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
/** | ||
* Define a prototype value | ||
@@ -182,3 +245,3 @@ * | ||
// If this is only a shim, and it already exists on the real class, use that | ||
if (shim && targetClass.prototype[name]) { | ||
if (shim && targetClass.prototype && targetClass.prototype[name]) { | ||
Blast.defineValue(objTarget.prototype, name, targetClass.prototype[name], true); | ||
@@ -289,6 +352,7 @@ } else { | ||
*/ | ||
Blast.getClientPath = function getClientPath() { | ||
Blast.getClientPath = function getClientPath(useCommon) { | ||
var template, | ||
result, | ||
cpath, | ||
files, | ||
@@ -300,4 +364,16 @@ code, | ||
if (Blast.clientPath) { | ||
return Blast.clientPath; | ||
if (useCommon) { | ||
if (Blast.clientPathCommon) { | ||
return Blast.clientPathCommon; | ||
} | ||
cpath = __dirname + '/../client-file-common.js'; | ||
Blast.clientPathCommon = cpath; | ||
} else { | ||
if (Blast.clientPath) { | ||
return Blast.clientPath; | ||
} | ||
cpath = __dirname + '/../client-file.js'; | ||
Blast.clientPath = cpath; | ||
} | ||
@@ -313,3 +389,3 @@ | ||
files = ['init', 'inflections', 'diacritics', 'misc'].concat(Names); | ||
files = ['init', 'inflections', 'diacritics', 'function_flow', 'benchmark', 'misc', 'string_entities', 'setimmediate'].concat(Names); | ||
@@ -330,9 +406,30 @@ files.forEach(function(name, index) { | ||
if (useCommon) { | ||
code += '\nuseCommon = true;\n'; | ||
} | ||
template = template.slice(0, id) + code + template.slice(id); | ||
fs.writeFileSync(__dirname + '/../client-file.js', template); | ||
fs.writeFileSync(cpath, template); | ||
Blast.clientPath = __dirname + '/../client-file.js'; | ||
return cpath; | ||
}; | ||
return Blast.clientPath; | ||
var whenReady = []; | ||
/** | ||
* Execute function after Blast has been completely defined. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Function} fnc | ||
*/ | ||
Blast.ready = function ready(fnc) { | ||
if (whenReady) { | ||
whenReady.push(fnc); | ||
} else { | ||
fnc(); | ||
} | ||
}; | ||
@@ -346,4 +443,8 @@ | ||
require('./string_entities.js')(Blast, Collection); | ||
require('./function_flow.js')(Blast, Collection); | ||
require('./setimmediate.js')(Blast, Collection); | ||
require('./inflections.js')(Blast, Collection); | ||
require('./diacritics.js')(Blast, Collection); | ||
require('./benchmark.js')(Blast, Collection); | ||
require('./misc.js')(Blast, Collection); | ||
@@ -370,3 +471,9 @@ | ||
for (var i = 0; i < whenReady.length; i++) { | ||
whenReady[i](); | ||
} | ||
whenReady = false; | ||
return Blast; | ||
}; |
241
lib/math.js
module.exports = function BlastMath(Blast, Collection) { | ||
/** | ||
* Sorter function | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
*/ | ||
function sortLowToHigh(a, b) { | ||
return a-b; | ||
} | ||
/** | ||
* Clone an array for calculating the median | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
*/ | ||
function cloneForMedian(arr) { | ||
arr = arr.slice(0); | ||
arr.sort(sortLowToHigh); | ||
return arr; | ||
} | ||
/** | ||
* Return a string representing the source code of the object. | ||
@@ -16,2 +40,219 @@ * | ||
/** | ||
* Return the n lowest numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} amount | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Math', 'lowest', function lowest(numbers, amount) { | ||
var result, | ||
i; | ||
if (!amount) { | ||
return Math.min.apply(Math, numbers); | ||
} | ||
// Clone the array | ||
numbers = numbers.slice(0); | ||
// Sort it from low to high | ||
numbers.sort(sortLowToHigh); | ||
// Return the wanted amount of values | ||
return numbers.slice(0, amount); | ||
}); | ||
/** | ||
* Return the n highest numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} amount | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Math', 'highest', function highest(numbers, amount) { | ||
var result, | ||
i; | ||
if (!amount) { | ||
return Math.max.apply(Math, numbers); | ||
} | ||
// Clone the array | ||
numbers = numbers.slice(0); | ||
// Sort it from low to high | ||
numbers.sort(sortLowToHigh); | ||
// Return the wanted amount of values | ||
return numbers.slice(0, amount).reverse(); | ||
}); | ||
/** | ||
* Return the sum of the given numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Math', 'sum', function sum(arr) { | ||
var numbers, | ||
result, | ||
i; | ||
if (Array.isArray(arr)) { | ||
numbers = arr; | ||
} else { | ||
numbers = Array.prototype.slice.call(arguments, 0); | ||
} | ||
result = 0; | ||
for (i = 0; i < numbers.length; i++) { | ||
result += numbers[i]; | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Return the mean/average of the given numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Math', 'mean', function mean(arr) { | ||
var numbers; | ||
if (Array.isArray(arr)) { | ||
numbers = arr; | ||
} else { | ||
numbers = Array.prototype.slice.call(arguments, 0); | ||
} | ||
return Blast.Bound.Math.sum(numbers) / numbers.length; | ||
}); | ||
/** | ||
* Return the variance of the given numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Math', 'variance', function variance(arr) { | ||
var deviations, | ||
numbers, | ||
mean, | ||
i; | ||
if (Array.isArray(arr)) { | ||
numbers = arr; | ||
} else { | ||
numbers = Array.prototype.slice.call(arguments, 0); | ||
} | ||
mean = Blast.Bound.Math.mean(numbers); | ||
deviations = []; | ||
// Get the deviations from the mean | ||
for (i = 0; i < numbers.length; i++) { | ||
deviations.push(Math.pow(numbers[i] - mean, 2)); | ||
} | ||
// Now return the mean value of that list, which is the variance | ||
return Blast.Bound.Math.mean(deviations); | ||
}); | ||
/** | ||
* Return the standard deviation of the given numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Array} arr An array of numbers | ||
* @param {Boolean} relative Return a percentage? | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Math', 'deviation', function deviation(arr, relative) { | ||
var numbers, | ||
dev; | ||
if (Array.isArray(arr)) { | ||
numbers = arr; | ||
} else { | ||
numbers = Array.prototype.slice.call(arguments, 0); | ||
relative = false; | ||
} | ||
// Now return the mean value of that list, which is the variance | ||
dev = Math.sqrt(Blast.Bound.Math.variance(numbers)); | ||
if (relative) { | ||
dev = (dev / Blast.Bound.Math.mean(numbers)) * 100; | ||
} | ||
return dev; | ||
}); | ||
/** | ||
* Return the median of the given numbers | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Math', 'median', function median(arr) { | ||
var numbers, | ||
half, | ||
len; | ||
if (Array.isArray(arr)) { | ||
numbers = arr; | ||
} else { | ||
numbers = Array.prototype.slice.call(arguments, 0); | ||
} | ||
// Get a sorted clone of the array | ||
numbers = cloneForMedian(numbers); | ||
// Get the amount of values | ||
len = numbers.length; | ||
// Get the halfway point | ||
half = ~~(len/2); | ||
if (len % 2) { | ||
return numbers[half]; | ||
} else { | ||
return (numbers[half-1] + numbers[half]) / 2; | ||
} | ||
}); | ||
}; |
module.exports = function BlastNumber(Blast, Collection) { | ||
/** | ||
* Return a random integer that can be at least `min` and at most `max` | ||
* Defaults to numbers between -1 and 101. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} min Optional minimum number (0 by default) | ||
* @param {Number} max Optional maximum number (100 by default) | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.defineStatic('Number', 'random', function random(min, max) { | ||
if (typeof max === 'undefined') { | ||
if (typeof min === 'undefined') { | ||
max = 100; | ||
} else { | ||
max = min; | ||
} | ||
min = 0; | ||
} | ||
return Math.floor(Math.random()*(max-min+1)+min); | ||
}); | ||
/** | ||
* Return a string representing the source code of the number. | ||
@@ -34,2 +63,23 @@ * | ||
/** | ||
* Humanize a number | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} delimiter | ||
* @param {String} separator | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('Number', 'humanize', function humanize(delimiter, separator) { | ||
var str = this.toString().split('.'); | ||
str[0] = str[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + (delimiter||',')); | ||
return str.join(separator||'.'); | ||
}); | ||
}; |
@@ -66,2 +66,123 @@ module.exports = function BlastObject(Blast, Collection) { | ||
/** | ||
* Check if the argument is actually an object | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj | ||
* | ||
* @return {Boolean} | ||
*/ | ||
Blast.defineStatic('Object', 'isObject', function isObject(obj) { | ||
if (!obj) { | ||
return false; | ||
} | ||
return typeof obj === 'object'; | ||
}); | ||
/** | ||
* Check if the argument is a plain object | ||
* (created with an object literal or new Object) | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj | ||
* | ||
* @return {Boolean} | ||
*/ | ||
Blast.defineStatic('Object', 'isPlainObject', function isPlainObject(obj) { | ||
if (!obj) { | ||
return false; | ||
} | ||
if (obj.constructor.name === 'Object') { | ||
return true; | ||
} | ||
return false; | ||
}); | ||
/** | ||
* Check if the argument is the object form of a primitive | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj | ||
* | ||
* @return {Boolean} | ||
*/ | ||
Blast.defineStatic('Object', 'isPrimitiveObject', function isPrimitiveObject(obj) { | ||
var id; | ||
// If the argument isn't even an object, return false | ||
if (!obj || typeof obj !== 'object') { | ||
return false; | ||
} | ||
// Get the constructor name | ||
id = obj.constructor.name; | ||
// If it's constructed by one of the 3 primitives, return true | ||
if (id == 'String' || id == 'Number' || id == 'Boolean') { | ||
return true; | ||
} | ||
return false; | ||
}); | ||
/** | ||
* Flatten an object | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj The object to flatten | ||
* | ||
* @return {Object} | ||
*/ | ||
Blast.defineStatic('Object', 'flatten', function flatten(obj) { | ||
var result = {}, | ||
temp, | ||
key, | ||
sub; | ||
for (key in obj) { | ||
// Only flatten own properties | ||
if (!obj.hasOwnProperty(key)) continue; | ||
if (Collection.Object.isPlainObject(obj[key])) { | ||
temp = flatten(obj[key]); | ||
// Inject the keys of the sub-object into the result | ||
for (sub in temp) { | ||
// Again: skip prototype properties | ||
if (!temp.hasOwnProperty(sub)) continue; | ||
result[key + '.' + sub] = temp[sub]; | ||
} | ||
} else if (Collection.Object.isPrimitiveObject(obj[key])) { | ||
// Convert object form of primitives to their primitive values | ||
result[key] = obj[key].valueOf(); | ||
} else { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Create a new object for every key-value and wrap them in an array | ||
@@ -94,2 +215,28 @@ * | ||
/** | ||
* Like divide, but key and value both become properties | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj The object to arrayify | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Object', 'dissect', function disect(obj) { | ||
var list = [], | ||
key; | ||
for (key in obj) { | ||
list[list.length] = { | ||
key: key, | ||
value: obj[key] | ||
}; | ||
} | ||
return list; | ||
}); | ||
/** | ||
* Get the value of the given property path | ||
@@ -99,3 +246,3 @@ * | ||
* @since 0.0.1 | ||
* @version 0.0.1 | ||
* @version 0.1.2 | ||
* | ||
@@ -117,7 +264,15 @@ * @param {Object} obj | ||
if (typeof path !== 'string') { | ||
return; | ||
if (Array.isArray(path)) { | ||
pieces = path; | ||
} else { | ||
return; | ||
} | ||
} else { | ||
pieces = []; | ||
for (i = 1; i < arguments.length; i++) { | ||
pieces = pieces.concat(arguments[i].split('.')); | ||
} | ||
} | ||
pieces = path.split('.'); | ||
here = obj; | ||
@@ -161,4 +316,4 @@ | ||
var pieces = path.split('.'), | ||
result = false, | ||
var pieces, | ||
result, | ||
hereType, | ||
@@ -170,2 +325,9 @@ here, | ||
if (!path) { | ||
return false; | ||
} | ||
result = false; | ||
pieces = path.split('.'); | ||
// Set the object as the current position | ||
@@ -300,3 +462,3 @@ here = obj; | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* @version 0.1.2 | ||
* | ||
@@ -321,2 +483,7 @@ * @param {Mixed} source | ||
// Convert object form of primitives to their primitive states | ||
if (Collection.Object.isPrimitiveObject(source)) { | ||
source = source.valueOf(); | ||
} | ||
if (Array.isArray(source)) { | ||
@@ -333,6 +500,14 @@ for (i = 0; i < source.length; i++) { | ||
} | ||
} else if (Collection.Object.isObject(source)) { | ||
Collection.Object.assign(result, source); | ||
} else { | ||
Collection.Object.assign(result, source); | ||
if (typeof source !== 'boolean' && (source || typeof source !== 'undefined')) { | ||
result[source] = value; | ||
} | ||
} | ||
if (!recursive) { | ||
return result; | ||
} | ||
for (key in result) { | ||
@@ -342,5 +517,3 @@ type = typeof result[key]; | ||
if (type == 'object') { | ||
if (recursive) { | ||
result[key] = Collection.Object.objectify(result[key], true, value); | ||
} | ||
result[key] = Collection.Object.objectify(result[key], true, value); | ||
} | ||
@@ -432,2 +605,40 @@ } | ||
/** | ||
* Extract data from objects using JSONPath | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object|Array} obj The object to search in | ||
* @param {String} expr The expression to use | ||
* | ||
* @return {Array} | ||
*/ | ||
Blast.defineStatic('Object', 'extract', function extract(obj, expr, arg) { | ||
var P = new Blast.Classes.JSONPath(expr, arg); | ||
return P.exec(obj); | ||
}); | ||
/** | ||
* See if a key exists in an object or array | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* | ||
* @param {Object|Array} target The object to search in | ||
* @param {String} property The key to look for | ||
* | ||
* @return {Boolean} | ||
*/ | ||
Blast.defineStatic('Object', 'hasProperty', function hasProperty(target, property) { | ||
if (target && (typeof target[property] !== 'undefined' || property in target)) { | ||
return true; | ||
} | ||
return false; | ||
}); | ||
/** | ||
* Look for a value in an object or array | ||
@@ -434,0 +645,0 @@ * |
@@ -19,2 +19,68 @@ module.exports = function BlastRegExp(Blast, Collection) { | ||
/** | ||
* Create a regular expression from a string. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} pattern | ||
* | ||
* @return {RegExp} | ||
*/ | ||
Blast.defineStatic('RegExp', 'interpret', function interpret(pattern) { | ||
var split = pattern.match(/^\/(.*?)\/([gim]*)$/); | ||
if (split) { | ||
// The input contains modifiers, use them | ||
return new RegExp(split[1], split[2]); | ||
} else { | ||
// There are no delimiters | ||
return new RegExp(pattern); | ||
} | ||
}); | ||
/** | ||
* Combine regular expressions together. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {RegExp} | ||
*/ | ||
Blast.defineStatic('RegExp', 'combine', function combine() { | ||
var source, | ||
arg, | ||
i; | ||
for (i = 0; i < arguments.length; i++) { | ||
arg = arguments[i]; | ||
// Make sure the argument is a valid regex | ||
if (typeof arg == 'string') { | ||
arg = Collection.RegExp.interpret(arg); | ||
} | ||
if (!arg || arg.constructor.name !== 'RegExp') { | ||
continue; | ||
} | ||
if (!source) { | ||
source = '('; | ||
} else { | ||
source += '|'; | ||
} | ||
source += '(?:' + Collection.RegExp.prototype.getPattern.call(arg) + ')'; | ||
} | ||
source += ')'; | ||
return new RegExp(source); | ||
}); | ||
/** | ||
* Return a string representing the source code of the regular expression. | ||
@@ -32,2 +98,48 @@ * | ||
/** | ||
* Return the pattern. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('RegExp', 'getPattern', function getPattern() { | ||
var source = this.toString(), | ||
split = source.match(/^\/(.*?)\/([gim]*)$/); | ||
if (split) { | ||
// The input contains modifiers, return only the pattern | ||
return split[1]; | ||
} else { | ||
// There are no delimiters | ||
return source; | ||
} | ||
}); | ||
/** | ||
* Return the flags. | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.0 | ||
* @version 0.1.0 | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('RegExp', 'getFlags', function getFlags() { | ||
var source = this.toString(), | ||
split = source.match(/^\/(.*?)\/([gim]*)$/); | ||
if (split) { | ||
// The input contains modifiers, return only the pattern | ||
return split[2]; | ||
} else { | ||
// There are no flags | ||
return ''; | ||
} | ||
}); | ||
}; |
@@ -9,2 +9,34 @@ module.exports = function BlastString(Blast, Collection) { | ||
/** | ||
* Serialize the given parameter to valid HTML attributes | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Object} obj The object to serialize | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.defineStatic('String', 'serializeAttributes', function serializeAttributes(obj) { | ||
var result = '', | ||
val, | ||
key; | ||
obj = Collection.Object.objectify(obj); | ||
for (key in obj) { | ||
// Add a space to separate values | ||
if (result) result += ' '; | ||
val = String(obj[key]).replace('"', '"'); | ||
result += key + '="' + val + '"'; | ||
} | ||
return result; | ||
}); | ||
/** | ||
* Return a string representing the source code of the object. | ||
@@ -23,2 +55,300 @@ * | ||
/** | ||
* Return the string after the given needle | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} needle The string to look for | ||
* @param {Boolean} first Get from the first or last | ||
* | ||
* @return {String} The string after the needle | ||
*/ | ||
Blast.definePrototype('String', 'after', function after(needle, first) { | ||
var count, | ||
arr, | ||
id; | ||
if (typeof first === 'undefined') { | ||
first = true; | ||
} | ||
if (first === true || first === 1) { | ||
id = this.indexOf(needle); | ||
} else if (first === false || first === 0 || first === -1) { // Last | ||
id = this.lastIndexOf(needle); | ||
} else if (typeof first === 'number') { | ||
// Use the count variable for readability | ||
count = first; | ||
// Return everything after a specific numbered occurence | ||
arr = this.split(needle); | ||
if (arr.length <= count) { | ||
return ''; | ||
} | ||
return arr.splice(count).join(needle); | ||
} else { | ||
return ''; | ||
} | ||
if (id === -1) { | ||
return ''; | ||
} | ||
return this.substr(id + needle.length); | ||
}); | ||
/** | ||
* Return the string after the last occurence of the given needle | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} needle The string to look for | ||
* | ||
* @return {String} The string after the needle | ||
*/ | ||
Blast.definePrototype('String', 'afterLast', function afterLast(needle) { | ||
return this.after(needle, false); | ||
}); | ||
/** | ||
* Return the string before the given needle | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} needle The string to look for | ||
* @param {Boolean} first Get from the first or last | ||
* | ||
* @return {String} The string without any tags | ||
*/ | ||
Blast.definePrototype('String', 'before', function before(needle, first) { | ||
var count, | ||
arr, | ||
id; | ||
if (typeof first === 'undefined') { | ||
first = true; | ||
} | ||
if (first === true || first === 1) { | ||
id = this.indexOf(needle); | ||
} else if (first === false || first === 0 || first === -1) { // Last | ||
id = this.lastIndexOf(needle); | ||
} else if (typeof first === 'number') { | ||
// Use the count variable for readability | ||
count = first; | ||
// Return everything before a specific numbered occurence | ||
arr = this.split(needle); | ||
if (arr.length <= count) { | ||
return ''; | ||
} | ||
return arr.splice(0, count).join(needle); | ||
} else { | ||
return ''; | ||
} | ||
if (id === -1) { | ||
return ''; | ||
} | ||
return this.substr(0, id); | ||
}); | ||
/** | ||
* Return the string before the last occurence of the given needle | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} needle The string to look for | ||
* | ||
* @return {String} The string after the needle | ||
*/ | ||
Blast.definePrototype('String', 'beforeLast', function beforeLast(needle) { | ||
return this.before(needle, false); | ||
}); | ||
/** | ||
* Remove HTML tags from the string | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @return {String} The string without any tags | ||
*/ | ||
Blast.definePrototype('String', 'stripTags', function stripTags() { | ||
return this.replace(/(<([^>]+)>)/ig, ''); | ||
}); | ||
/** | ||
* Dissect a string into parts inside the given delimiters | ||
* and outside of it | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} open The open tag | ||
* @param {String} close The close tag | ||
* | ||
* @return {Array} An array of objects | ||
*/ | ||
Blast.definePrototype('String', 'dissect', function dissect(open, close) { | ||
var closeLen = close.length, | ||
openLen = open.length, | ||
result = [], | ||
lineCount = 0, | ||
str = this, | ||
isOpen, | ||
obj, | ||
cur, | ||
i; | ||
for (i = 0; i < str.length; i++) { | ||
cur = str[i]; | ||
if (cur == '\n') { | ||
lineCount++; | ||
} | ||
// If the tag is open | ||
if (isOpen) { | ||
if (str.substr(i, closeLen) == close) { | ||
i += (closeLen - 1); | ||
isOpen = false; | ||
obj.lineEnd = lineCount; | ||
} else { | ||
obj.content += cur; | ||
} | ||
continue; | ||
} | ||
// See if a tag is being opened | ||
if (str.substr(i, openLen) == open) { | ||
if (obj && obj.type == 'normal') { | ||
obj.lineEnd = lineCount; | ||
} | ||
obj = {type: 'inside', lineStart: lineCount, lineEnd: undefined, content: ''}; | ||
result.push(obj); | ||
isOpen = true; | ||
i += (openLen - 1); | ||
continue; | ||
} | ||
// No tag is open, no tag is being opened | ||
if (!obj || obj.type != 'normal') { | ||
obj = {type: 'normal', lineStart: lineCount, lineEnd: undefined, content: ''}; | ||
result.push(obj); | ||
} | ||
obj.content += cur; | ||
} | ||
obj.lineEnd = lineCount; | ||
return result; | ||
}); | ||
/** | ||
* Truncate a string | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {Number} length The maximum length of the string | ||
* @param {Boolean} word Cut off at a word border | ||
* @param {String} ellipsis How to indicate it's been cut | ||
* | ||
* @return {String} The truncated string | ||
*/ | ||
Blast.definePrototype('String', 'truncate', function truncate(length, word, ellipsis) { | ||
var simpleCut, | ||
index; | ||
if (this.length <= length) { | ||
return this.toString(); | ||
} | ||
if (typeof ellipsis === 'undefined') { | ||
ellipsis = '...'; | ||
} else if (typeof ellipsis !== 'string') { | ||
ellipsis = ''; | ||
} | ||
// Get the simple cut | ||
simpleCut = this.substr(0, length - ellipsis.length); | ||
if (typeof word === 'undefined' || word) { | ||
// Get the last position of a word boundary | ||
index = Math.max(simpleCut.lastIndexOf(' '), simpleCut.lastIndexOf('.'), simpleCut.lastIndexOf('!'), simpleCut.lastIndexOf('?')); | ||
// If a word boundary was found near the end of the string... | ||
if (index !== -1 && index >= (length - 15)) { | ||
simpleCut = simpleCut.substr(0, index); | ||
} | ||
} | ||
return simpleCut + ellipsis; | ||
}); | ||
/** | ||
* Replace every occurence of needle in the string without using regexes | ||
* | ||
* @author Jelle De Loecker <jelle@codedor.be> | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* | ||
* @param {String} needle The string to look for | ||
* @param {String} replacement | ||
* | ||
* @return {String} The string after the replacement | ||
*/ | ||
Blast.definePrototype('String', 'replaceAll', function replaceAll(needle, replacement) { | ||
var count, | ||
str, | ||
len, | ||
i; | ||
count = this.match(RegExp(needle, 'g')); | ||
if (!count) { | ||
return this; | ||
} | ||
str = this; | ||
len = count.length; | ||
for (i = 0; i < len; i++) { | ||
str = str.replace(needle, replacement); | ||
} | ||
return str; | ||
}); | ||
/** | ||
* Count the number of capital letters in the string | ||
@@ -41,3 +371,3 @@ * | ||
* @since 0.0.1 | ||
* @version 0.0.1 | ||
* @version 0.1.2 | ||
* | ||
@@ -48,4 +378,27 @@ * @return {Number} The number of times the string appears | ||
var result = this.match(RegExp(word, 'g')); | ||
var result, | ||
pos; | ||
// When the string is less than 500 characters long, use a loop | ||
if (this.length < 500) { | ||
result = 0; | ||
pos = 0; | ||
while(true) { | ||
pos = this.indexOf(word, pos); | ||
if (pos >= 0) { | ||
result++; | ||
pos++; | ||
} else { | ||
break; | ||
} | ||
} | ||
return result; | ||
} | ||
// If it's longer, use a regex | ||
result = this.match(RegExp(word, 'g')); | ||
if (!result) { | ||
@@ -93,3 +446,3 @@ return 0; | ||
* @since 0.0.1 | ||
* @version 0.1.0 | ||
* @version 0.1.2 | ||
* | ||
@@ -108,3 +461,3 @@ * @param {String} postfix The string to append | ||
// Append the postfix if it isn't present yet | ||
if (!str.endsWith(postfix)) str += postfix; | ||
if (!Blast.Bound.String.endsWith(str, postfix)) str += postfix; | ||
@@ -293,3 +646,3 @@ return str; | ||
* @since 0.0.1 | ||
* @version 0.0.1 | ||
* @version 0.1.2 | ||
* | ||
@@ -312,3 +665,3 @@ * @param {Object} values | ||
if (values && typeof values == 'object') { | ||
params = this.placeholders(); | ||
params = Blast.Bound.String.placeholders(this); | ||
@@ -315,0 +668,0 @@ for (i = 0; i < params.length; i++) { |
{ | ||
"name": "protoblast", | ||
"description": "Handy functions for several classes' prototype", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"author": "Jelle De Loecker <jelle@codedor.be>", | ||
@@ -14,3 +14,4 @@ "keywords": ["prototype", "util", "functional", "server", "client", "browser"], | ||
"devDependencies": { | ||
"mocha": "1.20.x" | ||
"mocha": "1.20.x", | ||
"matcha": "skerit/matcha" | ||
}, | ||
@@ -17,0 +18,0 @@ "engines": { |
@@ -92,2 +92,55 @@ var assert = require('assert'), | ||
describe('.range(start, stop, step)', function() { | ||
it('should return an array containing arithmetic progressions', function() { | ||
var arr = Array.range(0, 10, 1); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
}); | ||
it('should be able to only receive the stop parameter', function() { | ||
var arr = Array.range(10); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
}); | ||
it('should be able to fill in the step parameter', function() { | ||
var arr = Array.range(0, 10); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
}); | ||
it('should honour use other steps', function() { | ||
var arr = Array.range(0, 10, 2); | ||
assert.equal('0,2,4,6,8', arr.join()); | ||
}); | ||
it('should return an empty array for impossible steps', function() { | ||
var arr = Array.range(0, 10, -1); | ||
assert.equal('', arr.join()); | ||
}); | ||
it('should allow negative steps for counting down', function() { | ||
var arr = Array.range(10, 0, -1); | ||
assert.equal('10,9,8,7,6,5,4,3,2,1', arr.join()); | ||
}); | ||
it('should default non-numeric steps to 1', function() { | ||
var arr = Array.range(0, 10, 'X'); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
}); | ||
it('should handle string arguments', function() { | ||
var arr = Array.range('10'); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
arr = Array.range('0', '10', '1'); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
arr = Array.range('0', '10'); | ||
assert.equal('0,1,2,3,4,5,6,7,8,9', arr.join()); | ||
arr = Array.range('0', '10', '-1'); | ||
assert.equal('', arr.join()); | ||
}); | ||
}); | ||
describe('#toSource()', function() { | ||
@@ -114,2 +167,62 @@ it('should return the source code representation of the array', function() { | ||
describe('#closest(goal)', function() { | ||
it('should return the closest value in the array', function() { | ||
var arr = Array.range(0, 100000, 33); | ||
assert.equal(3465, arr.closest(3470)); | ||
}); | ||
it('should support negative goals', function() { | ||
var arr = Array.range(0, 100000, 33); | ||
assert.equal(0, arr.closest(-1)); | ||
}); | ||
it('should return the first value when a non-numeric string is passed', function() { | ||
var arr = Array.range(0, 100000, 33); | ||
assert.equal(0, arr.closest('a')); | ||
}); | ||
}); | ||
describe('#insert(index, value, ...)', function() { | ||
it('should insert the value in the original array at the given index', function() { | ||
var a = [0,1,2,3], | ||
inserted = a.insert(2, 'inserted'); | ||
assert.equal(a, inserted, 'The array is not modified in place'); | ||
assert.equal('0,1,inserted,2,3', inserted.join()); | ||
}); | ||
it('should insert all the values given', function() { | ||
var a = [0,1,2,3], | ||
inserted = a.insert(2, 'i1', 'i2'); | ||
assert.equal(a, inserted, 'The array is not modified in place'); | ||
assert.equal('0,1,i1,i2,2,3', inserted.join()); | ||
}); | ||
it('should insert the values at the wanted index, even if the array is not long enough', function() { | ||
var a = [0,1,2,3], | ||
inserted = a.insert(6, 6, 7,8); | ||
assert.equal(a, inserted, 'The array is not modified in place'); | ||
assert.equal('0,1,2,3,,6,7,8', inserted.join()); | ||
}); | ||
}); | ||
describe('#unique()', function() { | ||
it('should return all the unique values', function() { | ||
var a = [1,2,1,3,6,2]; | ||
assert.equal('1,2,3,6', a.unique().join(',')); | ||
}); | ||
it('should return objects even when they have the same properties', function() { | ||
var a = [1,1, {a:1}, {a:1}]; | ||
assert.equal('1,[object Object],[object Object]', a.unique().join(',')); | ||
}); | ||
}); | ||
describe('#shared(secondArray)', function() { | ||
@@ -187,2 +300,28 @@ it('should return the shared values between 2 arrays as an array', function() { | ||
describe('#createIterator()', function() { | ||
var arr = ['a', 'b', 'c', 'd']; | ||
it('should return an iterator', function() { | ||
var iter = arr.createIterator(); | ||
assert.equal('Iterator', iter.constructor.name); | ||
}); | ||
it('should iterate', function() { | ||
var iter = arr.createIterator(), | ||
val, | ||
abc = ''; | ||
while (iter.hasNext()) { | ||
val = iter.next().value; | ||
abc += val; | ||
} | ||
assert.equal('abcd', abc); | ||
}); | ||
}); | ||
}); |
@@ -12,2 +12,12 @@ var assert = require('assert'), | ||
describe('.isDate(variable)', function() { | ||
it('should return true if the argument is a date object', function() { | ||
var date = new Date(), | ||
str = ''; | ||
assert.equal(true, Date.isDate(date)); | ||
assert.equal(false, Date.isDate(str)); | ||
}); | ||
}); | ||
describe('#toSource()', function() { | ||
@@ -14,0 +24,0 @@ it('should return the source code representation of the date', function() { |
@@ -43,2 +43,19 @@ var assert = require('assert'), | ||
describe('#curry()', function() { | ||
it('should create a function that already contains pre-filled-in arguments', function() { | ||
var adder, | ||
addTen; | ||
adder = function adder(a, b) { | ||
return a+b; | ||
} | ||
addTen = adder.curry(10); | ||
assert.equal(adder(10,5), addTen(5)); | ||
assert.equal(adder.name, addTen.name); | ||
}); | ||
}); | ||
}); |
@@ -6,2 +6,20 @@ var assert = require('assert'), | ||
describe('.random(min, max)', function() { | ||
it('should return a random number', function() { | ||
var def = Number.random(), | ||
dec = Number.random(0,10), | ||
neg = Number.random(-10,0); | ||
assert.equal(true, def > -1, 'Default should return an integer above -1'); | ||
assert.equal(true, def < 101, 'Default should return an integer under 101'); | ||
assert.equal(true, dec > -1, '(0,10) should return an integer above -1'); | ||
assert.equal(true, dec < 11, '(0,10) should return an integer under 11'); | ||
assert.equal(true, neg > -11, '(0,10) should return an integer above -11'); | ||
assert.equal(true, neg < 1, '(0,10) should return an integer under 1'); | ||
}); | ||
}); | ||
describe('#toSource()', function() { | ||
@@ -19,2 +37,12 @@ it('should return the source code representation of the number', function() { | ||
describe('#humanize(delimiter, separator)', function() { | ||
it('should humanize a number', function() { | ||
assert.equal('1,840,774.5', 1840774.5.humanize()); | ||
}); | ||
it('should humanize a number with given parameters', function() { | ||
assert.equal('1 840 774,5', 1840774.5.humanize(' ', ',')); | ||
}); | ||
}); | ||
}); |
@@ -22,2 +22,109 @@ var assert = require('assert'), | ||
describe('.isObject(obj)', function() { | ||
it('should return true for regular objects', function() { | ||
assert.equal(true, Object.isObject({})); | ||
assert.equal(true, Object.isObject(new Object())); | ||
}); | ||
it('should return true for arrays', function() { | ||
assert.equal(true, Object.isObject([])); | ||
assert.equal(true, Object.isObject(new Array())); | ||
}); | ||
it('should return true for the object form of primitives', function() { | ||
assert.equal(true, Object.isObject(new String())); | ||
assert.equal(true, Object.isObject(new Number())); | ||
assert.equal(true, Object.isObject(new Boolean())); | ||
}); | ||
it('should return false for null', function() { | ||
assert.equal(false, Object.isObject(null)); | ||
}); | ||
it('should return false for primitives', function() { | ||
assert.equal(false, Object.isObject('')); | ||
assert.equal(false, Object.isObject(1)); | ||
assert.equal(false, Object.isObject(true)); | ||
}); | ||
}); | ||
describe('.isPlainObject(obj)', function() { | ||
it('should return true for plain objects', function() { | ||
var obj = new Object(), | ||
obj2 = { | ||
one: 1, | ||
two: 2, | ||
three: 3 | ||
}; | ||
assert.equal(true, Object.isPlainObject(obj)); | ||
assert.equal(true, Object.isPlainObject(obj2)); | ||
}); | ||
it('should return false for other objects', function() { | ||
var arr = [], | ||
str = new String(), | ||
nr = new Number(); | ||
testclass = function testclass(){}, | ||
testobj = new testclass(); | ||
assert.equal(false, Object.isPlainObject(arr)); | ||
assert.equal(false, Object.isPlainObject(str)); | ||
assert.equal(false, Object.isPlainObject(nr)); | ||
assert.equal(false, Object.isPlainObject(testobj)); | ||
}); | ||
it('should return false for primitives', function() { | ||
assert.equal(false, Object.isPlainObject(1)); | ||
assert.equal(false, Object.isPlainObject('a')); | ||
assert.equal(false, Object.isPlainObject(true)); | ||
assert.equal(false, Object.isPlainObject(undefined)); | ||
assert.equal(false, Object.isPlainObject(null)); | ||
assert.equal(false, Object.isPlainObject(NaN)); | ||
}); | ||
}); | ||
describe('.isPrimitiveObject(obj)', function() { | ||
it('should return true for the object form of primitives', function() { | ||
assert.equal(true, Object.isPrimitiveObject(new String())); | ||
assert.equal(true, Object.isPrimitiveObject(new Number())); | ||
assert.equal(true, Object.isPrimitiveObject(new Boolean())); | ||
}); | ||
it('should return false for other objects', function() { | ||
assert.equal(false, Object.isPrimitiveObject([])); | ||
assert.equal(false, Object.isPrimitiveObject({})); | ||
}); | ||
it('should return false for regular primitives', function() { | ||
assert.equal(false, Object.isPrimitiveObject(0)); | ||
assert.equal(false, Object.isPrimitiveObject('')); | ||
assert.equal(false, Object.isPrimitiveObject(false)); | ||
assert.equal(false, Object.isPrimitiveObject(1)); | ||
assert.equal(false, Object.isPrimitiveObject('a')); | ||
assert.equal(false, Object.isPrimitiveObject(true)); | ||
}); | ||
}); | ||
describe('.flatten(obj)', function() { | ||
it('flatten an object', function() { | ||
var obj = { | ||
one: 1, | ||
settings: { | ||
two: 2, | ||
sub: { | ||
three: 3 | ||
} | ||
} | ||
}; | ||
assert.equal('{"one":1,"settings.two":2,"settings.sub.three":3}', JSON.stringify(Object.flatten(obj))); | ||
}); | ||
}); | ||
describe('.divide(obj)', function() { | ||
@@ -36,4 +143,16 @@ it('should create a new object for every key-value and wrap them in an array', function() { | ||
describe('.dissect(obj)', function() { | ||
it('should act like divide, but also store the key and value as properties', function() { | ||
var obj = { | ||
one: 1, | ||
two: 2, | ||
}; | ||
assert.equal('[{"key":"one","value":1},{"key":"two","value":2}]', JSON.stringify(Object.dissect(obj))); | ||
}); | ||
}); | ||
describe('.path(obj, path)', function() { | ||
it('should get the value of the given property path', function() { | ||
it('should get the value of the given property path (as a string)', function() { | ||
@@ -45,2 +164,18 @@ var obj = {well: {test: {property: 'one'}}}; | ||
}); | ||
it('should get the value of the given property path (as an array)', function() { | ||
var obj = {well: {test: {property: 'one'}}}; | ||
assert.equal('one', Object.path(obj, ['well', 'test', 'property'])); | ||
assert.equal(undefined, Object.path(obj, ['does'], ['not'], ['exist'])); | ||
}); | ||
it('should get the value of the given property path (as arguments)', function() { | ||
var obj = {well: {test: {property: 'one'}}}; | ||
assert.equal('one', Object.path(obj, 'well', 'test', 'property')); | ||
assert.equal(undefined, Object.path(obj, 'does', 'not', 'exist')); | ||
}); | ||
}); | ||
@@ -164,3 +299,18 @@ | ||
describe('.hasProperty(target, propertyName)', function() { | ||
it('should return true if the object has this property', function() { | ||
var obj = {one: 1, falsy: false, zero: 0, undef: undefined}; | ||
assert.equal(true, Object.hasProperty(obj, 'one')); | ||
assert.equal(true, Object.hasProperty(obj, 'falsy', 'Falsy values should also be present')); | ||
assert.equal(true, Object.hasProperty(obj, 'zero', 'Falsy values should also be present')); | ||
assert.equal(true, Object.hasProperty(obj, 'undef', 'Properties with the specific "undefined" value are also true')); | ||
assert.equal(false, Object.hasProperty(obj, 'doesnotexist')); | ||
}); | ||
}); | ||
describe('.hasValue(target, value)', function() { | ||
@@ -167,0 +317,0 @@ |
@@ -15,2 +15,18 @@ var assert = require('assert'), | ||
describe('.interpret(pattern)', function() { | ||
it('should convert a string pattern to a regex', function() { | ||
var pWithMod = '/a|b/gi', | ||
pWithout = 'a|b', | ||
pNoDel = '/a|b/', | ||
rWithMod = RegExp.interpret(pWithMod), | ||
rWithout = RegExp.interpret(pWithout), | ||
rNoDel = RegExp.interpret(pNoDel); | ||
assert.equal(pWithMod, rWithMod.toString()); | ||
assert.equal('/a|b/', rNoDel.toString()); | ||
assert.equal('/a|b/', rWithout.toString()); | ||
}); | ||
}); | ||
describe('#toSource()', function() { | ||
@@ -25,2 +41,20 @@ it('should return the source code representation of the regex', function() { | ||
describe('#getPattern()', function() { | ||
it('should return the pattern part of the regex', function() { | ||
var rx = /search/i; | ||
assert.equal('search', rx.getPattern()); | ||
}); | ||
}); | ||
describe('#getFlags()', function() { | ||
it('should return the flags used in the regex', function() { | ||
var rx = /search/i; | ||
assert.equal('i', rx.getFlags()); | ||
}); | ||
}); | ||
}); |
@@ -12,2 +12,130 @@ var assert = require('assert'), | ||
describe('#after(needle, first)', function() { | ||
var sentence = 'This is the string that contains the that needle that we need'; | ||
it('should return the string after the first occurence of the needle', function() { | ||
assert.strictEqual(' contains the that needle that we need', sentence.after('that')); | ||
}); | ||
it('should return the string after the last occurence of the needle', function() { | ||
assert.strictEqual(' we need', sentence.after('that', false)); | ||
}); | ||
it('should return the string after the wanted occurence of the needle', function() { | ||
assert.strictEqual(' needle that we need', sentence.after('that', 2)); | ||
assert.strictEqual(' we need', sentence.after('that', 3)); | ||
}); | ||
it('should return an empty string if an occurence is wanted that is not there', function() { | ||
assert.strictEqual('', sentence.after('that', 4)); | ||
assert.strictEqual('', sentence.after('castle')); | ||
}); | ||
it('should return an empty string for illegal parameters', function() { | ||
assert.strictEqual('', sentence.after()); | ||
assert.strictEqual('', sentence.after(function(){})); | ||
assert.strictEqual('', sentence.after(false)); | ||
assert.strictEqual('', sentence.after('that', function(){})); | ||
}); | ||
}); | ||
describe('#afterLast(needle)', function() { | ||
var sentence = 'This is the string that contains the that needle that we need'; | ||
it('should return the string after the last occurence of the needle', function() { | ||
assert.strictEqual(' we need', sentence.afterLast('that')); | ||
}); | ||
}); | ||
describe('#before(needle, first)', function() { | ||
var sentence = 'This is the string that contains the that needle that we need'; | ||
it('should return the string before the first occurence of the needle', function() { | ||
assert.strictEqual('This is the string ', sentence.before('that')); | ||
}); | ||
it('should return the string before the last occurence of the needle', function() { | ||
assert.strictEqual('This is the string that contains the that needle ', sentence.before('that', false)); | ||
}); | ||
it('should return the string before the second occurence of the needle', function() { | ||
assert.strictEqual('This is the string that contains the ', sentence.before('that', 2)); | ||
assert.strictEqual('This is the string that contains the that needle ', sentence.before('that', 3)); | ||
}); | ||
it('should return an empty string if an occurence is wanted that is not there', function() { | ||
assert.strictEqual('', sentence.before('that', 4)); | ||
assert.strictEqual('', sentence.before('castle')); | ||
}); | ||
it('should return an empty string for illegal parameters', function() { | ||
assert.strictEqual('', sentence.before()); | ||
assert.strictEqual('', sentence.before(function(){})); | ||
assert.strictEqual('', sentence.before(false)); | ||
assert.strictEqual('', sentence.before('that', function(){})); | ||
}); | ||
}); | ||
describe('#beforeLast(needle)', function() { | ||
var sentence = 'This is the string that contains the that needle that we need'; | ||
it('should return the string before the last occurence of the needle', function() { | ||
assert.strictEqual('This is the string that contains the that needle ', sentence.beforeLast('that')); | ||
}); | ||
}); | ||
describe('#stripTags()', function() { | ||
it('should remove HTML tags from the string', function() { | ||
var original = '<b>This is a <br/>bold string</b>'; | ||
assert.strictEqual('This is a bold string', original.stripTags()); | ||
}); | ||
}); | ||
describe('#dissect(openTag, closeTag)', function() { | ||
it('dissect a string into parts in- and outside of the given delimiters', function() { | ||
var original = 'This <% is a %> test', | ||
arr = original.dissect('<%', '%>'), | ||
expected = '[{"type":"normal","lineStart":0,"lineEnd":0,"content":"This "},{"type":"inside","lineStart":0,"lineEnd":0,"content":" is a "},{"type":"normal","lineStart":0,"lineEnd":0,"content":" test"}]'; | ||
assert.strictEqual(expected, JSON.stringify(arr)); | ||
}); | ||
}); | ||
describe('#encodeHTML()', function() { | ||
it('should encode certain characters to safe HTML code', function() { | ||
var original = '<string> & foo © bar ≠ baz 𝌆 qux'; | ||
assert.strictEqual('<string> & foo © bar ≠ baz �� qux', original.encodeHTML()); | ||
}); | ||
}); | ||
describe('#decodeHTML()', function() { | ||
it('should decode certain escaped HTML entities', function() { | ||
var original = '"<string> & foo © bar ≠ baz �� qux"&'; | ||
assert.strictEqual('"<string> & foo © bar ≠ baz 𝌆 qux"&', original.decodeHTML()); | ||
}); | ||
}); | ||
describe('#truncate(length, word, ellipsis)', function() { | ||
it('should truncate a string', function() { | ||
var original = 'This string is deemed a bit too longified to be put on the screen of the user!', | ||
simple = original.truncate(40, false), | ||
word = original.truncate(40), | ||
ell = original.truncate(40, true, ' (cont)'), | ||
noell = original.truncate(40, false, false); | ||
assert.strictEqual('This string is deemed a bit too longi...', simple); | ||
assert.strictEqual('This string is deemed a bit too...', word); | ||
assert.strictEqual('This string is deemed a bit too (cont)', ell); | ||
assert.strictEqual('This string is deemed a bit too longifie', noell); | ||
}); | ||
}); | ||
describe('#capitals()', function() { | ||
@@ -14,0 +142,0 @@ it('should return the amount of capitals in the string', function() { |
Sorry, the diff of this file is not supported yet
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
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
363870
54
9300
2
8
2