Make the head element optional to accomodate technically invalid OPMLs.

This commit is contained in:
Bauke 2020-05-26 10:28:19 +02:00
parent 53e76e8aa6
commit 769e566414
Signed by: Bauke
GPG Key ID: C1C0F29952BCF558
4 changed files with 29 additions and 15 deletions

View File

@ -7,7 +7,8 @@ fn main() -> Result<(), Box<dyn Error>> {
let xml = fs::read_to_string("examples/opml_samples/rust_feeds.opml")?; let xml = fs::read_to_string("examples/opml_samples/rust_feeds.opml")?;
let subscriptions = OPML::new(&xml)?; let subscriptions = OPML::new(&xml)?;
let title = subscriptions.head.title.unwrap(); let head = subscriptions.head.unwrap();
let title = head.title.unwrap();
println!(" {}", title); println!(" {}", title);
println!(" {}", "".repeat(title.len())); println!(" {}", "".repeat(title.len()));

View File

@ -7,7 +7,7 @@
//! ```rust //! ```rust
//! use opml::OPML; //! use opml::OPML;
//! //!
//! let xml = r#"<opml version="2.0"><head/><body><outline text="Outline"/></body></opml>"#; //! let xml = r#"<opml version="2.0"><body><outline text="Outline"/></body></opml>"#;
//! let parsed = OPML::new(xml).unwrap(); //! let parsed = OPML::new(xml).unwrap();
//! //!
//! println!("{:#?}", parsed); //! println!("{:#?}", parsed);
@ -16,7 +16,7 @@
//! ### Constructing //! ### Constructing
//! //!
//! ```rust //! ```rust
//! use opml::OPML; //! use opml::{Head, OPML};
//! //!
//! let mut opml = OPML::default(); //! let mut opml = OPML::default();
//! opml //! opml
@ -24,9 +24,11 @@
//! .add_feed( //! .add_feed(
//! "Inside Rust", //! "Inside Rust",
//! "https://blog.rust-lang.org/inside-rust/feed.xml", //! "https://blog.rust-lang.org/inside-rust/feed.xml",
//! ); //! )
//! //! .set_head(Head {
//! opml.head.title = Some("Rust Feeds".to_string()); //! title: Some("Rust Feeds".to_string()),
//! ..Head::default()
//! });
//! //!
//! let xml = opml.to_xml().unwrap(); //! let xml = opml.to_xml().unwrap();
//! println!("{}", xml); //! println!("{}", xml);
@ -69,7 +71,7 @@ pub struct OPML {
/// The `<head>` child element. Contains the metadata of the OPML document. /// The `<head>` child element. Contains the metadata of the OPML document.
#[xml(child = "head")] #[xml(child = "head")]
pub head: Head, pub head: Option<Head>,
/// The `<body>` child element. Contains all the `<outlines>`. /// The `<body>` child element. Contains all the `<outlines>`.
#[xml(child = "body")] #[xml(child = "body")]
@ -117,6 +119,12 @@ impl OPML {
self self
} }
pub fn set_head(&mut self, head: Head) -> &mut Self {
self.head = Some(head);
self
}
pub fn to_xml(&self) -> Result<String, String> { pub fn to_xml(&self) -> Result<String, String> {
let result: Result<String, XmlError> = self.to_string(); let result: Result<String, XmlError> = self.to_string();
@ -131,7 +139,7 @@ impl Default for OPML {
fn default() -> Self { fn default() -> Self {
OPML { OPML {
version: "2.0".to_string(), version: "2.0".to_string(),
head: Head::default(), head: Some(Head::default()),
body: Body::default(), body: Body::default(),
} }
} }

View File

@ -11,9 +11,11 @@ fn test_opml_construction_1() -> Result<(), Box<dyn Error>> {
.add_feed( .add_feed(
"Inside Rust", "Inside Rust",
"https://blog.rust-lang.org/inside-rust/feed.xml", "https://blog.rust-lang.org/inside-rust/feed.xml",
); )
.set_head(Head {
opml.head.title = Some("Rust Feeds".to_string()); title: Some("Rust Feeds".to_string()),
..Head::default()
});
let actual = opml.to_xml().unwrap(); let actual = opml.to_xml().unwrap();
let expected = read("tests/samples/construction_1.opml")?; let expected = read("tests/samples/construction_1.opml")?;
@ -26,6 +28,10 @@ fn test_opml_construction_1() -> Result<(), Box<dyn Error>> {
#[test] #[test]
fn test_opml_construction_2() -> Result<(), Box<dyn Error>> { fn test_opml_construction_2() -> Result<(), Box<dyn Error>> {
let mut opml = OPML::default(); let mut opml = OPML::default();
opml.set_head(Head {
title: Some("Rust Feeds".to_string()),
..Head::default()
});
let mut rust_group = Outline::default(); let mut rust_group = Outline::default();
rust_group.text = "Rust Feeds".to_string(); rust_group.text = "Rust Feeds".to_string();
@ -44,7 +50,6 @@ fn test_opml_construction_2() -> Result<(), Box<dyn Error>> {
opml.body.outlines.push(rust_group); opml.body.outlines.push(rust_group);
opml.body.outlines.push(mozilla_group); opml.body.outlines.push(mozilla_group);
opml.head.title = Some("Rust Feeds".to_string());
let actual = opml.to_xml().unwrap(); let actual = opml.to_xml().unwrap();
let expected = read("tests/samples/construction_2.opml")?; let expected = read("tests/samples/construction_2.opml")?;

View File

@ -8,7 +8,7 @@ fn test_minimum_valid_opml() {
OPML::new(&read("tests/samples/minimum_valid_opml.opml").unwrap()).unwrap(), OPML::new(&read("tests/samples/minimum_valid_opml.opml").unwrap()).unwrap(),
OPML { OPML {
version: "2.0".to_string(), version: "2.0".to_string(),
head: Head::default(), head: Some(Head::default()),
body: Body { body: Body {
outlines: vec![Outline { outlines: vec![Outline {
text: "Outline Text".to_string(), text: "Outline Text".to_string(),
@ -26,7 +26,7 @@ fn test_valid_opml_with_everything() {
.unwrap(), .unwrap(),
OPML { OPML {
version: "2.0".to_string(), version: "2.0".to_string(),
head: Head { head: Some(Head {
title: Some("Title".to_string()), title: Some("Title".to_string()),
date_created: Some("Date Created".to_string()), date_created: Some("Date Created".to_string()),
date_modified: Some("Date Modified".to_string()), date_modified: Some("Date Modified".to_string()),
@ -40,7 +40,7 @@ fn test_valid_opml_with_everything() {
window_left: Some(2), window_left: Some(2),
window_bottom: Some(3), window_bottom: Some(3),
window_right: Some(4), window_right: Some(4),
}, }),
body: Body { body: Body {
outlines: vec![Outline { outlines: vec![Outline {
text: "Outline Text".to_string(), text: "Outline Text".to_string(),