By Jason Chalom 2014, Entelect Software
Under the MIT License
This contains all helper functions
var exposed = {
saveFile: saveFile,
makeAFile: makeAFile,
log: log,
logObj: logObj,
findArrObj: findArrObj,
findArrObjFromName: findArrObjFromName,
findCell: findCell,
setDebug: setDebug,
getDebug: getDebug,
quickCompare: quickCompare,
deepCompare: deepCompare,
removeLineFromFile: removeLineFromFile,
appendFile: appendFile,
dumpObjToFile: dumpObjToFile,
isEmpty: isEmpty,
pseudoRandGen: pseudoRandGen,
removeLineEndings: removeLineEndings,
readFile: readFile,
readFileLinesArr: readFileLinesArr,
readFileStreamLines: readFileStreamLines,
strRegexSplit: strRegexSplit,
strNoLines: strNoLines,
strCommaSplit: strCommaSplit,
commaConcat: commaConcat,
strSplitLines: strSplitLines,
strCommaSplitNoLine: strCommaSplitNoLine,
concat: concat,
strSemiColonSplitNoLine: strSemiColonSplitNoLine,
semiColonConcat: semiColonConcat
};
module.exports = exposed;
var debug = false;
var fs = require('fs');
var util = require('util');
function concat(val1, val2){
return "" + val1 + val2;
}
function commaConcat(val1, val2) {
return val1 + "," + val2;
}
function semiColonConcat(val1, val2) {
return val1 + ";" + val2;
}
function strSplitLines(str){
return strRegexSplit(str, /\r\n|\r|\n/);
}
function strNoLines(str){
return strRegexSplit(str, /\r\n|\r|\n/).length;
}
function strCommaSplit(str){
return strRegexSplit(str, /;/);
}
function strCommaSplitNoLine(str){
return strRegexSplit(str, /,|\n|\r|\r\n|\n\r/);
}
function strSemiColonSplitNoLine(str){
return strRegexSplit(str, /;|\n|\r|\r\n|\n\r/);
}
function strRegexSplit(str, regex){
return str.split(regex);
}
function removeNewLinesFromString(str){
str = removeLineEndings(str);
}
function readFile(file) {
fs.readFile(file, function (err, data) {
if (err)
return err;
return data.toString();
});
}
function readFileLinesArr(file, regex) {
fs.readFile(file, function (err, data) {
if (err)
return err;
var ds = data.toString();
if (!regex)
regex = "\n";
return ds.split(regex);;
});
}
function readFileStreamLines(file, func) {//http://jesusjzp.github.io/blog/2014/04/15/nodejs-read-file/
var input = fs.createReadStream(file);
var remaining = '';
input.on('data', function(data) {
remaining += data;
var index = remaining.indexOf('\n');
while (index > -1) {
var line = remaining.substring(0, index);
remaining = remaining.substring(index + 1);
func(line);
index = remaining.indexOf('\n');
}
});
input.on('end', function() {
if (remaining.length > 0) {
func(remaining);
}
});
}
function removeLineEndings(str){
return str.replace(/\n|\r|\n\r|\r\n/g, '');
}
function pseudoRandGen(a, b, m){//predicatble pseudo rnd number
var high = 999;
var low = 0;
var now = new Date();
a = (now*44)%999; //arbitrary numbers, could use some kind of seed there as well
b = (now*876)%999;
m = (now*78)%999;
return Math.floor(((a*now+b) % m) + Math.random() * (high - low) + low);
}
function isEmpty(obj) {
// null and undefined are "empty"
if (obj === null) return true;
// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return false;
if (obj.length === 0) return true;
// Otherwise, does it have any properties of its own?
// Note that this doesn't handle
// toString and valueOf enumeration bugs in IE < 9
for (var key in obj) {
if (hasOwnProperty.call(obj, key)) return false;
}
return true;
}
function setDebug(flag) {
debug = flag;
}
function getDebug() {
return debug;
}
function saveFile(buf, outputFile) {
// build file
makeAFile(outputFile);
fs.writeFileSync(outputFile, buf);
}
function makeAFile(file) {
fs.writeFile(file, "", function(err) {
if (err) {
console.log(err);
} else {
console.log("The file was created!");
}
});
}
function dumpObjToFile(obj, outputFile){
saveFile(util.inspect(obj, false, null), outputFile);
}
function appendFile(file, search, line) {
line = line || 0;
var body = fs.readFileSync(file).toString();
if (body.indexOf(search) < 0 ) {
body = body.split('\n');
body.splice(line + 1,0,search);
body = body.filter(function(str){ return str; }); // remove empty lines
var output = body.join('\n');
fs.writeFileSync('example.js', output);
}
}
function removeLineFromFile(file, search) {
var body = fs.readFileSync(file).toString();
var idx = body.indexOf(search);
if (idx >= 0 ) {
var output = body.substr(0, idx) + body.substr(idx + search.length);
fs.writeFileSync(file, output);
}
}
function removeLineFromFile(file, search, addIndex) {
var body = fs.readFileSync(file).toString();
var idx = body.indexOf(search);
if (idx >= 0 ) {
var output = body.substr(0, idx) + body.substr(idx + search.length + addIndex);
fs.writeFileSync(file, output);
}
}
function log(p, prop) {
if (debug)
log(prop + " : " + p[prop]);
return "" + prop + " : " + p[prop];
}
function log(str) {
if (debug)
console.log("log: " + str);
return "log: " + str;
}
function logObj(obj) {
log("obj: " + util.inspect(obj, false, null));
return "obj: " + util.inspect(obj, false, null);
}
function findArrObj(arr, obj) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === obj) return arr[i];
}
return null;
}
function findArrObjFromName(arr, name) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].name === name) return arr[i];
}
return null;
}
function findCell(cells, ws, col, row) {
for (var i = 0; i < cells.length; i++) {
if (cells[i].col === col && cells[i].row === row && cells[i].ws === ws)
return cells[i];
}
return null;
}
function quickCompare(x, y) {
var xObj = JSON.stringify(x);
var yObj = JSON.stringify(y);
if (xObj === yObj)
return true;
return false;
}
function deepCompare() {
var i, l, leftChain, rightChain;
function compare2Objects(x, y) {
var p;
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on step when comparing prototypes
if (x === y) {
return true;
}
// Works in case when functions are created in constructor.
// Comparing dates is a common scenario. Another built-ins?
// We can even handle functions passed across iframes
if ((typeof x === 'function' && typeof y === 'function') ||
(x instanceof Date && y instanceof Date) ||
(x instanceof RegExp && y instanceof RegExp) ||
(x instanceof String && y instanceof String) ||
(x instanceof Number && y instanceof Number)) {
return x.toString() === y.toString();
}
// At last checking prototypes as good a we can
if (!(x instanceof Object && y instanceof Object)) {
return false;
}
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
return false;
}
if (x.constructor !== y.constructor) {
return false;
}
if (x.prototype !== y.prototype) {
return false;
}
// Check for infinitive linking loops
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
return false;
}
// Quick checking of one object beeing a subset of another.
// todo: cache the structure of arguments[0] for performance
for (p in y) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
} else if (typeof y[p] !== typeof x[p]) {
return false;
}
}
for (p in x) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
} else if (typeof y[p] !== typeof x[p]) {
return false;
}
switch (typeof(x[p])) {
case 'object':
case 'function':
leftChain.push(x);
rightChain.push(y);
if (!compare2Objects(x[p], y[p])) {
return false;
}
leftChain.pop();
rightChain.pop();
break;
default:
if (x[p] !== y[p]) {
return false;
}
break;
}
}
return true;
}
if (arguments.length < 1) {
return true; //Die silently? Don't know how to handle such case, please help...
// throw "Need two or more arguments to compare";
}
for (i = 1, l = arguments.length; i < l; i++) {
leftChain = []; //Todo: this can be cached
rightChain = [];
if (!compare2Objects(arguments[0], arguments[i])) {
return false;
}
}
return true;
}