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

Allow advanced lookups in lookup and lookup_mut #89

Merged
merged 7 commits into from
Mar 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 64 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a method to parse integers somewhere else, perhaps that could be leveraged here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think parsing integers accepts the +xx and -xx notation, which I don't think should be applicable. I'll need to look through the parser methods...
Edit: number_or_datetime can be used whilst evaluating the Value type to be an integer. I'll try leveraging it.
Edit2: fn integer may be the solution with allow_sign = false 👍

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