2
\$\begingroup\$

The following code should solve these issues:

  1. Handle namespaces;
  2. Be a class factory from Pojos
  3. Be a object factory
  4. Create a class with inheritance capabilities from a POJO using john resig inheritance implementation;
  5. Handle singletons

Here is an example of it's usage:

var OliveOil=require('OliveOil')();
var handler=new OliveOil(MY_PATH_FOR_DEFAULT_CLASSES);
//This should load a class that is on MY_PATH_FOR_DEFAULT_CLASSES and create a object form it
var SimpleClass=handler.createObject('SimpleClass',param1,param2,param3);
handler.setNamespaceDir('business',PATH_TO_BUSINESS_MODULE);
//This should load a class on the path to business module with the name of controller
var businessController=handler.createObject('business.Controller',param1);
var childOfSimpleClassPojo={
  'parent':'SimpleClass',
   _param4:null,
   'init':function(param1,param2,param3,param4){
      this._super(param1,param2,param3);//Invoking parent constructor
      this._param4=param4; 
   }

}
handler.setClassFromPojo('ChildOfSimpleClass',childOfSimpleClassPojo);
//This should create a class based on the pojo, and also inherits from the previously laoded simpleClass
var simpleObject=handler.createObject('ChildOfSimpleClass',param1,param2,param3,param4);

Here is the full code for the application:

var Class = require('class.extend');
var util=require('util');
var fs=require('fs');
module.exports=function(){
     /**
 * This class handles the initialization of several components, as well as path mapping, inheritances and namespace colisions
 * It's serve as a common library for object,classes and paths lookup
 * @type {Object}
 */
var oliveOil={

    //A map of classes in which the namespace class name is the index and the class object the item
    classMap:{

    },
    //A map of classes to it's class path
    classFileMap:{

    },
    //A map of class names to objects, it is handled in our singletons objects
    objectMap:{

    },
    //A map of directories based on the namespace
    namespaceDirMap:{

    },
    noNamespaceDir:null,
    /**
     * Get a class object from the given object
     * @param  {[type]} namespace [description]
     * @return {[type]}           [description]
     */
    getClass:function(name){
        if(this.isClassSet(name)){
            return this.classMap[name];
        }
        if(this.loadClass(name)){
            return this.classMap[name];
        }
        else{
            throw new Error('Was not able to load the class '+name);
        }

    },
    loadClass:function(name){
        var classPojo=this.getClassFileContents(name);
        if(this.setClassFromPojo(name,classPojo)){
            return true;
        }
        throw new Error('Was not able to load the class '+name+' on the path '+this.classFileMap[name]);
    },
    isObjectSet:function(name){
        return !!this.objectMap[name];
    },
    isClassSet:function(name){
        return !!this.classMap[name];
    },
    createObject:function(name, var_args){
        //Getting the var_args
        var params = Array.prototype.slice.call(arguments, 1);
        if(!this.isClassSet(name)){
            if(!this.loadClass(name)){
                throw new Error('The class "'+name+'" is not set');
            }
        }
        var DesiredClass=this.getClass(name);
        //Needed for us to apply the constructor
        var object = Object.create(DesiredClass.prototype);

        result= DesiredClass.apply(object, params);
        if (typeof result === 'object') {
            return result;
        }
        return object;



    },
    getClassFile:function(name){
        return this.classFileMap[name];
    },
    _getFile:function(path){
        if(path.indexOf('.js')!=path.length-3){
            path+='.js'
        }
        if(!fs.existsSync(path)){
            throw new Error('the path '+path+' does not exists');
        }
        return require(path);
    },
    getClassFileContents:function(name){
        if(!this.isClassFileSet(name)){
            var namespaceAndName=this.getNamespaceAndNameFromPath(name);
            var namespace=namespaceAndName['namespace'];
            var className=namespaceAndName['className'];
            if(namespace && !this.isNamespaceSet(namespace)){
                throw new Error('The namespace '+namespace+' is not set');
            }
            if(namespace){
                this.setClassFileByNamespace(namespace,className);
            }
            else{
                this.setClassFile(name,this.noNamespaceDir+name);
            }
        }


        return this._getFile(this.classFileMap[name]);

    },

    setClassFileByNamespace:function(namespace,className){
        var fullName=namespace+'.'+className;
        if(this.isClassFileSet(fullName)){
            throw new Error('The class '+className+' on the namespace '+namespace+' is already mapped');
        }
        var path=this.getNamespaceDir(namespace)+'/'+className;
        this.classFileMap[fullName]=path;
        return true;
    },
    getNamespaceAndNameFromPath:function(name){
        var pos=name.lastIndexOf('.');
        if(pos==-1){
            return {
                'namespace':false,
                'className':name
            }
        }
        return {
            'namespace':name.substr(0,pos),
            'className':name.substr(pos+1)
        };
    },
    getNamespaceFromPath:function(name){
        var pos=name.lastIndexOf('.');
        if(pos==-1){
            throw new Error(name+' is not a valid namespace');
        }
        return name.substr(0,pos);

    },
    getClassNameFromPath:function(name){
        var pos=name.lastIndexOf('.');
        if(pos==-1){
            throw new Error(name+ '  is not a namespace');
        }
        return name.substr(pos+1);

    },
    getSingletonObject:function(name,var_args){
        if(this.isObjectSet(name)){
            return this.objectMap[name];
        }
        this.objectMap[name]=this.createObject.apply(this,arguments);
        return this.objectMap[name];
    },
    /**
     * Sets a class on the given namespace to be the class object
     * @type {[type]}
     */
    setClassFromPojo:function(name,pojoData){
        var ParentClass;
        if(pojoData.parent){
            ParentClass=this.getClass(pojoData.parent);
        }
        else{
            ParentClass=Class;
        }
        return this.setClass(name,ParentClass.extend(pojoData));

    },

    /**
     * Sets a class on the given namespace to be the class object
     * @type {[type]}
     */
    setClass:function(name,classObject){
        if(this.isClassSet(name)){
            throw new Error('The class '+name+' is already set');
        }
        this.classMap[name]=classObject;
        return true;
    },
    setMultipleNamespacesDir:function(namespaceMap){
        for(var name in namespaceDirMap){
            this.setNamespaceDir(name,namespaceDirMap[name]);
        }
        return true;
    },
    setNamespaceDir:function(name,dir){
        if(this.isNamespaceSet(name)){
            throw new Error('The namespace '+name+' is already set');
        }
        this.namespaceDirMap[name]=dir;
        return true;
    },
    getNamespaceDir:function(name){

        return this.namespaceDirMap[name];
    },
    isNamespaceSet:function(name){
        return !!this.namespaceDirMap[name];
    },
    isClassFileSet:function(name){
        return !!this.classFileMap[name];

    },
    setClassFile:function(name,file){
        if(this.isClassFileSet(name)){
            throw new Error('The class '+name+' is already set with a path');
        }
        this.classFileMap[name]=file;
        return true;
    },
    setObject:function(name,object){
        if(this.isObjectSet(name)){
            throw new Error('The object '+name+' is already set');
        }
        this.objectMap[name]=object;
    },
    init:function(noNamespaceDir){
        this.noNamespaceDir=noNamespaceDir;
    }
};
    return  Class.extend(oliveOil);
}

What improvements could I make?

\$\endgroup\$
0

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.