Skip to content

Commit

Permalink
Merge pull request #2 from selfcontained/shallow-clone
Browse files Browse the repository at this point in the history
Added shallow clone and clone tests
  • Loading branch information
selfcontained committed Mar 21, 2014
2 parents 2136aab + 9730fc8 commit b5da55e
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 8 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ deap(deap, {
extend: lib.extend,
update: lib.update,
merge: lib.merge,
cloneShallow: lib.cloneShallow,
extendShallow: lib.extendShallow,
updateShallow: lib.updateShallow,
mergeShallow: lib.mergeShallow
Expand Down
28 changes: 22 additions & 6 deletions lib/deap.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ var typeOf = require('./typeof'),
slice = Array.prototype.slice;

module.exports = {
clone: clone,
clone: deepClone,
cloneShallow: clone,
extend: deepExtend,
extendShallow: extend,
update: deepUpdate,
Expand All @@ -12,11 +13,26 @@ module.exports = {
};

function clone(val) {
switch(typeOf(val)) {
case 'object':
return extend({}, val);
case 'array':
return [].concat(val);
case 'date':
return new Date(val.getTime());
case 'regexp':
return new RegExp(val);
default:
return val;
}
}

function deepClone(val) {
switch(typeOf(val)) {
case 'object':
return deepExtend({}, val);
case 'array':
return val.map(clone);
return val.map(deepClone);
case 'date':
return new Date(val.getTime());
case 'regexp':
Expand All @@ -41,7 +57,7 @@ function deepExtend(a, b /*, [b2..n] */) {
if(typeOf(b[p]) === 'object' && typeOf(a[p]) === 'object')
deepExtend(a[p], b[p]);
else
a[p] = clone(b[p]);
a[p] = deepClone(b[p]);
});
});
return a;
Expand Down Expand Up @@ -69,9 +85,9 @@ function deepUpdate(a, b /*, [b2..n] */) {
deepUpdate(ap, bp);
else if(tb === 'array' && ta === 'array') {
ap.length = 0;
ap.push.apply(ap, bp.map(clone));
ap.push.apply(ap, bp.map(deepClone));
} else
a[p] = clone(bp);
a[p] = deepClone(bp);
}
});
});
Expand All @@ -98,7 +114,7 @@ function deepMerge(a, b /*, [b2..n] */) {
if(tb === 'object' && ta === 'object')
deepMerge(ap, bp);
else if(!a.hasOwnProperty(p))
a[p] = clone(bp);
a[p] = deepClone(bp);
});
});
return a;
Expand Down
2 changes: 1 addition & 1 deletion shallow.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var lib = require('./lib/deap');
var deap = module.exports = lib.extendShallow;

deap(deap, {
clone: lib.clone,
clone: lib.cloneShallow,
extend: lib.extendShallow,
update: lib.updateShallow,
merge: lib.mergeShallow
Expand Down
206 changes: 206 additions & 0 deletions test/clone.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
var lib = require('../lib/deap'),
assert = require('chai').assert;

describe('shallow clone', function() {
var shallow = lib.cloneShallow;

it('should not return a reference to the first argument', function() {
var a = { burp: 'adurp' },
result = shallow(a);

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

it('should copy simple values', function() {
var a = { s: 'string', n: 1, b: false, a: [], o: {}},
b = shallow(a);

assert.deepEqual(b, a);
assert.equal(b.s, a.s);
assert.equal(b.n, a.n);
assert.equal(b.b, a.b);
assert.strictEqual(b.a, a.a);
assert.strictEqual(b.o, a.o);
});

it('should preserve object references', function() {
var deep = { foo: 'bar' },
a = { burp: 'adurp' , nested: deep },
result = shallow(a);

assert.strictEqual(result.nested, deep);
});

it('should preserve date references', function() {
var a = { burp: 'adurp', date: new Date() },
date = a.date;

var result = shallow(a);

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

it('should preserve regexp references', function() {
var a = { burp: 'adurp', regexp: /foo/g },
regexp = a.regexp;

var result = shallow(a);

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

it('should preserve array references', function() {
var a = { burp: 'adurp', array: [] },
array = a.array;

var result = shallow(a);

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

it('should clone Date objects', function() {
var a = new Date();

var result = shallow(a);

assert.equal(result.toString(), a.toString());
assert.notStrictEqual(result, a);
});

it('should clone RegExp objects', function() {
var a = /foo/;

var result = shallow(a);

assert.equal(result.toString(), a.toString());
assert.notStrictEqual(result, a);
});

describe('on an array', function() {

it('should preserve references', function() {
var a = ['string', 1, false, [], {}];

var result = shallow(a);

assert.deepEqual(result, a);
assert.equal(result[0], a[0]);
assert.equal(result[1], a[1]);
assert.equal(result[2], a[2]);
assert.strictEqual(result[3], a[3]);
assert.strictEqual(result[4], a[4]);
});

});

});


describe('clone', function() {
var clone = lib.clone;

it('should not return a reference to the first argument', function() {
var a = { burp: 'adurp' },
result = clone(a);

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

it('should copy simple values', function() {
var a = { s: 'string', n: 1, b: false, a: [], o: {}},
b = clone(a);

assert.deepEqual(b, a);
assert.equal(b.s, a.s);
assert.equal(b.n, a.n);
assert.equal(b.b, a.b);
assert.deepEqual(b.a, a.a);
assert.deepEqual(b.o, a.o);
});

it('should not preserve object references', function() {
var deeper = { boo: 'far' },
deep = { foo: 'bar', nested: deeper },
a = { burp: 'adurp' , nested: deep };

var result = clone(a);

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

it('should not preserve date references', function() {
var a = { burp: 'adurp', date: new Date() },
date = a.date;

var result = clone(a);

assert.deepEqual(result, a);
assert.equal(result.date.getTime(), date.getTime()); // added this because deepEqual doesn't work with dates
assert.notStrictEqual(result.date, date);
});

it('should not preserve regexp references', function() {
var a = { burp: 'adurp', regexp: /foo/g },
regexp = a.regexp;

var result = clone(a);

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

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

var result = clone(a);

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

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

it('should clone Date objects', function() {
var a = new Date();

var result = clone(a);

assert.equal(result.toString(), a.toString());
assert.notStrictEqual(result, a);
});

it('should clone RegExp objects', function() {
var a = /foo/;

var result = clone(a);

assert.equal(result.toString(), a.toString());
assert.notStrictEqual(result, a);
});

describe('on an array', function() {

it('should not preserve references', function() {
var a = ['string', 1, false, [], {}];

var result = clone(a);

assert.deepEqual(result, a);
assert.equal(result[0], a[0]);
assert.equal(result[1], a[1]);
assert.equal(result[2], a[2]);
assert.notStrictEqual(result[3], a[3]);
assert.notStrictEqual(result[4], a[4]);
});

});

});
5 changes: 5 additions & 0 deletions test/deap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ describe('deap', function() {
assert.deepEqual(deap.clone, lib.clone);
});

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

it('should have extend exposed as a top level function', function() {
assert.isFunction(deap);
assert.equal(deap, lib.extend);
Expand Down
2 changes: 1 addition & 1 deletion test/shallow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('shallow', function() {
assert.equal(shallow.extend, lib.extendShallow);
assert.equal(shallow.update, lib.updateShallow);
assert.equal(shallow.merge, lib.mergeShallow);
assert.equal(shallow.clone, lib.clone);
assert.equal(shallow.clone, lib.cloneShallow);
});

});

0 comments on commit b5da55e

Please sign in to comment.