|
|
define([],
|
|
|
|
|
|
function () {
|
|
|
var _create = Object.create,
|
|
|
_keys = Object.keys;
|
|
|
|
|
|
var safe = null;
|
|
|
safe = {
|
|
|
argumentNotNull: function (arg, name) {
|
|
|
if (arg === null || arg === undefined)
|
|
|
throw new Error("The argument " + name + " can't be null or undefined");
|
|
|
},
|
|
|
|
|
|
argumentNotEmptyString: function (arg, name) {
|
|
|
if (typeof (arg) !== "string" || !arg.length)
|
|
|
throw new Error("The argument '" + name + "' must be a not empty string");
|
|
|
},
|
|
|
|
|
|
argumentNotEmptyArray: function (arg, name) {
|
|
|
if (!(arg instanceof Array) || !arg.length)
|
|
|
throw new Error("The argument '" + name + "' must be a not empty array");
|
|
|
},
|
|
|
|
|
|
argumentOfType: function (arg, type, name) {
|
|
|
if (!(arg instanceof type))
|
|
|
throw new Error("The argument '" + name + "' type doesn't match");
|
|
|
},
|
|
|
|
|
|
isNull: function (arg) {
|
|
|
return (arg === null || arg === undefined);
|
|
|
},
|
|
|
|
|
|
isPrimitive: function (arg) {
|
|
|
return (arg === null || arg === undefined || typeof (arg) === "string" ||
|
|
|
typeof (arg) === "number" || typeof (arg) === "boolean");
|
|
|
},
|
|
|
|
|
|
isInteger: function (arg) {
|
|
|
return parseInt(arg) == arg;
|
|
|
},
|
|
|
|
|
|
isNumber: function (arg) {
|
|
|
return parseFloat(arg) == arg;
|
|
|
},
|
|
|
|
|
|
isString: function (val) {
|
|
|
return typeof (val) == "string" || val instanceof String;
|
|
|
},
|
|
|
|
|
|
isNullOrEmptyString: function (str) {
|
|
|
if (str === null || str === undefined ||
|
|
|
((typeof (str) == "string" || str instanceof String) && str.length === 0))
|
|
|
return true;
|
|
|
},
|
|
|
|
|
|
isNotEmptyArray: function (arg) {
|
|
|
return (arg instanceof Array && arg.length > 0);
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Выполняет метод для каждого элемента массива, останавливается, когда
|
|
|
* либо достигнут конец массива, либо функция <c>cb</c> вернула
|
|
|
* значение.
|
|
|
*
|
|
|
* @param{Array | Object} obj массив элементов для просмотра
|
|
|
* @param{Function} cb функция, вызываемая для каждого элемента
|
|
|
* @param{Object} thisArg значение, которое будет передано в качестве
|
|
|
* <c>this</c> в <c>cb</c>.
|
|
|
* @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
|
|
|
* если достигнут конец массива.
|
|
|
*/
|
|
|
each: function (obj, cb, thisArg) {
|
|
|
safe.argumentNotNull(cb, "cb");
|
|
|
var i, x;
|
|
|
if (obj instanceof Array) {
|
|
|
for (i = 0; i < obj.length; i++) {
|
|
|
x = cb.call(thisArg, obj[i], i);
|
|
|
if (x !== undefined)
|
|
|
return x;
|
|
|
}
|
|
|
} else {
|
|
|
var keys = _keys(obj);
|
|
|
for (i = 0; i < keys.length; i++) {
|
|
|
var k = keys[i];
|
|
|
x = cb.call(thisArg, obj[k], k);
|
|
|
if (x !== undefined)
|
|
|
return x;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Копирует свойства одного объекта в другой.
|
|
|
*
|
|
|
* @param{Any} dest объект в который нужно скопировать значения
|
|
|
* @param{Any} src источник из которого будут копироваться значения
|
|
|
* @tmpl{Object|Array} tmpl шаблон по которому будет происходить
|
|
|
* копирование. Если шаблон является массивом
|
|
|
* (список свойств), тогда значения этого массива
|
|
|
* являются именами свойсвт которые будут
|
|
|
* скопированы. Если шаблон является объектом (карта
|
|
|
* преобразования имен свойств src->dst), тогда
|
|
|
* копирование будет осуществляться только
|
|
|
* собственных свойств источника, присутсвующих в
|
|
|
* шаблоне, при этом значение свойства шаблона
|
|
|
* является именем свойства в которое будет
|
|
|
* произведено коприрование
|
|
|
*/
|
|
|
mixin: function (dest, src, tmpl) {
|
|
|
safe.argumentNotNull(dest, "dest");
|
|
|
if (!src)
|
|
|
return dest;
|
|
|
|
|
|
var keys, i, p;
|
|
|
if (arguments.length < 3) {
|
|
|
keys = _keys(src);
|
|
|
for (i = 0; i < keys.length; i++) {
|
|
|
p = keys[i];
|
|
|
dest[p] = src[p];
|
|
|
}
|
|
|
} else {
|
|
|
if (tmpl instanceof Array) {
|
|
|
for (i = 0; i < tmpl.length; i++) {
|
|
|
p = tmpl[i];
|
|
|
if (p in src)
|
|
|
dest[p] = src[p];
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
keys = _keys(src);
|
|
|
for (i = 0; i < keys.length; i++) {
|
|
|
p = keys[i];
|
|
|
if (p in tmpl)
|
|
|
dest[tmpl[p]] = src[p];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return dest;
|
|
|
},
|
|
|
|
|
|
/** Wraps the specified function to emulate an asynchronous execution.
|
|
|
* @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
|
|
|
* @param{Function|String} fn [Required] Function wich will be wrapped.
|
|
|
*/
|
|
|
async: function (fn, thisArg) {
|
|
|
if (arguments.length == 2 && !(fn instanceof Function))
|
|
|
fn = thisArg[fn];
|
|
|
|
|
|
if (fn == null)
|
|
|
throw new Error("The function must be specified");
|
|
|
|
|
|
function wrapresult(x, e) {
|
|
|
if (e) {
|
|
|
return {
|
|
|
then: function (cb, eb) {
|
|
|
try {
|
|
|
return eb ? wrapresult(eb(e)) : this;
|
|
|
} catch (e2) {
|
|
|
return wrapresult(null, e2);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
} else {
|
|
|
if (x && x.then)
|
|
|
return x;
|
|
|
return {
|
|
|
then : function(cb) {
|
|
|
try {
|
|
|
return cb ? wrapresult(cb(x)) : this;
|
|
|
} catch(e2) {
|
|
|
return wrapresult(e2);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return function() {
|
|
|
try {
|
|
|
return wrapresult(fn.apply(thisArg, arguments));
|
|
|
} catch (e) {
|
|
|
return wrapresult(null, e);
|
|
|
}
|
|
|
};
|
|
|
},
|
|
|
|
|
|
create: function () {
|
|
|
if (console && console.warn)
|
|
|
console.warn("implab/safe::create is deprecated use Object.create instead");
|
|
|
_create.apply(this, arguments);
|
|
|
},
|
|
|
|
|
|
delegate: function (target, method) {
|
|
|
if (!(method instanceof Function)) {
|
|
|
this.argumentNotNull(target, "target");
|
|
|
method = target[method];
|
|
|
}
|
|
|
|
|
|
if (!(method instanceof Function))
|
|
|
throw new Error("'method' argument must be a Function or a method name");
|
|
|
|
|
|
return function () {
|
|
|
return method.apply(target, arguments);
|
|
|
};
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Для каждого элемента массива вызывает указанную функцию и сохраняет
|
|
|
* возвращенное значение в массиве результатов.
|
|
|
*
|
|
|
* @remarks cb может выполняться асинхронно, при этом одновременно будет
|
|
|
* только одна операция.
|
|
|
*
|
|
|
* @async
|
|
|
*/
|
|
|
pmap: function (items, cb) {
|
|
|
safe.argumentNotNull(cb, "cb");
|
|
|
|
|
|
if (items && items.then instanceof Function)
|
|
|
return items.then(function (data) {
|
|
|
return safe.pmap(data, cb);
|
|
|
});
|
|
|
|
|
|
if (safe.isNull(items) || !items.length)
|
|
|
return items;
|
|
|
|
|
|
var i = 0,
|
|
|
result = [];
|
|
|
|
|
|
function next() {
|
|
|
var r, ri;
|
|
|
|
|
|
function chain(x) {
|
|
|
result[ri] = x;
|
|
|
return next();
|
|
|
}
|
|
|
|
|
|
while (i < items.length) {
|
|
|
r = cb(items[i], i);
|
|
|
ri = i;
|
|
|
i++;
|
|
|
if (r && r.then) {
|
|
|
return r.then(chain);
|
|
|
} else {
|
|
|
result[ri] = r;
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
return next();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Для каждого элемента массива вызывает указанную функцию, результаты
|
|
|
* не сохраняются
|
|
|
*
|
|
|
* @remarks cb может выполняться асинхронно, при этом одновременно будет
|
|
|
* только одна операция.
|
|
|
* @async
|
|
|
*/
|
|
|
pfor: function (items, cb) {
|
|
|
safe.argumentNotNull(cb, "cb");
|
|
|
|
|
|
if (items && items.then instanceof Function)
|
|
|
return items.then(function (data) {
|
|
|
return safe.pmap(data, cb);
|
|
|
});
|
|
|
|
|
|
if (safe.isNull(items) || !items.length)
|
|
|
return items;
|
|
|
|
|
|
var i = 0;
|
|
|
|
|
|
function next() {
|
|
|
while (i < items.length) {
|
|
|
var r = cb(items[i], i);
|
|
|
i++;
|
|
|
if (r && r.then)
|
|
|
return r.then(next);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return next();
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* Выбирает первый элемент из последовательности, или обещания, если в
|
|
|
* качестве параметра используется обещание, оно должно вернуть массив.
|
|
|
*
|
|
|
* @param{Function} cb обработчик результата, ему будет передан первый
|
|
|
* элемент последовательности в случае успеха
|
|
|
* @param{Fucntion} err обработчик исключения, если массив пустой, либо
|
|
|
* не массив
|
|
|
*
|
|
|
* @remarks Если не указаны ни cb ни err, тогда функция вернет либо
|
|
|
* обещание, либо первый элемент.
|
|
|
* @async
|
|
|
*/
|
|
|
first: function (sequence, cb, err) {
|
|
|
if (sequence) {
|
|
|
if (sequence.then instanceof Function) {
|
|
|
return sequence.then(function (res) {
|
|
|
return safe.first(res, cb, err);
|
|
|
}, err);
|
|
|
} else if (sequence && "length" in sequence) {
|
|
|
if (sequence.length === 0) {
|
|
|
if (err)
|
|
|
return err(new Error("The sequence is empty"));
|
|
|
else
|
|
|
throw new Error("The sequence is empty");
|
|
|
}
|
|
|
return cb ? cb(sequence[0]) : sequence[0];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (err)
|
|
|
return err(new Error("The sequence is required"));
|
|
|
else
|
|
|
throw new Error("The sequence is required");
|
|
|
}
|
|
|
};
|
|
|
|
|
|
return safe;
|
|
|
});
|