(function (root, factory) {
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], function () {
return factory();
});
} else if(typeof exports !== 'undefined'){
exports = module.exports = factory();
} else {
factory();
}
}(this, function () {
var etho = {};
Return the string passed as argument with the first letter uppercased.
Exemple:
etho.ucfirst('foo');
// Foo
etho.ucfirst = function ethoUcfirst(str){
return str.substr(0,1).toUpperCase() + str.substr(1);
};
Return the true type of anything as a string.
It always return the type “lowercase”d for consistency.
Exemples:
etho.getType('foo');
// "string"
etho.getType(3);
// "number"
etho.getType({});
// "object"
etho.getType([]);
// "array"
etho.getType(null);
// "null"
etho.getType(undefined);
// "undefined"
etho.getType = function ethoGetType(thing){
return Object.prototype.toString.call(thing).match(/^\[object\s+(\w+)\]$/)[1].toLowerCase();
};
Try to transform anything into an array and slice it.
Exemples:
function test(param){
var args = etho.toArraySliced(arguments);
return param + "|" + args.length;
}
test('foo')
//foo|1
test('foo','bar')
//foo|2
function test(param){
var args = etho.toArraySliced(arguments, 1);
return param + "|" + args.length;
}
test('foo')
//foo|0
test('foo','bar')
//foo|1
function test(param, /* foo, bar,.. */ ctx){
var args = etho.toArraySliced(arguments, 1, -1);
return param + "|" + args.length + "|" + ctx;
}
test('foo', 'bar')
//foo|0|bar
test('foo', 'baz', 'bar')
//foo|1|bar
etho.toArraySliced = function ethoToArraySliced(obj, sliceStart, sliceEnd){
sliceStart = sliceStart || 0;
if(etho.isA('undefined', sliceEnd)){
return Array.prototype.slice.call(obj, sliceStart);
}else{
return Array.prototype.slice.call(obj, sliceStart, sliceEnd);
}
};
Check the type of anything against the supposed type as a string.
Exemples:
etho.isA('string', "foo")
// true
etho.isA('string', {})
// false
etho.isA = function ethoIsA(type, obj){
return etho.getType(obj) === type;
};
Recursively deep copy an array
or an object
without any reference left !
Exemple:
var foo = {
arr : {
pirate : true,
fakelimb : [
'leftHand'
]
}
}
var bar = etho.shallowCopy(foo)
bar.arr.fakelimb.push('eye')
foo.arr.fakelimb.length
//1
bar.arr.fakelimb.length
//2
etho.shallowCopy = function ethoShallowCopy(obj){
var out = {};
switch(etho.getType(obj)){
case 'array':
return etho.toArraySliced(obj);
case 'object':
for (var key in obj){
if(
etho.isA('array',obj[key]) ||
etho.isA('object',obj[key])
){
out[key] = etho.shallowCopy(obj[key]);
}else{
out[key] = obj[key];
}
}
break;
default:
throw new Exception('Wrong Type.');
};
return out;
};
Run an iterator against each entries of an array or an object.
Exemple:
var foo = [1,2,3,4,5,6,7,8,9], out = 0;
etho.forEach(foo, function(val, key, list){ out += val; });
// out === 45
etho.forEach = function ethoForeach(obj, iterator, context) {
if (obj === null){ throw new Error('no object to iterate on !');}
if(typeof context === 'undefined'){ context = this; }
for (var key in obj) {
if ({}.hasOwnProperty.call(obj, key)) {
iterator.call(context, obj[key], key, obj);
}
}
return obj;
};
Recursively an type-checked merge things. Useful to enforce defaultOptions types in Classes Instances !
No parameters are affected, it return a shallowCopy of the first merged with the nexts !
Exemple:
var foo = {
arr : {
pirate : false,
fakelimb : [
'leftHand'
]
}
};
var bar = {
arr : {
pirate : true,
fakelimb : false
}
};
var result = etho.merge(foo, bar);
//result => {arr:{pirate:true,fakelimb:['leftHand']}}
etho.merge = function ethoMerge(target, seed/*, seed*… */){
var _return = etho.shallowCopy(target);
if(etho.isA('undefined', seed)){ return _return; }
var args = etho.toArraySliced(arguments, 1);
for (var i = 0; i < args.length; i++) {
var src = args[i];
for (var prop in _return) {
if (
_return.hasOwnProperty(prop) &&
!etho.isA('function',_return[prop]) &&
etho.getType(_return[prop]) === etho.getType(src[prop])
){
switch(etho.getType(_return[prop])){
case 'object':
_return[prop] = etho.merge(_return[prop], src[prop]);
break;
default:
_return[prop] = src[prop];
}
} else { continue; }
}
}
return _return;
};
With this function you can, using a string path, inside imbricated objects:
Exemple:
var target = {
foo: {
bar: {
baz: [
'madness'
]
}
}
};
deepAccess(target, 'foo.bar.baz').push('sparta');
//target → {foo:{bar:{baz:['madness', 'sparta']}}}
etho.deepAccess = function ethoDeepAccess(obj, path){
if(etho.isA('undefined',obj)) throw new Error('no object to navigate inside !');
if(etho.isA('string',path)){
path = path.replace(/\[/g, '.').replace(/\]/g, '').split('.');
}
return path.length === 1 ? obj[path.shift()] : etho.deepAccess(obj[path.shift()], path);
};
etho.inherit = function ethoInherit(child, parent) {
for (var key in parent) {
if ({}.hasOwnProperty.call(parent, key)){
child[key] = parent[key];
}
}
var wrapper = function wrapper() { this.constructor = child; }
wrapper.prototype = parent.prototype;
child.prototype = new wrapper();
child.__super__ = parent.prototype;
return child;
};
etho.x = function ethoX(classname, customConstructor, parentClass){
var args = etho.toArraySliced(arguments, 1);
if(args.length === 0){
parentClass = function Lambda(){};
}
var CHILD = this[classname] = customConstructor || etho.x.minimalConstructor();
if(etho.isA('undefined', classname)){
throw new Error('classname is missing !');
}
if(etho.isA('undefined', parentClass)){
parentClass = function Lambda(){};
}
return function protoCreation(proto){
return (function(parent){
etho.inherit(CHILD, parent);
for(var attr in proto){
if( proto.hasOwnProperty( attr ) ) {
CHILD.prototype[attr] = proto[attr];
}
}
var autoSuper = function autoSuper(method){
if(
!etho.isA('undefined', CHILD.__super__) &&
etho.isA('undefined', CHILD.__super__[method])
){
return CHILD.__super__[method];
}
};
for(var oldattr in parent){
if( parent.hasOwnProperty( oldattr ) ) {
CHILD.prototype[oldattr] = autoSuper(oldattr);
}
}
return CHILD;
})(parentClass);
}
};
etho.x.minimalConstructor = function(){ return function ethoGenericConstructor(options){
if(this.defaultOptions){
this.options = etho.merge(this.defaultOptions, options);
}else{
this.options = options;
}
if( this.init ){ this.init(); }
if( this.listen ){ this.listen(); }
return this;
};};
return etho;
}));