Skip to content

Commit

Permalink
feat($types): implemented env.types.Number and env.types.Boolean
Browse files Browse the repository at this point in the history
  • Loading branch information
FGRibreau committed Nov 4, 2015
1 parent 594a26e commit fc0582e
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 35 deletions.
6 changes: 5 additions & 1 deletion lib/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
'use strict';

var _ = require('lodash');
var types = require('./types');
var EventEmitter = require('events').EventEmitter;
var CommonEnvGetOrDieException = require('./CommonEnvGetOrDieException');
var CommonEnvGetOrDieAliasesException = require('./CommonEnvGetOrDieAliasesException');
Expand All @@ -12,6 +13,7 @@ var EVENT_FALLBACK = 'env:fallback';
module.exports = function envFactory() {
var em = new EventEmitter();


var getOrDie = getOrDieFactory(function (fullKeyName) {
throw new CommonEnvGetOrDieException(fullKeyName);
});
Expand Down Expand Up @@ -53,7 +55,7 @@ module.exports = function envFactory() {
throw new Error('Common-env: $aliases must be defined along side $default, key: ' + fullKeyName);
}

var $typeConverter = getTypeConverter(object.$default);
var $typeConverter = object.$type || getTypeConverter(object.$default);

return object.$aliases.concat([fullKeyName]).reduce(function (memo, varEnvName, i, aliases) {
var isLast = i === aliases.length - 1;
Expand Down Expand Up @@ -118,6 +120,8 @@ module.exports = function envFactory() {
EVENT_FOUND: EVENT_FOUND,
EVENT_FALLBACK: EVENT_FALLBACK,

types: types.convert,

CommonEnvGetOrDieException: CommonEnvGetOrDieException,
CommonEnvGetOrDieAliasesException: CommonEnvGetOrDieAliasesException
});
Expand Down
38 changes: 38 additions & 0 deletions lib/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

module.exports = {
seems: {
Integer: seemsInteger,
Boolean: seemsBoolean
},
convert: {
Integer: Integer,
Boolean: Boolean
}
};


function Integer(mixed) {
if (!seemsInteger(mixed)) {
throw new Error('`' + mixed + '` is not an integer, could not convert it.');
}
return parseInt(mixed, 10);
}

function seemsInteger(mixed){
var maybeInt = parseInt(mixed, 10);
return !isNaN(maybeInt) && mixed + '' === maybeInt.toFixed(0);
}

function Boolean(mixed) {
if (!seemsBoolean(mixed)) {
throw new Error('`' + mixed + '` is not an boolean, could not convert it.');
}

return String(mixed).toLowerCase() === 'true';
}

function seemsBoolean(mixed) {
var v = String(mixed).toLowerCase();
return v === 'true' || v === 'false';
}
164 changes: 130 additions & 34 deletions test/getOrElseAll.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,46 +156,142 @@ describe('.getOrElseAll', function () {
t.ok(_.has(eventsFallback, 'PLOP_API[1]_A'), 'PLOP_ROOT_TOKEN');
});

it('should handle special $aliases and $default object value', function () {
var config = env.getOrElseAll({
a: {
b: [{
a: {
$default: 'heyheyhey',
$aliases: ['BLABLA_BLABLA', 'AMQP_LOGIN']
}
describe('$aliases handling', function () {
it('should handle $default object value', function () {
var config = env.getOrElseAll({
a: {
b: [{
a: {
$default: 'heyheyhey',
$aliases: ['BLABLA_BLABLA', 'AMQP_LOGIN']
}
}, {
a: {
$default: 'plop2',
$aliases: ['BLABLA_BLABLA'] // `BLABLA_BLABLA` does not exist, it should fallback on "plop"
}
a: {
$default: 'plop2',
$aliases: ['BLABLA_BLABLA'] // `BLABLA_BLABLA` does not exist, it should fallback on "plop"
}
}]
},
b: {
$default: 10,
$aliases: ['BLABLA_BLABLA', 'AMQP_GOOD_PORT', 'BLABLA_BLABLA']
}
});
t.strictEqual(config.a.b[0].a, 'plop', 'should use AMQP_LOGIN value');
t.ok(_.has(eventsFound, 'AMQP_LOGIN'), 'AMQP_LOGIN should be printed');
},
b: {
$default: 10,
$aliases: ['BLABLA_BLABLA', 'AMQP_GOOD_PORT', 'BLABLA_BLABLA']
}
});
t.strictEqual(config.a.b[0].a, 'plop', 'should use AMQP_LOGIN value');
t.ok(_.has(eventsFound, 'AMQP_LOGIN'), 'AMQP_LOGIN should be printed');

t.strictEqual(config.b, 10);
t.ok(_.has(eventsFound, 'AMQP_GOOD_PORT'), 'A_B[1]_A was defined should be printed');
});
t.strictEqual(config.b, 10);
t.ok(_.has(eventsFound, 'AMQP_GOOD_PORT'), 'A_B[1]_A was defined should be printed');
});

it('should handle special $aliases and $default object value and fallback on default value', function () {
var config = env.getOrElseAll({
a: {
b: [{}, {
a: {
$default: 'plop2',
$aliases: ['BLABLA_BLABLA'] // `BLABLA_BLABLA` does not exist, it should fallback on "plop"
}
it('should handle $default object value and fallback on default value', function () {
var config = env.getOrElseAll({
a: {
b: [{}, {
a: {
$default: 'plop2',
$aliases: ['BLABLA_BLABLA'] // `BLABLA_BLABLA` does not exist, it should fallback on "plop"
}
}]
}
}
});
t.strictEqual(config.a.b[1].a, 'plop2');
t.ok(_.has(eventsFallback, 'A_B[1]_A'), 'A_B[1]_A was not defined should be printed');
});

describe('if $type was specified', function () {
let env = envFactory();
const tests = [
{
converter: env.types.Integer,
val: '10',
converted: 10
}, {
converter: env.types.Integer,
val: '102039.23',
converted: Error // because the value should be an integer
},{
converter: env.types.Boolean,
val:'true',
converted:true
},{
converter: env.types.Boolean,
val:'false',
converted:false
},{
converter: env.types.Boolean,
val:'TRUE',
converted:true
},{
converter: env.types.Boolean,
val:'oskdoskd',
converted:Error
},
// {
// converter: 'STRING',
// env:'string',
// converted:'string'
// },{
// converter: 'String',
// env:'a,b,c,d'
// converted:['a', 'b', 'c', 'd']
// }
].map(function (test) {
return Object.assign({}, {
varName: (test.converter.name.toUpperCase() + '_' + test.val).replace('.', '_')
}, test);
});

// ensure environment variables does not clash between them
it('should have unique vairables names', () => {
t.deepEqual(_.pluck(tests, 'varName'), _.chain(tests).pluck('varName').uniq().value());
})

beforeEach(() => {
_.forEach(tests, (v) => process.env[v.varName] = v.val);
});

afterEach(() => {
_.forEach(tests, (v) => delete process.env[v.varName]);
});



_.forEach(tests, (v) => {

describe(v.converter.name + ' (e.g. '+v.val+')', () => {
it('should be defined as a function', () => {
t.ok(_.isFunction(v.converter), v.converter.name + ' should be a function');
});
});

if (v.converted === Error) {
it('should throw an error when the converter ' + v.converter.name + ' does not receive a good value (e.g. with ' + v.val + ')', () => {

t.throws(() => {
env.getOrElseAll({
a: {
$type: v.converter,
$aliases: [v.varName]
}
});
});
});
return;
}

it('should handle ' + v.converter.name + ' converter as $type (e.g. with ' + JSON.stringify(v.val) + ')', () => {
var config = env.getOrElseAll({
a: {
$type: v.converter,
$aliases: [v.varName]
}
});

t.strictEqual(config.a, v.converted);
});
});
});
t.strictEqual(config.a.b[1].a, 'plop2');
t.ok(_.has(eventsFallback, 'A_B[1]_A'), 'A_B[1]_A was not defined should be printed');
});

describe('fail-fast behaviour', function () {
Expand Down

0 comments on commit fc0582e

Please sign in to comment.