Skip to content

Instantly share code, notes, and snippets.

@FireNeslo
Last active December 20, 2015 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FireNeslo/6048662 to your computer and use it in GitHub Desktop.
Save FireNeslo/6048662 to your computer and use it in GitHub Desktop.
An object with map and array like methods that keeps references to the same object for as long as possible; if you attatch a promise it will also resolve that promise before attempting to run any other chained functions. Useful for keeping references in for example angularjs while executing async logic.
function addScript(src) {
var script = document.createElement("script");
script.src = src;
document.body.appendChild(script);
return addScript;
}
addScript('//rawgithub.com/kriskowal/q/master/q.min.js');
/**
* A Object wrapper with some iteration helpers.
* @constructor
* @param {object} [obj] - The object to extend.
* @param {promise} [condition] - promise that needs to be fullfilled before running iteration.
*/
function ObjMap (obj, condition) {
var _self = this;
obj = obj || {};
if(condition && ObjMap.isFunction(condition.then) ) {
this.condition(condition);
}
this.extend(obj);
}
ObjMap.isObject = function(obj) {
return obj === Object(obj);
};
ObjMap.isFunction = function(obj) {
return typeof obj === 'function';
};
ObjMap.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
ObjMap.isNaN = function(obj) {
return _.isNumber(obj) && obj != +obj;
};
ObjMap.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
ObjMap.isNull = function(obj) {
return obj === null;
};
ObjMap.isUndefined = function(obj) {
return obj === void 0;
};
/**
* Add a conditon for iteration to continue
* @function
* @param {promise} promise - A condiion to be met before continuing iteration
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.condition = function(promise) {
var _self = this;
if(this.$$condition) {
this.$$condition = this.$$condition.then(function() {
_self.$$condition = promise;
return promise.then(function() {
delete _self.$$condition;
})
})
} else {
this.$$condition = promise.then(function() {
delete _self.$$condition;
})
}
return this;
};
/**
* Iterate Object as if it vas an array value key
* @function
* @param {function} cb- Iteration function with, value, key as params.
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.forEach = function(cb){
var _self = this;
if(this.$$condition) {
this.$$condition.then(function() {
for(var a in _self) {
if(_self.hasOwnProperty(a) && a[0] != '$' ) {
cb(_self[a], a);
}
}
})
} else {
for(var a in this) {
if(this.hasOwnProperty(a) && a[0] != '$') {
cb(this[a], a);
}
}
}
return this;
};
/**
* Get the object keys as an array
* @function
* @returns {array} keys - list of object keys
*/
ObjMap.prototype.keys = function() {
var arr = [];
this.forEach(function(val, key)  {
arr.push(key);
})
return arr;
};
/**
* Create a list of object values
* @function
* @returns {array} values - a list of values
*/
ObjMap.prototype.values = function() {
return this.toArray();
};
/**
* Add properties to object
* @function
* @param {object} obj - object with new properties..
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.extend = function(obj){
var _self = this;
this.forEach.call(obj, function(val,key) {
_self[key] = val;
});
return this;
};
/**
* Remove properties from object
* @function
* @param {object} cb- object with props to be removed;
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.exclude = function(obj){
var _self = this;
this.forEach.call(obj, function(val,key) {
delete _self[key];
});
return this;
};
/**
* Iterate Object as if it vas an array value key
* @function
* @param {string} key - New proberty key
* @param value - New property value
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.add = function(key, obj){
this[key] = obj;
return this;
};
/**
* Add all values from array with object property as key
* @function
* @param {array} array - New property values
* @param {string} key - Proberty key of array values to use as key.
* @param {boolean} remove - Remove the key from object
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.addAll = function( array, key, remove){
var _self = this;
array.forEach(function(val) {
_self.add(val[key], val);
if(remove) {
delete val[key];
}
});
return this;
};
/**
* Remove property by key
* @function
* @param {string} key - Key of proberty to remove.
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.remove = function(key){
delete this[key];
return this;
};
/**
* Remove properties from array
* @function
* @param {array} keys - Keys of proberties to remove.
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.removeAll = function(array){
var _self = this;
array.forEach(function(val, key) {
_self.remove(key);
});
return this;
};
/**
* Remove all properties
* @function
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.clear = function() {
var _self = this;
this.forEach(function(val, key) {_self.remove(key);});
return this;
};
/**
* Get number of properties
* @function
* @returns {number} size - Nuber of properties
*/
ObjMap.prototype.size = function() {
var _self = this;
var size = 0;
this.forEach(function() {size += 1;});
return size;
};
/**
* Iterate and replace values
* @function
* @param {function} cb - Iteration function
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.map = function(cb){
var _self = this;
this.forEach(function(val, key) {
_self[key] = cb(val, key);
});
return this;
}
/**
* Get value by key or default if none
* @function
* @param {string} key - Key to get
* @param defaulr - default value
* @returns value - value of key or default
*/
ObjMap.prototype.get = function(key, _default){
return this[key] || _default;
}
/**
* Set property
* @function
* @param {string} key - Key to get
* @param value - value to set
* @returns {ObjMap} self - a reference to itself for chaining
*/
ObjMap.prototype.set = function(key, val){
this[key] = val;
return this;
}
/**
* Create array from object
* @function
* @param {string} [id] - if specified assigns the property key as value of id;
* @param {array} array - array referece to use for result.
* @returns {array} self - The map as an array
*/
ObjMap.prototype.toArray = function(id, array){
var arr = array || [];
var _self = this;
this.forEach(function(val, key) {
if(id) {
val = _self.clone(val);
val[id] = key;
}
arr.push(val);
});
return arr;
}
/**
* Create a normal object from ObjMap
* @function
* @returns {object} self - The map as a normal object
*/
ObjMap.prototype.toJSON = function(){
var json = {};
this.forEach(function(val, key) {
json[key] = val;
});
return json;
}
/**
* Create a clone from an object or self
* @function
* @param {object} [obj] - if specified is cloned
* @returns {object} clone - TThe cloned object
*/
ObjMap.prototype.clone = function clone(obj) {
if (null == obj || "object" != typeof obj) {
obj = this;
};
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
/**
* An error for next() iteration ower async object
* @constructor
* @param {Promise} promise - the condition that still needs to be fullfilled
*/
ObjMap.AsyncIterationError = function AsyncItretaionError(promise) {
this.name = "ReferenceError";
this.message = 'Iterate async error';
this.condition = promise;
};
ObjMap.AsyncIterationError.prototype.toString = function() {
return this.name + ": " + this.message;
};
/**
* Next key
* @function
* @returns {string} key - Next key in object
*/
ObjMap.prototype.next = function(){
if(!this.$current) {
this.$current = {
array : this.keys(),
index : 0
}
}
if(this.$$condition) {
throw new ObjMap.AsyncIterationError(this.$$condition);
} else {
if (this.hasNext()) {
return this.$current.array[this.$current.index++];
} else {
delete this.$current;
return undefined;
}
}
};
/**
* Has next key
* @function
* @returns {boolean} hasNext - If has next key
*/
ObjMap.prototype.hasNext = function() {
return this.$current ? (this.$current.index < this.$current.array.length) : !!this.size();
}
// example
function example() {
function delay(ms) {
var deferred = Q.defer();
setTimeout(deferred.resolve, ms);
return deferred.promise;
}
var m = new ObjMap();
var promise = delay(1000).then(function() {
console.log("delay");
m.extend({"arrived":"late"});
});
var keys = m.
condition(promise).
keys();
console.log("now", keys)
setTimeout(function() {
console.log("later", keys)
}, 1100);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment