1 |
|
/* |
2 |
|
Copyright (c) 2012, Yahoo! Inc. All rights reserved. |
3 |
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
4 |
|
*/ |
5 |
|
|
6 |
1 |
var util = require('util'), |
7 |
|
path = require('path'), |
8 |
|
fs = require('fs'), |
9 |
|
abbrev = require('abbrev'); |
10 |
|
|
11 |
1 |
function Factory(kind, dir, allowAbbreviations) { |
12 |
3 |
this.kind = kind; |
13 |
3 |
this.dir = dir; |
14 |
3 |
this.allowAbbreviations = allowAbbreviations; |
15 |
3 |
this.classMap = {}; |
16 |
3 |
this.abbreviations = null; |
17 |
|
} |
18 |
|
|
19 |
1 |
Factory.prototype = { |
20 |
|
|
21 |
|
knownTypes: function () { |
22 |
11 |
var keys = Object.keys(this.classMap); |
23 |
11 |
keys.sort(); |
24 |
11 |
return keys; |
25 |
|
}, |
26 |
|
|
27 |
|
resolve: function (abbreviatedType) { |
28 |
37 |
if (!this.abbreviations) { |
29 |
1 |
this.abbreviations = abbrev(this.knownTypes()); |
30 |
|
} |
31 |
37 |
return this.abbreviations[abbreviatedType]; |
32 |
|
}, |
33 |
|
|
34 |
|
register: function (constructor) { |
35 |
15 |
var type = constructor.TYPE; |
36 |
15 |
if (!type) { throw new Error('Could not register ' + this.kind + ' constructor [no TYPE property]: ' + util.inspect(constructor)); } |
37 |
14 |
this.classMap[type] = constructor; |
38 |
14 |
this.abbreviations = null; |
39 |
|
}, |
40 |
|
|
41 |
|
create: function (type, opts) { |
42 |
39 |
var allowAbbrev = this.allowAbbreviations, |
43 |
|
realType = allowAbbrev ? this.resolve(type) : type, |
44 |
|
Cons; |
45 |
|
|
46 |
39 |
Cons = realType ? this.classMap[realType] : null; |
47 |
39 |
if (!Cons) { throw new Error('Invalid ' + this.kind + ' [' + type + '], allowed values are ' + this.knownTypes().join(', ')); } |
48 |
35 |
return new Cons(opts); |
49 |
|
}, |
50 |
|
|
51 |
|
loadStandard: function (dir) { |
52 |
3 |
var that = this; |
53 |
3 |
fs.readdirSync(dir).forEach(function (file) { |
54 |
17 |
if (file !== 'index.js' && file.indexOf('.js') === file.length - 3) { |
55 |
12 |
try { |
56 |
12 |
that.register(require(path.resolve(dir, file))); |
57 |
|
} catch (ex) { |
58 |
|
console.error(ex.message); |
59 |
|
console.error(ex.stack); |
60 |
|
throw new Error('Could not register ' + that.kind + ' from file ' + file); |
61 |
|
} |
62 |
|
} |
63 |
|
}); |
64 |
|
}, |
65 |
|
|
66 |
|
bindClassMethods: function (Cons) { |
67 |
3 |
var tmpKind = this.kind.charAt(0).toUpperCase() + this.kind.substring(1), //ucfirst |
68 |
|
allowAbbrev = this.allowAbbreviations; |
69 |
|
|
70 |
3 |
Cons.mix = Factory.mix; |
71 |
3 |
Cons.register = this.register.bind(this); |
72 |
3 |
Cons.create = this.create.bind(this); |
73 |
3 |
Cons.loadAll = this.loadStandard.bind(this, this.dir); |
74 |
3 |
Cons['get' + tmpKind + 'List'] = this.knownTypes.bind(this); |
75 |
3 |
if (allowAbbrev) { |
76 |
1 |
Cons['resolve' + tmpKind + 'Name'] = this.resolve.bind(this); |
77 |
|
} |
78 |
|
} |
79 |
|
}; |
80 |
|
|
81 |
1 |
Factory.mix = function (cons, proto) { |
82 |
12 |
Object.keys(proto).forEach(function (key) { |
83 |
39 |
cons.prototype[key] = proto[key]; |
84 |
|
}); |
85 |
|
}; |
86 |
|
|
87 |
1 |
module.exports = Factory; |
88 |
|
|
89 |
|
|