Skip to content

Commit

Permalink
Updated README, cleaned up leftovers
Browse files Browse the repository at this point in the history
  • Loading branch information
alexindigo committed Feb 21, 2016
1 parent ddb85d5 commit 47a81ce
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 12 deletions.
139 changes: 136 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,156 @@
# configly [![NPM Module](https://img.shields.io/npm/v/configly.svg?style=flat)](https://www.npmjs.com/package/configly)

A lightweight replacement for the `config` module that works with custom config directory and pluggable parsers.
A developer-friendly lightweight replacement for the `config` module that works with custom config directory and pluggable parsers.

[![Linux Build](https://img.shields.io/travis/alexindigo/configly/master.svg?label=linux:0.10-5.x&style=flat)](https://travis-ci.org/alexindigo/configly)
[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/configly/master.svg?label=windows:0.10-5.x&style=flat)](https://ci.appveyor.com/project/alexindigo/configly)

[![Coverage Status](https://img.shields.io/coveralls/alexindigo/configly/master.svg?label=code+coverage&style=flat)](https://coveralls.io/github/alexindigo/configly?branch=master)
[![Dependency Status](https://img.shields.io/david/alexindigo/configly.svg?style=flat)](https://david-dm.org/alexindigo/configly)

*Notice of change of ownership: Starting version 3.0.0 this package has changed it's owner and goals. The old version (2.0.3) is still available on npm via `npm install configly@2.0.3` and on [github.com/ksmithut/configly](https://github.com/ksmithut/configly). Thank you.*

## Install

```
$ npm install --save configly
```

## Why

Original `config` module is convenient and easy to start with library, but in the same time being focused that much on "easy" it lacks certain features to be a _"developer friendly"_ library.

This package is addressing those issues, while keeping easy of use and featureset on par with the original module.

## Usage

TBW
### Basic

To simply replace your current `config` setup, add following to your files:

```javascript
var config = require('configly')();

console.log(config.my.combined.options);
```

It will load `.js` and `.json` files from `./config` folder,
relative to the current working directory (`process.cwd()`).

It will cache the result, so files will be read only once per process.

### Pluggable formats and parsers

Out of the box `configly` supports only two formats (`.js` and `.json`), but developers can add their own parsers and support for more formats (e.g. `.ini`, `.yaml`, `.cson`).

```javascript
var config = require('configly');
// more parsers
var ini = require('ini');
var cson = require('cson');
var yaml = require('js-yaml');
var properties = require('properties');
var json5 = require('json5');

// assemble new parsers list
// order doesn't matter since they
// will be alphabetically sorted
config.PARSERS = {
ini : ini.parse,
// have it as a wrapper to prevent extra arguments leaking
cson : function(str) { return cson.parse(str); },
yml : function(str) { return yaml.safeLoad(str); },
// same options as used within `config` module
properties: function(str) { return properties.parse(str, {namespaces: true, variables: true, sections: true}); },
// use json5 instead of `JSON.parse`
json : json5.parse
// keep the original one
js : config.PARSERS.js,
};

var configObj = config();
```

Since `configly` is a singleton, this setup could be done in your index file,
and the rest of the files would use it the same way as in the "Basic" example.

### Custom config directory

To load config files from a custom directory, just specify it as the first argument.

```javascript
var config = require('configly')('./etc'); // `require('configly')('./etc');` would work the same way`
```

It will load files from the `etc` folder relative to the current working directory,
by providing absolute path, you can make sure exact location of the config files,
which is useful to libraries meant to be used within larger applications
and for command line apps that could be invoked from different directories.

```javascript
var path = require('path');
var config = require('configly')(path.join(__dirname, 'etc'));
```

Or you can set up new directory as default one
and invoke `configly` without custom arguments
from within other files.

```javascript
// index.js
var path = require('path');
var configly = require('configly');

configly.DEFAULTS.directory = path.join(__dirname, 'etc');

// app.js
var config = require('configly')();
```

### Additional config directories

It is possible to load files from more than one config directory within one application/module.

```javascript
var path = require('path');
var ini = require('ini');
var configly = require('configly');

var appConfig = configly(path.join(__dirname, 'app-config'));
// for example you have .ini config files there
var rulesConfig = configly(path.join(__dirname, 'rules-config'), {ini: ini.parse});
```

If there is a need to merge config objects into one,
you can use [deeply](http://npmjs.org/deeply) module
or any other package that provides deep merging.

```javascript
var merge = require('deeply');
var allConfig = merge(appConfig, rulesConfig);
```

### More examples

For more examples check out [test directory](test/).

## Differences

Main differences between `configly` and `config`:

- Configly doesn't read/write `NODE_CONFIG` environment variable.
- Configly doesn't pollute your logs with warnings of non-existent files,
it will either throw (if couldn't read/parse a file) or be silent.
- Configly doesn't provide `get`, `has` methods, it returns pure js object.
- Configly doesn't auto-strip comments from JSON files, use `configly.PARSERS['json'] = json5.parse;`.


- Configly provides deterministic (and controllable) order of the config files it loads from.
- Configly provides deterministic (and controllable) order of the file extensions it loads from.
- Configly provides post-load hooks for config files, (e.g. `custom-environment-variables` works via this mechanism).
- Configly provides ability to combine environment variables within one entry (e.g. `"endpoint": "${REMOTE_HOST}:${REMOTE_PORT}"`).
- Configly provides access to the underlying functions and defaults, allowing to utilize parts of the functionality for greater flexibility.

## License

EnVar is licensed under the MIT license.
Configly is licensed under the MIT license.
18 changes: 11 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ configly._compareExtensions = compare.ascendingIgnoreCase;

// defaults
configly.DEFAULTS = {
directory : './config',
environment : 'development',
customEnvVars: 'custom-environment-variables'
};
Expand Down Expand Up @@ -81,8 +82,9 @@ function configly(directory, parsers)
{
var cacheKey;

// fallback to default parsers if needed
parsers = parsers || configly.PARSERS;
// fallback to defaults
directory = directory || configly.DEFAULTS.directory;
parsers = parsers || configly.PARSERS;

// prepare cache key
cacheKey = configly._getCacheKey(directory, parsers);
Expand All @@ -92,7 +94,8 @@ function configly(directory, parsers)
configly.load(directory, parsers);
}

return configly._cache[cacheKey];
// return immutable copy
return merge(configly._cache[cacheKey]);
}

/**
Expand All @@ -111,8 +114,9 @@ function load(directory, parsers)
, cacheKey
;

// fallback to default parsers if needed
parsers = parsers || configly.PARSERS;
// fallback to defaults
directory = directory || configly.DEFAULTS.directory;
parsers = parsers || configly.PARSERS;

// prepare cache key
cacheKey = configly._getCacheKey(directory, parsers);
Expand All @@ -126,8 +130,8 @@ function load(directory, parsers)
// merge loaded layers
configly._cache[cacheKey] = configly._mergeLayers(layers);

// return results
return configly._cache[cacheKey];
// return immutable copy
return merge(configly._cache[cacheKey]);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "configly",
"version": "3.0.0",
"description": "A lightweight replacement for the `config` module that works with custom config directory and pluggable parsers",
"description": "A developer-friendly lightweight replacement for the `config` module that works with custom config directory and pluggable parsers",
"main": "index.js",
"scripts": {
"lint": "eslint index.js test/*.js",
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/config/default/custom-environment-variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Customers":
{
"dbName" :"from_custom-environment-variables_json",
"dbPassword" :"TESTLINEONE",
"dbPassword2" :"TESTLINETWO"
},
"Zap" : "${EMPTY_VAR}",
"Single" : "${JUST_VAR}",
"Combined" : "${VARPART1}:${VARPART2}",
"nosee" : "${NOEXISTING} + another ${EMPTY} var"
}
32 changes: 32 additions & 0 deletions test/fixtures/config/default/default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports =
{
Customers:
{
dbName : 'from_default_js',
dbPassword : 'password will be overwritten.',
dbPassword2: 'password will be overwritten.',

lang:
[
'en',
'es'
]
},
AnotherModule:
{
'parm1': 'value1'
},
staticArray:
[
2,
1,
3
],
Inline:
{
a: '',
b: '1'
},
ContainsQuote : '"this has a quote"',
MoreComplexQuote: '<a href="http://localhost:3000/offers/reply?id={{system.contact.value}}">Test String</a>'
};
15 changes: 15 additions & 0 deletions test/fixtures/config/default/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Customers": {
"dbName":"from_default_json",
"dbPassword":"password will be overwritten.",
"dbPassword2":"password will be overwritten.",
"lang":["en","es"]
},
"AnotherModule": {
"parm1":"value2"
},
"staticArray": [4,5,6],
"Inline": {"a": "", "b": "1"},
"ContainsQuote": "\"this has a quote\"",
"MoreComplexQuote": "<a href=\"http://localhost:3000/offers/reply?id=${{system.contact.value}}\">Test String</a>"
}
6 changes: 6 additions & 0 deletions test/fixtures/config/default/staging.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AnotherModule":
{
"parm1":"value3"
}
}
32 changes: 32 additions & 0 deletions test/fixtures/config/immutable/default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports =
{
Customers:
{
dbName : 'from_default_js',
dbPassword : 'password will be overwritten.',
dbPassword2: 'password will be overwritten.',

lang:
[
'en',
'es'
]
},
AnotherModule:
{
'parm1': 'value1'
},
staticArray:
[
2,
1,
3
],
Inline:
{
a: '',
b: '1'
},
ContainsQuote : '"this has a quote"',
MoreComplexQuote: '<a href="http://localhost:3000/offers/reply?id={{system.contact.value}}">Test String</a>'
};
15 changes: 15 additions & 0 deletions test/fixtures/config/immutable/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Customers": {
"dbName":"from_default_json",
"dbPassword":"password will be overwritten.",
"dbPassword2":"password will be overwritten.",
"lang":["en","es"]
},
"AnotherModule": {
"parm1":"value2"
},
"staticArray": [4,5,6],
"Inline": {"a": "", "b": "1"},
"ContainsQuote": "\"this has a quote\"",
"MoreComplexQuote": "<a href=\"http://localhost:3000/offers/reply?id=${{system.contact.value}}\">Test String</a>"
}
27 changes: 27 additions & 0 deletions test/fixtures/expected/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"Customers": {
"dbName": "from_default_json",
"dbPassword": "ABC",
"dbPassword2": "XYZ",
"lang": [
"en",
"es"
]
},
"AnotherModule": {
"parm1": "value3"
},
"staticArray": [
4,
5,
6
],
"Inline": {
"a": "",
"b": "1"
},
"ContainsQuote": "\"this has a quote\"",
"MoreComplexQuote": "<a href=\"http://localhost:3000/offers/reply?id=${{system.contact.value}}\">Test String</a>",
"Single": "A VAR",
"Combined": "COMBINED VAR 1/2:COMBINED VAR 2/2"
}
23 changes: 23 additions & 0 deletions test/test-default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
var testName = 'default';
var tap = require('tap');
var config = require('../');
var expected = require('./fixtures/expected/' + testName + '.json');
var configObj;

// augment `process.env` for stable testing`
process.env['NODE_ENV'] = 'staging';
process.env['EMPTY_VAR'] = '';
process.env['TESTLINEONE'] = 'ABC';
process.env['TESTLINETWO'] = 'XYZ';
process.env['JUST_VAR'] = 'A VAR';
process.env['VARPART1'] = 'COMBINED VAR 1/2';
process.env['VARPART2'] = 'COMBINED VAR 2/2';

// update default directory for the test
config.DEFAULTS.directory = './test/fixtures/config/default';
configObj = config();
tap.same(configObj, expected, 'expects to get proper config object from the default directory');

// same works for `config.load` function
configObj = config.load();
tap.same(configObj, expected, 'expects to get proper config object from the default directory');
Loading

0 comments on commit 47a81ce

Please sign in to comment.