├── .gitignore ├── tests ├── examples │ ├── modules │ │ ├── logic │ │ │ ├── boolean │ │ │ │ ├── .gitignore │ │ │ │ └── comparisons │ │ │ │ │ └── .gitignore │ │ │ └── fuzzy │ │ │ │ └── .gitignore │ │ ├── animals │ │ │ ├── AbstractAlive.js │ │ │ ├── Dolphin.js │ │ │ ├── AbstractAquatic.js │ │ │ └── AbstractMammal.js │ │ └── math │ │ │ ├── Sum.js │ │ │ ├── AbstractOperator.js │ │ │ └── Multiplication.js │ ├── Parent.js │ ├── GrandChild.js │ └── Child.js └── OliveOil.js ├── README.md ├── .gitattributes ├── package.json ├── index.js └── src └── OliveOil.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/* -------------------------------------------------------------------------------- /tests/examples/modules/logic/boolean/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore -------------------------------------------------------------------------------- /tests/examples/modules/logic/fuzzy/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Olive handles namespaces,class creation and inheritance -------------------------------------------------------------------------------- /tests/examples/modules/logic/boolean/comparisons/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore -------------------------------------------------------------------------------- /tests/examples/modules/animals/AbstractAlive.js: -------------------------------------------------------------------------------- 1 | module.exports= { 2 | isAlive:function(){ 3 | return true; 4 | } 5 | }; -------------------------------------------------------------------------------- /tests/examples/modules/animals/Dolphin.js: -------------------------------------------------------------------------------- 1 | module.exports= { 2 | 'parent':['animals.AbstractAquatic','animals.AbstractMammal',] 3 | }; -------------------------------------------------------------------------------- /tests/examples/modules/animals/AbstractAquatic.js: -------------------------------------------------------------------------------- 1 | module.exports= { 2 | parent:'animals.AbstractAlive', 3 | canSwim:function(){ 4 | return true; 5 | } 6 | }; -------------------------------------------------------------------------------- /tests/examples/modules/animals/AbstractMammal.js: -------------------------------------------------------------------------------- 1 | module.exports= { 2 | parent:'animals.AbstractAlive', 3 | drinkMilk:function(){ 4 | return true; 5 | }, 6 | hasFur:function(){ 7 | return true; 8 | } 9 | 10 | }; -------------------------------------------------------------------------------- /tests/examples/modules/math/Sum.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | name:null, 3 | parent:'math.AbstractOperator', 4 | init:function(){ 5 | this._super('Sum'); 6 | }, 7 | operate:function(a,b){ 8 | return a+b; 9 | } 10 | } -------------------------------------------------------------------------------- /tests/examples/Parent.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | name:null, 3 | generation:1, 4 | init:function(name){ 5 | this.name=name; 6 | 7 | }, 8 | toString:function(){ 9 | return 'Hello! My name is '+this.name; 10 | } 11 | } -------------------------------------------------------------------------------- /tests/examples/modules/math/AbstractOperator.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | name:null, 3 | init:function(operationName){ 4 | this.name=operationName; 5 | }, 6 | operate:function(a,b){ 7 | throw new Error('Operation not implmented'); 8 | } 9 | } -------------------------------------------------------------------------------- /tests/examples/modules/math/Multiplication.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | name:null, 3 | parent:'math.AbstractOperator', 4 | init:function(){ 5 | this._super('Multiplication'); 6 | }, 7 | operate:function(a,b){ 8 | return a*b; 9 | } 10 | } -------------------------------------------------------------------------------- /tests/examples/GrandChild.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | parent:'Child', 3 | email:null, 4 | generation:3, 5 | init:function(name,surName,email){ 6 | this._super(name,surName); 7 | this.email=email; 8 | }, 9 | toString:function(){ 10 | return this._super()+' and my email is '+this.email; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/examples/Child.js: -------------------------------------------------------------------------------- 1 | module.exports={ 2 | parent:'Parent', 3 | surName:null, 4 | generation:2, 5 | init:function(name,surName){ 6 | this._super(name); 7 | this.surName=surName; 8 | }, 9 | toString:function(){ 10 | return this._super()+' and my surName is '+this.surName; 11 | }, 12 | doChildThing:function(){ 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "olive_oil", 3 | "version": "0.0.6", 4 | "description": "A namespace handler,class factory and inheritance handler", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "test": "mocha tests/OliveOil.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/drFabio/OliveOil.git" 15 | }, 16 | "keywords": [ 17 | "Class", 18 | "Factory", 19 | "Namespaces", 20 | "Inheritance" 21 | ], 22 | "devDependencies": { 23 | "chai":"*" 24 | }, 25 | "dependencies": { 26 | "class.extend":"0.9.1", 27 | "async":"*", 28 | "lodash":"*" 29 | }, 30 | "author": "Fabio Oliveira Costa ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/drFabio/OliveOil/issues" 34 | }, 35 | "homepage": "https://github.com/drFabio/OliveOil" 36 | } 37 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Fabio Oliveira Costa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | module.exports=require(__dirname+'/src/OliveOil.js'); -------------------------------------------------------------------------------- /tests/OliveOil.js: -------------------------------------------------------------------------------- 1 | /*The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Fabio Oliveira Costa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | */ 23 | 24 | /** 25 | * Suite of tests for the ginger class factory 26 | * @todo Move the tests to another place 27 | */ 28 | var chai=require('chai'); 29 | chai.config.includeStack =true; 30 | var expect=chai.expect; 31 | var should = chai.should(); 32 | var OliveOil=require(__dirname+'/../src/OliveOil')(); 33 | var exampleDir=__dirname+'/examples/'; 34 | describe('Factory methods',function(){ 35 | var oliveOil; 36 | before(function(){ 37 | oliveOil=new OliveOil(exampleDir); 38 | }); 39 | it('Should be able to set a namespace directory',function(){ 40 | expect(oliveOil.setNamespaceDir('math',exampleDir+'modules/math')).to.be.true; 41 | }); 42 | it('Should be able to set a recursive namespace directory',function(done){ 43 | var setCb=function(err,data){ 44 | expect(err).to.not.exist; 45 | expect(oliveOil.isNamespaceSet('logic')).to.be.true; 46 | expect(oliveOil.isNamespaceSet('logic.boolean')).to.be.true; 47 | expect(oliveOil.isNamespaceSet('logic.boolean.comparisons')).to.be.true; 48 | expect(oliveOil.isNamespaceSet('logic.fuzzy')).to.be.true; 49 | done(); 50 | 51 | } 52 | oliveOil.setRecursiveNamespaceDir('logic',exampleDir+'modules/logic',setCb); 53 | 54 | }); 55 | it('Should be able to verify if a class file exists',function(){ 56 | expect(oliveOil.classFileExists('math.Sum')).to.be.true; 57 | expect(oliveOil.classFileExists('math.NonExistent')).to.be.false; 58 | 59 | }); 60 | it('Should be able to set multiple namespace directory',function(){ 61 | expect(oliveOil.setMultipleNamespacesDir({'log':exampleDir+'modules/log','text':exampleDir+'modules/text'})).to.be.true; 62 | }); 63 | 64 | it('Should be able to set a file path for a class',function(){ 65 | expect(oliveOil.setClassFile('Parent',exampleDir+'Parent')).to.be.true; 66 | }); 67 | it('Should be able to get a class file path',function(){ 68 | var path=oliveOil.getClassFile('Parent'); 69 | expect(path).to.not.be.empty; 70 | }); 71 | it('Should be able to create a class from a previously set file path',function(){ 72 | expect(oliveOil.getClass('Parent')).to.not.be.empty; 73 | 74 | }); 75 | it('Should be able to create a object from a previously loaded class',function(){ 76 | var parentObj=oliveOil.createObject('Parent','nameOfAParent'); 77 | expect(parentObj).to.not.be.empty; 78 | }); 79 | it('Should be able to get the file contents from a already set classFile',function(){ 80 | var parentData=oliveOil.getClassFileContents('Parent'); 81 | expect(parentData).to.not.be.empty; 82 | 83 | }); 84 | it('Should be able to get the file contents from not set classFile with a set namespace',function(){ 85 | var operatorData=oliveOil.getClassFileContents('math.AbstractOperator'); 86 | expect(operatorData).to.not.be.empty; 87 | }); 88 | 89 | it('Should be able to create a object from a POJO class',function(){ 90 | var pojoData={ 91 | 'foo':'bar', 92 | 'bar':'baz', 93 | init:function(){ 94 | 95 | } 96 | }; 97 | var ret=oliveOil.createClassFromPojo('pojoClass',pojoData); 98 | expect(ret).to.be.true; 99 | var obj=oliveOil.createObject('pojoClass'); 100 | expect(obj.foo).not.to.be.empty; 101 | 102 | }); 103 | it('NonSingleton objects should not be influenced by each other',function(){ 104 | var pojoData={ 105 | 'foo':'bar', 106 | 'bar':'baz', 107 | init:function(){ 108 | 109 | } 110 | }; 111 | var ret=oliveOil.createClassFromPojo('pojoNonSingletonClass',pojoData); 112 | var objA=oliveOil.createObject('pojoClass'); 113 | expect(objA.foo).to.equal('bar'); 114 | objA.foo='bar2'; 115 | var objB=oliveOil.createObject('pojoClass'); 116 | expect(objB.foo).to.equal('bar'); 117 | 118 | }) 119 | it('Should be able to get a previously set class',function(){ 120 | var operatorPOJO=oliveOil.getClassFileContents('math.AbstractOperator'); 121 | oliveOil.createClassFromPojo('math.AbstractOperator',operatorPOJO); 122 | operatorClass=oliveOil.getClass('math.AbstractOperator'); 123 | expect(operatorClass).to.not.be.empty; 124 | 125 | }); 126 | 127 | it('Should be able to create singleton Object',function(){ 128 | var comparisonValue='foo2'; 129 | var obj=oliveOil.getSingletonObject('pojoClass'); 130 | obj.foo=comparisonValue; 131 | var anotherObj=oliveOil.getSingletonObject('pojoClass'); 132 | expect(anotherObj.foo).to.equal(comparisonValue); 133 | }); 134 | it('Should fail if you try to overwrite a namespace',function(){ 135 | try{ 136 | 137 | oliveOil.setNamespaceDir('math',__dirname); 138 | //Here to guarantee that we have a exception 139 | expect(true).to.be.false; 140 | } 141 | catch(err){ 142 | expect(err).to.exist; 143 | } 144 | }); 145 | it('Should fail if you try to load an unexistent class',function(){ 146 | try{ 147 | 148 | oliveOil.getClass('unexistent.class'); 149 | //Here to guarantee that we have a exception 150 | expect(true).to.be.false; 151 | } 152 | catch(err){ 153 | expect(err).to.exist; 154 | } 155 | }); 156 | it('Should fail if you try to load an unexistent object',function(){ 157 | try{ 158 | 159 | oliveOil.createObject('unexistent.class'); 160 | //Here to guarantee that we have a exception 161 | expect(true).to.be.false; 162 | } 163 | catch(err){ 164 | expect(err).to.exist; 165 | } 166 | }); 167 | }); 168 | describe('Lazy Pojo handler',function(){ 169 | var oliveOil=null; 170 | var OliveOil=require(__dirname+'/../src/OliveOil')(); 171 | 172 | before(function(){ 173 | oliveOil=new OliveOil(exampleDir); 174 | expect(oliveOil.setNamespaceDir('math',exampleDir+'modules/math')).to.be.true; 175 | }); 176 | it('Should be able to set a class pojo for later use',function(){ 177 | var pojo={ 178 | 'isTest':true, 179 | init:function(){} 180 | } 181 | var ret=oliveOil.setClassPojo('pojoTest',pojo); 182 | expect(ret).to.be.true; 183 | }); 184 | it('Should be able to get a object from a class that the pojo was set',function(){ 185 | var obj=oliveOil.createObject('pojoTest'); 186 | expect(obj).to.exist; 187 | expect(obj.isTest).to.be.true; 188 | }); 189 | it('Should remove the pojo from the list if the class was already generated',function(){ 190 | var ret=oliveOil.isClassPojoAlreadyCreated('pojoTest'); 191 | expect(ret).to.be.true; 192 | }); 193 | it('Should be able to overwritte a set pojo object',function(){ 194 | var otherPojo={ 195 | 'anotherTest':true, 196 | init:function(){} 197 | } 198 | var ret=oliveOil.setClassPojo('anotherPojoTest',otherPojo); 199 | expect(ret).to.be.true; 200 | var yetAnotherPojo={ 201 | 'yetAnotherTest':true, 202 | init:function(){} 203 | }; 204 | var otherRet=oliveOil.setClassPojo('anotherPojoTest',yetAnotherPojo,true); 205 | expect(otherRet).to.be.true; 206 | 207 | 208 | }); 209 | it('Should not be able to overwritte a already generated pojo object',function(){ 210 | try{ 211 | var dumPojo={ 212 | init:function(){} 213 | }; 214 | var otherRet=oliveOil.setClassPojo('anotherPojoTest',dumPojo,true); 215 | expect(otherRet).to.not.exist; 216 | } 217 | catch(err){ 218 | expect(err).to.exist; 219 | } 220 | }); 221 | it('Should be able to get a parent from a set pojo that was not already created as a class',function(){ 222 | var parentPojo={ 223 | 'iAmAParent':true, 224 | init:function(){} 225 | }; 226 | var ret=oliveOil.setClassPojo('parentPojo',parentPojo,true); 227 | expect(ret).to.be.true; 228 | var childPojo={ 229 | 'iAmChild':true, 230 | 'parent':'parentPojo', 231 | init:function(){} 232 | }; 233 | var ret=oliveOil.setClassPojo('childPojo',childPojo,true); 234 | expect(ret).to.be.true; 235 | var obj=oliveOil.createObject('childPojo'); 236 | expect(obj.iAmAParent).to.be.true; 237 | expect(obj.iAmChild).to.be.true; 238 | 239 | }); 240 | 241 | 242 | }); 243 | describe('Object inheritance',function(){ 244 | var oliveOil=null; 245 | var OliveOil=require(__dirname+'/../src/OliveOil')(); 246 | 247 | before(function(){ 248 | oliveOil=new OliveOil(exampleDir); 249 | expect(oliveOil.setNamespaceDir('math',exampleDir+'modules/math')).to.be.true; 250 | }); 251 | it('Should be able to create a object that inherits another loaded class',function(){ 252 | var load=oliveOil.loadClass('Parent'); 253 | expect(load).to.be.true; 254 | var child=oliveOil.createObject('Child','childName','surName'); 255 | expect(child).to.exist; 256 | expect(child.name).to.equal('childName'); 257 | expect(child.surName).to.equal('surName'); 258 | 259 | }); 260 | it('Should be able to create a grandChild ',function(){ 261 | var grandChild=oliveOil.createObject('GrandChild','grandChildName','surName','email@email.com'); 262 | expect(grandChild).to.exist; 263 | expect(grandChild.name).to.equal('grandChildName'); 264 | expect(grandChild.surName).to.equal('surName'); 265 | expect(grandChild.email).to.equal('email@email.com'); 266 | 267 | }); 268 | it('Should be able to load a parent even if the parent isn\'t loaded yet',function(){ 269 | var parentPojo={ 270 | 'a':1, 271 | 'b':2, 272 | init:function(name){ 273 | this._name=name; 274 | }, 275 | getName:function(){ 276 | return this._name; 277 | } 278 | } 279 | var childPojo={ 280 | parent:'notLoadedParentPojo', 281 | init:function(name){ 282 | this._super(name+'SUFIX') 283 | } 284 | } 285 | 286 | var ret=oliveOil.setClassPojo('notLoadedParentPojo',parentPojo,true); 287 | expect(ret).to.be.true; 288 | var ret=oliveOil.setClassPojo('someChildPojo',childPojo,true); 289 | expect(ret).to.be.true; 290 | 291 | var obj=oliveOil.createObject('someChildPojo','name'); 292 | expect(obj).to.not.be.empty; 293 | expect(obj.getName()).to.equal('nameSUFIX'); 294 | }); 295 | describe('multiple inheritance',function(){ 296 | var oliveOil=null; 297 | var OliveOil=require(__dirname+'/../src/OliveOil')(); 298 | before(function(){ 299 | oliveOil=new OliveOil(exampleDir); 300 | expect(oliveOil.setNamespaceDir('animals',exampleDir+'modules/animals')).to.be.true; 301 | }); 302 | it('Should be able to inherit from multiple parents',function(){ 303 | var obj=oliveOil.createObject('animals.Dolphin'); 304 | expect(obj.canSwim()).to.be.true; 305 | expect(obj.isAlive()).to.be.true; 306 | expect(obj.drinkMilk()).to.be.true; 307 | expect(obj.hasFur()).to.be.true; 308 | }); 309 | }) 310 | }); -------------------------------------------------------------------------------- /src/OliveOil.js: -------------------------------------------------------------------------------- 1 | var async=require('async'); 2 | /*The MIT License (MIT) 3 | 4 | Copyright (c) 2014 Fabio Oliveira Costa 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | var Class = require('class.extend'); 25 | var util=require('util'); 26 | var _=require('lodash'); 27 | var fs=require('fs'); 28 | module.exports=function(){ 29 | /** 30 | * This class handles the initialization of several components, as well as path mapping, inheritances and namespace colisions 31 | * It's serve as a common library for object,classes and paths lookup 32 | * @type {Object} 33 | */ 34 | var oliveOil={ 35 | 36 | //A map of classes in which the namespace class name is the index and the class object the item 37 | classMap:{ 38 | 39 | }, 40 | //A map of classes to it's class path 41 | classFileMap:{ 42 | 43 | }, 44 | //A map of class names to objects, it is handled in our singletons objects 45 | objectMap:{ 46 | 47 | }, 48 | //A map of directories based on the namespace 49 | namespaceDirMap:{ 50 | 51 | }, 52 | classPojoMap:{ 53 | 54 | }, 55 | createdPojoMap:{ 56 | 57 | }, 58 | noNamespaceDir:null, 59 | /** 60 | * Get a class object from the given object 61 | * @param {[type]} namespace [description] 62 | * @return {[type]} [description] 63 | */ 64 | getClass:function(name){ 65 | if(this.isClassSet(name) || this.loadClass(name)){ 66 | return _.clone(this.classMap[name]); 67 | } 68 | else{ 69 | throw new Error('Was not able to load the class '+name); 70 | } 71 | 72 | }, 73 | loadClass:function(name){ 74 | 75 | var classPojo; 76 | 77 | classPojo=this.getClassPojo(name); 78 | 79 | if(this.createClassFromPojo(name,classPojo)){ 80 | return true; 81 | } 82 | throw new Error('Was not able to load the class '+name+' on the path '+this.classFileMap[name]); 83 | }, 84 | isObjectSet:function(name){ 85 | return !!this.objectMap[name]; 86 | }, 87 | isClassSet:function(name){ 88 | return !!this.classMap[name]; 89 | }, 90 | createObject:function(name, var_args){ 91 | //Getting the var_args 92 | var params = Array.prototype.slice.call(arguments, 1); 93 | if(!this.isClassSet(name) && !this.isClassPojoSet(name)){ 94 | if(!this.loadClass(name)){ 95 | throw new Error('The class "'+name+'" is not set'); 96 | } 97 | } 98 | var DesiredClass=this.getClass(name); 99 | //Needed for us to apply the constructor 100 | var object = Object.create(DesiredClass.prototype); 101 | 102 | result= DesiredClass.apply(object, params); 103 | if (typeof result === 'object') { 104 | return result; 105 | } 106 | return object; 107 | }, 108 | getClassFile:function(name){ 109 | return this.classFileMap[name]; 110 | }, 111 | normalizeJsFile:function(name){ 112 | var index=name.lastIndexOf('.js'); 113 | if(index==-1 || index!=(name.length-4)){ 114 | name+='.js' 115 | } 116 | return name; 117 | }, 118 | _getFile:function(path){ 119 | name=this.normalizeJsFile(path); 120 | if(!fs.existsSync(path)){ 121 | throw new Error('the path '+path+' does not exists'); 122 | } 123 | return require(path); 124 | }, 125 | 126 | getClassFileContents:function(name){ 127 | if(!this.isClassFileSet(name)){ 128 | var namespaceAndName=this.getNamespaceAndNameFromPath(name); 129 | var namespace=namespaceAndName['namespace']; 130 | var className=namespaceAndName['className']; 131 | if(namespace && !this.isNamespaceSet(namespace)){ 132 | throw new Error('The namespace '+namespace+' is not set (trying to get '+name+')'); 133 | } 134 | if(namespace){ 135 | this.setClassFileByNamespace(namespace,className); 136 | } 137 | else{ 138 | this.setClassFile(name,this.noNamespaceDir+name); 139 | } 140 | } 141 | return this._getFile(this.classFileMap[name]); 142 | }, 143 | setClassFileByNamespace:function(namespace,className){ 144 | var fullName=namespace+'.'+className; 145 | if(this.isClassFileSet(fullName)){ 146 | throw new Error('The class '+className+' on the namespace '+namespace+' is already mapped'); 147 | } 148 | var path=this.normalizeJsFile(this.getNamespaceDir(namespace)+className); 149 | this.classFileMap[fullName]=path; 150 | return true; 151 | }, 152 | getNamespaceAndNameFromPath:function(name){ 153 | var pos=name.lastIndexOf('.'); 154 | if(pos==-1){ 155 | return { 156 | 'namespace':false, 157 | 'className':name 158 | } 159 | } 160 | return { 161 | 'namespace':name.substr(0,pos), 162 | 'className':name.substr(pos+1) 163 | }; 164 | }, 165 | getNamespaceFromPath:function(name){ 166 | var pos=name.lastIndexOf('.'); 167 | if(pos==-1){ 168 | throw new Error(name+' is not a valid namespace'); 169 | } 170 | return name.substr(0,pos); 171 | 172 | }, 173 | getClassNameFromPath:function(name){ 174 | var pos=name.lastIndexOf('.'); 175 | if(pos==-1){ 176 | throw new Error(name+ ' is not a namespace'); 177 | } 178 | return name.substr(pos+1); 179 | 180 | }, 181 | getSingletonObject:function(name,var_args){ 182 | if(this.isObjectSet(name)){ 183 | return this.objectMap[name]; 184 | } 185 | this.objectMap[name]=this.createObject.apply(this,arguments); 186 | return this.objectMap[name]; 187 | }, 188 | isClassPojoAlreadyCreated:function(name){ 189 | return this.createdPojoMap[name]; 190 | }, 191 | isClassPojoSet:function(name){ 192 | return this.isClassPojoAlreadyCreated(name) || typeof(this.classPojoMap[name])!=='undefined'; 193 | }, 194 | 195 | setClassPojo:function(name,pojoData,overwrite){ 196 | if(this.isClassPojoAlreadyCreated(name)){ 197 | throw new Error("The class "+name+" is already created and cannot have it's pojo changed"); 198 | } 199 | if(!overwrite && this.isClassPojoSet(name)){ 200 | throw new Error('Class pojo is already set, please pass a overwrride parameter if you want to reset it'); 201 | } 202 | this.classPojoMap[name]=_.clone(pojoData); 203 | return true; 204 | }, 205 | getClassPojo:function(name){ 206 | if(this.isClassPojoSet(name)){ 207 | return _.clone(this.classPojoMap[name]); 208 | } 209 | else{ 210 | var classPojo=this.getClassFileContents(name); 211 | this.setClassPojo(name,classPojo); 212 | return _.clone(this.classPojoMap[name]); 213 | } 214 | }, 215 | _setClassPojoAsUsed:function(name){ 216 | this.createdPojoMap[name]=true; 217 | }, 218 | /** 219 | * Sets a class on the given namespace to be the class object 220 | * @type {[type]} 221 | */ 222 | createClassFromPojo:function(name,pojoData){ 223 | var ParentClass; 224 | if(!pojoData){ 225 | pojoData=this.getClassPojo(name); 226 | } 227 | if(pojoData.parent){ 228 | if(Array.isArray(pojoData.parent)){ 229 | var currentObj=Class; 230 | var currentParent; 231 | var self=this; 232 | pojoData.parent.forEach(function(p){ 233 | 234 | currentParent=self.getClass(p); 235 | currentObj=currentObj.extend(currentParent.prototype) 236 | }); 237 | ParentClass=currentObj; 238 | } 239 | else{ 240 | 241 | ParentClass=this.getClass(pojoData.parent); 242 | } 243 | } 244 | else{ 245 | ParentClass=Class; 246 | } 247 | var ret= this.setClass(name,ParentClass.extend(pojoData)); 248 | this._setClassPojoAsUsed(name); 249 | return ret; 250 | }, 251 | 252 | /** 253 | * Sets a class on the given namespace to be the class object 254 | * @type {[type]} 255 | */ 256 | setClass:function(name,classObject){ 257 | if(this.isClassSet(name)){ 258 | throw new Error('The class '+name+' is already set'); 259 | } 260 | this.classMap[name]=classObject; 261 | return true; 262 | }, 263 | setMultipleNamespacesDir:function(namespaceMap){ 264 | for(var name in namespaceMap){ 265 | this.setNamespaceDir(name,namespaceMap[name]); 266 | } 267 | return true; 268 | }, 269 | 270 | setNamespaceDir:function(name,dir){ 271 | if(this.isNamespaceSet(name)){ 272 | throw new Error('The namespace '+name+' is already set'); 273 | return; 274 | } 275 | dir=this.normalizeDirectory(dir); 276 | this.namespaceDirMap[name]=dir; 277 | return true; 278 | }, 279 | setRecursiveNamespaceDir:function(name,dir,cb){ 280 | if(this.isNamespaceSet(name)){ 281 | cb(new Error('The namespace '+name+' is already set')); 282 | return; 283 | } 284 | dir=this.normalizeDirectory(dir); 285 | this.namespaceDirMap[name]=dir; 286 | this._walkDirectoryAndSetNamespace(name,dir,cb); 287 | 288 | }, 289 | _walkDirectoryAndSetNamespace:function(previousNamespaces,dir,cb){ 290 | var self=this; 291 | var readDirCb=function(err,list){ 292 | if(err){ 293 | cb(err); 294 | return; 295 | } 296 | 297 | var stat; 298 | var funcsToSetNamespace=[]; 299 | list.forEach(function(item){ 300 | var newNamespace; 301 | var path=dir+item; 302 | stat=fs.statSync(path); 303 | if(stat.isDirectory()){ 304 | newNamespace=self.buildNamespace(item,previousNamespaces); 305 | funcsToSetNamespace.push(function(asynccb){ 306 | self.setRecursiveNamespaceDir(newNamespace,path,asynccb); 307 | }); 308 | } 309 | }); 310 | if(funcsToSetNamespace.length==0){ 311 | cb(); 312 | return; 313 | } 314 | async.series(funcsToSetNamespace,cb); 315 | } 316 | list=fs.readdir(dir,readDirCb); 317 | }, 318 | normalizeDirectory:function(dir){ 319 | 320 | if(dir.lastIndexOf('/')!=(dir.length-1)){ 321 | dir+='/'; 322 | } 323 | return dir; 324 | }, 325 | classFileExists:function(name){ 326 | var namespaceAndName=this.getNamespaceAndNameFromPath(name); 327 | var namespace=namespaceAndName['namespace']; 328 | var className=namespaceAndName['className']; 329 | if(!this.isNamespaceSet(namespace)){ 330 | return false; 331 | } 332 | var path; 333 | if(namespace){ 334 | path=this.getNamespaceDir(namespace); 335 | } 336 | else{ 337 | path=this.noNamespaceDir; 338 | } 339 | var fileName=this.normalizeJsFile(className); 340 | 341 | return fs.existsSync(path+fileName); 342 | 343 | }, 344 | getNamespaceDir:function(name){ 345 | 346 | return this.namespaceDirMap[name]; 347 | }, 348 | isNamespaceSet:function(name){ 349 | return !!this.namespaceDirMap[name]; 350 | }, 351 | isClassFileSet:function(name){ 352 | return !!this.classFileMap[name]; 353 | 354 | }, 355 | buildNamespace:function(currentNamespace,previousNamespace){ 356 | if(previousNamespace){ 357 | return previousNamespace+'.'+currentNamespace; 358 | } 359 | return currentNamespace; 360 | }, 361 | setClassFile:function(name,file){ 362 | if(this.isClassFileSet(name)){ 363 | throw new Error('The class '+name+' is already set with a path'); 364 | } 365 | this.classFileMap[name]=this.normalizeJsFile(file); 366 | return true; 367 | }, 368 | setSingletonObject:function(name,object){ 369 | if(this.isObjectSet(name)){ 370 | throw new Error('The object '+name+' is already set'); 371 | } 372 | this.objectMap[name]=object; 373 | }, 374 | init:function(noNamespaceDir){ 375 | this.setNoNamespaceDir(noNamespaceDir); 376 | }, 377 | setNoNamespaceDir:function(noNamespaceDir){ 378 | if(noNamespaceDir!==null){ 379 | noNamespaceDir=this.normalizeDirectory(noNamespaceDir); 380 | } 381 | this.noNamespaceDir=noNamespaceDir; 382 | } 383 | }; 384 | return Class.extend(oliveOil); 385 | } 386 | 387 | --------------------------------------------------------------------------------