Skip to content

Commit

Permalink
Add file based environment loading tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher Sidell committed Jan 18, 2017
1 parent 5cf4e4a commit 4d96508
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 27 deletions.
4 changes: 4 additions & 0 deletions .spaces.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"NS/": "tests/Namespace",
"ENV/": "tests/ENV/dev"
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,16 @@ level as your node_modules folder.

Currently it follows the [PSR-4](http://www.php-fig.org/psr/psr-4/) because I have yet to create a javascript spec
for loading namespaces neatly and include options for glob loading.

A namespace can be created from any object as long as it follows the format of the **key** being the namespace
where the **value** is the location on the file system relative to the *.spaces.js* file.

```
#.spaces.js
'use strict';
module.exports = {
'NS/': 'Namespace/',
'NS/Config': 'Namespace/Something/Config'
};
```
67 changes: 62 additions & 5 deletions lib/Space.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,93 @@
const path = require('path');

class Space {
constructor({name, location, root, test}){

/**
* Create namespace
* @param name {string} Namespace name
* @param location {string} Relative path from root
* @param root {string} Root path to use
*/
constructor({name, location, root}){
/**
* @type {string}
* @private
*/
this._name = name;
this._location = location;
this._root = root;

/**
* @type {string}
* @private
*/
this._location = Space._ensureEndSlash(location);

/**
* @type {string}
* @private
*/
this._root = Space._ensureEndSlash(root);

/**
* @type RegExp
* @private
*/
this._test = test;
this._test = new RegExp(`^${name}`);
}

/**
* Ensure string ends with path separator
* @param str {string} Path to ensure
* @returns {string}
* @private
*/
static _ensureEndSlash(str){
return str.replace(new RegExp(`${path.sep}*$`), '')+path.sep;
}

/**
* Test request against space
* @param req {string} Request string
* @return {boolean}
*/
test(req){
return this._test.exec(req);
return !!this._test.exec(req);
}

/**
* Build filepath from namespace
* @param req {string} Request path
* @return {string}
*/
path(req){
return path.normalize(path.join(this.root(), this.location(), req.replace(this.name(), '')));
}

/**
* Get root
* @return {string}
*/
root(){
return this._root;
}

/**
* Get relative location
* @return {string}
*/
location(){
return this._location;
}

/**
* Get namespace name
* @return {string}
*/
name(){
return this._name;
}
}

/**
* @type {Space}
*/
module.exports = Space;
63 changes: 45 additions & 18 deletions namespacer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const path = require('path');
const path = require('path'),
fs = require('fs');

const Space = require('./lib/Space');

Expand Down Expand Up @@ -35,31 +36,16 @@ class Namespace {
return require(Namespace.resolve(req));
}

/**
* Ensure string ends with path separator
* @param str {string} Path to ensure
* @returns {string}
* @private
*/
static _ensureEndSlash(str){
return str.replace(new RegExp(`${path.sep}*$`), '')+path.sep;
}

/**
* Create space from name, relative path from root
* @param name {string} Namespace
* @param rel {string} Path to namespace
* @param root {string} Path to root
* @returns {{name: string, root: string, location: string, test: RegExp}}
* @returns {Space}
* @private
*/
static _createSpace({ name, rel, root }){
return new Space({
name,
root: Namespace._ensureEndSlash(root),
location: Namespace._ensureEndSlash(rel),
test: new RegExp(`^${name}`)
});
return new Space({ name, root, location: rel });
}

/**
Expand All @@ -70,6 +56,16 @@ class Namespace {
return process.cwd(); //path.dirname(module.parent.paths[0])
}

/**
* Get spaces file relative to including module
* @param fp {string} Relative path to spaces file
* @private
* @return {string}
*/
static _getSpaceRootFromIncludedModule(fp){
return path.normalize(path.join(path.dirname(module.parent.filename), fp));
}

/**
* Read from configuration
* @param conf {Object} Namespace configuration object
Expand Down Expand Up @@ -126,6 +122,37 @@ class Namespace {
Namespace._sortSpaces();
}

/**
* Load namespace from file
* @param fp {string|null} Absolute or relative path
*/
static addSpacesFromFile(fp=null){
if(fp == null){
//Find default files
let js = path.normalize(path.join(Namespace._getSpaceRoot(), '.spaces.js'));
let json = path.normalize(path.join(Namespace._getSpaceRoot(), '.spaces.json'));

if(fs.existsSync(js))
fp = js;
else if (fs.existsSync(json))
fp = json;
else
throw new Error('No .space file could be found!');
}

if(path.isAbsolute(fp))
Namespace.addSpacesFromObject(require(fp), path.dirname(fp));
else {
let absolute = Namespace._getSpaceRootFromIncludedModule(fp);
Namespace.addSpacesFromObject(require(absolute), path.dirname(absolute));
}
}

/**
* Clear out namespaces
* This destroys data
* @private
*/
static _clearSpaces(){
Namespace._spaces = []
}
Expand Down
6 changes: 6 additions & 0 deletions tests/.env.spaces.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

module.exports = (env) => ({
'NS/': 'Namespace/',
'ENV/': `ENV/${env}`
});
5 changes: 5 additions & 0 deletions tests/.spaces.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
'NS/': 'Namespace/'
};
3 changes: 3 additions & 0 deletions tests/ENV/dev/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = "Loaded from dev/config.js";
3 changes: 3 additions & 0 deletions tests/ENV/prod/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use strict';

module.exports = "Loaded from prod/config.js";
115 changes: 111 additions & 4 deletions tests/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('Namespace Tests', function(){
});

it('Should clear spaces correctly', function(){
let instance = namespace.instance({'NS/': 'Namespace/'}, path.resolve('./tests'));
namespace.instance({'NS/': 'Namespace/'}, path.resolve('./tests'));

expect(Namespace.getSpaces().length > 0).to.eql(true);

Expand All @@ -39,7 +39,7 @@ describe('Namespace Tests', function(){
});

it('Should have correct root if passed', function(){
let instance = namespace.instance({'NS/': 'Namespace/'}, path.resolve('./tests'));
namespace.instance({'NS/': 'Namespace/'}, path.resolve('./tests'));

let space = Namespace._spaces[0];

Expand All @@ -49,7 +49,7 @@ describe('Namespace Tests', function(){
});

it('Should have pull root with node_modules', function(){
let instance = namespace.instance({'NS/': 'Namespace/'});
namespace.instance({'NS/': 'Namespace/'});

let space = Namespace._spaces[0];

Expand Down Expand Up @@ -103,7 +103,114 @@ describe('Namespace Tests', function(){
namespace.instance({'NS/': 'Namespace/'}, path.resolve('./tests'));
let thing = new (Namespace.require('NS/Thing.js'));

expect(thing instanceof Thing).to.eql(true);
expect(thing).to.be.a(Thing);
});
});

describe('File testing', function(){

beforeEach(function(done){
Namespace._clearSpaces();
done();
});

describe('Absolute filepathing', function(){
it('Can load namespaces', function(){
Namespace.addSpacesFromFile(path.resolve('./tests/.spaces.js'));

expect(Namespace.getSpaces()).to.have.length(1);
});

it('Can require from namespaces', function(){
Namespace.addSpacesFromFile(path.resolve('./tests/.spaces.js'));

const Thing = require('./Namespace/Thing');

let thing = new (Namespace.require('NS/Thing.js'));

expect(thing).to.be.a(Thing);
});
});

describe('Relative filepathing', function(){
it('Can load namespaces', function(){
Namespace.addSpacesFromFile('./.spaces.js');

expect(Namespace.getSpaces()).to.have.length(1);
});

it('Can require from namespaces', function(){
Namespace.addSpacesFromFile('./.spaces.js');

const Thing = require('./Namespace/Thing');

let thing = new (Namespace.require('NS/Thing.js'));

expect(thing).to.be.a(Thing);
});
});

describe('Default filepathing', function(){
it('Can load namespaces from default JSON', function(){
Namespace.addSpacesFromFile();

expect(Namespace.getSpaces()).to.have.length(2);

const DevConfig = require('./ENV/dev/config');

//This is to verify it's the JSON not JS file being loaded
let config = Namespace.require('ENV/config.js');

expect(config).to.eql(DevConfig);
});

it('Can load namespaces from default JS', function(done){
try {
process.chdir('./tests');

Namespace.addSpacesFromFile();
expect(Namespace.getSpaces()).to.have.length(1);

done();
} catch(e){
done(e);
} finally {
process.chdir('../');
}
});

it('Can require from namespaces', function(){
Namespace.addSpacesFromFile();

const Thing = require('./Namespace/Thing');

let thing = new (Namespace.require('NS/Thing.js'));

expect(thing).to.be.a(Thing);
});
});

describe('Enviroment Namespace', function(){
const DevConfig = require('./ENV/dev/config');
const ProdConfig = require('./ENV/prod/config');

it('Can load dev environment file', function(){
Namespace.addSpacesFromObject(require('./.env.spaces')('dev'), path.resolve('./tests'));

let config = Namespace.require('ENV/config.js');

expect(config).to.eql(DevConfig);
expect(config).not.to.equal(ProdConfig);
});

it('Can load prod environment file', function(){
Namespace.addSpacesFromObject(require('./.env.spaces')('prod'), path.resolve('./tests'));

let config = Namespace.require('ENV/config.js');

expect(config).to.eql(ProdConfig);
expect(config).not.to.equal(DevConfig);
});
});
});
});

0 comments on commit 4d96508

Please sign in to comment.