blob: 9f3d6f36faaca9cca09b4edd8deba95f3be8be91 [file] [log] [blame]
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
var util = require('util'),
path = require('path'),
fs = require('fs'),
abbrev = require('abbrev');
function Factory(kind, dir, allowAbbreviations) {
this.kind = kind;
this.dir = dir;
this.allowAbbreviations = allowAbbreviations;
this.classMap = {};
this.abbreviations = null;
}
Factory.prototype = {
knownTypes: function () {
var keys = Object.keys(this.classMap);
keys.sort();
return keys;
},
resolve: function (abbreviatedType) {
if (!this.abbreviations) {
this.abbreviations = abbrev(this.knownTypes());
}
return this.abbreviations[abbreviatedType];
},
register: function (constructor) {
var type = constructor.TYPE;
if (!type) { throw new Error('Could not register ' + this.kind + ' constructor [no TYPE property]: ' + util.inspect(constructor)); }
this.classMap[type] = constructor;
this.abbreviations = null;
},
create: function (type, opts) {
var allowAbbrev = this.allowAbbreviations,
realType = allowAbbrev ? this.resolve(type) : type,
Cons;
Cons = realType ? this.classMap[realType] : null;
if (!Cons) { throw new Error('Invalid ' + this.kind + ' [' + type + '], allowed values are ' + this.knownTypes().join(', ')); }
return new Cons(opts);
},
loadStandard: function (dir) {
var that = this;
fs.readdirSync(dir).forEach(function (file) {
if (file !== 'index.js' && file.indexOf('.js') === file.length - 3) {
try {
that.register(require(path.resolve(dir, file)));
} catch (ex) {
console.error(ex.message);
console.error(ex.stack);
throw new Error('Could not register ' + that.kind + ' from file ' + file);
}
}
});
},
bindClassMethods: function (Cons) {
var tmpKind = this.kind.charAt(0).toUpperCase() + this.kind.substring(1), //ucfirst
allowAbbrev = this.allowAbbreviations;
Cons.mix = Factory.mix;
Cons.register = this.register.bind(this);
Cons.create = this.create.bind(this);
Cons.loadAll = this.loadStandard.bind(this, this.dir);
Cons['get' + tmpKind + 'List'] = this.knownTypes.bind(this);
if (allowAbbrev) {
Cons['resolve' + tmpKind + 'Name'] = this.resolve.bind(this);
}
}
};
Factory.mix = function (cons, proto) {
Object.keys(proto).forEach(function (key) {
cons.prototype[key] = proto[key];
});
};
module.exports = Factory;