Skip to content

Commit

Permalink
adding merge - pull in ONLY new properties, leave existing ones alone
Browse files Browse the repository at this point in the history
  • Loading branch information
selfcontained committed Jul 25, 2013
1 parent 389546b commit 547f36e
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 4 deletions.
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ deap(deap, {
clone: lib.clone,
extend: lib.extend,
update: lib.update,
merge: lib.merge,
extendShallow: lib.extendShallow,
updateShallow: lib.updateShallow
updateShallow: lib.updateShallow,
mergeShallow: lib.mergeShallow
});
30 changes: 29 additions & 1 deletion lib/deap.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ module.exports = {
extend: deepExtend,
extendShallow: extend,
update: deepUpdate,
updateShallow: update
updateShallow: update,
merge: deepMerge,
mergeShallow: merge
};

function clone(val) {
Expand Down Expand Up @@ -75,3 +77,29 @@ function deepUpdate(a, b /*, [b2..n] */) {
});
return a;
}

function merge(a, b /*, [b2..n] */) {
slice.call(arguments, 1).forEach(function(b) {
Object.keys(b).forEach(function(p) {
if(!a.hasOwnProperty(p)) a[p] = b[p];
});
});
return a;
}

function deepMerge(a, b /*, [b2..n] */) {
slice.call(arguments, 1).forEach(function(b) {
var ap, bp, ta, tb;
Object.keys(b).forEach(function(p) {
ap = a[p];
bp = b[p];
ta = typeOf(ap);
tb = typeOf(bp);
if(tb === 'object' && ta === 'object')
deepMerge(ap, bp);
else if(!a.hasOwnProperty(p))
a[p] = clone(bp);
});
});
return a;
}
3 changes: 2 additions & 1 deletion shallow.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ var deap = module.exports = lib.extendShallow;
deap(deap, {
clone: lib.clone,
extend: lib.extendShallow,
update: lib.updateShallow
update: lib.updateShallow,
merge: lib.mergeShallow
});
10 changes: 10 additions & 0 deletions test/deap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,15 @@ describe('deap', function() {
assert.deepEqual(deap.updateShallow, lib.updateShallow);
});

it('should have merge defined', function() {
assert.isFunction(deap.merge);
assert.deepEqual(deap.merge, lib.merge);
});

it('should have mergeShallow defined', function() {
assert.isFunction(deap.mergeShallow);
assert.deepEqual(deap.mergeShallow, lib.mergeShallow);
});


});
134 changes: 134 additions & 0 deletions test/merge.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
var lib = require('../lib/deap'),
assert = require('chai').assert;

describe('shallow merge', function() {
var shallowMerge = lib.mergeShallow;

it('should merge everything into an empty object', function() {
var a = { foo: 'bar' },
result = shallowMerge({}, a);

assert.deepEqual(result, a);
});

it('should return a reference to the first argument', function() {
var a = { burp: 'adurp' },
b = { burp: 'zing', grr: 'arghh' };

var result = shallowMerge(a, b);

assert.strictEqual(result, a);
});

it('should not replace existing values', function() {
var a = { burp: 'adurp' },
b = { burp: 'zing', grr: 'arghh' };

var result = shallowMerge(a, b);

assert.deepEqual(result, { burp: 'adurp', grr: 'arghh' });
assert.equal(result.burp, a.burp);
});

});

describe('deep merge', function() {
var deepMerge = lib.merge;

it('should return a reference to the first argument', function() {
var a = { burp: 'adurp' },
b = { burp: 'zing', grr: 'arghh' };

var result = deepMerge(a, b);

assert.strictEqual(result, a);
});

it('should merge a nested object one level deep', function() {
var a = { foo: 'bar', deep: { foo: 'bar', baz: 'buzz' }},
b = { foo: 'bop', deep: { foo: 'beep', biz: 'baz' } };

var result = deepMerge(a, b);

assert.equal(result.foo, 'bar');
assert.equal(result.deep.foo, 'bar');
assert.equal(result.deep.baz, 'buzz');
assert.equal(result.deep.biz, 'baz');
});

it('should merge a nested object two levels deep', function() {
var a = { foo: 'bar', deep: { hi: 'hello', deeper: { foo: 'bar', baz: 'buzz' }}},
b = { foo: 'baz', deep: { hi: 'bye', bye: 'hi', deeper: { foo: 'beep', bop: 'boop' } } };

var result = deepMerge({}, a, b);

assert.equal(result.foo, a.foo);
assert.isObject(result.deep);
assert.equal(result.deep.hi, a.deep.hi);
assert.equal(result.deep.bye, b.deep.bye);
assert.isObject(result.deep.deeper);
assert.equal(result.deep.deeper.foo, a.deep.deeper.foo);
assert.equal(result.deep.deeper.baz, a.deep.deeper.baz);
assert.equal(result.deep.deeper.bop, b.deep.deeper.bop);
});

it('should merge properties from multiple objects', function() {
var a = { foo: ['one'], boo: 'far', poo: 'tar' },
b = { foo: ['two', 'three'], zoo: 'car' },
c = { boo: 'star', two: 'czar' };

var result = deepMerge({}, a, b, c);

assert.deepEqual(result, {
foo: a.foo,
boo: a.boo,
poo: a.poo,
zoo: b.zoo,
two: c.two
});
});

it('should not preserve nested object references', function() {
var a = { foo: 'bar' },
nested = { grr: 'argh' },
newFoo = { burp: nested },
b = { foo: newFoo, foo2: newFoo };

var result = deepMerge(a, b);
assert.equal(a.foo, 'bar');
assert.deepEqual(a.foo2.burp, b.foo2.burp);
assert.notStrictEqual(a.foo2.burp, nested);
});

it('should not override a string with an object', function() {
var a = { foo: 'bar' },
b = { foo: { biz: 'baz' } };

var result = deepMerge(a, b);
assert.deepEqual(a, { foo: 'bar' });
});

it('should preserve array references', function() {
var a = { nested: [{ foo: 'bar' }] },
b = { nested: [{ boo: 'far' }] },
deep = a.nested;

var result = deepMerge(a, b);

assert.deepEqual(result.nested, a.nested);
assert.notStrictEqual(result.nested, b.nested);
assert.strictEqual(result.nested, deep);
});

it('should not preserve references in arrays', function() {
var a = { nested: [{ foo: 'bar' }] },
b = { nested: [{ boo: 'far' }] },
deeper = a.nested[0];

var result = deepMerge({}, a, b);

assert.deepEqual(result.nested, a.nested);
assert.notStrictEqual(result.nested[0], deeper);
});

});
4 changes: 3 additions & 1 deletion test/shallow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ describe('shallow', function() {

assert.isFunction(shallow.extend);
assert.isFunction(shallow.update);
assert.isFunction(shallow.merge);
assert.isFunction(shallow.clone);
});

it('should be shallow functions', function() {
it('should have shallow functions', function() {
assert.equal(shallow, lib.extendShallow);
assert.equal(shallow.extend, lib.extendShallow);
assert.equal(shallow.update, lib.updateShallow);
assert.equal(shallow.merge, lib.mergeShallow);
assert.equal(shallow.clone, lib.clone);
});

Expand Down

0 comments on commit 547f36e

Please sign in to comment.