Skip to content

Commit

Permalink
support options style constructor & non-standard property injection
Browse files Browse the repository at this point in the history
implements: #4
implements: #3
  • Loading branch information
bodenr committed Jun 20, 2014
1 parent abd3d4f commit 1a91f0f
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 9 deletions.
57 changes: 57 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,63 @@ Response: Request a file you have permissions to access
```

Use the options style constructor to assign standard properties:
```js
console.log(new errors.Http401Error({
message: "Expired Token",
explanation: "Your token has expired"}).toString());
```

outputs:
```
Http401Error: Expired Token
Code: 401
Explanation: Your token has expired
Error: Expired Token
```

Using the options style constructor you can also assign
arbitrary non-standard properties:
```js
console.log(new errors.Http401Error({
message: "Expired Token",
explanation: "Your token has expired",
expired: new Date()}).toString());
```

outputs:
```
Http401Error: Expired Token
Code: 401
Explanation: Your token has expired
expired: Fri Jun 20 2014 04:19:41 GMT-0400 (EDT)
```

Note however that you cannot assign values to the
`stack`, `name` or `code` standard property:
```js
console.log(new errors.Http401Error({
name: "ExpiredToken"}).toString());
```

outputs:
```
/home/boden/workspace/errors/lib/errors.js:261
throw Error("Properties 'stack', 'name' or 'code' " +
^
Error: Properties 'stack', 'name' or 'code' cannot be overridden
at Error (<anonymous>)
at new scope.(anonymous function) (/home/boden/workspace/errors/lib/errors.js:261:14)
at Object.<anonymous> (/home/boden/workspace/errors/examples/basic/usage.js:126:13)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
```

## Error codes

If you don't provide a `code` when defining the error, a unique code will
Expand Down
14 changes: 14 additions & 0 deletions examples/basic/usage.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,17 @@ console.log("-------------");
errors.stacks(true);
console.log(new errors.Http413Error().toString());
console.log(new errors.Http413Error().toJSON());


console.log("---------------");

// options style constructor
errors.create({name:'IdentifiableError'});
console.log(new errors.IdentifiableError({
message: "Unexpected error",
refID: "a1b2c3",
status: 500}).toString());
console.log(new errors.IdentifiableError({
message: "Unexpected error",
refID: "a1b2c3",
status: 500}).toJSON());
59 changes: 52 additions & 7 deletions lib/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,42 @@ var create = exports.create = function(options) {


/**
* Create a new instance of the exception which accepts
* 2 forms of parameters.
*
* (a) Passing the message, explanation and response
* as individual argument strings:
* Create a new instance of the exception optionally
* specifying a message, explanation and response
* for the new instance. If any of the arguments are
* null, their value will default to their respective
* default value use on the `create` call, or will
* be null if no default was specified.
*
* @param {String} msg The message to use for the error.
* (b) Passing an options style object which contains
* key / value pairs. In this form keys map to the
* attributes of the error object. Note that the properties
* 'stack', 'name' and 'code' cannot be set via the options
* style object in this form.
*
* @param {String|Object} msg The message to use for the error.
* @param {String} expl The explanation to use for the error.
* @param {String} fix The response to use for the error.
* @return {Object} The newly created error.
*/

scope[className] = function(msg, expl, fix) {
var attrs = {};
if (typeof msg !== null && typeof msg === 'object') {
attrs = msg;
msg = attrs['message'] || defaultMessage;
if (attrs.hasOwnProperty('stack')
|| attrs.hasOwnProperty('name')
|| attrs.hasOwnProperty('code')) {
throw Error("Properties 'stack', 'name' or 'code' " +
"cannot be overridden");
}
}
msg = msg || defaultMessage;
expl = expl || defaultExplanation;
fix = fix || defaultResponse;
Expand All @@ -262,7 +284,7 @@ var create = exports.create = function(options) {
enumerable: false,
get: function() {
if (!formattedStack) {
formattedStack = stack.stack.replace('[object Object]', 'Error: ' + msg);
formattedStack = stack.stack.replace('[object Object]', 'Error: ' + this.message);
}
return formattedStack;
}
Expand All @@ -276,7 +298,7 @@ var create = exports.create = function(options) {
*/

Object.defineProperty(this, 'explanation', {
value: expl,
value: attrs['explanation'] || expl,
configurable: true,
enumerable: true
});
Expand All @@ -289,7 +311,7 @@ var create = exports.create = function(options) {
*/

Object.defineProperty(this, 'response', {
value: fix,
value: attrs['response'] || fix,
configurable: true,
enumerable: true
});
Expand All @@ -302,7 +324,7 @@ var create = exports.create = function(options) {
*/

Object.defineProperty(this, 'code', {
value: errorCode,
value: attrs['code'] || errorCode,
configurable: true,
enumerable: true
});
Expand All @@ -318,7 +340,7 @@ var create = exports.create = function(options) {
*/

Object.defineProperty(this, 'status', {
value: http.STATUS_CODES[errorCode] ? errorCode : 500,
value: attrs['status'] || (http.STATUS_CODES[errorCode] ? errorCode : 500),
configurable: true,
// normalize for http status code and connect compat
enumerable: true
Expand All @@ -345,10 +367,22 @@ var create = exports.create = function(options) {
*/

Object.defineProperty(this, 'message', {
value: msg,
value: attrs['message'] || msg,
configurable: true,
enumerable: true
});

// expose extra conf attrs as properties
for (var key in attrs) {
if (!this.hasOwnProperty(key)) {
Object.defineProperty(this, key, {
value: attrs[key],
configurable: true,
enumerable: true
});
}
}

};

util.inherits(scope[className], parent);
Expand Down Expand Up @@ -400,6 +434,17 @@ var create = exports.create = function(options) {
if (this.response) {
msg += "\nResponse: " + this.response;
}

function isExtra(key) {
return ['name', 'message', 'status', 'code',
'response', 'explanation', 'stack'].indexOf(key) < 0;
}

// extra properties
Object.keys(this).filter(isExtra).forEach(function(key) {
msg += util.format("\n%s: %s", key, this[key]);
}, this);

if (useStack) {
msg += "\n" + this.stack;
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "errors",
"version": "0.1.0",
"version": "0.2.0",
"description": "A comprehensive, robust, yet lightweight set of error utilities for node.js enabling you to do errors more effectively.",
"keywords": [
"error",
Expand All @@ -9,7 +9,7 @@
"connect",
"utilities"
],
"author": "Boden Russell <bodensemail@gmail.com>",
"author": "Boden Russell <bodenru@gmail.com>",
"repository": {
"type": "git",
"url": "git://github.com/bodenr/errors.git"
Expand Down
38 changes: 38 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,41 @@ describe('errors.title()', function() {
errors.title().should.equal('My Title');
});
});

describe('options style constructor', function() {
var IdentifiableError = errors.create('IdentifiableError'),
err = new IdentifiableError({message: 'Error with ref ID',
status: 501, refID: 'a1b2c3'});

it('should contain refID property', function() {
err.refID.should.equal('a1b2c3');
});

it('should have overridden status', function() {
err.status.should.equal(501);
});

it('toString() should output refID', function() {
err.toString().should.include('refID: a1b2c3');
});

it('toJSON() should include refID', function() {
err.toJSON().should.include({refID: 'a1b2c3'});
});

it('should have overriden message', function() {
err.toString().should.include(': Error with ref ID');
});

it('should not allow overriding of stack', function() {
new IdentifiableError({stack: 'fail'}).should.throw();
});

it('should not allow overriding of name', function() {
new IdentifiableError({name: 'fail'}).should.throw();
});

it('should not allow overriding of code', function() {
new IdentifiableError({code: 601}).should.throw();
});
});

0 comments on commit 1a91f0f

Please sign in to comment.