Permalink
Browse files

[api] First pass at adding ability to specify custom resource methods.

…#116 Examples working. Needs tests.
  • Loading branch information...
1 parent ff957d1 commit efb409fad52d667f485f861baee4a98906c41cc3 @Marak Marak committed Sep 3, 2012
Showing with 110 additions and 2 deletions.
  1. +60 −0 examples/custom-methods.js
  2. +14 −0 lib/resourceful/core.js
  3. +6 −0 lib/resourceful/definers.js
  4. +30 −2 lib/resourceful/resource.js
View
@@ -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);
+ });
+});
View
@@ -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) {
resourceful.defineProperty(self, k, Factory.schema.properties[k]);
});
@@ -204,6 +204,12 @@ module.exports = {
return val.slice().reverse();
}
})
+ },
+ method: {
+ required: function (val, condition, options) {
+ enforceType(val, "boolean");
+ return this.define("required", val, condition, options);
+ }
}
};
@@ -1,4 +1,5 @@
var util = require('util'),
+ utile = require('utile'),
validator = require('revalidator'),
definers = require('./definers'),
resourceful = require('../resourceful');
@@ -721,13 +722,41 @@ Resource.object = function (name, 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) {
var definer = {};
var type = (function () {
switch (Array.isArray(typeOrSchema) ? 'array' : typeof typeOrSchema) {
case "array":
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 "undefined": return "string";
default: throw new(Error)("Argument Error");
@@ -747,7 +776,6 @@ Resource.property = function (name, typeOrSchema, schema) {
this.schema.properties[name].messages = {};
this.schema.properties[name].conditions = {};
definer.name = name;
-
resourceful.mixin(definer, definers.all, definers[schema.type] || {});
return definer;

0 comments on commit efb409f

Please sign in to comment.