Skip to content

Commit

Permalink
Merge pull request #106 from hapijs/clone-shallow
Browse files Browse the repository at this point in the history
Clone, shallow, and stringify
  • Loading branch information
nlf committed Nov 10, 2014
2 parents 2f6b4ca + 5ab2233 commit 6d18a89
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 5 deletions.
23 changes: 23 additions & 0 deletions README.md
Expand Up @@ -23,6 +23,8 @@ Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf)
* [flatten](#flattenarray-target "flatten")
* [reach](#reachobj-chain-options "reach")
* [transform](#transformobj-transform-options "transform")
* [shallow](#shallowobj "shallow")
* [stringify](#stringifyobj "stringify")
* [Timer](#timer "Timer")
* [Bench](#bench "Bench")
* [Binary Encoding/Decoding](#binary-encodingdecoding "Binary Encoding/Decoding")
Expand Down Expand Up @@ -313,6 +315,27 @@ var result = Hoek.transform(source, {
// }
```

### shallow(obj)

Performs a shallow copy by copying the references of all the top level children where:
- `obj` - the object to be copied.

```javascript
var shallow = Hoek.shallow({ a: { b: 1 } });
```

### stringify(obj)

Converts an object to string using the built-in `JSON.stringify()` method with the difference that any errors are caught
and reported back in the form of the returned string. Used as a shortcut for displaying information to the console (e.g. in
error message) without the need to worry about invalid conversion.

```javascript
var a = {};
a.b = a;
Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]'
```

# Timer

A Timer object. Initializing a new timer object sets the ts to the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.
Expand Down
36 changes: 31 additions & 5 deletions lib/index.js
Expand Up @@ -64,7 +64,9 @@ exports.clone = function (obj, seen) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
var descriptor = Object.getOwnPropertyDescriptor(obj, i);
if (descriptor.get) {
if (descriptor.get ||
descriptor.set) {

Object.defineProperty(newObj, i, descriptor);
}
else {
Expand Down Expand Up @@ -169,7 +171,7 @@ exports.cloneWithShallow = function (source, keys) {
return source;
}

return internals.shallow(source, keys, function () {
return internals.withShallow(source, keys, function () {

return exports.clone(source);
});
Expand All @@ -180,14 +182,14 @@ exports.cloneWithShallow = function (source, keys) {

exports.applyToDefaultsWithShallow = function (defaults, options, keys) {

return internals.shallow(options, keys, function () {
return internals.withShallow(options, keys, function () {

return exports.applyToDefaults(defaults, options);
});
};


internals.shallow = function (source, keys, clone) {
internals.withShallow = function (source, keys, clone) {

// Move shallow copy items to storage

Expand Down Expand Up @@ -631,7 +633,7 @@ exports.assert = function (condition /*, msg1, msg2, msg3 */) {

msgs = msgs.map(function (msg) {

return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : JSON.stringify(msg);
return typeof msg === 'string' ? msg : msg instanceof Error ? msg.message : exports.stringify(msg);
});
throw new Error(msgs.join(' ') || 'Unknown error');
};
Expand Down Expand Up @@ -864,3 +866,27 @@ exports.uniqueFilename = function (path, extension) {
var name = [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-') + extension;
return Path.join(path, name);
};


exports.stringify = function () {

try {
return JSON.stringify.apply(null, arguments);
}
catch (err) {
return '[Cannot display object: ' + err.message + ']';
}
};


exports.shallow = function (source) {

var target = {};
var keys = Object.keys(source);
for (var i = 0, il = keys.length; i < il; ++i) {
var key = keys[i];
target[key] = source[key];
}

return target;
};
85 changes: 85 additions & 0 deletions test/index.js
Expand Up @@ -293,6 +293,54 @@ describe('clone()', function () {
expect(execCount).to.equal(1);
done();
});

it('clones an object with property getter and setter', function (done) {

var obj = {
_test: 0
};

Object.defineProperty(obj, 'test', {
enumerable: true,
configurable: true,
get: function () {

return this._test;
},
set: function (value) {

this._test = value - 1;
}
});

var copy = Hoek.clone(obj);
expect(copy.test).to.equal(0);
copy.test = 5;
expect(copy.test).to.equal(4);
done();
});

it('clones an object with only property setter', function (done) {

var obj = {
_test: 0
};

Object.defineProperty(obj, 'test', {
enumerable: true,
configurable: true,
set: function (value) {

this._test = value - 1;
}
});

var copy = Hoek.clone(obj);
expect(copy._test).to.equal(0);
copy.test = 5;
expect(copy._test).to.equal(4);
done();
});
});

describe('merge()', function () {
Expand Down Expand Up @@ -1897,3 +1945,40 @@ describe('uniqueFilename()', function () {
done();
});
});

describe('stringify()', function (done) {

it('converts object to string', function (done) {

var obj = { a: 1 };
expect(Hoek.stringify(obj)).to.equal('{"a":1}');
done();
});

it('returns error in result string', function (done) {

var obj = { a: 1 };
obj.b = obj;
expect(Hoek.stringify(obj)).to.equal('[Cannot display object: Converting circular structure to JSON]');
done();
});
});

describe('shallow()', function (done) {

it('shallow copies an object', function (done) {

var obj = {
a: 5,
b: {
c: 6
}
};

var shallow = Hoek.shallow(obj);
expect(shallow).to.not.equal(obj);
expect(shallow).to.deep.equal(obj);
expect(shallow.b).to.equal(obj.b);
done();
});
});

0 comments on commit 6d18a89

Please sign in to comment.