diff --git a/README.md b/README.md index 94d33bb..d06f4f1 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ use serde::Deserialize; fn main() { let mut matter: Matter = Matter::new(); - matter.delimiter = "~~~".to_owned(); + matter.delimiter = ["~~~".to_owned(), "~~~".to_owned()]; matter.excerpt_delimiter = Some("".to_owned()); #[derive(Deserialize, Debug)] diff --git a/src/matter.rs b/src/matter.rs index faee4e2..d0a6e9e 100644 --- a/src/matter.rs +++ b/src/matter.rs @@ -12,7 +12,7 @@ enum Part { /// Coupled with an [`Engine`](crate::engine::Engine) of choice, `Matter` stores delimiter(s) and /// handles parsing. pub struct Matter { - pub delimiter: String, + pub delimiter: [String; 2], pub excerpt_delimiter: Option, engine: PhantomData, } @@ -26,7 +26,7 @@ impl Default for Matter { impl Matter { pub fn new() -> Self { Self { - delimiter: "---".to_string(), + delimiter: ["---".to_string(), "---".to_string()], excerpt_delimiter: None, engine: PhantomData, } @@ -58,8 +58,10 @@ impl Matter { matter: String::new(), }; + let [open_delimiter, close_delimiter] = &self.delimiter; + // Check if input is empty or shorter than the delimiter - if input.is_empty() || input.len() <= self.delimiter.len() { + if input.is_empty() || input.len() <= open_delimiter.len() { return parsed_entity; } @@ -67,12 +69,11 @@ impl Matter { let excerpt_delimiter = self .excerpt_delimiter .clone() - .unwrap_or_else(|| self.delimiter.clone()); - + .unwrap_or_else(|| close_delimiter.clone()); // If first line starts with a delimiter followed by newline, we are looking at front // matter. Else, we might be looking at an excerpt. let (mut looking_at, lines) = match input.split_once('\n') { - Some((first_line, rest)) if first_line.trim_end() == self.delimiter => { + Some((first_line, rest)) if first_line.trim_end() == open_delimiter => { (Part::Matter, rest.lines()) } _ => (Part::MaybeExcerpt, input.lines()), @@ -83,7 +84,7 @@ impl Matter { let line = line.trim_end(); match looking_at { Part::Matter => { - if line == self.delimiter { + if line == open_delimiter || line == close_delimiter { let matter = acc.trim().to_string(); if !matter.is_empty() { @@ -189,7 +190,7 @@ mod tests { "{}", "should get front matter as {front_matter:?}", ); - matter.delimiter = "~~~".to_string(); + matter.delimiter = ["~~~".to_string(), "~~~".to_string()]; let result = matter.parse("---\nabc: xyz\n---"); assert!(result.data.is_none(), "should get no front matter"); let result: ParsedEntityStruct = @@ -203,6 +204,37 @@ mod tests { assert!(result.data.is_none(), "should get no front matter"); } + #[test] + fn test_front_matter_with_different_delimiters() { + #[derive(serde::Deserialize, PartialEq, Debug)] + struct FrontMatter { + abc: String, + } + let front_matter = FrontMatter { + abc: "xyz".to_string(), + }; + let mut matter: Matter = Matter::new(); + let result: ParsedEntityStruct = + matter.parse_with_struct("---\nabc: xyz\n---").unwrap(); + assert!( + result.data == front_matter, + "{}", + "should get front matter as {front_matter:?}" + ); + matter.delimiter = ["".to_string()]; + let result = matter.parse("---\nabc: xyz\n---"); + assert!(result.data.is_none(), "should get no front matter"); + let result: ParsedEntityStruct = + matter.parse_with_struct("").unwrap(); + assert_eq!( + result.data, front_matter, + "{}", + "should get front matter by custom delimiter" + ); + let result = matter.parse("\nabc: xyz\n~~~"); + assert!(result.data.is_none(), "should get no front matter"); + } + #[test] pub fn test_empty_matter() { let matter: Matter = Matter::new();