Skip to content

Instantly share code, notes, and snippets.

@ammmir
Created November 27, 2010 09:31
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ammmir/717740 to your computer and use it in GitHub Desktop.
Save ammmir/717740 to your computer and use it in GitHub Desktop.
Client model factory (node.js)
// generated user.js
function User() { // @extends Backbone.Model
return Backbone.Model.apply(this, arguments);
}
User.prototype = Backbone.Model.prototype;
User.EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
User.prototype.validate = function validate() {
var email = this.get('email');
return !!email.match(User.EMAIL_REGEX);
};
// Models should live in ./models
// ClientModelFactory.makeAll() will generate the client-side source for models, with
// only properties defined in the constructor's __exports__ array property.
var util = require('util'),
fs = require('fs');
var EXTENDS_REGEX = /@extends (.+)/,
JS_REGEX = /^[a-zA-Z0-9_\-]+\.js$/;
function log(s) {
util.puts('[ClientModelFactory] ' + s);
}
function serialize(object, name, property) {
if(property in object) {
return name + '.' + property + ' = ' + object[property] + ';\n';
} else if(property in object.prototype) {
return name + '.prototype.' + property + ' = ' + object.prototype[property] + ';\n';
} else {
return '';
}
}
function ClientModelFactory(modelpath) {
this.models = {};
var files = fs.readdirSync(modelpath);
for(var i = 0; i < files.length; i++) {
if(!files[i].match(JS_REGEX))
continue;
var name = files[i].replace('.js', '');
log('loading model file: ' + files[i]);
var module;
try {
module = require(modelpath + files[i]);
} catch(e) {
log(' skipping due to exception: ' + e);
continue;
}
this.models[name] = '';
for(var export in module) {
if(typeof module[export] != 'function')
continue;
if('__exports__' in module[export]) {
// constructor
this.models[name] += module[export] + "\n";
// handle inheritance using ghetto @extends comments
var match = (''+module[export]).match(EXTENDS_REGEX);
if(match) {
this.models[name] += this.extend(export, match[1]);
}
var export_list = module[export]['__exports__'];
for(var j = 0; j < export_list.length; j++) {
var prop = export_list[j];
if(typeof prop == 'function') { // regular expression
for(var p in module[export]) {
if(module[export].hasOwnProperty(p) && p.match(prop))
this.models[name] += serialize(module[export], export, p);
}
} else if(typeof prop == 'string') { // exact string
this.models[name] += serialize(module[export], export, prop);
}
}
}
}
}
}
ClientModelFactory.prototype.extend = function extend(child, parent) {
// this code is inserted immediately after a constructor
return child + '.prototype = ' + parent + '.prototype;\n';
};
ClientModelFactory.prototype.make = function make(model) {
return this.models[model];
};
ClientModelFactory.prototype.makeAll = function makeAll() {
var sources = [];
for(var model in this.models) {
sources.push(this.make(model));
}
return sources.join('');
};
exports.ClientModelFactory = global['ClientModelFactory'] || (global['ClientModelFactory'] = new ClientModelFactory(__dirname + '/models/'));
var Backbone = require('backbone');
function User() { // @extends Backbone.Model
return Backbone.Model.apply(this, arguments);
}
User.prototype = Backbone.Model.prototype;
// by default export all uppercase properties and validate
User.__exports__ = [/^[A-Z]+[A-Z_]+/, 'validate'];
User.EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
User.prototype.validate = function validate() {
var email = this.get('email');
return !!email.match(User.EMAIL_REGEX);
};
User.prototype.updateDB = function updateDB() {
// server-only logic here...
};
exports.User = User;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment