Merge pull request #72 from hoodie/bugfix/quoted_booleans
fixing emitter issues
This commit is contained in:
commit
fd047060de
3 changed files with 188 additions and 64 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "yaml-rust"
|
name = "yaml-rust"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
authors = ["Yuheng Chen <yuhengchen@sensetime.com>"]
|
authors = ["Yuheng Chen <yuhengchen@sensetime.com>"]
|
||||||
homepage = "http://chyh1990.github.io/yaml-rust/"
|
homepage = "http://chyh1990.github.io/yaml-rust/"
|
||||||
documentation = "http://chyh1990.github.io/yaml-rust/doc/yaml_rust/"
|
documentation = "http://chyh1990.github.io/yaml-rust/doc/yaml_rust/"
|
||||||
|
|
|
@ -134,55 +134,20 @@ impl<'a> YamlEmitter<'a> {
|
||||||
|
|
||||||
fn emit_node_compact(&mut self, node: &Yaml) -> EmitResult {
|
fn emit_node_compact(&mut self, node: &Yaml) -> EmitResult {
|
||||||
match *node {
|
match *node {
|
||||||
Yaml::Array(ref v) => {
|
Yaml::Array(ref v) => self.emit_array_compact(v),
|
||||||
try!(write!(self.writer, "["));
|
Yaml::Hash(ref h) => self.emit_hash_compact(h),
|
||||||
if self.level >= 0 {
|
|
||||||
try!(write!(self.writer, "+ "));
|
|
||||||
}
|
|
||||||
self.level += 1;
|
|
||||||
for (cnt, x) in v.iter().enumerate() {
|
|
||||||
try!(self.write_indent());
|
|
||||||
if cnt > 0 { try!(write!(self.writer, ", ")); }
|
|
||||||
try!(self.emit_node(x));
|
|
||||||
}
|
|
||||||
self.level -= 1;
|
|
||||||
try!(write!(self.writer, "]"));
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
Yaml::Hash(ref h) => {
|
|
||||||
try!(self.writer.write_str("{"));
|
|
||||||
self.level += 1;
|
|
||||||
for (cnt, (k, v)) in h.iter().enumerate() {
|
|
||||||
if cnt > 0 {
|
|
||||||
try!(write!(self.writer, ", "));
|
|
||||||
}
|
|
||||||
match *k {
|
|
||||||
// complex key is not supported
|
|
||||||
Yaml::Array(_) | Yaml::Hash(_) => {
|
|
||||||
return Err(EmitError::BadHashmapKey);
|
|
||||||
},
|
|
||||||
_ => { try!(self.emit_node(k)); }
|
|
||||||
}
|
|
||||||
try!(write!(self.writer, ": "));
|
|
||||||
try!(self.emit_node(v));
|
|
||||||
}
|
|
||||||
try!(self.writer.write_str("}"));
|
|
||||||
self.level -= 1;
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
_ => self.emit_node(node),
|
_ => self.emit_node(node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_node(&mut self, node: &Yaml) -> EmitResult {
|
fn emit_node(&mut self, node: &Yaml) -> EmitResult {
|
||||||
match *node {
|
match *node {
|
||||||
Yaml::Array(ref v) => self.emit_array(v),
|
Yaml::Array(ref v) => self.emit_array(v, !node.is_array()),
|
||||||
Yaml::Hash(ref h) => self.emit_hash(h),
|
Yaml::Hash(ref h) => self.emit_hash(h),
|
||||||
Yaml::String(ref v) => {
|
Yaml::String(ref v) => {
|
||||||
if need_quotes(v) {
|
if need_quotes(v) {
|
||||||
try!(escape_str(self.writer, v));
|
try!(escape_str(self.writer, v));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
try!(write!(self.writer, "{}", v));
|
try!(write!(self.writer, "{}", v));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -212,24 +177,43 @@ impl<'a> YamlEmitter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_array(&mut self, v: &[Yaml]) -> EmitResult {
|
fn emit_array(&mut self, v: &[Yaml], indent_first: bool) -> EmitResult {
|
||||||
if v.is_empty() {
|
if v.is_empty() {
|
||||||
try!(write!(self.writer, "[]"));
|
try!(write!(self.writer, "[]"));
|
||||||
} else {
|
} else {
|
||||||
for (cnt, x) in v.iter().enumerate() {
|
for (cnt, x) in v.iter().enumerate() {
|
||||||
|
self.level += 1;
|
||||||
if cnt > 0 {
|
if cnt > 0 {
|
||||||
try!(write!(self.writer, "\n"));
|
try!(write!(self.writer, "\n"));
|
||||||
}
|
}
|
||||||
try!(self.write_indent());
|
if cnt > 0 || indent_first {
|
||||||
self.level += 1;
|
try!(self.write_indent());
|
||||||
|
}
|
||||||
try!(write!(self.writer, "- "));
|
try!(write!(self.writer, "- "));
|
||||||
try!(self.emit_node(x));
|
if self.level > 2 {
|
||||||
|
try!(self.emit_node_compact(x));
|
||||||
|
} else {
|
||||||
|
try!(self.emit_node(x));
|
||||||
|
}
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_array_compact(&mut self, v: &[Yaml]) -> EmitResult {
|
||||||
|
try!(write!(self.writer, "["));
|
||||||
|
if self.level >= 0 {
|
||||||
|
try!(write!(self.writer, ""));
|
||||||
|
}
|
||||||
|
for (cnt, x) in v.iter().enumerate() {
|
||||||
|
if cnt > 0 { try!(write!(self.writer, ", ")); }
|
||||||
|
try!(self.emit_node(x));
|
||||||
|
}
|
||||||
|
try!(write!(self.writer, "]"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_hash(&mut self, h: &Hash) -> EmitResult {
|
fn emit_hash(&mut self, h: &Hash) -> EmitResult {
|
||||||
if h.is_empty() {
|
if h.is_empty() {
|
||||||
try!(self.writer.write_str("{}"));
|
try!(self.writer.write_str("{}"));
|
||||||
|
@ -255,7 +239,7 @@ impl<'a> YamlEmitter<'a> {
|
||||||
} else {
|
} else {
|
||||||
try!(write!(self.writer, ":\n"));
|
try!(write!(self.writer, ":\n"));
|
||||||
}
|
}
|
||||||
try!(self.emit_array(v));
|
try!(self.emit_array(v, true));
|
||||||
}
|
}
|
||||||
Yaml::Hash(ref h) => {
|
Yaml::Hash(ref h) => {
|
||||||
if h.is_empty() {
|
if h.is_empty() {
|
||||||
|
@ -278,6 +262,29 @@ impl<'a> YamlEmitter<'a> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_hash_compact(&mut self, h: &Hash) -> EmitResult {
|
||||||
|
try!(self.writer.write_str("{"));
|
||||||
|
self.level += 1;
|
||||||
|
for (cnt, (k, v)) in h.iter().enumerate() {
|
||||||
|
if cnt > 0 {
|
||||||
|
try!(write!(self.writer, ", "));
|
||||||
|
}
|
||||||
|
match *k {
|
||||||
|
// complex key is not supported
|
||||||
|
Yaml::Array(_) | Yaml::Hash(_) => {
|
||||||
|
return Err(EmitError::BadHashmapKey);
|
||||||
|
},
|
||||||
|
_ => { try!(self.emit_node(k)); }
|
||||||
|
}
|
||||||
|
try!(write!(self.writer, ": "));
|
||||||
|
try!(self.emit_node(v));
|
||||||
|
}
|
||||||
|
try!(self.writer.write_str("}"));
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the string requires quoting.
|
/// Check if the string requires quoting.
|
||||||
|
@ -306,17 +313,20 @@ fn need_quotes(string: &str) -> bool {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|| string == "true"
|
|| [// http://yaml.org/type/bool.html
|
||||||
|| string == "false"
|
"y","Y","yes","Yes","YES","n","N","no","No","NO",
|
||||||
|| string == "null"
|
"True", "TRUE", "true", "False", "FALSE", "false",
|
||||||
|| string == "~"
|
"on","On","ON","off","Off","OFF",
|
||||||
|
// http://yaml.org/type/null.html
|
||||||
|
"null","Null","NULL", "~"
|
||||||
|
].contains(&string)
|
||||||
|| string.starts_with('.')
|
|| string.starts_with('.')
|
||||||
|| string.parse::<i64>().is_ok()
|
|| string.parse::<i64>().is_ok()
|
||||||
|| string.parse::<f64>().is_ok()
|
|| string.parse::<f64>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use YamlLoader;
|
use YamlLoader;
|
||||||
|
|
||||||
|
@ -331,15 +341,8 @@ a1:
|
||||||
a2: 4 # i'm comment
|
a2: 4 # i'm comment
|
||||||
a3: [1, 2, 3]
|
a3: [1, 2, 3]
|
||||||
a4:
|
a4:
|
||||||
- - a1
|
- [a1, a2]
|
||||||
- a2
|
|
||||||
- 2
|
- 2
|
||||||
- []
|
|
||||||
- {}
|
|
||||||
a5: 'single_quoted'
|
|
||||||
a6: \"double_quoted\"
|
|
||||||
a7: 你好
|
|
||||||
'key 1': \"ddd\\\tbbb\"
|
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,7 +353,12 @@ a7: 你好
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
emitter.dump(doc).unwrap();
|
emitter.dump(doc).unwrap();
|
||||||
}
|
}
|
||||||
let docs_new = YamlLoader::load_from_str(&s).unwrap();
|
println!("original:\n{}", s);
|
||||||
|
println!("emitted:\n{}", writer);
|
||||||
|
let docs_new = match YamlLoader::load_from_str(&writer) {
|
||||||
|
Ok(y) => y,
|
||||||
|
Err(e) => panic!(format!("{}", e))
|
||||||
|
};
|
||||||
let doc_new = &docs_new[0];
|
let doc_new = &docs_new[0];
|
||||||
|
|
||||||
assert_eq!(doc, doc_new);
|
assert_eq!(doc, doc_new);
|
||||||
|
@ -384,7 +392,10 @@ products:
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
emitter.dump(doc).unwrap();
|
emitter.dump(doc).unwrap();
|
||||||
}
|
}
|
||||||
let docs_new = YamlLoader::load_from_str(&s).unwrap();
|
let docs_new = match YamlLoader::load_from_str(&writer) {
|
||||||
|
Ok(y) => y,
|
||||||
|
Err(e) => panic!(format!("{}", e))
|
||||||
|
};
|
||||||
let doc_new = &docs_new[0];
|
let doc_new = &docs_new[0];
|
||||||
assert_eq!(doc, doc_new);
|
assert_eq!(doc, doc_new);
|
||||||
}
|
}
|
||||||
|
@ -421,7 +432,8 @@ products:
|
||||||
"true": bool key
|
"true": bool key
|
||||||
"{}": empty hash key
|
"{}": empty hash key
|
||||||
x: test
|
x: test
|
||||||
y: string with spaces"#;
|
"y": "can't avoid quoting here"
|
||||||
|
z: string with spaces"#;
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(&s).unwrap();
|
let docs = YamlLoader::load_from_str(&s).unwrap();
|
||||||
let doc = &docs[0];
|
let doc = &docs[0];
|
||||||
|
@ -434,6 +446,42 @@ y: string with spaces"#;
|
||||||
assert_eq!(s, writer, "actual:\n\n{}\n", writer);
|
assert_eq!(s, writer, "actual:\n\n{}\n", writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn emit_quoted_bools() {
|
||||||
|
let input = r#"---
|
||||||
|
string0: yes
|
||||||
|
string1: no
|
||||||
|
string2: "true"
|
||||||
|
string3: "false"
|
||||||
|
string4: "~"
|
||||||
|
null0: ~
|
||||||
|
[true, false]: real_bools
|
||||||
|
[True, TRUE, False, FALSE, y,Y,yes,Yes,YES,n,N,no,No,NO,on,On,ON,off,Off,OFF]: false_bools
|
||||||
|
bool0: true
|
||||||
|
bool1: false"#;
|
||||||
|
let expected = r#"---
|
||||||
|
string0: "yes"
|
||||||
|
string1: "no"
|
||||||
|
string2: "true"
|
||||||
|
string3: "false"
|
||||||
|
string4: "~"
|
||||||
|
null0: ~
|
||||||
|
[true, false]: real_bools
|
||||||
|
["True", "TRUE", "False", "FALSE", "y", "Y", "yes", "Yes", "YES", "n", "N", "no", "No", "NO", "on", "On", "ON", "off", "Off", "OFF"]: false_bools
|
||||||
|
bool0: true
|
||||||
|
bool1: false"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(&input).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(expected, writer, "actual:\n\n{}\n", writer);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_and_nested() {
|
fn test_empty_and_nested() {
|
||||||
let s = r#"---
|
let s = r#"---
|
||||||
|
@ -442,9 +490,9 @@ a:
|
||||||
c: hello
|
c: hello
|
||||||
d: {}
|
d: {}
|
||||||
e:
|
e:
|
||||||
- f
|
- f
|
||||||
- g
|
- g
|
||||||
- h: []"#;
|
- h: []"#;
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(&s).unwrap();
|
let docs = YamlLoader::load_from_str(&s).unwrap();
|
||||||
let doc = &docs[0];
|
let doc = &docs[0];
|
||||||
|
@ -456,4 +504,73 @@ e:
|
||||||
|
|
||||||
assert_eq!(s, writer);
|
assert_eq!(s, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_arrays() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
- b
|
||||||
|
- - c
|
||||||
|
- d
|
||||||
|
- - e
|
||||||
|
- f"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(&s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{}", s);
|
||||||
|
println!("emitted:\n{}", writer);
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deeply_nested_arrays() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
- b
|
||||||
|
- - c
|
||||||
|
- d
|
||||||
|
- - e
|
||||||
|
- [f, e]"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(&s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{}", s);
|
||||||
|
println!("emitted:\n{}", writer);
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_hashes() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c:
|
||||||
|
d:
|
||||||
|
e: f"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(&s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{}", s);
|
||||||
|
println!("emitted:\n{}", writer);
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,13 @@ impl Yaml {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_array(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Yaml::Array(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_f64(&self) -> Option<f64> {
|
pub fn as_f64(&self) -> Option<f64> {
|
||||||
match *self {
|
match *self {
|
||||||
Yaml::Real(ref v) => parse_f64(v),
|
Yaml::Real(ref v) => parse_f64(v),
|
||||||
|
|
Loading…
Reference in a new issue