Skip to content

Commit

Permalink
[api] First pass at adding ability to specify custom resource methods.
Browse files Browse the repository at this point in the history
…#116 Examples working. Needs tests.
  • Loading branch information
Marak committed Sep 3, 2012
1 parent ff957d1 commit efb409f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 2 deletions.
60 changes: 60 additions & 0 deletions examples/custom-methods.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// custom-methods.js - example of extending resources to have methods
//

var resourceful = require('../lib/resourceful');
resourceful.use('memory');

var Creature = resourceful.define('creature');

var lazer = function(options){
console.log('firing mah lazar @ ' + options.powa);
};

//
// Resource.method takes three arguments:
//
// name, Function, schema
//
// The schema represents an optional JSON-Schema,
// which if present, is enforced on the Function's arguments
//
//
Creature.method('fire', lazer, { properties: {
"powa": {
"type": "string",
"enum": ["high", "low", "med", "SUPA POWA"],
"required": true
}
}});

Creature.fire({ powa: "med"});
Creature.fire({ powa: "TOO HIGH"}, function(err, result){
// errors since TOO HIGH is not in enum
console.log(err, result);
});

// throws validation error
// Creature.fire({ powa: "TOO HIGH"});

Creature.create({
id: 'Marak'
}, function(err, marak){
if(err){
console.log(err.validate)

}
marak.fire({ powa: "med"});

// throws validation error
// marak.fire({ powa: "TOO HIGH"});

marak.fire({ powa: "low"}, function(err, result){
console.log(err, result);
});

marak.fire({ powa: "TOO HIGH"}, function(err, result){
// errors since TOO HIGH is not in enum
console.log(err, result);
});
});
14 changes: 14 additions & 0 deletions lib/resourceful/core.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@ resourceful.define = function (name, definition) {
}); });
} }


//
// Resource.method definitions
//
// TODO: add ID lookup here for instance methods
for (var m in Factory) {
if(typeof Factory[m] !== 'undefined' && Factory[m].type === "method") {
if(typeof this[m] !== 'undefined') {
throw new Error(m + ' is a reserved word on the Resource instance');
}
this[m] = Factory[m];
this[m].type = "method" ;
this[m].required = false;
}
}
Object.keys(this._properties).forEach(function (k) { Object.keys(this._properties).forEach(function (k) {
resourceful.defineProperty(self, k, Factory.schema.properties[k]); resourceful.defineProperty(self, k, Factory.schema.properties[k]);
}); });
Expand Down
6 changes: 6 additions & 0 deletions lib/resourceful/definers.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ module.exports = {
return val.slice().reverse(); return val.slice().reverse();
} }
}) })
},
method: {
required: function (val, condition, options) {
enforceType(val, "boolean");
return this.define("required", val, condition, options);
}
} }
}; };


Expand Down
32 changes: 30 additions & 2 deletions lib/resourceful/resource.js
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,5 @@
var util = require('util'), var util = require('util'),
utile = require('utile'),
validator = require('revalidator'), validator = require('revalidator'),
definers = require('./definers'), definers = require('./definers'),
resourceful = require('../resourceful'); resourceful = require('../resourceful');
Expand Down Expand Up @@ -721,13 +722,41 @@ Resource.object = function (name, schema) {
return this.property(name, Object, schema); return this.property(name, Object, schema);
}; };


Resource.method = function (name, fn, schema) {
if(typeof this[name] !== 'undefined') {
throw new Error(name + ' is a reserved word on the Resource definition')
}
if (typeof schema === 'object') {
this[name] = function(){
var args = utile.args(arguments);
var valid = validator.validate(args[0], schema);
if(!valid.valid) {
if(typeof args.cb === 'function') {
args.cb(valid);
} else {
throw new Error(JSON.stringify(valid.errors)); // TODO: better errors
}
} else {
fn.apply(this, arguments);
}
};
} else {
this[name] = fn;
}
this[name].type = "method";
this[name].schema = schema;
return;
};



Resource.property = function (name, typeOrSchema, schema) { Resource.property = function (name, typeOrSchema, schema) {
var definer = {}; var definer = {};
var type = (function () { var type = (function () {
switch (Array.isArray(typeOrSchema) ? 'array' : typeof typeOrSchema) { switch (Array.isArray(typeOrSchema) ? 'array' : typeof typeOrSchema) {
case "array": case "array":
case "string": return typeOrSchema; case "string": return typeOrSchema;
case "function": return typeOrSchema.name.toLowerCase(); case "function": return typeOrSchema.name.toLowerCase(); // TODO: <= might be incorrect
case "object": schema = typeOrSchema; case "object": schema = typeOrSchema;
case "undefined": return "string"; case "undefined": return "string";
default: throw new(Error)("Argument Error"); default: throw new(Error)("Argument Error");
Expand All @@ -747,7 +776,6 @@ Resource.property = function (name, typeOrSchema, schema) {
this.schema.properties[name].messages = {}; this.schema.properties[name].messages = {};
this.schema.properties[name].conditions = {}; this.schema.properties[name].conditions = {};
definer.name = name; definer.name = name;

resourceful.mixin(definer, definers.all, definers[schema.type] || {}); resourceful.mixin(definer, definers.all, definers[schema.type] || {});


return definer; return definer;
Expand Down

0 comments on commit efb409f

Please sign in to comment.