Skip to content
This repository has been archived by the owner on Sep 24, 2022. It is now read-only.

Commit

Permalink
Merge pull request #89 from BourgondAries/master
Browse files Browse the repository at this point in the history
Allow advanced lookups in lookup and lookup_mut
  • Loading branch information
alexcrichton committed Mar 28, 2016
2 parents b0a134a + 644dc88 commit c53fceb
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 10 deletions.
67 changes: 64 additions & 3 deletions src/lib.rs
Expand Up @@ -181,12 +181,16 @@ impl Value {
/// assert_eq!(no_bar.is_none(), true);
/// ```
pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
let ref path = match Parser::new(path).lookup() {
Some(path) => path,
None => return None,
};
let mut cur_value = self;
if path.len() == 0 {
return Some(cur_value)
}

for key in path.split('.') {
for key in path {
match *cur_value {
Value::Table(ref hm) => {
match hm.get(key) {
Expand All @@ -205,8 +209,8 @@ impl Value {
};

Some(cur_value)
}

}
/// Lookups for mutable value at specified path.
///
/// Uses '.' as a path separator.
Expand Down Expand Up @@ -237,12 +241,17 @@ impl Value {
/// assert_eq!(result.as_str().unwrap(), "foo");
/// ```
pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
let ref path = match Parser::new(path).lookup() {
Some(path) => path,
None => return None,
};

let mut cur = self;
if path.len() == 0 {
return Some(cur)
}

for key in path.split('.') {
for key in path {
let tmp = cur;
match *tmp {
Value::Table(ref mut hm) => {
Expand Down Expand Up @@ -428,4 +437,56 @@ mod tests {
let baz = foo.lookup("foo").unwrap();
assert_eq!(baz.as_str().unwrap(), "bar");
}

#[test]
fn lookup_advanced() {
let value: Value = "[table]\n\"value\" = 0".parse().unwrap();
let looked = value.lookup("table.\"value\"").unwrap();
assert_eq!(*looked, Value::Integer(0));
}

#[test]
fn lookup_advanced_table() {
let value: Value = r#"[table."name.other"] value = "my value""#.parse().unwrap();
let looked = value.lookup(r#"table."name.other".value"#).unwrap();
assert_eq!(*looked, Value::String(String::from("my value")));
}

#[test]
fn lookup_mut_advanced() {
let mut value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
let looked = value.lookup_mut("table.\"value\".1").unwrap();
assert_eq!(*looked, Value::Integer(1));
}

#[test]
fn single_dot() {
let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
assert_eq!(None, value.lookup("."));
}

#[test]
fn array_dot() {
let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
assert_eq!(None, value.lookup("0."));
}

#[test]
fn dot_inside() {
let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
assert_eq!(None, value.lookup("table.\"value.0\""));
}

#[test]
fn table_with_quotes() {
let value: Value = "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
assert_eq!(None, value.lookup("\"table.element\".\"value\".0"));
}

#[test]
fn table_with_quotes_2() {
let value: Value = "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
assert_eq!(Value::Integer(0), *value.lookup("table.\"element\".\"value\".0").unwrap());
}

}
75 changes: 68 additions & 7 deletions src/parser.rs
Expand Up @@ -290,6 +290,31 @@ impl<'a> Parser<'a> {
}
}

// Parse an array index as a natural number
fn array_index(&mut self) -> Option<String> {
self.integer(0, false, false)
}

/// Parse a path into a vector of paths
pub fn lookup(&mut self) -> Option<Vec<String>> {
if self.input.len() == 0 {
return Some(vec![]);
}
let mut keys = Vec::new();
loop {
self.ws();
if let Some(s) = self.key_name() {
keys.push(s);
} else if let Some(s) = self.array_index() {
keys.push(s);
} else {
return None
}
self.ws();
if !self.expect('.') { return Some(keys) }
}
}

// Parse a single key name starting at `start`
fn key_name(&mut self) -> Option<String> {
let start = self.next_pos();
Expand Down Expand Up @@ -969,6 +994,42 @@ mod tests {
})
}

#[test]
fn lookup_internal() {
let mut parser = Parser::new(r#"hello."world\t".a.0.'escaped'.value"#);
let result = vec![
String::from("hello"),
String::from("world\t"),
String::from("a"),
String::from("0"),
String::from("escaped"),
String::from("value")
];

assert_eq!(parser.lookup().unwrap(), result);
}

#[test]
fn lookup_internal_void() {
let mut parser = Parser::new("");
assert_eq!(parser.lookup().unwrap(), Vec::<String>::new());
}

#[test]
fn lookup_internal_simple() {
let mut parser = Parser::new("value");
assert_eq!(parser.lookup().unwrap(), vec![String::from("value")]);
}

// This is due to key_name not parsing an empty "" correctly. Disabled for now.
#[test]
#[ignore]
fn lookup_internal_quoted_void() {
let mut parser = Parser::new("\"\"");
assert_eq!(parser.lookup().unwrap(), vec![String::from("")]);
}


#[test]
fn crlf() {
let mut p = Parser::new("\
Expand Down Expand Up @@ -1246,10 +1307,10 @@ trimmed in raw strings.
assert!(table.lookup("foo_3").is_some());
assert!(table.lookup("foo_-2--3--r23f--4-f2-4").is_some());
assert!(table.lookup("a").is_some());
assert!(table.lookup("!").is_some());
assert!(table.lookup("\"").is_some());
assert!(table.lookup("character encoding").is_some());
assert!(table.lookup("ʎǝʞ").is_some());
assert!(table.lookup("\"!\"").is_some());
assert!(table.lookup("\"\\\"\"").is_some());
assert!(table.lookup("\"character encoding\"").is_some());
assert!(table.lookup("'ʎǝʞ'").is_some());
}

#[test]
Expand Down Expand Up @@ -1293,9 +1354,9 @@ trimmed in raw strings.
");
let table = Table(p.parse().unwrap());
assert!(table.lookup("a.b").is_some());
assert!(table.lookup("f f").is_some());
assert!(table.lookup("\"").is_some());
assert!(table.lookup("\"\"").is_some());
assert!(table.lookup("\"f f\"").is_some());
assert!(table.lookup("\"\\\"\"").is_some());
assert!(table.lookup("'\"\"'").is_some());
}

#[test]
Expand Down

0 comments on commit c53fceb

Please sign in to comment.