(function(root) {
Underscore-contrib (underscore.object.builders.js 0.0.1) (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors Underscore-contrib may be freely distributed under the MIT license.
(function(root) {
Establish the root object, window
in the browser, or global
on the server.
var _ = root._ || require('underscore');
Create quick reference variables for speed access to core prototypes.
var slice = Array.prototype.slice,
concat = Array.prototype.concat;
var existy = function(x) { return x != null; };
var truthy = function(x) { return (x !== false) && existy(x); };
var isAssociative = function(x) { return _.isArray(x) || _.isObject(x); };
var curry2 = function(fun) {
return function(last) {
return function(first) {
return fun(first, last);
};
};
};
_.mixin({
Merges two or more objects starting with the left-most and applying the keys right-word {any:any}* -> {any:any}
merge: function(/* objs */){
var dest = _.some(arguments) ? {} : null;
if (truthy(dest)) {
_.extend.apply(null, concat.call([dest], _.toArray(arguments)));
}
return dest;
},
Takes an object and another object of strings to strings where the second object describes the key renaming to occur in the first object.
renameKeys: function(obj, kobj) {
return _.reduce(kobj, function(o, nu, old) {
if (existy(obj[old])) {
o[nu] = obj[old];
return o;
}
else
return o;
},
_.omit.apply(null, concat.call([obj], _.keys(kobj))));
},
Snapshots an object deeply. Based on the version by Keith Devens until we can find a more efficient and robust way to do it.
snapshot: function(obj) {
if(obj == null || typeof(obj) != 'object') {
return obj;
}
var temp = new obj.constructor();
for(var key in obj) {
temp[key] = _.snapshot(obj[key]);
}
return temp;
},
Updates the value at any depth in a nested object based on the path described by the keys given. The function provided is supplied the current value and is expected to return a value for use as the new value. If no keys are provided, then the object itself is presented to the given function.
updatePath: function(obj, fun, ks) {
if (!isAssociative(obj)) throw new TypeError("Attempted to update a non-associative object.");
if (!existy(ks)) return fun(obj);
var deepness = _.isArray(ks);
var keys = deepness ? ks : [ks];
var ret = deepness ? _.snapshot(obj) : _.clone(obj);
var lastKey = _.last(keys);
var target = ret;
_.each(_.initial(keys), function(key) {
target = target[key];
});
target[lastKey] = fun(target[lastKey]);
return ret;
},
Sets the value at any depth in a nested object based on the path described by the keys given.
setPath: function(obj, value, ks) {
if (!existy(ks)) throw new TypeError("Attempted to set a property at a null path.");
return _.updatePath(obj, function() { return value; }, ks);
},
Returns an object where each element of an array is keyed to the number of times that it occurred in said array.
frequencies: curry2(_.countBy)(_.identity)
});
})(this);