Repository: mehcode/config-rs (rust)

Issue:
Picking up values from environment not working
Hi,

I am trying to use the environment only, to grep the configuration. Because that did not work, I also tried with an additional Settings.toml. Then the value from file is picked up, but not the environment.

Code:


    let mut settings = config::Config::default();
    settings
       .merge(config::File::with_name("Settings"))
        .unwrap()
        .merge(config::Environment::with_prefix("APP"))
        .unwrap();

    let x = settings.get::<String>("foo").expect("ok");
    println!("CFG: {:?}", x);


Settings.toml:
`foo = "20"`

Calling the program with `APP_FOO=10 target/debug/prog`. Only the value from toml is picked up.

I must be doing something very stupid, but I cannot get this to work. Can you spot my error?

**UPDATE** Also tried the simple example, with APP_DEBUG=FOO without success. The toml file wins.

The crazy thing is that to me the code in Environment looks fine, I am just not getting what is going on.

**UPDATE**
See new comment https://github.com/mehcode/config-rs/issues/47#issuecomment-339638438 below.

Pull request description:
Adjust environment variable handling
One more try to resolve #47

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6fc38aa..308f401 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,13 +4,6 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
-## 0.8.0 - 2018-01-26
- - Update lazy_static and yaml_rust
-
-## 0.7.1 - 2018-01-26
- - Be compatible with nom's verbose_errors feature (#50)[https://github.com/mehcode/config-rs/pull/50]
- - Add `derive(PartialEq)` for Value (#54)[https://github.com/mehcode/config-rs/pull/54]
-
 ## 0.7.0 - 2017-08-05
  - Fix conflict with `serde_yaml`. [#39]
 
diff --git a/Cargo.toml b/Cargo.toml
index 8ee4d4c..c3789ab 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "config"
-version = "0.8.0"
+version = "0.7.0"
 description = "Layered configuration system for Rust applications."
 homepage = "https://github.com/mehcode/config-rs"
 repository = "https://github.com/mehcode/config-rs"
@@ -20,13 +20,13 @@ yaml = ["yaml-rust"]
 hjson = ["serde-hjson"]
 
 [dependencies]
-lazy_static = "1.0"
+lazy_static = "0.2"
 serde = "^1.0.8"
-nom = "^3.2.1"
+nom = "^3.0.0"
 
 toml = { version = "^0.4.1", optional = true }
 serde_json = { version = "^1.0.2", optional = true }
-yaml-rust = { version = "^0.4", optional = true }
+yaml-rust = { version = "^0.3.5", optional = true }
 serde-hjson = { version = "^0.8.1", optional = true }
 
 [dev-dependencies]
diff --git a/README.md b/README.md
index ea2d4b0..9beaac6 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@
 
 ```toml
 [dependencies]
-config = "0.8"
+config = "0.6"
 ```
 
  - `json` - Adds support for reading JSON files
diff --git a/src/env.rs b/src/env.rs
index aec4de4..b26dc56 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -9,19 +9,16 @@ pub struct Environment {
     /// Optional prefix that will limit access to the environment to only keys that
     /// begin with the defined prefix.
     ///
-    /// A prefix, followed by `_` (the seperator),
-    /// is tested to be present on each key before its considered
+    /// A prefix with a separator of `_` is tested to be present on each key before its considered
     /// to be part of the source environment.
     ///
     /// For example, the key `CONFIG_DEBUG` would become `DEBUG` with a prefix of `config`.
     prefix: Option<String>,
 
-    /// The character sequence that separates each key segment in an environment key pattern.
+    /// Optional character sequence that separates each key segment in an environment key pattern.
     /// Consider a nested configuration such as `redis.password`, a separator of `_` would allow
     /// an environment key of `REDIS_PASSWORD` to match.
-    ///
-    /// The default separator is `_`.
-    separator: String,
+    separator: Option<String>,
 }
 
 impl Environment {
@@ -36,13 +33,13 @@ impl Environment {
         }
     }
 
-    pub fn prefix(&mut self, s: String) -> &mut Self {
-        self.prefix = s.into();
+    pub fn prefix(&mut self, s: &str) -> &mut Self {
+        self.prefix = Some(s.into());
         self
     }
 
-    pub fn separator(&mut self, s: String) -> &mut Self {
-        self.separator = s;
+    pub fn separator(&mut self, s: &str) -> &mut Self {
+        self.separator = Some(s.into());
         self
     }
 }
@@ -51,7 +48,7 @@ impl Default for Environment {
     fn default() -> Environment {
         Environment {
             prefix: None,
-            separator: "_".into(),
+            separator: None,
         }
     }
 }
@@ -65,9 +62,14 @@ impl Source for Environment {
         let mut m = HashMap::new();
         let uri: String = "the environment".into();
 
-        // Define a prefiux pattern to test and exclude from keys
+        let separator = match self.separator {
+            Some(ref separator) => separator,
+            _ => ""
+        };
+
+        // Define a prefix pattern to test and exclude from keys
         let prefix_pattern = match self.prefix {
-            Some(ref prefix) => Some(prefix.clone() + &self.separator),
+            Some(ref prefix) => Some(prefix.clone() + "_"),
             _ => None,
         };
 
@@ -76,7 +78,7 @@ impl Source for Environment {
 
             // Check for prefix
             if let Some(ref prefix_pattern) = prefix_pattern {
-                if key.to_lowercase().starts_with(prefix_pattern) {
+                if key.to_lowercase().starts_with(&prefix_pattern.to_lowercase()) {
                     // Remove this prefix from the key
                     key = key[prefix_pattern.len()..].to_string();
                 } else {
@@ -85,8 +87,10 @@ impl Source for Environment {
                 }
             }
 
-            // Replace `separator` with `.`
-            key = key.replace(&self.separator, ".");
+            // If separator is given replace with `.`
+            if !separator.is_empty() {
+                key = key.replace(separator, ".");
+            }
 
             m.insert(
                 key.to_lowercase(),
diff --git a/src/path/parser.rs b/src/path/parser.rs
index 7629193..d4b13dd 100644
--- a/src/path/parser.rs
+++ b/src/path/parser.rs
@@ -65,7 +65,7 @@ pub fn from_str(input: &str) -> Result<Expression, ErrorKind> {
 
                     // Forward Incomplete and Error
                     result => {
-                        return result.to_result().map_err(|e| e.into_error_kind());
+                        return result.to_result();
                     }
                 }
             }
@@ -74,7 +74,7 @@ pub fn from_str(input: &str) -> Result<Expression, ErrorKind> {
         }
 
         // Forward Incomplete and Error
-        result => result.to_result().map_err(|e| e.into_error_kind()),
+        result => result.to_result(),
     }
 }
 
diff --git a/src/value.rs b/src/value.rs
index a8ae94a..3b700cf 100644
--- a/src/value.rs
+++ b/src/value.rs
@@ -5,7 +5,7 @@ use error::*;
 use serde::de::{Deserialize, Deserializer, Visitor};
 
 /// Underlying kind of the configuration value.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone)]
 pub enum ValueKind {
     Nil,
     Boolean(bool),
@@ -114,7 +114,7 @@ impl Display for ValueKind {
 }
 
 /// A configuration value.
-#[derive(Default, Debug, Clone, PartialEq)]
+#[derive(Default, Debug, Clone)]
 pub struct Value {
     /// A description of the original location of the value.
     ///


Test patch:
diff --git a/tests/env.rs b/tests/env.rs
new file mode 100644
index 0000000..b204118
--- /dev/null
+++ b/tests/env.rs
@@ -0,0 +1,63 @@
+extern crate config;
+
+use config::*;
+use std::env;
+
+#[test]
+fn test_default() {
+    env::set_var("A_B_C", "abc");
+
+    let environment = Environment::new();
+
+    assert!(environment.collect().unwrap().contains_key("a_b_c"));
+
+    env::remove_var("A_B_C");
+}
+
+#[test]
+fn test_prefix_is_removed_from_key() {
+    env::set_var("B_A_C", "abc");
+
+    let environment = Environment::with_prefix("B");
+
+    assert!(environment.collect().unwrap().contains_key("a_c"));
+
+    env::remove_var("B_A_C");
+}
+
+#[test]
+fn test_prefix_with_variant_forms_of_spelling() {
+    env::set_var("a_A_C", "abc");
+
+    let environment = Environment::with_prefix("a");
+
+    assert!(environment.collect().unwrap().contains_key("a_c"));
+
+    env::remove_var("a_A_C");
+    env::set_var("aB_A_C", "abc");
+
+    let environment = Environment::with_prefix("aB");
+
+    assert!(environment.collect().unwrap().contains_key("a_c"));
+
+    env::remove_var("aB_A_C");
+    env::set_var("Ab_A_C", "abc");
+
+    let environment = Environment::with_prefix("ab");
+
+    assert!(environment.collect().unwrap().contains_key("a_c"));
+
+    env::remove_var("Ab_A_C");
+}
+
+#[test]
+fn test_separator_behavior() {
+    env::set_var("C_B_A", "abc");
+
+    let mut environment = Environment::with_prefix("C");
+    environment.separator("_");
+
+    assert!(environment.collect().unwrap().contains_key("b.a"));
+
+    env::remove_var("C_B_A");
+}