Socket
Socket
Sign inDemoInstall

protoblast

Package Overview
Dependencies
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

protoblast - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

.travis.yml

39

CHANGELOG.md

@@ -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;
}
});
};

173

lib/inflections.js

@@ -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 @@ }

@@ -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;
};
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('"', '&quot;');
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('&#60;string&#62; &#38; foo &#169; bar &#8800; baz &#55348;&#57094; qux', original.encodeHTML());
});
});
describe('#decodeHTML()', function() {
it('should decode certain escaped HTML entities', function() {
var original = '&quot;&#60;string&#62; &#38; foo &#169; bar &#8800; baz &#55348;&#57094; qux&quot;&amp;';
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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc