Code coverage report for istanbul/lib/util/factory.js

Statements: 93.18% (41 / 44)      Branches: 100% (16 / 16)      Functions: 100% (10 / 10)      Lines: 92.86% (39 / 42)      Ignored: none     

All files » istanbul/lib/util/ » factory.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89          89         89 267 267 267 267 267     89     199 199 199       130 87   130       1783 1783 1782 1782       1549       1549 1549 1543       267 267 2314 1780 1780                     267     267 267 267 267 267 267 89         89 1780 6319       89    
/*
 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;