summaryrefslogtreecommitdiffstats
path: root/src/config.rs
diff options
context:
space:
mode:
authorRyan Leckey <leckey.ryan@gmail.com>2017-02-07 17:09:41 -0800
committerRyan Leckey <leckey.ryan@gmail.com>2017-02-07 17:09:41 -0800
commit9239ee5c27eb6d87098b10cb8e1f4ea9465d1add (patch)
treef4a3fb1098a94ca1fc148360ab90434c06400b4f /src/config.rs
parent115fe07e2c11aa72e91a5ce9b028ed1c1ff7d806 (diff)
Add path resolution using a strict subset of JSONPath
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs73
1 files changed, 71 insertions, 2 deletions
diff --git a/src/config.rs b/src/config.rs
index 126d31b..1de8f44 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,5 +1,6 @@
use value::Value;
use source::{Source, SourceBuilder};
+use path;
use std::error::Error;
use std::fmt;
@@ -213,8 +214,55 @@ impl Config {
Ok(())
}
- pub fn get<'a>(&'a self, key: &str) -> Option<&'a Value> {
- self.cache.get(key)
+ // Child ( Child ( Identifier( "x" ), "y" ), "z" )
+ fn path_get<'a, 'b>(&'a self, expr: path::Expression) -> Option<&'a Value> {
+ match expr {
+ path::Expression::Identifier(text) => {
+ self.cache.get(&text)
+ }
+
+ path::Expression::Child(expr, member) => {
+ match self.path_get(*expr) {
+ Some(&Value::Table(ref table)) => {
+ table.get(&member)
+ }
+
+ _ => None
+ }
+ }
+
+ path::Expression::Subscript(expr, mut index) => {
+ match self.path_get(*expr) {
+ Some(&Value::Array(ref array)) => {
+ let len = array.len() as i32;
+
+ if index < 0 {
+ index = len + index;
+ }
+
+ if index < 0 || index >= len {
+ None
+ } else {
+ Some(&array[index as usize])
+ }
+ }
+
+ _ => None
+ }
+ }
+ }
+ }
+
+ pub fn get<'a>(&'a self, key_path: &str) -> Option<&'a Value> {
+ let key_expr: path::Expression = match key_path.parse() {
+ Ok(expr) => expr,
+ Err(_) => {
+ // TODO: Log warning here
+ return None;
+ }
+ };
+
+ self.path_get(key_expr)
}
pub fn get_str<'a>(&'a self, key: &str) -> Option<Cow<'a, str>> {
@@ -428,4 +476,25 @@ mod test {
assert_eq!(m.get("db").unwrap().as_str().unwrap(), "1");
}
}
+
+ // Path expression
+ #[test]
+ fn test_path() {
+ use file::{File, FileFormat};
+
+ let mut c = Config::new();
+
+ c.merge(File::from_str(r#"
+ [redis]
+ address = "localhost:6379"
+
+ [[databases]]
+ name = "test_db"
+ options = { trace = true }
+ "#, FileFormat::Toml)).unwrap();
+
+ assert_eq!(c.get_str("redis.address").unwrap(), "localhost:6379");
+ assert_eq!(c.get_str("databases[0].name").unwrap(), "test_db");
+ assert_eq!(c.get_str("databases[0].options.trace").unwrap(), "true");
+ }
}