summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2023-01-28 09:02:43 +0200
committerLars Wirzenius <liw@liw.fi>2023-01-28 09:02:43 +0200
commit387f0b7675fba94115ead348c358c7d3e7638e4c (patch)
tree82483e5dad773cbf90884716e66a47629aa487fa
parentfa5765189eef33bed301479410c4a53dc274acf0 (diff)
downloadsubplot-387f0b7675fba94115ead348c358c7d3e7638e4c.tar.gz
refactor: move YamlMetadata to src/metadata.rs
YamlMetadata was in src/ast.rs, because originally it was only used to parse metadata out of Markdown. Markdown parsing is now in its own module, leaving ast.rs to only contain YamlMetadata. In this situation, it seems tidy to have both kinds of metadata in the same module, and to drop the now-empty ast.rs module. Sponsored-by: author
-rw-r--r--src/ast.rs172
-rw-r--r--src/doc.rs8
-rw-r--r--src/error.rs2
-rw-r--r--src/lib.rs5
-rw-r--r--src/metadata.rs174
5 files changed, 177 insertions, 184 deletions
diff --git a/src/ast.rs b/src/ast.rs
deleted file mode 100644
index ed163f0..0000000
--- a/src/ast.rs
+++ /dev/null
@@ -1,172 +0,0 @@
-use lazy_static::lazy_static;
-use regex::Regex;
-use serde::Deserialize;
-use serde_yaml::Value;
-use std::collections::{BTreeMap, HashMap};
-use std::path::{Path, PathBuf};
-
-lazy_static! {
- // Pattern that recognises a YAML block at the beginning of a file.
- static ref LEADING_YAML_PATTERN: Regex = Regex::new(r"^(?:\S*\n)*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?P<text>(.*\n)*)$").unwrap();
-
-
- // Pattern that recognises a YAML block at the end of a file.
- static ref TRAILING_YAML_PATTERN: Regex = Regex::new(r"(?P<text>(.*\n)*)\n*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?:\S*\n)*$").unwrap();
-}
-
-/// Errors from Markdown parsing.
-#[derive(Debug, thiserror::Error)]
-pub enum Error {
- #[error(transparent)]
- Regex(#[from] regex::Error),
-
- #[error("Markdown doesn't contain a YAML block for document metadata")]
- NoMetadata,
-
- #[error(transparent)]
- Yaml(#[from] serde_yaml::Error),
-}
-
-/// Document metadata.
-///
-/// This is expressed in the Markdown input file as an embedded YAML
-/// block.
-///
-/// Note that this structure needs to be able to capture any metadata
-/// block we can work with, in any input file. By being strict here we
-/// make it easier to tell the user when a metadata block has, say, a
-/// misspelled field.
-#[derive(Debug, Default, Clone, Deserialize)]
-#[serde(deny_unknown_fields)]
-pub struct YamlMetadata {
- title: String,
- subtitle: Option<String>,
- authors: Option<Vec<String>>,
- date: Option<String>,
- classes: Option<Vec<String>>,
- bibliography: Option<Vec<PathBuf>>,
- markdowns: Vec<PathBuf>,
- bindings: Option<Vec<PathBuf>>,
- documentclass: Option<String>,
- #[serde(default)]
- impls: BTreeMap<String, Vec<PathBuf>>,
- pandoc: Option<HashMap<String, Value>>,
-}
-
-impl YamlMetadata {
- #[cfg(test)]
- fn new(yaml_text: &str) -> Result<Self, Error> {
- let meta: Self = serde_yaml::from_str(yaml_text)?;
- Ok(meta)
- }
-
- /// Name of file with the Markdown for the subplot document.
- pub fn markdown(&self) -> &Path {
- &self.markdowns[0]
- }
-
- /// Title.
- pub fn title(&self) -> &str {
- &self.title
- }
-
- /// Subtitle.
- pub fn subtitle(&self) -> Option<&str> {
- self.subtitle.as_deref()
- }
-
- /// Date.
- pub fn date(&self) -> Option<&str> {
- self.date.as_deref()
- }
-
- /// Authors.
- pub fn authors(&self) -> Option<&[String]> {
- self.authors.as_deref()
- }
-
- /// Names of bindings files.
- pub fn bindings_filenames(&self) -> Option<&[PathBuf]> {
- self.bindings.as_deref()
- }
-
- /// Impls section.
- pub fn impls(&self) -> &BTreeMap<String, Vec<PathBuf>> {
- &self.impls
- }
-
- /// Bibliographies.
- pub fn bibliographies(&self) -> Option<&[PathBuf]> {
- self.bibliography.as_deref()
- }
-
- /// Classes..
- pub fn classes(&self) -> Option<&[String]> {
- self.classes.as_deref()
- }
-
- /// Documentclass.
- pub fn documentclass(&self) -> Option<&str> {
- self.documentclass.as_deref()
- }
-
- /// Pandoc metadata.
- pub fn pandoc(&self) -> Option<&HashMap<String, Value>> {
- if let Some(x) = &self.pandoc {
- Some(x)
- } else {
- None
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::YamlMetadata;
- use std::path::{Path, PathBuf};
-
- #[test]
- fn full_meta() {
- let meta = YamlMetadata::new(
- "\
-title: Foo Bar
-date: today
-classes: [json, text]
-impls:
- python:
- - foo.py
- - bar.py
-bibliography:
-- foo.bib
-- bar.bib
-markdowns:
-- test.md
-bindings:
-- foo.yaml
-- bar.yaml
-",
- )
- .unwrap();
- assert_eq!(meta.title, "Foo Bar");
- assert_eq!(meta.date.unwrap(), "today");
- assert_eq!(meta.classes.unwrap(), &["json", "text"]);
- assert_eq!(
- meta.bibliography.unwrap(),
- &[path("foo.bib"), path("bar.bib")]
- );
- assert_eq!(meta.markdowns, vec![Path::new("test.md")]);
- assert_eq!(
- meta.bindings.unwrap(),
- &[path("foo.yaml"), path("bar.yaml")]
- );
- assert!(!meta.impls.is_empty());
- for (k, v) in meta.impls.iter() {
- assert_eq!(k, "python");
- assert_eq!(v, &[path("foo.py"), path("bar.py")]);
- }
- }
-
- fn path(s: &str) -> PathBuf {
- PathBuf::from(s)
- }
-}
diff --git a/src/doc.rs b/src/doc.rs
index 7a7e64c..a39ab99 100644
--- a/src/doc.rs
+++ b/src/doc.rs
@@ -1,4 +1,3 @@
-use crate::ast;
use crate::bindings::CaptureType;
use crate::generate_test_program;
use crate::get_basedir_from;
@@ -6,12 +5,11 @@ use crate::md::Markdown;
use crate::EmbeddedFile;
use crate::EmbeddedFiles;
use crate::MatchedScenario;
-use crate::Metadata;
use crate::PartialStep;
use crate::Scenario;
use crate::Style;
use crate::SubplotError;
-use crate::YamlMetadata;
+use crate::{Metadata, YamlMetadata};
use crate::{Warning, Warnings};
use std::collections::HashSet;
@@ -106,7 +104,7 @@ impl Document {
basedir: P,
subplot: PathBuf,
markdowns: Vec<PathBuf>,
- yamlmeta: &ast::YamlMetadata,
+ yamlmeta: &YamlMetadata,
mut md: Markdown,
style: Style,
template: Option<&str>,
@@ -422,7 +420,7 @@ impl Document {
fn load_metadata_from_yaml_file(filename: &Path) -> Result<YamlMetadata, SubplotError> {
let yaml = read(filename).map_err(|e| SubplotError::ReadFile(filename.into(), e))?;
trace!("Parsing YAML metadata from {}", filename.display());
- let meta: ast::YamlMetadata = serde_yaml::from_slice(&yaml)
+ let meta: YamlMetadata = serde_yaml::from_slice(&yaml)
.map_err(|e| SubplotError::MetadataFile(filename.into(), e))?;
Ok(meta)
}
diff --git a/src/error.rs b/src/error.rs
index a729bf0..0ac2abf 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -308,7 +308,7 @@ pub enum SubplotError {
/// Abstract syntax tree error.
#[error(transparent)]
- Ast(#[from] crate::ast::Error),
+ Ast(#[from] crate::metadata::Error),
/// UTF8 conversion error.
#[error("failed to parse UTF8 in file {0}")]
diff --git a/src/lib.rs b/src/lib.rs
index 747b375..1ae64d4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,7 @@ mod policy;
pub use policy::get_basedir_from;
mod metadata;
-pub use metadata::Metadata;
+pub use metadata::{Metadata, YamlMetadata};
mod doc;
pub mod md;
@@ -72,6 +72,3 @@ pub use templatespec::TemplateSpec;
mod codegen;
pub use codegen::generate_test_program;
-
-mod ast;
-pub use ast::YamlMetadata;
diff --git a/src/metadata.rs b/src/metadata.rs
index e88c732..b840633 100644
--- a/src/metadata.rs
+++ b/src/metadata.rs
@@ -1,11 +1,181 @@
-use crate::{Bindings, SubplotError, TemplateSpec, YamlMetadata};
+use crate::{Bindings, SubplotError, TemplateSpec};
+use lazy_static::lazy_static;
use log::trace;
-use std::collections::HashMap;
+use regex::Regex;
+use serde::Deserialize;
+use serde_yaml::Value;
+use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::ops::Deref;
use std::path::{Path, PathBuf};
+lazy_static! {
+ // Pattern that recognises a YAML block at the beginning of a file.
+ static ref LEADING_YAML_PATTERN: Regex = Regex::new(r"^(?:\S*\n)*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?P<text>(.*\n)*)$").unwrap();
+
+
+ // Pattern that recognises a YAML block at the end of a file.
+ static ref TRAILING_YAML_PATTERN: Regex = Regex::new(r"(?P<text>(.*\n)*)\n*(?P<yaml>-{3,}\n([^.].*\n)*\.{3,}\n)(?:\S*\n)*$").unwrap();
+}
+
+/// Errors from Markdown parsing.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+ #[error(transparent)]
+ Regex(#[from] regex::Error),
+
+ #[error("Markdown doesn't contain a YAML block for document metadata")]
+ NoMetadata,
+
+ #[error(transparent)]
+ Yaml(#[from] serde_yaml::Error),
+}
+
+/// Document metadata.
+///
+/// This is expressed in the Markdown input file as an embedded YAML
+/// block.
+///
+/// Note that this structure needs to be able to capture any metadata
+/// block we can work with, in any input file. By being strict here we
+/// make it easier to tell the user when a metadata block has, say, a
+/// misspelled field.
+#[derive(Debug, Default, Clone, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct YamlMetadata {
+ title: String,
+ subtitle: Option<String>,
+ authors: Option<Vec<String>>,
+ date: Option<String>,
+ classes: Option<Vec<String>>,
+ bibliography: Option<Vec<PathBuf>>,
+ markdowns: Vec<PathBuf>,
+ bindings: Option<Vec<PathBuf>>,
+ documentclass: Option<String>,
+ #[serde(default)]
+ impls: BTreeMap<String, Vec<PathBuf>>,
+ pandoc: Option<HashMap<String, Value>>,
+}
+
+impl YamlMetadata {
+ #[cfg(test)]
+ fn new(yaml_text: &str) -> Result<Self, Error> {
+ let meta: Self = serde_yaml::from_str(yaml_text)?;
+ Ok(meta)
+ }
+
+ /// Name of file with the Markdown for the subplot document.
+ pub fn markdown(&self) -> &Path {
+ &self.markdowns[0]
+ }
+
+ /// Title.
+ pub fn title(&self) -> &str {
+ &self.title
+ }
+
+ /// Subtitle.
+ pub fn subtitle(&self) -> Option<&str> {
+ self.subtitle.as_deref()
+ }
+
+ /// Date.
+ pub fn date(&self) -> Option<&str> {
+ self.date.as_deref()
+ }
+
+ /// Authors.
+ pub fn authors(&self) -> Option<&[String]> {
+ self.authors.as_deref()
+ }
+
+ /// Names of bindings files.
+ pub fn bindings_filenames(&self) -> Option<&[PathBuf]> {
+ self.bindings.as_deref()
+ }
+
+ /// Impls section.
+ pub fn impls(&self) -> &BTreeMap<String, Vec<PathBuf>> {
+ &self.impls
+ }
+
+ /// Bibliographies.
+ pub fn bibliographies(&self) -> Option<&[PathBuf]> {
+ self.bibliography.as_deref()
+ }
+
+ /// Classes..
+ pub fn classes(&self) -> Option<&[String]> {
+ self.classes.as_deref()
+ }
+
+ /// Documentclass.
+ pub fn documentclass(&self) -> Option<&str> {
+ self.documentclass.as_deref()
+ }
+
+ /// Pandoc metadata.
+ pub fn pandoc(&self) -> Option<&HashMap<String, Value>> {
+ if let Some(x) = &self.pandoc {
+ Some(x)
+ } else {
+ None
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::YamlMetadata;
+ use std::path::{Path, PathBuf};
+
+ #[test]
+ fn full_meta() {
+ let meta = YamlMetadata::new(
+ "\
+title: Foo Bar
+date: today
+classes: [json, text]
+impls:
+ python:
+ - foo.py
+ - bar.py
+bibliography:
+- foo.bib
+- bar.bib
+markdowns:
+- test.md
+bindings:
+- foo.yaml
+- bar.yaml
+",
+ )
+ .unwrap();
+ assert_eq!(meta.title, "Foo Bar");
+ assert_eq!(meta.date.unwrap(), "today");
+ assert_eq!(meta.classes.unwrap(), &["json", "text"]);
+ assert_eq!(
+ meta.bibliography.unwrap(),
+ &[path("foo.bib"), path("bar.bib")]
+ );
+ assert_eq!(meta.markdowns, vec![Path::new("test.md")]);
+ assert_eq!(
+ meta.bindings.unwrap(),
+ &[path("foo.yaml"), path("bar.yaml")]
+ );
+ assert!(!meta.impls.is_empty());
+ for (k, v) in meta.impls.iter() {
+ assert_eq!(k, "python");
+ assert_eq!(v, &[path("foo.py"), path("bar.py")]);
+ }
+ }
+
+ fn path(s: &str) -> PathBuf {
+ PathBuf::from(s)
+ }
+}
+
/// Metadata of a document, as needed by Subplot.
#[derive(Debug)]
pub struct Metadata {