Skip to content

Loading…

Need ability to call get on multiple values until truthy one is reached #41

Closed
wants to merge 4 commits into from

3 participants

@digitalicarus

I'm not super familiar with the project so I may have gotten some things wrong. In my use case I want to deploy an app into multiple environments. Each of them surface the desired running port in a different environment variable:

Cloud Foundry: VCAP_APP_PORT
Cloud 9: PORT
Default dev port: port

New ports for new environments keep surfacing and I would like to keep this type of configuration detail out of my application logic.

My solution is that you have a new method called getFirst in the provider that takes a key to a list reference in the config. The getFirst method iterates over each item in the list and calls get on that key. The first truthy value is returned to the caller.

For example, I have the following test fixture:

{
"ports": ["VCAP_APP_PORT", "PORT", "devPort"],
"VCAP_APP_PORT": null,
"PORT": true,
"devPort": 8000,
"monPort": 8001
}

getFirst() returns the value for nconf.get("PORT") since that's the first truthy value.

This is my solution to this config problem. If you have a more novel solution that prevents this configuration detail from appearing in code logic I'd enjoy hearing it.

@indexzero
Owner

I like this, but the API semantics are a little off. .getFirst() does not imply the functionality you have implemented. Any other thoughts around the API?

@digitalicarus

I completely agree about the naming. I was struggling to find a descriptive but terse name. The first thought was getFirstTruthy or something like that.

One thought I had was the ability to actually define helpers like this in the configuration. So I could basically extend nconf with the config itself. I could ruminate more on abstract and perhaps more powerful enhancements that would take nconf beyond static configuration, but I was really trying to solve the problem that I described in the pull request. If a broader and more powerful enhancement is a conversation you would like you have, then we can certainly discuss it :)

@bmeck

indexzero what about changing this to any(keys..., cb) for its name, so it would instead of auto dereferencing the names allow for conf.any(conf.get('ports')). It is slightly less elegant, but less magical.

@indexzero indexzero referenced this pull request
Open

.any() #126

@indexzero
Owner

Agree with @bmeck here. Closing this. @digitalicarus if you'd like to write .any that would be awesome! Sorry it took so long to get back to you :cry:

@indexzero indexzero closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Showing with 37 additions and 0 deletions.
  1. +17 −0 lib/nconf/provider.js
  2. +8 −0 test/fixtures/get-first.json
  3. +12 −0 test/provider-test.js
View
17 lib/nconf/provider.js
@@ -244,6 +244,23 @@ Provider.prototype.get = function (key, callback) {
});
};
+
+//
+// ### function getFirst (listRefKey, callback)
+// #### @listRefKey {string} a key which has a list value of gets to try
+// Iterates over a list and calls get. Returns first truthy result, otherwise null.
+//
+Provider.prototype.getFirst = function(listRef) {
+ var list = this.get(listRef);
+ for(var i in list) {
+ var ret = null;
+ if(ret = this.get(list[i])) {
+ return ret;
+ }
+ }
+ return null;
+};
+
//
// ### function set (key, value, callback)
// #### @key {string} Key to set in this instance
View
8 test/fixtures/get-first.json
@@ -0,0 +1,8 @@
+{
+ "ports": ["VCAP_APP_PORT", "PORT", "devPort"],
+ "VCAP_APP_PORT": null,
+ "PORT": true,
+ "devPort": 8000,
+ "monPort": 8001
+}
+
View
12 test/provider-test.js
@@ -16,6 +16,7 @@ var assert = require('assert'),
var fixturesDir = path.join(__dirname, 'fixtures'),
mergeFixtures = path.join(fixturesDir, 'merge'),
files = [path.join(mergeFixtures, 'file1.json'), path.join(mergeFixtures, 'file2.json')],
+ getFirstFixture = path.join(fixturesDir, 'get-first.json'),
override = JSON.parse(fs.readFileSync(files[0]), 'utf8');
vows.describe('nconf/provider').addBatch({
@@ -80,6 +81,17 @@ vows.describe('nconf/provider').addBatch({
}).addBatch({
"When using nconf": {
"an instance of 'nconf.Provider'": {
+ "the getFirst() method": {
+ topic: new nconf.Provider().use('file', { file: getFirstFixture}),
+ "should use the first truthy get in the keyList": function(provider) {
+ assert.equal(provider.getFirst("ports"), true);
+ }
+ }
+ }
+ }
+}).addBatch({
+ "When using nconf": {
+ "an instance of 'nconf.Provider'": {
"the load() method": {
"when sources are passed in": {
topic: new nconf.Provider({
Something went wrong with that request. Please try again.