aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2016-03-27 22:54:34 -0700
committerAlex Crichton <alex@alexcrichton.com>2016-03-27 22:54:34 -0700
commitc53fceb42c6600983021e5fa7dca9976c36590f4 (patch)
tree8cba7aa5e5caff31472ad45e94a31bf61add7ad9
parentb0a134a1d9e33719298a747bcc6a43969e313ff3 (diff)
parent644dc88c0410dffacb7def8cd7195edb9b382afc (diff)
downloadmilf-rs-c53fceb42c6600983021e5fa7dca9976c36590f4.tar.gz
milf-rs-c53fceb42c6600983021e5fa7dca9976c36590f4.zip
Merge pull request #89 from BourgondAries/master
Allow advanced lookups in lookup and lookup_mut
-rw-r--r--src/lib.rs67
-rw-r--r--src/parser.rs75
2 files changed, 132 insertions, 10 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 8afaa3d..ec8106a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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) {
@@ -205,8 +209,8 @@ impl Value {
};
Some(cur_value)
- }
+ }
/// Lookups for mutable value at specified path.
///
/// Uses '.' as a path separator.
@@ -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) => {
@@ -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());
+ }
+
}
diff --git a/src/parser.rs b/src/parser.rs
index 185f325..9eb506a 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -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();
@@ -970,6 +995,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("\
[project]\r\n\
@@ -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]
@@ -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]